You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by er...@apache.org on 2004/09/28 20:55:17 UTC

svn commit: rev 47414 - incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto

Author: erodriguez
Date: Tue Sep 28 11:55:16 2004
New Revision: 47414

Added:
   incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/
   incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/Confounder.java
   incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/CryptoService.java
   incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/DesStringToKey.java
   incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/GlobalSequenceNumber.java
   incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/Nonce.java
   incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/SequenceNumber.java
Log:
kerberos crypto package

Added: incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/Confounder.java
==============================================================================
--- (empty file)
+++ incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/Confounder.java	Tue Sep 28 11:55:16 2004
@@ -0,0 +1,62 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.kerberos.crypto;
+
+import java.security.*;
+
+public class Confounder {
+	
+	private static final SecureRandom random = new SecureRandom();
+	
+	public static synchronized byte[] bytes(int size) {
+		return bytes(size, false);
+	}
+	
+	public static synchronized byte[] bytes(int size, boolean testMode) {
+		
+		/*
+		 * Use setSeed call to improve unit test performance or else
+		 * the first call to SecureRandom may take a second.
+		 * 
+		 * TODO - consider removing testMode; in practice, I haven't found
+		 *        SecureRandom to start slowly at all
+		 */
+		if (testMode)
+			random.setSeed("testModeSeedString".getBytes());
+		
+		byte[] bytes = new byte[size];
+		random.nextBytes(bytes);
+		return bytes;
+	}
+
+	public static synchronized int intValue() {
+		byte[] data = Confounder.bytes(4);
+		int result = 0;
+		for (int i = 0; i < 4; i++)
+			result += data[i] * (16 ^ i);
+		return result;
+	}
+
+	public static synchronized long longValue() {
+		byte[] data = Confounder.bytes(4);
+		long result = 0;
+		for (int i = 0; i < 8; i++)
+			result += (data[i]) * (16L ^ i);
+		return result;
+	}
+}
+

Added: incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/CryptoService.java
==============================================================================
--- (empty file)
+++ incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/CryptoService.java	Tue Sep 28 11:55:16 2004
@@ -0,0 +1,167 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.kerberos.crypto;
+
+import org.apache.kerberos.crypto.checksum.*;
+import org.apache.kerberos.crypto.encryption.*;
+import org.apache.kerberos.kdc.*;
+import org.apache.kerberos.messages.value.*;
+import org.apache.kerberos.util.*;
+
+import java.util.*;
+
+public class CryptoService {
+
+	private static final Map _encryptionEngines = new HashMap();
+	private static final Map _checksumEngines   = new HashMap();
+	
+	// TODO - these maps are classic configuration and, as such, probably belong elsewhere
+	public CryptoService() {
+		_encryptionEngines.put(EncryptionType.NULL,        new NullEncryption());
+		_encryptionEngines.put(EncryptionType.DES_CBC_CRC, new DesCbcCrcEncryption());
+		_encryptionEngines.put(EncryptionType.DES_CBC_MD4, new DesCbcMd4Encryption());
+		_encryptionEngines.put(EncryptionType.DES_CBC_MD5, new DesCbcMd5Encryption());
+		
+		_checksumEngines.put(ChecksumType.CRC32,   new Crc32Checksum());
+		_checksumEngines.put(ChecksumType.RSA_MD4, new RsaMd4Checksum());
+		_checksumEngines.put(ChecksumType.RSA_MD5, new RsaMd5Checksum());
+		_checksumEngines.put(ChecksumType.SHA1,    new Sha1Checksum());
+	}
+
+	public static ChecksumEngine getInstance(ChecksumType type) throws KerberosException {
+		if (!_checksumEngines.containsKey(type))
+			throw KerberosException.KDC_ERR_SUMTYPE_NOSUPP;
+		return (ChecksumEngine)_checksumEngines.get(type);
+	}
+	
+	public static EncryptionEngine getInstance(EncryptionType type) throws KerberosException {
+		if (!_encryptionEngines.containsKey(type))
+			throw KerberosException.KDC_ERR_ETYPE_NOSUPP;
+		return (EncryptionEngine)_encryptionEngines.get(type);
+	}
+	
+	public static EncryptionType getBestEncryptionType(EncryptionType[] requestedTypes) {
+		
+		for (int i = 0; i < requestedTypes.length; i++) {
+			for (int j = 0; j < LocalConfig.DEFAULT_ETYPE_LIST.length; j++) {
+				if (requestedTypes[i] == LocalConfig.DEFAULT_ETYPE_LIST[j])
+					return LocalConfig.DEFAULT_ETYPE_LIST[j];
+			}
+		}
+		return LocalConfig.DEFAULT_ETYPE;
+	}
+	
+	public static EncryptionKey getNewSessionKey() {
+		byte[] confounder = Confounder.bytes(8);
+		DesStringToKey subSessionKey = new DesStringToKey(new String(confounder));
+		return new EncryptionKey(EncryptionType.DES_CBC_MD5, subSessionKey.getKey());
+	}
+
+	public static byte[] getEncryptedTimestamp(EncryptionKey key, Date date)
+			throws KerberosException {
+		EncryptionEngine encryptionEngine = getInstance(key.getKeyType());
+		byte[] plaintext = ConversionUtils.long2octet(date.getTime());
+		return encryptionEngine.encrypt(plaintext, key.getKeyValue());
+	}
+
+	public byte[] encrypt(EncryptionKey key, byte[] plaintext) throws KerberosException {
+		EncryptionEngine encryptionEngine = getInstance(key.getKeyType());
+		return encryptionEngine.encrypt(plaintext, key.getKeyValue());
+	}
+
+	public EncryptionKey getEncryptionKey(String username, String password, String realm) {
+		DesStringToKey key = new DesStringToKey(username, password, realm);
+		byte[] keyBytes = key.getKey();
+		return new EncryptionKey(EncryptionType.DES_CBC_MD5, keyBytes);
+	}
+
+	public byte[] decrypt(EncryptionKey key, EncryptedData data) throws KerberosException {
+		// TODO - check for matching encryptionType and keyVersion
+		EncryptionEngine type = getInstance(key.getKeyType());
+		
+		byte[] decTicketPart = type.decrypt(data.getCipherText(), key.getKeyValue());
+		
+		byte[] asn1ticket = removeBytes(decTicketPart, type.confounderSize(), type.checksumSize());
+		
+		return asn1ticket;
+	}
+	
+	public EncryptedData getEncryptedData(EncryptionKey key, byte[] plainText)
+			throws KerberosException {
+		
+		EncryptionEngine type = getInstance(key.getKeyType());
+		
+		byte[] conFounder      = Confounder.bytes(type.confounderSize());
+		byte[] zeroedChecksum  = new byte[type.checksumSize()];
+		byte[] dataBytes       = concatenateBytes(conFounder, concatenateBytes(zeroedChecksum,
+				padString(plainText)));
+		byte[] checksumBytes   = type.calculateChecksum(dataBytes);
+		byte[] paddedDataBytes = padString(dataBytes);
+		for (int i = type.confounderSize(); i < type.confounderSize() + type.checksumSize(); i++)
+			paddedDataBytes[i] = checksumBytes[i - type.confounderSize()];
+		byte[] encryptedData   = encrypt(key, paddedDataBytes);
+		
+		return new EncryptedData(type.encryptionType(), key.getKeyVersion(), encryptedData);
+	}
+	
+	// TODO - The classes below are key production util code and I can picture them moving
+	//        to a key production base class when I add DES3 and/or AES support.
+	
+	private byte[] padString(byte encodedString[]) {
+		int x;
+		if (encodedString.length < 8)
+			x = encodedString.length;
+		else
+			x = encodedString.length % 8;
+
+		if (x == 0)
+			return encodedString;
+
+		byte paddedByteArray[] = new byte[(8 - x) + encodedString.length];
+		for (int y = paddedByteArray.length - 1; y > encodedString.length - 1; y--)
+			paddedByteArray[y] = 0;
+
+		System.arraycopy(encodedString, 0, paddedByteArray, 0, encodedString.length);
+
+		return paddedByteArray;
+	}
+
+	private byte[] concatenateBytes(byte[] array1, byte[] array2) {
+		byte concatenatedBytes[] = new byte[array1.length + array2.length];
+
+		for (int i = 0; i < array1.length; i++)
+			concatenatedBytes[i] = array1[i];
+
+		for (int j = array1.length; j < concatenatedBytes.length; j++)
+			concatenatedBytes[j] = array2[j - array1.length];
+
+		return concatenatedBytes;
+	}
+	
+	private byte[] removeBytes(byte[] array, int confounder, int checksum) {
+		byte lessBytes[] = new byte[array.length - confounder - checksum];
+		
+		int j = 0;
+		for (int i = confounder + checksum; i < array.length; i++) {
+			lessBytes[j] = array[i];
+			j++;
+		}
+
+		return lessBytes;
+	}
+}
+

Added: incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/DesStringToKey.java
==============================================================================
--- (empty file)
+++ incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/DesStringToKey.java	Tue Sep 28 11:55:16 2004
@@ -0,0 +1,173 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.kerberos.crypto;
+
+import org.bouncycastle.crypto.engines.*;
+import org.bouncycastle.crypto.modes.*;
+import org.bouncycastle.crypto.params.*;
+
+public class DesStringToKey {
+	
+	private byte[] _desKey;
+	
+	public DesStringToKey(String passPhrase) {
+		_desKey = generateKey(passPhrase);
+	}
+	
+	// This is the concatenation order as designated in RFC 1510
+	public DesStringToKey(String password, String realmName, String userName) {
+		_desKey = generateKey(password + realmName + userName);
+	}
+	
+	public byte[] getKey() {
+		return _desKey;
+	}
+	
+	private byte[] generateKey(String passPhrase) {
+
+		byte encodedByteArray[] = characterEncodeString(passPhrase);
+
+		byte paddedByteArray[] = padString(encodedByteArray);
+
+		byte secretKey[] = fanFold(paddedByteArray);
+		
+		DESParameters.setOddParity(secretKey);
+		
+		if (DESParameters.isWeakKey(secretKey, 0))
+			secretKey = getStrongKey(secretKey);
+
+		secretKey = encryptSecretKey(paddedByteArray, secretKey);
+
+		DESParameters.setOddParity(secretKey);
+
+		if (DESParameters.isWeakKey(secretKey, 0))
+			secretKey = getStrongKey(secretKey);
+		
+		return secretKey;
+	}
+
+	private byte[] fanFold(byte[] paddedByteArray) {
+		
+		byte secretKey[] = new byte[8];
+		
+		int i = paddedByteArray.length / 8;
+
+		for (int x = 0; x < i; x++) {
+			byte blockValue1[] = new byte[8];
+			System.arraycopy(paddedByteArray, x * 8, blockValue1, 0, 8);
+
+			if (x % 2 == 1) {
+				byte tempbyte1 = 0;
+				byte tempbyte2 = 0;
+				byte blockValue2[] = new byte[8];
+
+				for (int y = 0; y < 8; y++) {
+					tempbyte2 = 0;
+					for (int z = 0; z < 4; z++) {
+						tempbyte2 = (byte) ((1 << (7 - z)) & 0xff);
+						tempbyte1 |= (blockValue1[y] & tempbyte2) >>> (7 - 2 * z);
+						tempbyte2 = 0;
+					}
+					for (int z = 4; z < 8; z++) {
+						tempbyte2 = (byte) ((1 << (7 - z)) & 0xff);
+						tempbyte1 |= (blockValue1[y] & tempbyte2) << (2 * z - 7);
+						tempbyte2 = 0;
+					}
+					blockValue2[7 - y] = tempbyte1;
+					tempbyte1 = 0;
+				}
+
+				for (int a = 0; a < 8; a++)
+					blockValue2[a] = (byte) (((blockValue2[a] & 0xff) >>> 1) & 0xff);
+
+				System.arraycopy(blockValue2, 0, blockValue1, 0, blockValue2.length);
+			}
+
+			for (int a = 0; a < 8; a++)
+				blockValue1[a] = (byte) (((blockValue1[a] & 0xff) << 1) & 0xff);
+			
+			// ... eXclusive-ORed with itself to form an 8-byte DES key
+			for (int b = 0; b < 8; b++)
+				secretKey[b] ^= blockValue1[b];
+		}
+		return secretKey;
+	}
+	
+	// TODO - Re-evaluate when DES3 keys are supported.  This is duplicated
+	//        with parts of CryptoService, but makes this class standalone.
+	private byte[] encryptSecretKey(byte data[], byte key[]) {
+		
+		CBCBlockCipher cipher = new CBCBlockCipher(new DESEngine());
+		KeyParameter kp = new KeyParameter(key);
+		ParametersWithIV iv;
+		
+		iv = new ParametersWithIV(kp, key);
+		cipher.init(true, iv);
+
+		byte encKey[] = new byte[data.length];
+		byte ivBytes[] = new byte[8];
+
+		for (int x = 0; x < data.length / 8; x++) {
+			cipher.processBlock(data, x * 8, encKey, x * 8);
+			System.arraycopy(encKey, x * 8, ivBytes, 0, 8);
+			iv = new ParametersWithIV(kp, ivBytes);
+			cipher.init(true, iv);
+		}
+
+		return ivBytes;
+	}
+
+	// Corrects the weak key by exclusive OR with 0xF0 constant.
+	private byte[] getStrongKey(byte keyValue[]) {
+		keyValue[7] ^= 0xf0;
+		return keyValue;
+	}
+
+	// Encodes string with ISO-Latin encoding
+	private byte[] characterEncodeString(String str) {
+		byte encodedByteArray[] = new byte[str.length()];
+		try {
+			encodedByteArray = str.getBytes("8859_1");
+		} catch (java.io.UnsupportedEncodingException ue) {
+		}
+		return encodedByteArray;
+	}
+
+	// Add padding to make an exact multiple of 8.
+	// TODO - Re-evaluate when DES3 keys are supported.  This is duplicated
+	//        with parts of CryptoService, but makes this class standalone.
+	private byte[] padString(byte encodedString[]) {
+		int x;
+		if (encodedString.length < 8)
+			x = encodedString.length;
+		else
+			x = encodedString.length % 8;
+
+		if (x == 0)
+			return encodedString;
+
+		byte paddedByteArray[] = new byte[(8 - x) + encodedString.length];
+		for (int y = paddedByteArray.length - 1; y > encodedString.length - 1; y--)
+			paddedByteArray[y] = 0;
+
+		System.arraycopy(encodedString, 0, paddedByteArray, 0, encodedString.length);
+
+		return paddedByteArray;
+
+	}
+}
+

Added: incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/GlobalSequenceNumber.java
==============================================================================
--- (empty file)
+++ incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/GlobalSequenceNumber.java	Tue Sep 28 11:55:16 2004
@@ -0,0 +1,43 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.kerberos.crypto;
+
+public class GlobalSequenceNumber implements SequenceNumber {
+
+	private int _sequenceNumber = Confounder.intValue();
+
+	public GlobalSequenceNumber(int start) {
+		_sequenceNumber = start;
+	}
+	
+	public synchronized void init() {
+		_sequenceNumber = Confounder.intValue();
+	}
+	
+	public synchronized int current() {
+		return _sequenceNumber;
+	}
+
+	public synchronized int next() {
+		return _sequenceNumber + 1;
+	}
+	
+	public synchronized void step() {
+		_sequenceNumber++;
+	}
+}
+

Added: incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/Nonce.java
==============================================================================
--- (empty file)
+++ incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/Nonce.java	Tue Sep 28 11:55:16 2004
@@ -0,0 +1,32 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.kerberos.crypto;
+
+public class Nonce {
+	
+	private static int _nonce;
+
+	public static synchronized int getValue() {
+		int temp = (int)(System.currentTimeMillis() / 1000);
+		if (temp <= _nonce)
+			_nonce++;
+		else
+		    _nonce = temp;
+		return _nonce;
+	}
+}
+

Added: incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/SequenceNumber.java
==============================================================================
--- (empty file)
+++ incubator/directory/kerberos/trunk/source/java/org/apache/kerberos/crypto/SequenceNumber.java	Tue Sep 28 11:55:16 2004
@@ -0,0 +1,45 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.kerberos.crypto;
+
+/**
+ * Sequence number 
+ */
+public interface SequenceNumber {
+
+	/**
+	 * Random initialization
+	 */
+	public void init();
+	
+	/**
+	 * Returns current value
+	 */
+	public int current();
+	
+	/**
+	 * Returns next value
+	 */
+	public int next();
+	
+	/**
+	 * Increments the value
+	 */
+	public void step();
+
+}
+