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(); + +} +
