All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.filesys.server.auth.PasswordEncryptor Maven / Gradle / Ivy

Go to download

Java file server with SMB, FTP/FTPS and NFS support, virtual filesystems, database filesystems

There is a newer version: 1.4.0
Show newest version
/*
 * Copyright (C) 2006-2010 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see .
 */

package org.filesys.server.auth;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import org.filesys.debug.Debug;

/**
 * Password Encryptor Class
 *
 * 

* Generates LanMan and NTLMv1 encrypted passwords from the plain text password and challenge key. * * @author GKSpencer */ public class PasswordEncryptor { // Encryption algorithm types public static final int LANMAN = 0; public static final int NTLM1 = 1; public static final int NTLM2 = 2; public static final int MD4 = 3; // Encrpytion algorithm names private final static String[] _algNames = {"LanMan", "NTLMv1", "NTLMv2", "MD4"}; /** * Default constructor */ public PasswordEncryptor() { } /** * Check if the required algorithms are available * * @return boolean */ public static final boolean checkEncryptionAlgorithms() { boolean algOK = false; try { // Check if MD4 is available MessageDigest.getInstance("MD4"); // Check if DES is available Cipher.getInstance("DES"); // Check if HMAC-MD5 is available Mac.getInstance("HMACMD5"); // Indicate required algorithms are available algOK = true; } catch (NoSuchAlgorithmException ex) { } catch (NoSuchPaddingException ex) { } // Return the encryption algorithm status return algOK; } /** * Encrypt the plain text password with the specified encryption key using the specified * encryption algorithm. * * @param plainPwd Plaintext password string * @param encryptKey byte[] Encryption key * @param alg int Encryption algorithm * @param userName String * @param domain String * @return byte[] Encrypted password * @throws NoSuchAlgorithmException If a required encryption algorithm is not available * @throws InvalidKeyException Key is invalid */ public byte[] generateEncryptedPassword(String plainPwd, byte[] encryptKey, int alg, String userName, String domain) throws NoSuchAlgorithmException, InvalidKeyException { // Get the password String pwd = plainPwd; if (pwd == null) pwd = ""; // Determine the encryption algorithm byte[] encPwd = null; MessageDigest md4 = null; int len = 0; byte[] pwdBytes = null; switch (alg) { // LanMan DES encryption case LANMAN: encPwd = P24(pwd, encryptKey); break; // NTLM v1 encryption case NTLM1: // Create the MD4 hash md4 = MessageDigest.getInstance("MD4"); try { pwdBytes = pwd.getBytes("UnicodeLittleUnmarked"); } catch (UnsupportedEncodingException ex) { } md4.update(pwdBytes); byte[] p21 = new byte[21]; System.arraycopy(md4.digest(), 0, p21, 0, 16); // Now use the LM encryption encPwd = P24(p21, encryptKey); break; // NTLM v2 encryption case NTLM2: // Get the MD4 hash of the plaintext password byte[] md4Hash = generateEncryptedPassword(plainPwd, encryptKey, MD4, null, null); // HMAC-MD5 the username + domain string using the MD4 hash as the key Mac hmacMd5 = Mac.getInstance("HMACMD5"); SecretKeySpec key = new SecretKeySpec(md4Hash, 0, md4Hash.length, "MD5"); hmacMd5.init(key); // Build the username + domain string and convert to bytes StringBuffer str = new StringBuffer(); str.append(userName.toUpperCase()); str.append(domain.toUpperCase()); byte[] dataByts = null; try { // Convert the string to a byte array String dataStr = str.toString(); dataByts = dataStr.getBytes("UnicodeLittleUnmarked"); } catch (UnsupportedEncodingException ex) { } // Encrypt the username+domain bytes to generate the NTLMv2 hash encPwd = hmacMd5.doFinal(dataByts); break; // MD4 encryption case MD4: // Create the MD4 hash md4 = MessageDigest.getInstance("MD4"); len = pwd.length(); pwdBytes = new byte[len * 2]; for (int i = 0; i < len; i++) { char ch = pwd.charAt(i); pwdBytes[i * 2] = (byte) ch; pwdBytes[i * 2 + 1] = (byte) ((ch >> 8) & 0xFF); } md4.update(pwdBytes); encPwd = new byte[16]; System.arraycopy(md4.digest(), 0, encPwd, 0, 16); break; } // Return the encrypted password return encPwd; } /** * P16 encryption * * @param pwd java.lang.String * @param s8 byte[] * @return byte[] * @throws NoSuchAlgorithmException If a required encryption algorithm is not available */ public final byte[] P16(String pwd, byte[] s8) throws NoSuchAlgorithmException { // Make a 14 byte string using the password string. Truncate the // password or pad with nulls to 14 characters. StringBuffer p14str = new StringBuffer(); p14str.append(pwd.toUpperCase()); if (p14str.length() > 14) p14str.setLength(14); while (p14str.length() < 14) p14str.append((char) 0x00); // Convert the P14 string to an array of bytes. Allocate a 21 byte buffer as the result is // usually passed // through the P24() method byte[] p14 = p14str.toString().getBytes(); byte[] p16 = new byte[21]; try { // DES encrypt the password bytes using the challenge key Cipher des = Cipher.getInstance("DES"); // Set the encryption seed using the first 7 bytes of the password string. // Generate the first 8 bytes of the return value. byte[] key = generateKey(p14, 0); SecretKeySpec chKey = new SecretKeySpec(key, 0, key.length, "DES"); des.init(Cipher.ENCRYPT_MODE, chKey); byte[] res = des.doFinal(s8); System.arraycopy(res, 0, p16, 0, 8); // Encrypt the second block key = generateKey(p14, 7); chKey = new SecretKeySpec(key, 0, key.length, "DES"); des.init(Cipher.ENCRYPT_MODE, chKey); res = des.doFinal(s8); System.arraycopy(res, 0, p16, 8, 8); } catch (NoSuchPaddingException ex) { p16 = null; } catch (IllegalBlockSizeException ex) { p16 = null; } catch (BadPaddingException ex) { p16 = null; } catch (InvalidKeyException ex) { p16 = null; } // Return the 16 byte encrypted value return p16; } /** * P24 DES encryption * * @param pwd String * @param c8 byte[] * @return byte[] * @throws NoSuchAlgorithmException If a required encryption algorithm is not available */ private final byte[] P24(String pwd, byte[] c8) throws NoSuchAlgorithmException { // Generate the 16 byte encrypted value using the password string and well // known value. byte[] s8 = "KGS!@#$%".getBytes(); byte[] p16 = P16(pwd, s8); // Generate the 24 byte encrypted value return P24(p16, c8); } /** * P24 DES encryption * * @param p21 Plain password or hashed password bytes * @param ch Challenge bytes * @return Encrypted password * @throws NoSuchAlgorithmException If a required encryption algorithm is not available */ private final byte[] P24(byte[] p21, byte[] ch) throws NoSuchAlgorithmException { byte[] enc = null; try { // DES encrypt the password bytes using the challenge key Cipher des = Cipher.getInstance("DES"); // Allocate the output bytes enc = new byte[24]; // Encrypt the first block byte[] key = generateKey(p21, 0); SecretKeySpec chKey = new SecretKeySpec(key, 0, key.length, "DES"); des.init(Cipher.ENCRYPT_MODE, chKey); byte[] res = des.doFinal(ch); System.arraycopy(res, 0, enc, 0, 8); // Encrypt the second block key = generateKey(p21, 7); chKey = new SecretKeySpec(key, 0, key.length, "DES"); des.init(Cipher.ENCRYPT_MODE, chKey); res = des.doFinal(ch); System.arraycopy(res, 0, enc, 8, 8); // Encrypt the last block key = generateKey(p21, 14); chKey = new SecretKeySpec(key, 0, key.length, "DES"); des.init(Cipher.ENCRYPT_MODE, chKey); res = des.doFinal(ch); System.arraycopy(res, 0, enc, 16, 8); } catch (NoSuchPaddingException ex) { Debug.println(ex); enc = null; } catch (IllegalBlockSizeException ex) { Debug.println(ex); enc = null; } catch (BadPaddingException ex) { Debug.println(ex); enc = null; } catch (InvalidKeyException ex) { Debug.println(ex); enc = null; } // Return the encrypted password, or null if an error occurred return enc; } /** * Return the encryption algorithm as a string * * @param alg int * @return String */ public static String getAlgorithmName(int alg) { if (alg >= 0 && alg < _algNames.length) return _algNames[alg]; return "Unknown"; } /** * Make a 7-byte string into a 64 bit/8 byte/longword key. * * @param byt byte[] * @param off int * @return byte[] */ private byte[] generateKey(byte[] byt, int off) { // Allocate the key byte[] key = new byte[8]; // Make a key from the input string key[0] = (byte) (byt[off + 0] >> 1); key[1] = (byte) (((byt[off + 0] & 0x01) << 6) | ((byt[off + 1] & 0xFF) >> 2)); key[2] = (byte) (((byt[off + 1] & 0x03) << 5) | ((byt[off + 2] & 0xFF) >> 3)); key[3] = (byte) (((byt[off + 2] & 0x07) << 4) | ((byt[off + 3] & 0xFF) >> 4)); key[4] = (byte) (((byt[off + 3] & 0x0F) << 3) | ((byt[off + 4] & 0xFF) >> 5)); key[5] = (byte) (((byt[off + 4] & 0x1F) << 2) | ((byt[off + 5] & 0xFF) >> 6)); key[6] = (byte) (((byt[off + 5] & 0x3F) << 1) | ((byt[off + 6] & 0xFF) >> 7)); key[7] = (byte) (byt[off + 6] & 0x7F); for (int i = 0; i < 8; i++) { key[i] = (byte) (key[i] << 1); } return key; } /** * NTLM1 encryption of the MD4 hashed password * * @param p21 byte[] * @param c8 byte[] * @return byte[] * @throws NoSuchAlgorithmException If a required encryption algorithm is not available */ public final byte[] doNTLM1Encryption(byte[] p21, byte[] c8) throws NoSuchAlgorithmException { return P24(p21, c8); } /** * NTLM2 encryption of the MD4 hashed password * * @param md4Hash byte[] * @param userName String * @param domain String * @return byte[] * @exception NoSuchAlgorithmException If a required encryption algorithm is not available * @exception InvalidKeyException Invalid encryption key */ public final byte[] doNTLM2Encryption(byte[] md4Hash, String userName, String domain) throws NoSuchAlgorithmException, InvalidKeyException { // Use the MD4 hashed password as the key for HMAC-MD5 Mac hmacMd5 = Mac.getInstance("HMACMD5"); SecretKeySpec key = new SecretKeySpec(md4Hash, 0, md4Hash.length, "MD5"); hmacMd5.init(key); // Build the data to be encrypted StringBuffer str = new StringBuffer(); str.append(userName.toUpperCase()); // Client should sent the domain name as uppercase // Windows 11 can send the value 'MicrosoftAccount' which is case sensitive str.append(domain); String dataStr = str.toString(); byte[] dataByts = null; try { dataByts = dataStr.getBytes("UnicodeLittleUnmarked"); } catch (UnsupportedEncodingException ex) { } // Encrypt the data return hmacMd5.doFinal(dataByts); } /** * LanMan first stage of the encryption * * @param pwd String * @return byte[] * @throws NoSuchAlgorithmException If a required encryption algorithm is not available */ public final byte[] doLanManBaseEncryption(String pwd) throws NoSuchAlgorithmException { // Generate the 16 byte encrypted value using the password string and well // known value. byte[] s8 = "KGS!@#$%".getBytes(); return P16(pwd, s8); } /** * LanMan encryption of a password previously encrypted with the well known value * * @param p21 byte[] * @param c8 byte[] * @return byte[] * @throws NoSuchAlgorithmException If a required encryption algorithm is not available */ public final byte[] doLanManEncryption(byte[] p21, byte[] c8) throws NoSuchAlgorithmException { return P24(p21, c8); } /** * MD4 password hashinh * * @param pwdBytes byte[] * @return byte[] * @throws NoSuchAlgorithmException If a required encryption algorithm is not available * @throws InvalidKeyException Key not valid * */ public final byte[] doMD4Hashing(byte[] pwdBytes) throws NoSuchAlgorithmException, InvalidKeyException { // Create the MD4 hash MessageDigest md4 = MessageDigest.getInstance("MD4"); md4.update(pwdBytes); return md4.digest(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy