feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.internal.crypto.dk.AesDkCrypto;
import sun.security.krb5.KrbCryptoException;
import java.security.GeneralSecurityException;
/**
* Class with static methods for doing AES operations.
*
* @author Seema Malkani
*/
public class Aes128 {
private static final AesDkCrypto CRYPTO = new AesDkCrypto(128);
private Aes128() {
}
public static byte[] stringToKey(char[] password, String salt, byte[] params)
throws GeneralSecurityException {
return CRYPTO.stringToKey(password, salt, params);
}
// in bytes
public static int getChecksumLength() {
return CRYPTO.getChecksumLength();
}
public static byte[] calculateChecksum(byte[] baseKey, int usage,
byte[] input, int start, int len) throws GeneralSecurityException {
return CRYPTO.calculateChecksum(baseKey, usage, input, start, len);
}
public static byte[] encrypt(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encrypt(baseKey, usage, ivec, null /* new_ivec */,
plaintext, start, len);
}
/* Encrypt plaintext; do not add confounder, or checksum */
public static byte[] encryptRaw(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encryptRaw(baseKey, usage, ivec, plaintext, start, len);
}
public static byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
return CRYPTO.decrypt(baseKey, usage, ivec, ciphertext, start, len);
}
/* Decrypt ciphertext; do not remove confounder, or check checksum */
public static byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
return CRYPTO.decryptRaw(baseKey, usage, ivec, ciphertext, start, len);
}
};

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.GeneralSecurityException;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.Checksum;
/*
* This class encapsulates the encryption type for AES128
*
* @author Seema Malkani
*/
public final class Aes128CtsHmacSha1EType extends EType {
public int eType() {
return EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96;
}
public int minimumPadSize() {
return 0;
}
public int confounderSize() {
return blockSize();
}
public int checksumType() {
return Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128;
}
public int checksumSize() {
return Aes128.getChecksumLength();
}
public int blockSize() {
return 16;
}
public int keyType() {
return Krb5.KEYTYPE_AES;
}
public int keySize() {
return 16; // bytes
}
public byte[] encrypt(byte[] data, byte[] key, int usage)
throws KrbCryptoException {
byte[] ivec = new byte[blockSize()];
return encrypt(data, key, ivec, usage);
}
public byte[] encrypt(byte[] data, byte[] key, byte[] ivec, int usage)
throws KrbCryptoException {
try {
return Aes128.encrypt(key, usage, ivec, data, 0, data.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
public byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException, KrbCryptoException {
byte[] ivec = new byte[blockSize()];
return decrypt(cipher, key, ivec, usage);
}
public byte[] decrypt(byte[] cipher, byte[] key, byte[] ivec, int usage)
throws KrbApErrException, KrbCryptoException {
try {
return Aes128.decrypt(key, usage, ivec, cipher, 0, cipher.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
// Override default, because our decrypted data does not return confounder
// Should eventually get rid of EType.decryptedData and
// EncryptedData.decryptedData altogether
public byte[] decryptedData(byte[] data) {
return data;
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.internal.crypto.dk.AesDkCrypto;
import sun.security.krb5.KrbCryptoException;
import java.security.GeneralSecurityException;
/**
* Class with static methods for doing AES operations.
*
* @author Seema Malkani
*/
public class Aes256 {
private static final AesDkCrypto CRYPTO = new AesDkCrypto(256);
private Aes256() {
}
public static byte[] stringToKey(char[] password, String salt, byte[] params)
throws GeneralSecurityException {
return CRYPTO.stringToKey(password, salt, params);
}
// in bytes
public static int getChecksumLength() {
return CRYPTO.getChecksumLength();
}
public static byte[] calculateChecksum(byte[] baseKey, int usage,
byte[] input, int start, int len) throws GeneralSecurityException {
return CRYPTO.calculateChecksum(baseKey, usage, input, start, len);
}
public static byte[] encrypt(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encrypt(baseKey, usage, ivec, null /* new_ivec */,
plaintext, start, len);
}
/* Encrypt plaintext; do not add confounder, padding, or checksum */
public static byte[] encryptRaw(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encryptRaw(baseKey, usage, ivec, plaintext, start, len);
}
public static byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
return CRYPTO.decrypt(baseKey, usage, ivec, ciphertext, start, len);
}
/*
* Decrypt ciphertext; do not remove confounder, padding, or check
* checksum
*/
public static byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
return CRYPTO.decryptRaw(baseKey, usage, ivec, ciphertext, start, len);
}
};

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.GeneralSecurityException;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.Checksum;
/*
* This class encapsulates the encryption type for AES256
*
* @author Seema Malkani
*/
public final class Aes256CtsHmacSha1EType extends EType {
public int eType() {
return EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96;
}
public int minimumPadSize() {
return 0;
}
public int confounderSize() {
return blockSize();
}
public int checksumType() {
return Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256;
}
public int checksumSize() {
return Aes256.getChecksumLength();
}
public int blockSize() {
return 16;
}
public int keyType() {
return Krb5.KEYTYPE_AES;
}
public int keySize() {
return 32; // bytes
}
public byte[] encrypt(byte[] data, byte[] key, int usage)
throws KrbCryptoException {
byte[] ivec = new byte[blockSize()];
return encrypt(data, key, ivec, usage);
}
public byte[] encrypt(byte[] data, byte[] key, byte[] ivec, int usage)
throws KrbCryptoException {
try {
return Aes256.encrypt(key, usage, ivec, data, 0, data.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
public byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException, KrbCryptoException {
byte[] ivec = new byte[blockSize()];
return decrypt(cipher, key, ivec, usage);
}
public byte[] decrypt(byte[] cipher, byte[] key, byte[] ivec, int usage)
throws KrbApErrException, KrbCryptoException {
try {
return Aes256.decrypt(key, usage, ivec, cipher, 0, cipher.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
// Override default, because our decrypted data does not return confounder
// Should eventually get rid of EType.decryptedData and
// EncryptedData.decryptedData altogether
public byte[] decryptedData(byte[] data) {
return data;
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.internal.crypto.dk.ArcFourCrypto;
import sun.security.krb5.KrbCryptoException;
import java.security.GeneralSecurityException;
/**
* Class with static methods for doing RC4-HMAC operations.
*
* @author Seema Malkani
*/
public class ArcFourHmac {
private static final ArcFourCrypto CRYPTO = new ArcFourCrypto(128);
private ArcFourHmac() {
}
public static byte[] stringToKey(char[] password)
throws GeneralSecurityException {
return CRYPTO.stringToKey(password);
}
// in bytes
public static int getChecksumLength() {
return CRYPTO.getChecksumLength();
}
public static byte[] calculateChecksum(byte[] baseKey, int usage,
byte[] input, int start, int len) throws GeneralSecurityException {
return CRYPTO.calculateChecksum(baseKey, usage, input, start, len);
}
/* Encrypt Sequence Number */
public static byte[] encryptSeq(byte[] baseKey, int usage,
byte[] checksum, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encryptSeq(baseKey, usage, checksum, plaintext, start, len);
}
/* Decrypt Sequence Number */
public static byte[] decryptSeq(byte[] baseKey, int usage, byte[] checksum,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.decryptSeq(baseKey, usage, checksum, ciphertext, start, len);
}
public static byte[] encrypt(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encrypt(baseKey, usage, ivec, null /* new_ivec */,
plaintext, start, len);
}
/* Encrypt plaintext; do not add confounder, or checksum */
public static byte[] encryptRaw(byte[] baseKey, int usage,
byte[] seqNum, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encryptRaw(baseKey, usage, seqNum, plaintext, start, len);
}
public static byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
return CRYPTO.decrypt(baseKey, usage, ivec, ciphertext, start, len);
}
/* Decrypt ciphertext; do not remove confounder, or check checksum */
public static byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len, byte[] seqNum)
throws GeneralSecurityException {
return CRYPTO.decryptRaw(baseKey, usage, ivec, ciphertext, start, len, seqNum);
}
};

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.GeneralSecurityException;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.Checksum;
/*
* This class encapsulates the encryption type for RC4-HMAC
*
* @author Seema Malkani
*/
public final class ArcFourHmacEType extends EType {
public int eType() {
return EncryptedData.ETYPE_ARCFOUR_HMAC;
}
public int minimumPadSize() {
return 1;
}
public int confounderSize() {
return 8;
}
public int checksumType() {
return Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR;
}
public int checksumSize() {
return ArcFourHmac.getChecksumLength();
}
public int blockSize() {
return 1;
}
public int keyType() {
return Krb5.KEYTYPE_ARCFOUR_HMAC;
}
public int keySize() {
return 16; // bytes
}
public byte[] encrypt(byte[] data, byte[] key, int usage)
throws KrbCryptoException {
byte[] ivec = new byte[blockSize()];
return encrypt(data, key, ivec, usage);
}
public byte[] encrypt(byte[] data, byte[] key, byte[] ivec, int usage)
throws KrbCryptoException {
try {
return ArcFourHmac.encrypt(key, usage, ivec, data, 0, data.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
public byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException, KrbCryptoException {
byte[] ivec = new byte[blockSize()];
return decrypt(cipher, key, ivec, usage);
}
public byte[] decrypt(byte[] cipher, byte[] key, byte[] ivec, int usage)
throws KrbApErrException, KrbCryptoException {
try {
return ArcFourHmac.decrypt(key, usage, ivec, cipher, 0, cipher.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
// Override default, because our decrypted data does not return confounder
// Should eventually get rid of EType.decryptedData and
// EncryptedData.decryptedData altogether
public byte[] decryptedData(byte[] data) {
return data;
}
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
public abstract class CksumType {
private static boolean DEBUG = Krb5.DEBUG;
public static CksumType getInstance(int cksumTypeConst)
throws KdcErrException {
CksumType cksumType = null;
String cksumTypeName = null;
switch (cksumTypeConst) {
case Checksum.CKSUMTYPE_CRC32:
cksumType = new Crc32CksumType();
cksumTypeName = "sun.security.krb5.internal.crypto.Crc32CksumType";
break;
case Checksum.CKSUMTYPE_DES_MAC:
cksumType = new DesMacCksumType();
cksumTypeName = "sun.security.krb5.internal.crypto.DesMacCksumType";
break;
case Checksum.CKSUMTYPE_DES_MAC_K:
cksumType = new DesMacKCksumType();
cksumTypeName =
"sun.security.krb5.internal.crypto.DesMacKCksumType";
break;
case Checksum.CKSUMTYPE_RSA_MD5:
cksumType = new RsaMd5CksumType();
cksumTypeName = "sun.security.krb5.internal.crypto.RsaMd5CksumType";
break;
case Checksum.CKSUMTYPE_RSA_MD5_DES:
cksumType = new RsaMd5DesCksumType();
cksumTypeName =
"sun.security.krb5.internal.crypto.RsaMd5DesCksumType";
break;
case Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD:
cksumType = new HmacSha1Des3KdCksumType();
cksumTypeName =
"sun.security.krb5.internal.crypto.HmacSha1Des3KdCksumType";
break;
case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128:
cksumType = new HmacSha1Aes128CksumType();
cksumTypeName =
"sun.security.krb5.internal.crypto.HmacSha1Aes128CksumType";
break;
case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256:
cksumType = new HmacSha1Aes256CksumType();
cksumTypeName =
"sun.security.krb5.internal.crypto.HmacSha1Aes256CksumType";
break;
case Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR:
cksumType = new HmacMd5ArcFourCksumType();
cksumTypeName =
"sun.security.krb5.internal.crypto.HmacMd5ArcFourCksumType";
break;
// currently we don't support MD4.
case Checksum.CKSUMTYPE_RSA_MD4_DES_K:
// cksumType = new RsaMd4DesKCksumType();
// cksumTypeName =
// "sun.security.krb5.internal.crypto.RsaMd4DesKCksumType";
case Checksum.CKSUMTYPE_RSA_MD4:
// cksumType = new RsaMd4CksumType();
// linux box support rsamd4, how to solve conflict?
// cksumTypeName =
// "sun.security.krb5.internal.crypto.RsaMd4CksumType";
case Checksum.CKSUMTYPE_RSA_MD4_DES:
// cksumType = new RsaMd4DesCksumType();
// cksumTypeName =
// "sun.security.krb5.internal.crypto.RsaMd4DesCksumType";
default:
throw new KdcErrException(Krb5.KDC_ERR_SUMTYPE_NOSUPP);
}
if (DEBUG) {
System.out.println(">>> CksumType: " + cksumTypeName);
}
return cksumType;
}
public abstract int confounderSize();
public abstract int cksumType();
public abstract boolean isKeyed();
public abstract int cksumSize();
public abstract int keyType();
public abstract int keySize();
// Note: key and usage will be ignored for an unkeyed checksum.
public abstract byte[] calculateChecksum(byte[] data, int size,
byte[] key, int usage) throws KrbCryptoException;
// Note: key and usage will be ignored for an unkeyed checksum.
public abstract boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) throws KrbCryptoException;
public static boolean isChecksumEqual(byte[] cksum1, byte[] cksum2) {
if (cksum1 == cksum2)
return true;
if ((cksum1 == null && cksum2 != null) ||
(cksum1 != null && cksum2 == null))
return false;
if (cksum1.length != cksum2.length)
return false;
for (int i = 0; i < cksum1.length; i++)
if (cksum1[i] != cksum2[i])
return false;
return true;
}
}

View File

@@ -0,0 +1,93 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.*;
import sun.security.krb5.internal.*;
public class Crc32CksumType extends CksumType {
public Crc32CksumType() {
}
public int confounderSize() {
return 0;
}
public int cksumType() {
return Checksum.CKSUMTYPE_CRC32;
}
public boolean isKeyed() {
return false;
}
public int cksumSize() {
return 4;
}
public int keyType() {
return Krb5.KEYTYPE_NULL;
}
public int keySize() {
return 0;
}
public byte[] calculateChecksum(byte[] data, int size,
byte[] key, int usage) {
return crc32.byte2crc32sum_bytes(data, size);
}
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) {
return CksumType.isChecksumEqual(checksum,
crc32.byte2crc32sum_bytes(data));
}
public static byte[] int2quad(long input) {
byte[] output = new byte[4];
for (int i = 0; i < 4; i++) {
output[i] = (byte)((input >>> (i * 8)) & 0xff);
}
return output;
}
public static long bytes2long(byte[] input) {
long result = 0;
result |= (((long)input[0]) & 0xffL) << 24;
result |= (((long)input[1]) & 0xffL) << 16;
result |= (((long)input[2]) & 0xffL) << 8;
result |= (((long)input[3]) & 0xffL);
return result;
}
}

View File

@@ -0,0 +1,368 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;
import java.security.GeneralSecurityException;
import javax.crypto.spec.IvParameterSpec;
import sun.security.krb5.KrbCryptoException;
import java.util.Arrays;
import sun.security.action.GetPropertyAction;
public final class Des {
// RFC 3961 demands that UTF-8 encoding be used in DES's
// string-to-key function. For historical reasons, some
// implementations use a locale-specific encoding. Even
// so, when the client and server use different locales,
// they must agree on a common value, normally the one
// used when the password is set/reset.
//
// The following system property is provided to perform the
// string-to-key encoding. When set, the specified charset
// name is used. Otherwise, the system default charset.
private final static String CHARSET =
java.security.AccessController.doPrivileged(
new GetPropertyAction("sun.security.krb5.msinterop.des.s2kcharset"));
private static final long[] bad_keys = {
0x0101010101010101L, 0xfefefefefefefefeL,
0x1f1f1f1f1f1f1f1fL, 0xe0e0e0e0e0e0e0e0L,
0x01fe01fe01fe01feL, 0xfe01fe01fe01fe01L,
0x1fe01fe00ef10ef1L, 0xe01fe01ff10ef10eL,
0x01e001e001f101f1L, 0xe001e001f101f101L,
0x1ffe1ffe0efe0efeL, 0xfe1ffe1ffe0efe0eL,
0x011f011f010e010eL, 0x1f011f010e010e01L,
0xe0fee0fef1fef1feL, 0xfee0fee0fef1fef1L
};
private static final byte[] good_parity = {
1, 1, 2, 2, 4, 4, 7, 7,
8, 8, 11, 11, 13, 13, 14, 14,
16, 16, 19, 19, 21, 21, 22, 22,
25, 25, 26, 26, 28, 28, 31, 31,
32, 32, 35, 35, 37, 37, 38, 38,
41, 41, 42, 42, 44, 44, 47, 47,
49, 49, 50, 50, 52, 52, 55, 55,
56, 56, 59, 59, 61, 61, 62, 62,
64, 64, 67, 67, 69, 69, 70, 70,
73, 73, 74, 74, 76, 76, 79, 79,
81, 81, 82, 82, 84, 84, 87, 87,
88, 88, 91, 91, 93, 93, 94, 94,
97, 97, 98, 98, 100, 100, 103, 103,
104, 104, 107, 107, 109, 109, 110, 110,
112, 112, 115, 115, 117, 117, 118, 118,
121, 121, 122, 122, 124, 124, 127, 127,
(byte)128, (byte)128, (byte)131, (byte)131,
(byte)133, (byte)133, (byte)134, (byte)134,
(byte)137, (byte)137, (byte)138, (byte)138,
(byte)140, (byte)140, (byte)143, (byte)143,
(byte)145, (byte)145, (byte)146, (byte)146,
(byte)148, (byte)148, (byte)151, (byte)151,
(byte)152, (byte)152, (byte)155, (byte)155,
(byte)157, (byte)157, (byte)158, (byte)158,
(byte)161, (byte)161, (byte)162, (byte)162,
(byte)164, (byte)164, (byte)167, (byte)167,
(byte)168, (byte)168, (byte)171, (byte)171,
(byte)173, (byte)173, (byte)174, (byte)174,
(byte)176, (byte)176, (byte)179, (byte)179,
(byte)181, (byte)181, (byte)182, (byte)182,
(byte)185, (byte)185, (byte)186, (byte)186,
(byte)188, (byte)188, (byte)191, (byte)191,
(byte)193, (byte)193, (byte)194, (byte)194,
(byte)196, (byte)196, (byte)199, (byte)199,
(byte)200, (byte)200, (byte)203, (byte)203,
(byte)205, (byte)205, (byte)206, (byte)206,
(byte)208, (byte)208, (byte)211, (byte)211,
(byte)213, (byte)213, (byte)214, (byte)214,
(byte)217, (byte)217, (byte)218, (byte)218,
(byte)220, (byte)220, (byte)223, (byte)223,
(byte)224, (byte)224, (byte)227, (byte)227,
(byte)229, (byte)229, (byte)230, (byte)230,
(byte)233, (byte)233, (byte)234, (byte)234,
(byte)236, (byte)236, (byte)239, (byte)239,
(byte)241, (byte)241, (byte)242, (byte)242,
(byte)244, (byte)244, (byte)247, (byte)247,
(byte)248, (byte)248, (byte)251, (byte)251,
(byte)253, (byte)253, (byte)254, (byte)254
};
public static final byte[] set_parity(byte[] key) {
for (int i=0; i < 8; i++) {
key[i] = good_parity[key[i] & 0xff];
}
return key;
}
public static final long set_parity(long key) {
return octet2long(set_parity(long2octet(key)));
}
public static final boolean bad_key(long key) {
for (int i = 0; i < bad_keys.length; i++) {
if (bad_keys[i] == key) {
return true;
}
}
return false;
}
public static final boolean bad_key(byte[] key) {
return bad_key(octet2long(key));
}
public static long octet2long(byte[] input) {
return octet2long(input, 0);
}
public static long octet2long(byte[] input, int offset) { //convert a 8-byte to a long
long result = 0;
for (int i = 0; i < 8; i++) {
if (i + offset < input.length) {
result |= (((long)input[i + offset]) & 0xffL) << ((7 - i) * 8);
}
}
return result;
}
public static byte[] long2octet(long input) {
byte[] output = new byte[8];
for (int i = 0; i < 8; i++) {
output[i] = (byte)((input >>> ((7 - i) * 8)) & 0xffL);
}
return output;
}
public static void long2octet(long input, byte[] output) {
long2octet(input, output, 0);
}
public static void long2octet(long input, byte[] output, int offset) {
for (int i = 0; i < 8; i++) {
if (i + offset < output.length) {
output[i + offset] =
(byte)((input >>> ((7 - i) * 8)) & 0xffL);
}
}
}
/**
* Creates a DES cipher in Electronic Codebook mode, with no padding.
* @param input plain text.
* @param output the buffer for the result.
* @param key DES the key to encrypt the text.
* @param ivec initialization vector.
*
* @created by Yanni Zhang, Dec 6 99.
*/
public static void cbc_encrypt (
byte[] input,
byte[] output,
byte[] key,
byte[] ivec,
boolean encrypt) throws KrbCryptoException {
Cipher cipher = null;
try {
cipher = Cipher.getInstance("DES/CBC/NoPadding");
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException("JCE provider may not be installed. "
+ e.getMessage());
ke.initCause(e);
throw ke;
}
IvParameterSpec params = new IvParameterSpec(ivec);
SecretKeySpec skSpec = new SecretKeySpec(key, "DES");
try {
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
// SecretKey sk = skf.generateSecret(skSpec);
SecretKey sk = (SecretKey) skSpec;
if (encrypt)
cipher.init(Cipher.ENCRYPT_MODE, sk, params);
else
cipher.init(Cipher.DECRYPT_MODE, sk, params);
byte[] result;
result = cipher.doFinal(input);
System.arraycopy(result, 0, output, 0, result.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
/**
* Generates DES key from the password.
* @param passwdChars a char[] used to create the key.
* @return DES key.
*
* @modified by Yanni Zhang, Dec 6, 99
*/
public static long char_to_key(char[] passwdChars) throws KrbCryptoException {
long key = 0;
long octet, octet1, octet2 = 0;
byte[] cbytes = null;
// Convert password to byte array
try {
if (CHARSET == null) {
cbytes = (new String(passwdChars)).getBytes();
} else {
cbytes = (new String(passwdChars)).getBytes(CHARSET);
}
} catch (Exception e) {
// clear-up sensitive information
if (cbytes != null) {
Arrays.fill(cbytes, 0, cbytes.length, (byte) 0);
}
KrbCryptoException ce =
new KrbCryptoException("Unable to convert passwd, " + e);
ce.initCause(e);
throw ce;
}
// pad data
byte[] passwdBytes = pad(cbytes);
byte[] newkey = new byte[8];
int length = (passwdBytes.length / 8) + (passwdBytes.length % 8 == 0 ? 0 : 1);
for (int i = 0; i < length; i++) {
octet = octet2long(passwdBytes, i * 8) & 0x7f7f7f7f7f7f7f7fL;
if (i % 2 == 1) {
octet1 = 0;
for (int j = 0; j < 64; j++) {
octet1 |= ((octet & (1L << j)) >>> j) << (63 - j);
}
octet = octet1 >>> 1;
}
key ^= (octet << 1);
}
key = set_parity(key);
if (bad_key(key)) {
byte [] temp = long2octet(key);
temp[7] ^= 0xf0;
key = octet2long(temp);
}
newkey = des_cksum(long2octet(key), passwdBytes, long2octet(key));
key = octet2long(set_parity(newkey));
if (bad_key(key)) {
byte [] temp = long2octet(key);
temp[7] ^= 0xf0;
key = octet2long(temp);
}
// clear-up sensitive information
if (cbytes != null) {
Arrays.fill(cbytes, 0, cbytes.length, (byte) 0);
}
if (passwdBytes != null) {
Arrays.fill(passwdBytes, 0, passwdBytes.length, (byte) 0);
}
return key;
}
/**
* Encrypts the message blocks using DES CBC and output the
* final block of 8-byte ciphertext.
* @param ivec Initialization vector.
* @param msg Input message as an byte array.
* @param key DES key to encrypt the message.
* @return the last block of ciphertext.
*
* @created by Yanni Zhang, Dec 6, 99.
*/
public static byte[] des_cksum(byte[] ivec, byte[] msg, byte[] key) throws KrbCryptoException {
Cipher cipher = null;
byte[] result = new byte[8];
try{
cipher = Cipher.getInstance("DES/CBC/NoPadding");
} catch (Exception e) {
KrbCryptoException ke = new KrbCryptoException("JCE provider may not be installed. "
+ e.getMessage());
ke.initCause(e);
throw ke;
}
IvParameterSpec params = new IvParameterSpec(ivec);
SecretKeySpec skSpec = new SecretKeySpec(key, "DES");
try {
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
// SecretKey sk = skf.generateSecret(skSpec);
SecretKey sk = (SecretKey) skSpec;
cipher.init(Cipher.ENCRYPT_MODE, sk, params);
for (int i = 0; i < msg.length / 8; i++) {
result = cipher.doFinal(msg, i * 8, 8);
cipher.init(Cipher.ENCRYPT_MODE, sk, (new IvParameterSpec(result)));
}
}
catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
return result;
}
/**
* Pads the data so that its length is a multiple of 8 bytes.
* @param data the raw data.
* @return the data being padded.
*
* @created by Yanni Zhang, Dec 6 99. //Kerberos does not use PKCS5 padding.
*/
static byte[] pad(byte[] data) {
int len;
if (data.length < 8) len = data.length;
else len = data.length % 8;
if (len == 0) return data;
else {
byte[] padding = new byte[ 8 - len + data.length];
for (int i = padding.length - 1; i > data.length - 1; i--) {
padding[i] = 0;
}
System.arraycopy(data, 0, padding, 0, data.length);
return padding;
}
}
// Caller is responsible for clearing password
public static byte[] string_to_key_bytes(char[] passwdChars)
throws KrbCryptoException {
return long2octet(char_to_key(passwdChars));
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.internal.crypto.dk.Des3DkCrypto;
import sun.security.krb5.KrbCryptoException;
import java.security.GeneralSecurityException;
/**
* Class with static methods for doing Triple DES operations.
*/
public class Des3 {
private static final Des3DkCrypto CRYPTO = new Des3DkCrypto();
private Des3() {
}
public static byte[] stringToKey(char[] chars)
throws GeneralSecurityException {
return CRYPTO.stringToKey(chars);
}
public static byte[] parityFix(byte[] value)
throws GeneralSecurityException {
return CRYPTO.parityFix(value);
}
// in bytes
public static int getChecksumLength() {
return CRYPTO.getChecksumLength();
}
public static byte[] calculateChecksum(byte[] baseKey, int usage,
byte[] input, int start, int len) throws GeneralSecurityException {
return CRYPTO.calculateChecksum(baseKey, usage, input, start, len);
}
public static byte[] encrypt(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encrypt(baseKey, usage, ivec, null /* new_ivec */,
plaintext, start, len);
}
/* Encrypt plaintext; do not add confounder, padding, or checksum */
public static byte[] encryptRaw(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
return CRYPTO.encryptRaw(baseKey, usage, ivec, plaintext, start, len);
}
public static byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
return CRYPTO.decrypt(baseKey, usage, ivec, ciphertext, start, len);
}
/**
* Decrypt ciphertext; do not remove confounder, padding,
* or check checksum
*/
public static byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
return CRYPTO.decryptRaw(baseKey, usage, ivec, ciphertext, start, len);
}
};

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.GeneralSecurityException;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.Checksum;
public final class Des3CbcHmacSha1KdEType extends EType {
public int eType() {
return EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD;
}
public int minimumPadSize() {
return 0;
}
public int confounderSize() {
return blockSize();
}
public int checksumType() {
return Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD;
}
public int checksumSize() {
return Des3.getChecksumLength();
}
public int blockSize() {
return 8;
}
public int keyType() {
return Krb5.KEYTYPE_DES3;
}
public int keySize() {
return 24; // bytes
}
public byte[] encrypt(byte[] data, byte[] key, int usage)
throws KrbCryptoException {
byte[] ivec = new byte[blockSize()];
return encrypt(data, key, ivec, usage);
}
public byte[] encrypt(byte[] data, byte[] key, byte[] ivec, int usage)
throws KrbCryptoException {
try {
return Des3.encrypt(key, usage, ivec, data, 0, data.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
public byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException, KrbCryptoException{
byte[] ivec = new byte[blockSize()];
return decrypt(cipher, key, ivec, usage);
}
public byte[] decrypt(byte[] cipher, byte[] key, byte[] ivec, int usage)
throws KrbApErrException, KrbCryptoException {
try {
return Des3.decrypt(key, usage, ivec, cipher, 0, cipher.length);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
// Override default, because our decrypted data does not return confounder
// Should eventually get rid of EType.decryptedData and
// EncryptedData.decryptedData altogether
public byte[] decryptedData(byte[] data) {
return data;
}
}

View File

@@ -0,0 +1,92 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
public class DesCbcCrcEType extends DesCbcEType {
public DesCbcCrcEType() {
}
public int eType() {
return EncryptedData.ETYPE_DES_CBC_CRC;
}
public int minimumPadSize() {
return 4;
}
public int confounderSize() {
return 8;
}
public int checksumType() {
return Checksum.CKSUMTYPE_RSA_MD5;
}
public int checksumSize() {
return 4;
}
/**
* Encrypts data using DES in CBC mode with CRC32.
* @param data the data to be encrypted.
* @param key the secret key to encrypt the data. It is also used as initialization vector during cipher block chaining.
* @return the buffer for cipher text.
*
* @written by Yanni Zhang, Dec 10, 1999
*/
public byte[] encrypt(byte[] data, byte[] key, int usage)
throws KrbCryptoException {
return encrypt(data, key, key, usage);
}
/**
* Decrypts data with provided key using DES in CBC mode with CRC32.
* @param cipher the cipher text to be decrypted.
* @param key the secret key to decrypt the data.
*
* @written by Yanni Zhang, Dec 10, 1999
*/
public byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException, KrbCryptoException{
return decrypt(cipher, key, key, usage);
}
protected byte[] calculateChecksum(byte[] data, int size) {
return crc32.byte2crc32sum_bytes(data, size);
}
}

View File

@@ -0,0 +1,222 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Confounder;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
abstract class DesCbcEType extends EType {
protected abstract byte[] calculateChecksum(byte[] data, int size)
throws KrbCryptoException;
public int blockSize() {
return 8;
}
public int keyType() {
return Krb5.KEYTYPE_DES;
}
public int keySize() {
return 8;
}
/**
* Encrypts the data using DES in CBC mode.
* @param data the buffer for plain text.
* @param key the key to encrypt the data.
* @return the buffer for encrypted data.
*
* @written by Yanni Zhang, Dec 6 99.
*/
public byte[] encrypt(byte[] data, byte[] key, int usage)
throws KrbCryptoException {
byte[] ivec = new byte[keySize()];
return encrypt(data, key, ivec, usage);
}
/**
* Encrypts the data using DES in CBC mode.
* @param data the buffer for plain text.
* @param key the key to encrypt the data.
* @param ivec initialization vector.
* @return buffer for encrypted data.
*
* @modified by Yanni Zhang, Feb 24 00.
*/
public byte[] encrypt(byte[] data, byte[] key, byte[] ivec,
int usage) throws KrbCryptoException {
/*
* To meet export control requirements, double check that the
* key being used is no longer than 64 bits.
*
* Note that from a protocol point of view, an
* algorithm that is not DES will be rejected before this
* point. Also, a DES key that is not 64 bits will be
* rejected by a good implementations of JCE.
*/
if (key.length > 8)
throw new KrbCryptoException("Invalid DES Key!");
int new_size = data.length + confounderSize() + checksumSize();
byte[] new_data;
byte pad;
/*Data padding: using Kerberos 5 GSS-API mechanism (1.2.2.3), Jun 1996.
*Before encryption, plain text data is padded to the next highest multiple of blocksize.
*by appending between 1 and 8 bytes, the value of each such byte being the total number
*of pad bytes. For example, if new_size = 10, blockSize is 8, we should pad 2 bytes,
*and the value of each byte is 2.
*If plaintext data is a multiple of blocksize, we pad a 8 bytes of 8.
*/
if (new_size % blockSize() == 0) {
new_data = new byte[new_size + blockSize()];
pad = (byte)8;
}
else {
new_data = new byte[new_size + blockSize() - new_size % blockSize()];
pad = (byte)(blockSize() - new_size % blockSize());
}
for (int i = new_size; i < new_data.length; i++) {
new_data[i] = pad;
}
byte[] conf = Confounder.bytes(confounderSize());
System.arraycopy(conf, 0, new_data, 0, confounderSize());
System.arraycopy(data, 0, new_data, startOfData(), data.length);
byte[] cksum = calculateChecksum(new_data, new_data.length);
System.arraycopy(cksum, 0, new_data, startOfChecksum(),
checksumSize());
byte[] cipher = new byte[new_data.length];
Des.cbc_encrypt(new_data, cipher, key, ivec, true);
return cipher;
}
/**
* Decrypts the data using DES in CBC mode.
* @param cipher the input buffer.
* @param key the key to decrypt the data.
*
* @written by Yanni Zhang, Dec 6 99.
*/
public byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException, KrbCryptoException{
byte[] ivec = new byte[keySize()];
return decrypt(cipher, key, ivec, usage);
}
/**
* Decrypts the data using DES in CBC mode.
* @param cipher the input buffer.
* @param key the key to decrypt the data.
* @param ivec initialization vector.
*
* @modified by Yanni Zhang, Dec 6 99.
*/
public byte[] decrypt(byte[] cipher, byte[] key, byte[] ivec, int usage)
throws KrbApErrException, KrbCryptoException {
/*
* To meet export control requirements, double check that the
* key being used is no longer than 64 bits.
*
* Note that from a protocol point of view, an
* algorithm that is not DES will be rejected before this
* point. Also, a DES key that is not 64 bits will be
* rejected by a good JCE provider.
*/
if (key.length > 8)
throw new KrbCryptoException("Invalid DES Key!");
byte[] data = new byte[cipher.length];
Des.cbc_encrypt(cipher, data, key, ivec, false);
if (!isChecksumValid(data))
throw new KrbApErrException(Krb5.KRB_AP_ERR_BAD_INTEGRITY);
return data;
}
private void copyChecksumField(byte[] data, byte[] cksum) {
for (int i = 0; i < checksumSize(); i++)
data[startOfChecksum() + i] = cksum[i];
}
private byte[] checksumField(byte[] data) {
byte[] result = new byte[checksumSize()];
for (int i = 0; i < checksumSize(); i++)
result[i] = data[startOfChecksum() + i];
return result;
}
private void resetChecksumField(byte[] data) {
for (int i = startOfChecksum(); i < startOfChecksum() +
checksumSize(); i++)
data[i] = 0;
}
/*
// Not used.
public void setChecksum(byte[] data, int size) throws KrbCryptoException{
resetChecksumField(data);
byte[] cksum = calculateChecksum(data, size);
copyChecksumField(data, cksum);
}
*/
private byte[] generateChecksum(byte[] data) throws KrbCryptoException{
byte[] cksum1 = checksumField(data);
resetChecksumField(data);
byte[] cksum2 = calculateChecksum(data, data.length);
copyChecksumField(data, cksum1);
return cksum2;
}
private boolean isChecksumEqual(byte[] cksum1, byte[] cksum2) {
if (cksum1 == cksum2)
return true;
if ((cksum1 == null && cksum2 != null) ||
(cksum1 != null && cksum2 == null))
return false;
if (cksum1.length != cksum2.length)
return false;
for (int i = 0; i < cksum1.length; i++)
if (cksum1[i] != cksum2[i])
return false;
return true;
}
protected boolean isChecksumValid(byte[] data) throws KrbCryptoException {
byte[] cksum1 = checksumField(data);
byte[] cksum2 = generateChecksum(data);
return isChecksumEqual(cksum1, cksum2);
}
}

View File

@@ -0,0 +1,89 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.internal.*;
import sun.security.krb5.Checksum;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.KrbCryptoException;
import java.security.MessageDigest;
import java.security.Provider;
import java.security.Security;
public final class DesCbcMd5EType extends DesCbcEType {
public DesCbcMd5EType() {
}
public int eType() {
return EncryptedData.ETYPE_DES_CBC_MD5;
}
public int minimumPadSize() {
return 0;
}
public int confounderSize() {
return 8;
}
public int checksumType() {
return Checksum.CKSUMTYPE_RSA_MD5;
}
public int checksumSize() {
return 16;
}
/**
* Calculates checksum using MD5.
* @param data the input data.
* @param size the length of data.
* @return the checksum.
*
* @modified by Yanni Zhang, 12/06/99.
*/
protected byte[] calculateChecksum(byte[] data, int size)
throws KrbCryptoException {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
throw new KrbCryptoException("JCE provider may not be installed. " + e.getMessage());
}
try {
md5.update(data);
return(md5.digest());
} catch (Exception e) {
throw new KrbCryptoException(e.getMessage());
}
}
}

View File

@@ -0,0 +1,180 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.Confounder;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import javax.crypto.spec.DESKeySpec;
import java.security.InvalidKeyException;
public class DesMacCksumType extends CksumType {
public DesMacCksumType() {
}
public int confounderSize() {
return 8;
}
public int cksumType() {
return Checksum.CKSUMTYPE_DES_MAC;
}
public boolean isKeyed() {
return true;
}
public int cksumSize() {
return 16;
}
public int keyType() {
return Krb5.KEYTYPE_DES;
}
public int keySize() {
return 8;
}
/**
* Calculates keyed checksum.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @param key the key used to encrypt the checksum.
* @return keyed checksum.
*
* @modified by Yanni Zhang, 12/08/99.
*/
public byte[] calculateChecksum(byte[] data, int size, byte[] key,
int usage) throws KrbCryptoException {
byte[] new_data = new byte[size + confounderSize()];
byte[] conf = Confounder.bytes(confounderSize());
System.arraycopy(conf, 0, new_data, 0, confounderSize());
System.arraycopy(data, 0, new_data, confounderSize(), size);
//check for weak keys
try {
if (DESKeySpec.isWeak(key, 0)) {
key[7] = (byte)(key[7] ^ 0xF0);
}
} catch (InvalidKeyException ex) {
// swallow, since it should never happen
}
byte[] residue_ivec = new byte[key.length];
byte[] residue = Des.des_cksum(residue_ivec, new_data, key);
byte[] cksum = new byte[cksumSize()];
System.arraycopy(conf, 0, cksum, 0, confounderSize());
System.arraycopy(residue, 0, cksum, confounderSize(),
cksumSize() - confounderSize());
byte[] new_key = new byte[keySize()];
System.arraycopy(key, 0, new_key, 0, key.length);
for (int i = 0; i < new_key.length; i++)
new_key[i] = (byte)(new_key[i] ^ 0xf0);
//check for weak keys
try {
if (DESKeySpec.isWeak(new_key, 0)) {
new_key[7] = (byte)(new_key[7] ^ 0xF0);
}
} catch (InvalidKeyException ex) {
// swallow, since it should never happen
}
byte[] ivec = new byte[new_key.length];
//des-cbc encrypt
byte[] enc_cksum = new byte[cksum.length];
Des.cbc_encrypt(cksum, enc_cksum, new_key, ivec, true);
return enc_cksum;
}
/**
* Verifies keyed checksum.
* @param data the data.
* @param size the length of data.
* @param key the key used to encrypt the checksum.
* @param checksum the checksum.
* @return true if verification is successful.
*
* @modified by Yanni Zhang, 12/08/99.
*/
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
byte[] cksum = decryptKeyedChecksum(checksum, key);
byte[] new_data = new byte[size + confounderSize()];
System.arraycopy(cksum, 0, new_data, 0, confounderSize());
System.arraycopy(data, 0, new_data, confounderSize(), size);
//check for weak keys
try {
if (DESKeySpec.isWeak(key, 0)) {
key[7] = (byte)(key[7] ^ 0xF0);
}
} catch (InvalidKeyException ex) {
// swallow, since it should never happen
}
byte[] ivec = new byte[key.length];
byte[] new_cksum = Des.des_cksum(ivec, new_data, key);
byte[] orig_cksum = new byte[cksumSize() - confounderSize()];
System.arraycopy(cksum, confounderSize(), orig_cksum, 0,
cksumSize() - confounderSize());
return isChecksumEqual(orig_cksum, new_cksum);
}
/**
* Decrypts keyed checksum.
* @param enc_cksum the buffer for encrypted checksum.
* @param key the key.
* @return the checksum.
*
* @modified by Yanni Zhang, 12/08/99.
*/
private byte[] decryptKeyedChecksum(byte[] enc_cksum, byte[] key) throws KrbCryptoException {
byte[] new_key = new byte[keySize()];
System.arraycopy(key, 0, new_key, 0, key.length);
for (int i = 0; i < new_key.length; i++)
new_key[i] = (byte)(new_key[i] ^ 0xf0);
//check for weak keys
try {
if (DESKeySpec.isWeak(new_key, 0)) {
new_key[7] = (byte)(new_key[7] ^ 0xF0);
}
} catch (InvalidKeyException ex) {
// swallow, since it should never happen
}
byte[] ivec = new byte[new_key.length];
byte[] cksum = new byte[enc_cksum.length];
Des.cbc_encrypt(enc_cksum, cksum, new_key, ivec, false);
return cksum;
}
}

View File

@@ -0,0 +1,98 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import javax.crypto.spec.DESKeySpec;
import java.security.InvalidKeyException;
public class DesMacKCksumType extends CksumType {
public DesMacKCksumType() {
}
public int confounderSize() {
return 0;
}
public int cksumType() {
return Checksum.CKSUMTYPE_DES_MAC_K;
}
public boolean isKeyed() {
return true;
}
public int cksumSize() {
return 16;
}
public int keyType() {
return Krb5.KEYTYPE_DES;
}
public int keySize() {
return 8;
}
/**
* Calculates keyed checksum.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @param key the key used to encrypt the checksum.
* @return keyed checksum.
*
* @modified by Yanni Zhang, 12/08/99.
*/
public byte[] calculateChecksum(byte[] data, int size, byte[] key,
int usage) throws KrbCryptoException {
//check for weak keys
try {
if (DESKeySpec.isWeak(key, 0)) {
key[7] = (byte)(key[7] ^ 0xF0);
}
} catch (InvalidKeyException ex) {
// swallow, since it should never happen
}
byte[] ivec = new byte[key.length];
System.arraycopy(key, 0, ivec, 0, key.length);
byte[] cksum = Des.des_cksum(ivec, data, key);
return cksum;
}
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
byte[] new_cksum = calculateChecksum(data, data.length, key, usage);
return isChecksumEqual(checksum, new_cksum);
}
}

View File

@@ -0,0 +1,370 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.internal.*;
import sun.security.krb5.Config;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.EncryptionKey;
import sun.security.krb5.KrbException;
import sun.security.krb5.KrbCryptoException;
import javax.crypto.*;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
//only needed if dataSize() implementation changes back to spec;
//see dataSize() below
public abstract class EType {
private static final boolean DEBUG = Krb5.DEBUG;
private static boolean allowWeakCrypto;
static {
initStatic();
}
public static void initStatic() {
boolean allowed = false;
try {
Config cfg = Config.getInstance();
allowed = cfg.getBooleanObject("libdefaults", "allow_weak_crypto")
== Boolean.TRUE;
} catch (Exception exc) {
if (DEBUG) {
System.out.println ("Exception in getting allow_weak_crypto, " +
"using default value " +
exc.getMessage());
}
}
allowWeakCrypto = allowed;
}
public static EType getInstance (int eTypeConst)
throws KdcErrException {
EType eType = null;
String eTypeName = null;
switch (eTypeConst) {
case EncryptedData.ETYPE_NULL:
eType = new NullEType();
eTypeName = "sun.security.krb5.internal.crypto.NullEType";
break;
case EncryptedData.ETYPE_DES_CBC_CRC:
eType = new DesCbcCrcEType();
eTypeName = "sun.security.krb5.internal.crypto.DesCbcCrcEType";
break;
case EncryptedData.ETYPE_DES_CBC_MD5:
eType = new DesCbcMd5EType();
eTypeName = "sun.security.krb5.internal.crypto.DesCbcMd5EType";
break;
case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
eType = new Des3CbcHmacSha1KdEType();
eTypeName =
"sun.security.krb5.internal.crypto.Des3CbcHmacSha1KdEType";
break;
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
eType = new Aes128CtsHmacSha1EType();
eTypeName =
"sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType";
break;
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
eType = new Aes256CtsHmacSha1EType();
eTypeName =
"sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType";
break;
case EncryptedData.ETYPE_ARCFOUR_HMAC:
eType = new ArcFourHmacEType();
eTypeName = "sun.security.krb5.internal.crypto.ArcFourHmacEType";
break;
default:
String msg = "encryption type = " + toString(eTypeConst)
+ " (" + eTypeConst + ")";
throw new KdcErrException(Krb5.KDC_ERR_ETYPE_NOSUPP, msg);
}
if (DEBUG) {
System.out.println(">>> EType: " + eTypeName);
}
return eType;
}
public abstract int eType();
public abstract int minimumPadSize();
public abstract int confounderSize();
public abstract int checksumType();
public abstract int checksumSize();
public abstract int blockSize();
public abstract int keyType();
public abstract int keySize();
public abstract byte[] encrypt(byte[] data, byte[] key, int usage)
throws KrbCryptoException;
public abstract byte[] encrypt(byte[] data, byte[] key, byte[] ivec,
int usage) throws KrbCryptoException;
public abstract byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException, KrbCryptoException;
public abstract byte[] decrypt(byte[] cipher, byte[] key, byte[] ivec,
int usage) throws KrbApErrException, KrbCryptoException;
public int dataSize(byte[] data)
// throws Asn1Exception
{
// EncodeRef ref = new EncodeRef(data, startOfData());
// return ref.end - startOfData();
// should be the above according to spec, but in fact
// implementations include the pad bytes in the data size
return data.length - startOfData();
}
public int padSize(byte[] data) {
return data.length - confounderSize() - checksumSize() -
dataSize(data);
}
public int startOfChecksum() {
return confounderSize();
}
public int startOfData() {
return confounderSize() + checksumSize();
}
public int startOfPad(byte[] data) {
return confounderSize() + checksumSize() + dataSize(data);
}
public byte[] decryptedData(byte[] data) {
int tempSize = dataSize(data);
byte[] result = new byte[tempSize];
System.arraycopy(data, startOfData(), result, 0, tempSize);
return result;
}
// Note: the first 2 entries of BUILTIN_ETYPES and BUILTIN_ETYPES_NOAES256
// should be kept DES-related. They will be removed when allow_weak_crypto
// is set to false.
private static final int[] BUILTIN_ETYPES = new int[] {
EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96,
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
EncryptedData.ETYPE_ARCFOUR_HMAC,
EncryptedData.ETYPE_DES_CBC_CRC,
EncryptedData.ETYPE_DES_CBC_MD5,
};
private static final int[] BUILTIN_ETYPES_NOAES256 = new int[] {
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
EncryptedData.ETYPE_ARCFOUR_HMAC,
EncryptedData.ETYPE_DES_CBC_CRC,
EncryptedData.ETYPE_DES_CBC_MD5,
};
// used in Config
public static int[] getBuiltInDefaults() {
int allowed = 0;
try {
allowed = Cipher.getMaxAllowedKeyLength("AES");
} catch (Exception e) {
// should not happen
}
int[] result;
if (allowed < 256) {
result = BUILTIN_ETYPES_NOAES256;
} else {
result = BUILTIN_ETYPES;
}
if (!allowWeakCrypto) {
// The last 4 etypes are now weak ones
return Arrays.copyOfRange(result, 0, result.length - 4);
}
return result;
}
/**
* Retrieves the default etypes from the configuration file, or
* if that's not available, return the built-in list of default etypes.
* This result is always non-empty. If no etypes are found,
* an exception is thrown.
*/
public static int[] getDefaults(String configName)
throws KrbException {
Config config = null;
try {
config = Config.getInstance();
} catch (KrbException exc) {
if (DEBUG) {
System.out.println("Exception while getting " +
configName + exc.getMessage());
System.out.println("Using default builtin etypes");
}
return getBuiltInDefaults();
}
return config.defaultEtype(configName);
}
/**
* Retrieve the default etypes from the configuration file for
* those etypes for which there are corresponding keys.
* Used in scenario we have some keys from a keytab with etypes
* different from those named in configName. Then, in order
* to decrypt an AS-REP, we should only ask for etypes for which
* we have keys.
*/
public static int[] getDefaults(String configName, EncryptionKey[] keys)
throws KrbException {
int[] answer = getDefaults(configName);
List<Integer> list = new ArrayList<>(answer.length);
for (int i = 0; i < answer.length; i++) {
if (EncryptionKey.findKey(answer[i], keys) != null) {
list.add(answer[i]);
}
}
int len = list.size();
if (len <= 0) {
StringBuffer keystr = new StringBuffer();
for (int i = 0; i < keys.length; i++) {
keystr.append(toString(keys[i].getEType()));
keystr.append(" ");
}
throw new KrbException(
"Do not have keys of types listed in " + configName +
" available; only have keys of following type: " +
keystr.toString());
} else {
answer = new int[len];
for (int i = 0; i < len; i++) {
answer[i] = list.get(i);
}
return answer;
}
}
public static boolean isSupported(int eTypeConst, int[] config) {
for (int i = 0; i < config.length; i++) {
if (eTypeConst == config[i]) {
return true;
}
}
return false;
}
public static boolean isSupported(int eTypeConst) {
int[] enabledETypes = getBuiltInDefaults();
return isSupported(eTypeConst, enabledETypes);
}
/**
* https://tools.ietf.org/html/rfc4120#section-3.1.3:
*
* A "newer" enctype is any enctype first officially
* specified concurrently with or subsequent to the issue of this RFC.
* The enctypes DES, 3DES, or RC4 and any defined in [RFC1510] are not
* "newer" enctypes.
*
* @param eTypeConst the encryption type
* @return true if "newer"
*/
public static boolean isNewer(int eTypeConst) {
return eTypeConst != EncryptedData.ETYPE_DES_CBC_CRC &&
eTypeConst != EncryptedData.ETYPE_DES_CBC_MD4 &&
eTypeConst != EncryptedData.ETYPE_DES_CBC_MD5 &&
eTypeConst != EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD &&
eTypeConst != EncryptedData.ETYPE_ARCFOUR_HMAC &&
eTypeConst != EncryptedData.ETYPE_ARCFOUR_HMAC_EXP;
}
public static String toString(int type) {
switch (type) {
case 0:
return "NULL";
case 1:
return "DES CBC mode with CRC-32";
case 2:
return "DES CBC mode with MD4";
case 3:
return "DES CBC mode with MD5";
case 4:
return "reserved";
case 5:
return "DES3 CBC mode with MD5";
case 6:
return "reserved";
case 7:
return "DES3 CBC mode with SHA1";
case 9:
return "DSA with SHA1- Cms0ID";
case 10:
return "MD5 with RSA encryption - Cms0ID";
case 11:
return "SHA1 with RSA encryption - Cms0ID";
case 12:
return "RC2 CBC mode with Env0ID";
case 13:
return "RSA encryption with Env0ID";
case 14:
return "RSAES-0AEP-ENV-0ID";
case 15:
return "DES-EDE3-CBC-ENV-0ID";
case 16:
return "DES3 CBC mode with SHA1-KD";
case 17:
return "AES128 CTS mode with HMAC SHA1-96";
case 18:
return "AES256 CTS mode with HMAC SHA1-96";
case 23:
return "RC4 with HMAC";
case 24:
return "RC4 with HMAC EXP";
}
return "Unknown (" + type + ")";
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.GeneralSecurityException;
/**
* This class encapsulates the checksum type for HMAC RC4
*
* @author Seema Malkani
*/
public class HmacMd5ArcFourCksumType extends CksumType {
public HmacMd5ArcFourCksumType() {
}
public int confounderSize() {
return 8;
}
public int cksumType() {
return Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR;
}
public boolean isKeyed() {
return true;
}
public int cksumSize() {
return 16; // bytes
}
public int keyType() {
return Krb5.KEYTYPE_ARCFOUR_HMAC;
}
public int keySize() {
return 16; // bytes
}
/**
* Calculates keyed checksum.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @param key the key used to encrypt the checksum.
* @return keyed checksum.
*/
public byte[] calculateChecksum(byte[] data, int size, byte[] key,
int usage) throws KrbCryptoException {
try {
return ArcFourHmac.calculateChecksum(key, usage, data, 0, size);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
/**
* Verifies keyed checksum.
* @param data the data.
* @param size the length of data.
* @param key the key used to encrypt the checksum.
* @param checksum the checksum.
* @return true if verification is successful.
*/
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
try {
byte[] newCksum = ArcFourHmac.calculateChecksum(key, usage,
data, 0, size);
return isChecksumEqual(checksum, newCksum);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.GeneralSecurityException;
/*
* This class encapsulates the checksum type for AES128
*
* @author Seema Malkani
*/
public class HmacSha1Aes128CksumType extends CksumType {
public HmacSha1Aes128CksumType() {
}
public int confounderSize() {
return 16;
}
public int cksumType() {
return Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128;
}
public boolean isKeyed() {
return true;
}
public int cksumSize() {
return 12; // bytes
}
public int keyType() {
return Krb5.KEYTYPE_AES;
}
public int keySize() {
return 16; // bytes
}
/**
* Calculates keyed checksum.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @param key the key used to encrypt the checksum.
* @return keyed checksum.
*/
public byte[] calculateChecksum(byte[] data, int size, byte[] key,
int usage) throws KrbCryptoException {
try {
return Aes128.calculateChecksum(key, usage, data, 0, size);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
/**
* Verifies keyed checksum.
* @param data the data.
* @param size the length of data.
* @param key the key used to encrypt the checksum.
* @param checksum the checksum.
* @return true if verification is successful.
*/
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
try {
byte[] newCksum = Aes128.calculateChecksum(key, usage,
data, 0, size);
return isChecksumEqual(checksum, newCksum);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.GeneralSecurityException;
/*
* This class encapsulates the checksum type for AES256
*
* @author Seema Malkani
*/
public class HmacSha1Aes256CksumType extends CksumType {
public HmacSha1Aes256CksumType() {
}
public int confounderSize() {
return 16;
}
public int cksumType() {
return Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256;
}
public boolean isKeyed() {
return true;
}
public int cksumSize() {
return 12; // bytes
}
public int keyType() {
return Krb5.KEYTYPE_AES;
}
public int keySize() {
return 32; // bytes
}
/**
* Calculates keyed checksum.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @param key the key used to encrypt the checksum.
* @return keyed checksum.
*/
public byte[] calculateChecksum(byte[] data, int size, byte[] key,
int usage) throws KrbCryptoException {
try {
return Aes256.calculateChecksum(key, usage, data, 0, size);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
/**
* Verifies keyed checksum.
* @param data the data.
* @param size the length of data.
* @param key the key used to encrypt the checksum.
* @param checksum the checksum.
* @return true if verification is successful.
*/
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
try {
byte[] newCksum = Aes256.calculateChecksum(key, usage, data,
0, size);
return isChecksumEqual(checksum, newCksum);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.GeneralSecurityException;
public class HmacSha1Des3KdCksumType extends CksumType {
public HmacSha1Des3KdCksumType() {
}
public int confounderSize() {
return 8;
}
public int cksumType() {
return Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD;
}
public boolean isKeyed() {
return true;
}
public int cksumSize() {
return 20; // bytes
}
public int keyType() {
return Krb5.KEYTYPE_DES3;
}
public int keySize() {
return 24; // bytes
}
/**
* Calculates keyed checksum.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @param key the key used to encrypt the checksum.
* @return keyed checksum.
*/
public byte[] calculateChecksum(byte[] data, int size, byte[] key,
int usage) throws KrbCryptoException {
try {
return Des3.calculateChecksum(key, usage, data, 0, size);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
/**
* Verifies keyed checksum.
* @param data the data.
* @param size the length of data.
* @param key the key used to encrypt the checksum.
* @param checksum the checksum.
* @return true if verification is successful.
*/
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
try {
byte[] newCksum = Des3.calculateChecksum(key, usage,
data, 0, size);
return isChecksumEqual(checksum, newCksum);
} catch (GeneralSecurityException e) {
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
ke.initCause(e);
throw ke;
}
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.security.krb5.internal.crypto;
/**
* Key usages used for key derivation in Kerberos.
*/
public class KeyUsage {
private KeyUsage() {
}
public static final int KU_UNKNOWN = 0; // Cannot be 0
// Defined in draft-yu-krb-wg-kerberos-extensions-00.txt, Appendix A
public static final int KU_PA_ENC_TS = 1; // KrbAsReq
public static final int KU_TICKET = 2; // KrbApReq (ticket)
public static final int KU_ENC_AS_REP_PART = 3; // KrbAsRep
public static final int KU_TGS_REQ_AUTH_DATA_SESSKEY= 4; // KrbTgsReq
public static final int KU_TGS_REQ_AUTH_DATA_SUBKEY = 5; // KrbTgsReq
public static final int KU_PA_TGS_REQ_CKSUM = 6; // KrbTgsReq
public static final int KU_PA_TGS_REQ_AUTHENTICATOR = 7; // KrbApReq
public static final int KU_ENC_TGS_REP_PART_SESSKEY = 8; // KrbTgsRep
public static final int KU_ENC_TGS_REP_PART_SUBKEY = 9; // KrbTgsRep
public static final int KU_AUTHENTICATOR_CKSUM = 10;
public static final int KU_AP_REQ_AUTHENTICATOR = 11; // KrbApReq
public static final int KU_ENC_AP_REP_PART = 12; // KrbApRep
public static final int KU_ENC_KRB_PRIV_PART = 13; // KrbPriv
public static final int KU_ENC_KRB_CRED_PART = 14; // KrbCred
public static final int KU_KRB_SAFE_CKSUM = 15; // KrbSafe
public static final int KU_PA_FOR_USER_ENC_CKSUM = 17; // S4U2user
public static final int KU_AD_KDC_ISSUED_CKSUM = 19;
public static final int KU_AS_REQ = 56;
public static final boolean isValid(int usage) {
return usage >= 0;
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
public class Nonce {
public static synchronized int value() {
return sun.security.krb5.Confounder.intValue() & 0x7fffffff;
}
}

View File

@@ -0,0 +1,94 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.internal.*;
public class NullEType extends EType {
public NullEType() {
}
public int eType() {
return EncryptedData.ETYPE_NULL;
}
public int minimumPadSize() {
return 0;
}
public int confounderSize() {
return 0;
}
public int checksumType() {
return Checksum.CKSUMTYPE_NULL;
}
public int checksumSize() {
return 0;
}
public int blockSize() {
return 1;
}
public int keyType() {
return Krb5.KEYTYPE_NULL;
}
public int keySize() {
return 0;
}
public byte[] encrypt(byte[] data, byte[] key, int usage) {
byte[] cipher = new byte[data.length];
System.arraycopy(data, 0, cipher, 0, data.length);
return cipher;
}
public byte[] encrypt(byte[] data, byte[] key, byte[] ivec, int usage) {
byte[] cipher = new byte[data.length];
System.arraycopy(data, 0, cipher, 0, data.length);
return cipher;
}
public byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException {
return cipher.clone();
}
public byte[] decrypt(byte[] cipher, byte[] key, byte[] ivec, int usage)
throws KrbApErrException {
return cipher.clone();
}
}

View File

@@ -0,0 +1,104 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import java.security.MessageDigest;
public final class RsaMd5CksumType extends CksumType {
public RsaMd5CksumType() {
}
public int confounderSize() {
return 0;
}
public int cksumType() {
return Checksum.CKSUMTYPE_RSA_MD5;
}
public boolean isKeyed() {
return false;
}
public int cksumSize() {
return 16;
}
public int keyType() {
return Krb5.KEYTYPE_NULL;
}
public int keySize() {
return 0;
}
/**
* Calculates checksum using MD5.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @return the checksum.
*
* @modified by Yanni Zhang, 12/08/99.
*/
public byte[] calculateChecksum(byte[] data, int size,
byte[] key, int usage) throws KrbCryptoException{
MessageDigest md5;
byte[] result = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
throw new KrbCryptoException("JCE provider may not be installed. " + e.getMessage());
}
try {
md5.update(data);
result = md5.digest();
} catch (Exception e) {
throw new KrbCryptoException(e.getMessage());
}
return result;
}
@Override
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage)
throws KrbCryptoException {
try {
byte[] calculated = MessageDigest.getInstance("MD5").digest(data);
return CksumType.isChecksumEqual(calculated, checksum);
} catch (Exception e) {
return false;
}
}
}

View File

@@ -0,0 +1,196 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
package sun.security.krb5.internal.crypto;
import sun.security.krb5.Checksum;
import sun.security.krb5.Confounder;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.internal.*;
import javax.crypto.spec.DESKeySpec;
import java.security.MessageDigest;
import java.security.InvalidKeyException;
public final class RsaMd5DesCksumType extends CksumType {
public RsaMd5DesCksumType() {
}
public int confounderSize() {
return 8;
}
public int cksumType() {
return Checksum.CKSUMTYPE_RSA_MD5_DES;
}
public boolean isKeyed() {
return true;
}
public int cksumSize() {
return 24;
}
public int keyType() {
return Krb5.KEYTYPE_DES;
}
public int keySize() {
return 8;
}
/**
* Calculates keyed checksum.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @param key the key used to encrypt the checksum.
* @return keyed checksum.
*
* @modified by Yanni Zhang, 12/08/99.
*/
public byte[] calculateChecksum(byte[] data, int size, byte[] key,
int usage) throws KrbCryptoException {
//prepend confounder
byte[] new_data = new byte[size + confounderSize()];
byte[] conf = Confounder.bytes(confounderSize());
System.arraycopy(conf, 0, new_data, 0, confounderSize());
System.arraycopy(data, 0, new_data, confounderSize(), size);
//calculate md5 cksum
byte[] mdc_cksum = calculateRawChecksum(new_data, new_data.length);
byte[] cksum = new byte[cksumSize()];
System.arraycopy(conf, 0, cksum, 0, confounderSize());
System.arraycopy(mdc_cksum, 0, cksum, confounderSize(),
cksumSize() - confounderSize());
//compute modified key
byte[] new_key = new byte[keySize()];
System.arraycopy(key, 0, new_key, 0, key.length);
for (int i = 0; i < new_key.length; i++)
new_key[i] = (byte)(new_key[i] ^ 0xf0);
//check for weak keys
try {
if (DESKeySpec.isWeak(new_key, 0)) {
new_key[7] = (byte)(new_key[7] ^ 0xF0);
}
} catch (InvalidKeyException ex) {
// swallow, since it should never happen
}
byte[] ivec = new byte[new_key.length];
//des-cbc encrypt
byte[] enc_cksum = new byte[cksum.length];
Des.cbc_encrypt(cksum, enc_cksum, new_key, ivec, true);
return enc_cksum;
}
/**
* Verifies keyed checksum.
* @param data the data.
* @param size the length of data.
* @param key the key used to encrypt the checksum.
* @param checksum the checksum.
* @return true if verification is successful.
*
* @modified by Yanni Zhang, 12/08/99.
*/
public boolean verifyChecksum(byte[] data, int size,
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
//decrypt checksum
byte[] cksum = decryptKeyedChecksum(checksum, key);
//prepend confounder
byte[] new_data = new byte[size + confounderSize()];
System.arraycopy(cksum, 0, new_data, 0, confounderSize());
System.arraycopy(data, 0, new_data, confounderSize(), size);
byte[] new_cksum = calculateRawChecksum(new_data, new_data.length);
//extract original cksum value
byte[] orig_cksum = new byte[cksumSize() - confounderSize()];
System.arraycopy(cksum, confounderSize(), orig_cksum, 0,
cksumSize() - confounderSize());
return isChecksumEqual(orig_cksum, new_cksum);
}
/**
* Decrypts keyed checksum.
* @param enc_cksum the buffer for encrypted checksum.
* @param key the key.
* @return the checksum.
*
* @modified by Yanni Zhang, 12/08/99.
*/
private byte[] decryptKeyedChecksum(byte[] enc_cksum, byte[] key) throws KrbCryptoException {
//compute modified key
byte[] new_key = new byte[keySize()];
System.arraycopy(key, 0, new_key, 0, key.length);
for (int i = 0; i < new_key.length; i++)
new_key[i] = (byte)(new_key[i] ^ 0xf0);
//check for weak keys
try {
if (DESKeySpec.isWeak(new_key, 0)) {
new_key[7] = (byte)(new_key[7] ^ 0xF0);
}
} catch (InvalidKeyException ex) {
// swallow, since it should never happen
}
byte[] ivec = new byte[new_key.length];
byte[] cksum = new byte[enc_cksum.length];
Des.cbc_encrypt(enc_cksum, cksum, new_key, ivec, false);
return cksum;
}
/**
* Calculates checksum using MD5.
* @param data the data used to generate the checksum.
* @param size length of the data.
* @return the checksum.
*
* @modified by Yanni Zhang, 12/08/99.
*/
private byte[] calculateRawChecksum(byte[] data, int size) throws KrbCryptoException{
MessageDigest md5;
byte[] result = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
throw new KrbCryptoException("JCE provider may not be installed. " + e.getMessage());
}
try {
md5.update(data);
result = md5.digest();
} catch (Exception e) {
throw new KrbCryptoException(e.getMessage());
}
return result;
}
}

View File

@@ -0,0 +1,278 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
// crc32.java
package sun.security.krb5.internal.crypto;
import java.security.MessageDigestSpi;
import java.security.DigestException;
public final class crc32 extends MessageDigestSpi implements Cloneable {
private static final int CRC32_LENGTH = 4; //32-bit
private int seed;
private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG;
// buffer;
// private int bufferIndex, bufferLeft;
public crc32() {
init();
}
public Object clone() {
try {
crc32 crc = (crc32)super.clone();
crc.init();
return crc;
}
catch (CloneNotSupportedException e) {
}
return null;
}
/**
* Return the digest length in bytes
*/
protected int engineGetDigestLength() {
return (CRC32_LENGTH);
}
/**
*/
protected byte[] engineDigest() {
byte[] result = new byte[CRC32_LENGTH];
result = int2quad(seed);
//processBuffer(buffer, 0, bufferIndex, result, 0);
init();
return result;
}
/**
*/
protected int engineDigest(byte[] buf, int offset, int len) throws DigestException {
byte[] result = new byte[CRC32_LENGTH];
result = int2quad(seed);
if (len < CRC32_LENGTH) {
throw new DigestException("partial digests not returned");
}
if (buf.length - offset < CRC32_LENGTH) {
throw new DigestException("insufficient space in the output " +
"buffer to store the digest");
}
System.arraycopy(result, 0, buf, offset, CRC32_LENGTH);
//processBuffer(buffer, 0, bufferIndex, result, 0);
/*if (len < CRC32_LENGTH) {
throw new DigestException("partial digests not returned");
}
if (buf.length - offset < CRC32_LENGTH) {
throw new DigestException("insufficient space in the output " +
"buffer to store the digest");
}
System.arraycopy(result, 0, buf, offset, CRC32_LENGTH); */
init();
return CRC32_LENGTH;
}
/**
* Update adds the passed byte to the digested data.
*/
protected synchronized void engineUpdate(byte b) {
byte[] input = new byte[1];
input[0] = b;
//engineUpdate(input, 0, 1);
engineUpdate(input, seed, 1);
}
/**
* Update adds the selected part of an array of bytes to the digest.
* This version is more efficient than the byte-at-a-time version;
* it avoids data copies and reduces per-byte call overhead.
*/
protected synchronized void engineUpdate(byte input[], int offset,
int len) {
processData(input, offset, len);
}
private static int[] crc32Table = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
protected void engineReset() {
init();
}
/**
* Initialize the CRC32 information
*/
public void init() {
seed = 0;
}
private void processData(byte[] data, int off, int len) {
int result = seed;
for (int i = 0; i < len; i++)
result = (result >>> 8) ^ crc32Table[(result ^ data[i]) & 0xff];
seed = result;
}
public static int int2crc32(int b) {
int crc = b;
for (int i = 8; i > 0; i--) {
if ((crc & 1) != 0)
crc = (crc >>> 1) ^ 0xedb88320;
else
crc = crc >>> 1;
}
return crc;
}
public static void printcrc32Table() {
String temp;
String zerofill = "00000000";
System.out.print("\tpublic static int[] crc32Table = {");
for (int i = 0; i < 256; i++) {
if ((i % 4) == 0)
System.out.print("\n\t\t");
temp = Integer.toHexString(int2crc32(i));
System.out.print("0x" +
zerofill.substring(temp.length()) + temp);
if (i != 255)
System.out.print(", ");
}
System.out.println("\n\t};");
}
public static int byte2crc32sum(int seed, byte[] data, int size) {
int crc = seed;
for (int i = 0; i < size; i++)
crc = (crc >>> 8) ^ crc32Table[(crc ^ data[i]) & 0xff];
return crc;
}
public static int byte2crc32sum(int seed, byte[] data) {
return byte2crc32sum(seed, data, data.length);
}
//sum from zero, i.e., no pre- or post-conditioning
public static int byte2crc32sum(byte[] data) {
return byte2crc32sum(0, data);
}
//CCITT ITU-T 3309 CRC-32 w/ standard pre- and post-conditioning
public static int byte2crc32(byte[] data) {
return ~byte2crc32sum(0xffffffff, data);
}
public static byte[] byte2crc32sum_bytes(byte[] data) {
int temp = byte2crc32sum(data);
return int2quad(temp);
}
public static byte[] byte2crc32sum_bytes(byte[] data, int size) {
int temp = byte2crc32sum(0, data, size);
if (DEBUG) {
System.out.println(">>>crc32: " + Integer.toHexString(temp));
System.out.println(">>>crc32: " + Integer.toBinaryString(temp));
}
return int2quad(temp);
}
public static byte[] int2quad(long input) {
byte[] output = new byte[4];
for (int i = 0; i < 4; i++) {
output[i] = (byte)((input >>> (i * 8)) & 0xff);
}
return output;
}
}

View File

@@ -0,0 +1,501 @@
/*
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.security.krb5.internal.crypto.dk;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import java.security.spec.KeySpec;
import java.security.GeneralSecurityException;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.Confounder;
import sun.security.krb5.internal.crypto.KeyUsage;
import java.util.Arrays;
/**
* This class provides the implementation of AES Encryption for Kerberos
* as defined RFC 3962.
* http://www.ietf.org/rfc/rfc3962.txt
*
* Algorithm profile described in [KCRYPTO]:
* +--------------------------------------------------------------------+
* | protocol key format 128- or 256-bit string |
* | |
* | string-to-key function PBKDF2+DK with variable |
* | iteration count (see |
* | above) |
* | |
* | default string-to-key parameters 00 00 10 00 |
* | |
* | key-generation seed length key size |
* | |
* | random-to-key function identity function |
* | |
* | hash function, H SHA-1 |
* | |
* | HMAC output size, h 12 octets (96 bits) |
* | |
* | message block size, m 1 octet |
* | |
* | encryption/decryption functions, AES in CBC-CTS mode |
* | E and D (cipher block size 16 |
* | octets), with next to |
* | last block as CBC-style |
* | ivec |
* +--------------------------------------------------------------------+
*
* Supports AES128 and AES256
*
* @author Seema Malkani
*/
public class AesDkCrypto extends DkCrypto {
private static final boolean debug = false;
private static final int BLOCK_SIZE = 16;
private static final int DEFAULT_ITERATION_COUNT = 4096;
private static final byte[] ZERO_IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
private static final int hashSize = 96/8;
private final int keyLength;
public AesDkCrypto(int length) {
keyLength = length;
}
protected int getKeySeedLength() {
return keyLength; // bits; AES key material
}
public byte[] stringToKey(char[] password, String salt, byte[] s2kparams)
throws GeneralSecurityException {
byte[] saltUtf8 = null;
try {
saltUtf8 = salt.getBytes("UTF-8");
return stringToKey(password, saltUtf8, s2kparams);
} catch (Exception e) {
return null;
} finally {
if (saltUtf8 != null) {
Arrays.fill(saltUtf8, (byte)0);
}
}
}
private byte[] stringToKey(char[] secret, byte[] salt, byte[] params)
throws GeneralSecurityException {
int iter_count = DEFAULT_ITERATION_COUNT;
if (params != null) {
if (params.length != 4) {
throw new RuntimeException("Invalid parameter to stringToKey");
}
iter_count = readBigEndian(params, 0, 4);
}
byte[] tmpKey = randomToKey(PBKDF2(secret, salt, iter_count,
getKeySeedLength()));
byte[] result = dk(tmpKey, KERBEROS_CONSTANT);
return result;
}
protected byte[] randomToKey(byte[] in) {
// simple identity operation
return in;
}
protected Cipher getCipher(byte[] key, byte[] ivec, int mode)
throws GeneralSecurityException {
// IV
if (ivec == null) {
ivec = ZERO_IV;
}
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
IvParameterSpec encIv = new IvParameterSpec(ivec, 0, ivec.length);
cipher.init(mode, secretKey, encIv);
return cipher;
}
// get an instance of the AES Cipher in CTS mode
public int getChecksumLength() {
return hashSize; // bytes
}
/**
* Get the truncated HMAC
*/
protected byte[] getHmac(byte[] key, byte[] msg)
throws GeneralSecurityException {
SecretKey keyKi = new SecretKeySpec(key, "HMAC");
Mac m = Mac.getInstance("HmacSHA1");
m.init(keyKi);
// generate hash
byte[] hash = m.doFinal(msg);
// truncate hash
byte[] output = new byte[hashSize];
System.arraycopy(hash, 0, output, 0, hashSize);
return output;
}
/**
* Calculate the checksum
*/
public byte[] calculateChecksum(byte[] baseKey, int usage, byte[] input,
int start, int len) throws GeneralSecurityException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
// Derive keys
byte[] constant = new byte[5];
constant[0] = (byte) ((usage>>24)&0xff);
constant[1] = (byte) ((usage>>16)&0xff);
constant[2] = (byte) ((usage>>8)&0xff);
constant[3] = (byte) (usage&0xff);
constant[4] = (byte) 0x99;
byte[] Kc = dk(baseKey, constant); // Checksum key
if (debug) {
System.err.println("usage: " + usage);
traceOutput("input", input, start, Math.min(len, 32));
traceOutput("constant", constant, 0, constant.length);
traceOutput("baseKey", baseKey, 0, baseKey.length);
traceOutput("Kc", Kc, 0, Kc.length);
}
try {
// Generate checksum
// H1 = HMAC(Kc, input)
byte[] hmac = getHmac(Kc, input);
if (debug) {
traceOutput("hmac", hmac, 0, hmac.length);
}
if (hmac.length == getChecksumLength()) {
return hmac;
} else if (hmac.length > getChecksumLength()) {
byte[] buf = new byte[getChecksumLength()];
System.arraycopy(hmac, 0, buf, 0, buf.length);
return buf;
} else {
throw new GeneralSecurityException("checksum size too short: " +
hmac.length + "; expecting : " + getChecksumLength());
}
} finally {
Arrays.fill(Kc, 0, Kc.length, (byte)0);
}
}
/**
* Performs encryption using derived key; adds confounder.
*/
public byte[] encrypt(byte[] baseKey, int usage,
byte[] ivec, byte[] new_ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
byte[] output = encryptCTS(baseKey, usage, ivec, new_ivec, plaintext,
start, len, true);
return output;
}
/**
* Performs encryption using derived key; does not add confounder.
*/
public byte[] encryptRaw(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
byte[] output = encryptCTS(baseKey, usage, ivec, null, plaintext,
start, len, false);
return output;
}
/**
* @param baseKey key from which keys are to be derived using usage
* @param ciphertext E(Ke, conf | plaintext | padding, ivec) | H1[1..h]
*/
public byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len) throws GeneralSecurityException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
byte[] output = decryptCTS(baseKey, usage, ivec, ciphertext,
start, len, true);
return output;
}
/**
* Decrypts data using specified key and initial vector.
* @param baseKey encryption key to use
* @param ciphertext encrypted data to be decrypted
* @param usage ignored
*/
public byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
byte[] output = decryptCTS(baseKey, usage, ivec, ciphertext,
start, len, false);
return output;
}
/**
* Encrypt AES in CBC-CTS mode using derived keys.
*/
private byte[] encryptCTS(byte[] baseKey, int usage, byte[] ivec,
byte[] new_ivec, byte[] plaintext, int start, int len,
boolean confounder_exists)
throws GeneralSecurityException, KrbCryptoException {
byte[] Ke = null;
byte[] Ki = null;
if (debug) {
System.err.println("usage: " + usage);
if (ivec != null) {
traceOutput("old_state.ivec", ivec, 0, ivec.length);
}
traceOutput("plaintext", plaintext, start, Math.min(len, 32));
traceOutput("baseKey", baseKey, 0, baseKey.length);
}
try {
// derive Encryption key
byte[] constant = new byte[5];
constant[0] = (byte) ((usage>>24)&0xff);
constant[1] = (byte) ((usage>>16)&0xff);
constant[2] = (byte) ((usage>>8)&0xff);
constant[3] = (byte) (usage&0xff);
constant[4] = (byte) 0xaa;
Ke = dk(baseKey, constant); // Encryption key
byte[] toBeEncrypted = null;
if (confounder_exists) {
byte[] confounder = Confounder.bytes(BLOCK_SIZE);
toBeEncrypted = new byte[confounder.length + len];
System.arraycopy(confounder, 0, toBeEncrypted,
0, confounder.length);
System.arraycopy(plaintext, start, toBeEncrypted,
confounder.length, len);
} else {
toBeEncrypted = new byte[len];
System.arraycopy(plaintext, start, toBeEncrypted, 0, len);
}
// encryptedData + HMAC
byte[] output = new byte[toBeEncrypted.length + hashSize];
// AES in JCE
Cipher cipher = Cipher.getInstance("AES/CTS/NoPadding");
SecretKeySpec secretKey = new SecretKeySpec(Ke, "AES");
IvParameterSpec encIv = new IvParameterSpec(ivec, 0, ivec.length);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, encIv);
cipher.doFinal(toBeEncrypted, 0, toBeEncrypted.length, output);
// Derive integrity key
constant[4] = (byte) 0x55;
Ki = dk(baseKey, constant);
if (debug) {
traceOutput("constant", constant, 0, constant.length);
traceOutput("Ki", Ki, 0, Ke.length);
}
// Generate checksum
// H1 = HMAC(Ki, conf | plaintext | pad)
byte[] hmac = getHmac(Ki, toBeEncrypted);
// encryptedData + HMAC
System.arraycopy(hmac, 0, output, toBeEncrypted.length,
hmac.length);
return output;
} finally {
if (Ke != null) {
Arrays.fill(Ke, 0, Ke.length, (byte) 0);
}
if (Ki != null) {
Arrays.fill(Ki, 0, Ki.length, (byte) 0);
}
}
}
/**
* Decrypt AES in CBC-CTS mode using derived keys.
*/
private byte[] decryptCTS(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len, boolean confounder_exists)
throws GeneralSecurityException {
byte[] Ke = null;
byte[] Ki = null;
try {
// Derive encryption key
byte[] constant = new byte[5];
constant[0] = (byte) ((usage>>24)&0xff);
constant[1] = (byte) ((usage>>16)&0xff);
constant[2] = (byte) ((usage>>8)&0xff);
constant[3] = (byte) (usage&0xff);
constant[4] = (byte) 0xaa;
Ke = dk(baseKey, constant); // Encryption key
if (debug) {
System.err.println("usage: " + usage);
if (ivec != null) {
traceOutput("old_state.ivec", ivec, 0, ivec.length);
}
traceOutput("ciphertext", ciphertext, start, Math.min(len, 32));
traceOutput("constant", constant, 0, constant.length);
traceOutput("baseKey", baseKey, 0, baseKey.length);
traceOutput("Ke", Ke, 0, Ke.length);
}
// Decrypt [confounder | plaintext ] (without checksum)
// AES in JCE
Cipher cipher = Cipher.getInstance("AES/CTS/NoPadding");
SecretKeySpec secretKey = new SecretKeySpec(Ke, "AES");
IvParameterSpec encIv = new IvParameterSpec(ivec, 0, ivec.length);
cipher.init(Cipher.DECRYPT_MODE, secretKey, encIv);
byte[] plaintext = cipher.doFinal(ciphertext, start, len-hashSize);
if (debug) {
traceOutput("AES PlainText", plaintext, 0,
Math.min(plaintext.length, 32));
}
// Derive integrity key
constant[4] = (byte) 0x55;
Ki = dk(baseKey, constant); // Integrity key
if (debug) {
traceOutput("constant", constant, 0, constant.length);
traceOutput("Ki", Ki, 0, Ke.length);
}
// Verify checksum
// H1 = HMAC(Ki, conf | plaintext | pad)
byte[] calculatedHmac = getHmac(Ki, plaintext);
int hmacOffset = start + len - hashSize;
if (debug) {
traceOutput("calculated Hmac", calculatedHmac,
0, calculatedHmac.length);
traceOutput("message Hmac", ciphertext, hmacOffset, hashSize);
}
boolean cksumFailed = false;
if (calculatedHmac.length >= hashSize) {
for (int i = 0; i < hashSize; i++) {
if (calculatedHmac[i] != ciphertext[hmacOffset+i]) {
cksumFailed = true;
if (debug) {
System.err.println("Checksum failed !");
}
break;
}
}
}
if (cksumFailed) {
throw new GeneralSecurityException("Checksum failed");
}
if (confounder_exists) {
// Get rid of confounder
// [ confounder | plaintext ]
byte[] output = new byte[plaintext.length - BLOCK_SIZE];
System.arraycopy(plaintext, BLOCK_SIZE, output,
0, output.length);
return output;
} else {
return plaintext;
}
} finally {
if (Ke != null) {
Arrays.fill(Ke, 0, Ke.length, (byte) 0);
}
if (Ki != null) {
Arrays.fill(Ki, 0, Ki.length, (byte) 0);
}
}
}
/*
* Invoke the PKCS#5 PBKDF2 algorithm
*/
private static byte[] PBKDF2(char[] secret, byte[] salt,
int count, int keyLength) throws GeneralSecurityException {
PBEKeySpec keySpec = new PBEKeySpec(secret, salt, count, keyLength);
SecretKeyFactory skf =
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey key = skf.generateSecret(keySpec);
byte[] result = key.getEncoded();
return result;
}
public static final int readBigEndian(byte[] data, int pos, int size) {
int retVal = 0;
int shifter = (size-1)*8;
while (size > 0) {
retVal += (data[pos] & 0xff) << shifter;
shifter -= 8;
pos++;
size--;
}
return retVal;
}
}

View File

@@ -0,0 +1,482 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto.dk;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.*;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.KrbCryptoException;
import sun.security.krb5.Confounder;
import sun.security.krb5.internal.crypto.KeyUsage;
/**
* Support for ArcFour in Kerberos
* as defined in RFC 4757.
* http://www.ietf.org/rfc/rfc4757.txt
*
* @author Seema Malkani
*/
public class ArcFourCrypto extends DkCrypto {
private static final boolean debug = false;
private static final int confounderSize = 8;
private static final byte[] ZERO_IV = new byte[] {0, 0, 0, 0, 0, 0, 0, 0};
private static final int hashSize = 16;
private final int keyLength;
public ArcFourCrypto(int length) {
keyLength = length;
}
protected int getKeySeedLength() {
return keyLength; // bits; RC4 key material
}
protected byte[] randomToKey(byte[] in) {
// simple identity operation
return in;
}
public byte[] stringToKey(char[] passwd)
throws GeneralSecurityException {
return stringToKey(passwd, null);
}
/*
* String2Key(Password)
* K = MD4(UNICODE(password))
*/
private byte[] stringToKey(char[] secret, byte[] opaque)
throws GeneralSecurityException {
if (opaque != null && opaque.length > 0) {
throw new RuntimeException("Invalid parameter to stringToKey");
}
byte[] passwd = null;
byte[] digest = null;
try {
// convert ascii to unicode
passwd = charToUtf16(secret);
// provider for MD4
MessageDigest md = sun.security.provider.MD4.getInstance();
md.update(passwd);
digest = md.digest();
} catch (Exception e) {
return null;
} finally {
if (passwd != null) {
Arrays.fill(passwd, (byte)0);
}
}
return digest;
}
protected Cipher getCipher(byte[] key, byte[] ivec, int mode)
throws GeneralSecurityException {
// IV
if (ivec == null) {
ivec = ZERO_IV;
}
SecretKeySpec secretKey = new SecretKeySpec(key, "ARCFOUR");
Cipher cipher = Cipher.getInstance("ARCFOUR");
IvParameterSpec encIv = new IvParameterSpec(ivec, 0, ivec.length);
cipher.init(mode, secretKey, encIv);
return cipher;
}
public int getChecksumLength() {
return hashSize; // bytes
}
/**
* Get the HMAC-MD5
*/
protected byte[] getHmac(byte[] key, byte[] msg)
throws GeneralSecurityException {
SecretKey keyKi = new SecretKeySpec(key, "HmacMD5");
Mac m = Mac.getInstance("HmacMD5");
m.init(keyKi);
// generate hash
byte[] hash = m.doFinal(msg);
return hash;
}
/**
* Calculate the checksum
*/
public byte[] calculateChecksum(byte[] baseKey, int usage, byte[] input,
int start, int len) throws GeneralSecurityException {
if (debug) {
System.out.println("ARCFOUR: calculateChecksum with usage = " +
usage);
}
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
byte[] Ksign = null;
// Derive signing key from session key
try {
byte[] ss = "signaturekey".getBytes();
// need to append end-of-string 00
byte[] new_ss = new byte[ss.length+1];
System.arraycopy(ss, 0, new_ss, 0, ss.length);
Ksign = getHmac(baseKey, new_ss);
} catch (Exception e) {
GeneralSecurityException gse =
new GeneralSecurityException("Calculate Checkum Failed!");
gse.initCause(e);
throw gse;
}
// get the salt using key usage
byte[] salt = getSalt(usage);
// Generate checksum of message
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
GeneralSecurityException gse =
new GeneralSecurityException("Calculate Checkum Failed!");
gse.initCause(e);
throw gse;
}
messageDigest.update(salt);
messageDigest.update(input, start, len);
byte[] md5tmp = messageDigest.digest();
// Generate checksum
byte[] hmac = getHmac(Ksign, md5tmp);
if (debug) {
traceOutput("hmac", hmac, 0, hmac.length);
}
if (hmac.length == getChecksumLength()) {
return hmac;
} else if (hmac.length > getChecksumLength()) {
byte[] buf = new byte[getChecksumLength()];
System.arraycopy(hmac, 0, buf, 0, buf.length);
return buf;
} else {
throw new GeneralSecurityException("checksum size too short: " +
hmac.length + "; expecting : " + getChecksumLength());
}
}
/**
* Performs encryption of Sequence Number using derived key.
*/
public byte[] encryptSeq(byte[] baseKey, int usage,
byte[] checksum, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
// derive encryption for sequence number
byte[] salt = new byte[4];
byte[] kSeq = getHmac(baseKey, salt);
// derive new encryption key salted with sequence number
kSeq = getHmac(kSeq, checksum);
Cipher cipher = Cipher.getInstance("ARCFOUR");
SecretKeySpec secretKey = new SecretKeySpec(kSeq, "ARCFOUR");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] output = cipher.doFinal(plaintext, start, len);
return output;
}
/**
* Performs decryption of Sequence Number using derived key.
*/
public byte[] decryptSeq(byte[] baseKey, int usage,
byte[] checksum, byte[] ciphertext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
// derive decryption for sequence number
byte[] salt = new byte[4];
byte[] kSeq = getHmac(baseKey, salt);
// derive new encryption key salted with sequence number
kSeq = getHmac(kSeq, checksum);
Cipher cipher = Cipher.getInstance("ARCFOUR");
SecretKeySpec secretKey = new SecretKeySpec(kSeq, "ARCFOUR");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] output = cipher.doFinal(ciphertext, start, len);
return output;
}
/**
* Performs encryption using derived key; adds confounder.
*/
public byte[] encrypt(byte[] baseKey, int usage,
byte[] ivec, byte[] new_ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
if (debug) {
System.out.println("ArcFour: ENCRYPT with key usage = " + usage);
}
// get the confounder
byte[] confounder = Confounder.bytes(confounderSize);
// add confounder to the plaintext for encryption
int plainSize = roundup(confounder.length + len, 1);
byte[] toBeEncrypted = new byte[plainSize];
System.arraycopy(confounder, 0, toBeEncrypted, 0, confounder.length);
System.arraycopy(plaintext, start, toBeEncrypted,
confounder.length, len);
/* begin the encryption, compute K1 */
byte[] k1 = new byte[baseKey.length];
System.arraycopy(baseKey, 0, k1, 0, baseKey.length);
// get the salt using key usage
byte[] salt = getSalt(usage);
// compute K2 using K1
byte[] k2 = getHmac(k1, salt);
// generate checksum using K2
byte[] checksum = getHmac(k2, toBeEncrypted);
// compute K3 using K2 and checksum
byte[] k3 = getHmac(k2, checksum);
Cipher cipher = Cipher.getInstance("ARCFOUR");
SecretKeySpec secretKey = new SecretKeySpec(k3, "ARCFOUR");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] output = cipher.doFinal(toBeEncrypted, 0, toBeEncrypted.length);
// encryptedData + HMAC
byte[] result = new byte[hashSize + output.length];
System.arraycopy(checksum, 0, result, 0, hashSize);
System.arraycopy(output, 0, result, hashSize, output.length);
return result;
}
/**
* Performs encryption using derived key; does not add confounder.
*/
public byte[] encryptRaw(byte[] baseKey, int usage,
byte[] seqNum, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
if (debug) {
System.out.println("\nARCFOUR: encryptRaw with usage = " + usage);
}
// Derive encryption key for data
// Key derivation salt = 0
byte[] klocal = new byte[baseKey.length];
for (int i = 0; i <= 15; i++) {
klocal[i] = (byte) (baseKey[i] ^ 0xF0);
}
byte[] salt = new byte[4];
byte[] kcrypt = getHmac(klocal, salt);
// Note: When using this RC4 based encryption type, the sequence number
// is always sent in big-endian rather than little-endian order.
// new encryption key salted with sequence number
kcrypt = getHmac(kcrypt, seqNum);
Cipher cipher = Cipher.getInstance("ARCFOUR");
SecretKeySpec secretKey = new SecretKeySpec(kcrypt, "ARCFOUR");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] output = cipher.doFinal(plaintext, start, len);
return output;
}
/**
* @param baseKey key from which keys are to be derived using usage
* @param ciphertext E(Ke, conf | plaintext | padding, ivec) | H1[1..h]
*/
public byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
if (debug) {
System.out.println("\nARCFOUR: DECRYPT using key usage = " + usage);
}
// compute K1
byte[] k1 = new byte[baseKey.length];
System.arraycopy(baseKey, 0, k1, 0, baseKey.length);
// get the salt using key usage
byte[] salt = getSalt(usage);
// compute K2 using K1
byte[] k2 = getHmac(k1, salt);
// compute K3 using K2 and checksum
byte[] checksum = new byte[hashSize];
System.arraycopy(ciphertext, start, checksum, 0, hashSize);
byte[] k3 = getHmac(k2, checksum);
// Decrypt [confounder | plaintext ] (without checksum)
Cipher cipher = Cipher.getInstance("ARCFOUR");
SecretKeySpec secretKey = new SecretKeySpec(k3, "ARCFOUR");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] plaintext = cipher.doFinal(ciphertext, start+hashSize,
len-hashSize);
// Verify checksum
byte[] calculatedHmac = getHmac(k2, plaintext);
if (debug) {
traceOutput("calculated Hmac", calculatedHmac, 0,
calculatedHmac.length);
traceOutput("message Hmac", ciphertext, 0,
hashSize);
}
boolean cksumFailed = false;
if (calculatedHmac.length >= hashSize) {
for (int i = 0; i < hashSize; i++) {
if (calculatedHmac[i] != ciphertext[i]) {
cksumFailed = true;
if (debug) {
System.err.println("Checksum failed !");
}
break;
}
}
}
if (cksumFailed) {
throw new GeneralSecurityException("Checksum failed");
}
// Get rid of confounder
// [ confounder | plaintext ]
byte[] output = new byte[plaintext.length - confounderSize];
System.arraycopy(plaintext, confounderSize, output, 0, output.length);
return output;
}
/**
* Decrypts data using specified key and initial vector.
* @param baseKey encryption key to use
* @param ciphertext encrypted data to be decrypted
* @param usage ignored
*/
public byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len, byte[] seqNum)
throws GeneralSecurityException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
if (debug) {
System.out.println("\nARCFOUR: decryptRaw with usage = " + usage);
}
// Derive encryption key for data
// Key derivation salt = 0
byte[] klocal = new byte[baseKey.length];
for (int i = 0; i <= 15; i++) {
klocal[i] = (byte) (baseKey[i] ^ 0xF0);
}
byte[] salt = new byte[4];
byte[] kcrypt = getHmac(klocal, salt);
// need only first 4 bytes of sequence number
byte[] sequenceNum = new byte[4];
System.arraycopy(seqNum, 0, sequenceNum, 0, sequenceNum.length);
// new encryption key salted with sequence number
kcrypt = getHmac(kcrypt, sequenceNum);
Cipher cipher = Cipher.getInstance("ARCFOUR");
SecretKeySpec secretKey = new SecretKeySpec(kcrypt, "ARCFOUR");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] output = cipher.doFinal(ciphertext, start, len);
return output;
}
// get the salt using key usage
private byte[] getSalt(int usage) {
int ms_usage = arcfour_translate_usage(usage);
byte[] salt = new byte[4];
salt[0] = (byte)(ms_usage & 0xff);
salt[1] = (byte)((ms_usage >> 8) & 0xff);
salt[2] = (byte)((ms_usage >> 16) & 0xff);
salt[3] = (byte)((ms_usage >> 24) & 0xff);
return salt;
}
// Key usage translation for MS
private int arcfour_translate_usage(int usage) {
switch (usage) {
case 3: return 8;
case 9: return 8;
case 23: return 13;
default: return usage;
}
}
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.krb5.internal.crypto.dk;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.spec.KeySpec;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.util.Arrays;
public class Des3DkCrypto extends DkCrypto {
private static final byte[] ZERO_IV = new byte[] {0, 0, 0, 0, 0, 0, 0, 0};
public Des3DkCrypto() {
}
protected int getKeySeedLength() {
return 168; // bits; 3DES key material has 21 bytes
}
public byte[] stringToKey(char[] salt) throws GeneralSecurityException {
byte[] saltUtf8 = null;
try {
saltUtf8 = charToUtf8(salt);
return stringToKey(saltUtf8, null);
} finally {
if (saltUtf8 != null) {
Arrays.fill(saltUtf8, (byte)0);
}
// Caller responsible for clearing its own salt
}
}
private byte[] stringToKey(byte[] secretAndSalt, byte[] opaque)
throws GeneralSecurityException {
if (opaque != null && opaque.length > 0) {
throw new RuntimeException("Invalid parameter to stringToKey");
}
byte[] tmpKey = randomToKey(nfold(secretAndSalt, getKeySeedLength()));
return dk(tmpKey, KERBEROS_CONSTANT);
}
public byte[] parityFix(byte[] value)
throws GeneralSecurityException {
// fix key parity
setParityBit(value);
return value;
}
/*
* From RFC 3961.
*
* The 168 bits of random key data are converted to a protocol key value
* as follows. First, the 168 bits are divided into three groups of 56
* bits, which are expanded individually into 64 bits as in des3Expand().
* Result is a 24 byte (192-bit) key.
*/
protected byte[] randomToKey(byte[] in) {
if (in.length != 21) {
throw new IllegalArgumentException("input must be 168 bits");
}
byte[] one = keyCorrection(des3Expand(in, 0, 7));
byte[] two = keyCorrection(des3Expand(in, 7, 14));
byte[] three = keyCorrection(des3Expand(in, 14, 21));
byte[] key = new byte[24];
System.arraycopy(one, 0, key, 0, 8);
System.arraycopy(two, 0, key, 8, 8);
System.arraycopy(three, 0, key, 16, 8);
return key;
}
private static byte[] keyCorrection(byte[] key) {
// check for weak key
try {
if (DESKeySpec.isWeak(key, 0)) {
key[7] = (byte)(key[7] ^ 0xF0);
}
} catch (InvalidKeyException ex) {
// swallow, since it should never happen
}
return key;
}
/**
* From RFC 3961.
*
* Expands a 7-byte array into an 8-byte array that contains parity bits.
* The 56 bits are expanded into 64 bits as follows:
* 1 2 3 4 5 6 7 p
* 9 10 11 12 13 14 15 p
* 17 18 19 20 21 22 23 p
* 25 26 27 28 29 30 31 p
* 33 34 35 36 37 38 39 p
* 41 42 43 44 45 46 47 p
* 49 50 51 52 53 54 55 p
* 56 48 40 32 24 16 8 p
*
* (PI,P2,...,P8) are reserved for parity bits computed on the preceding
* seven independent bits and set so that the parity of the octet is odd,
* i.e., there is an odd number of "1" bits in the octet.
*
* @param start index of starting byte (inclusive)
* @param end index of ending byte (exclusive)
*/
private static byte[] des3Expand(byte[] input, int start, int end) {
if ((end - start) != 7)
throw new IllegalArgumentException(
"Invalid length of DES Key Value:" + start + "," + end);
byte[] result = new byte[8];
byte last = 0;
System.arraycopy(input, start, result, 0, 7);
byte posn = 0;
// Fill in last row
for (int i = start; i < end; i++) {
byte bit = (byte) (input[i]&0x01);
if (debug) {
System.out.println(i + ": " + Integer.toHexString(input[i]) +
" bit= " + Integer.toHexString(bit));
}
++posn;
if (bit != 0) {
last |= (bit<<posn);
}
}
if (debug) {
System.out.println("last: " + Integer.toHexString(last));
}
result[7] = last;
setParityBit(result);
return result;
}
/**
* Sets the parity bit (0th bit) in each byte so that each byte
* contains an odd number of 1's.
*/
private static void setParityBit(byte[] key) {
for (int i = 0; i < key.length; i++) {
int b = key[i] & 0xfe;
b |= (Integer.bitCount(b) & 1) ^ 1;
key[i] = (byte) b;
}
}
protected Cipher getCipher(byte[] key, byte[] ivec, int mode)
throws GeneralSecurityException {
// NoSuchAlgorithException
SecretKeyFactory factory = SecretKeyFactory.getInstance("desede");
// InvalidKeyException
KeySpec spec = new DESedeKeySpec(key, 0);
// InvalidKeySpecException
SecretKey secretKey = factory.generateSecret(spec);
// IV
if (ivec == null) {
ivec = ZERO_IV;
}
// NoSuchAlgorithmException, NoSuchPaddingException
// NoSuchProviderException
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
IvParameterSpec encIv = new IvParameterSpec(ivec, 0, ivec.length);
// InvalidKeyException, InvalidAlgorithParameterException
cipher.init(mode, secretKey, encIv);
return cipher;
}
public int getChecksumLength() {
return 20; // bytes
}
protected byte[] getHmac(byte[] key, byte[] msg)
throws GeneralSecurityException {
SecretKey keyKi = new SecretKeySpec(key, "HmacSHA1");
Mac m = Mac.getInstance("HmacSHA1");
m.init(keyKi);
return m.doFinal(msg);
}
}

View File

@@ -0,0 +1,699 @@
/*
* Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright (C) 1998 by the FundsXpress, INC.
*
* All rights reserved.
*
* Export of this software from the United States of America may require
* a specific license from the United States Government. It is the
* responsibility of any person or organization contemplating export to
* obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of FundsXpress. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. FundsXpress makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
package sun.security.krb5.internal.crypto.dk;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import java.security.GeneralSecurityException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.nio.CharBuffer;
import java.nio.ByteBuffer;
import sun.misc.HexDumpEncoder;
import sun.security.krb5.Confounder;
import sun.security.krb5.internal.crypto.KeyUsage;
import sun.security.krb5.KrbCryptoException;
/**
* Implements Derive Key cryptography functionality as defined in RFC 3961.
* http://www.ietf.org/rfc/rfc3961.txt
*
* This is an abstract class. Concrete subclasses need to implement
* the abstract methods.
*/
public abstract class DkCrypto {
protected static final boolean debug = false;
// These values correspond to the ASCII encoding for the string "kerberos"
static final byte[] KERBEROS_CONSTANT =
{0x6b, 0x65, 0x72, 0x62, 0x65, 0x72, 0x6f, 0x73};
protected abstract int getKeySeedLength(); // in bits
protected abstract byte[] randomToKey(byte[] in);
protected abstract Cipher getCipher(byte[] key, byte[] ivec, int mode)
throws GeneralSecurityException;
public abstract int getChecksumLength(); // in bytes
protected abstract byte[] getHmac(byte[] key, byte[] plaintext)
throws GeneralSecurityException;
/**
* From RFC 3961.
*
* encryption function conf = random string of length c
* pad = shortest string to bring confounder
* and plaintext to a length that's a
* multiple of m
* (C1, newIV) = E(Ke, conf | plaintext | pad,
* oldstate.ivec)
* H1 = HMAC(Ki, conf | plaintext | pad)
* ciphertext = C1 | H1[1..h]
* newstate.ivec = newIV
*
* @param ivec initial vector to use when initializing the cipher; if null,
* then blocksize number of zeros are used,
* @param new_ivec if non-null, it is updated upon return to be the
* new ivec to use when calling encrypt next time
*/
public byte[] encrypt(byte[] baseKey, int usage,
byte[] ivec, byte[] new_ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
byte[] Ke = null;
byte[] Ki = null;
try {
// Derive encryption key
byte[] constant = new byte[5];
constant[0] = (byte) ((usage>>24)&0xff);
constant[1] = (byte) ((usage>>16)&0xff);
constant[2] = (byte) ((usage>>8)&0xff);
constant[3] = (byte) (usage&0xff);
constant[4] = (byte) 0xaa;
Ke = dk(baseKey, constant);
if (debug) {
System.err.println("usage: " + usage);
if (ivec != null) {
traceOutput("old_state.ivec", ivec, 0, ivec.length);
}
traceOutput("plaintext", plaintext, start, Math.min(len, 32));
traceOutput("constant", constant, 0, constant.length);
traceOutput("baseKey", baseKey, 0, baseKey.length);
traceOutput("Ke", Ke, 0, Ke.length);
}
// Encrypt
// C1 = E(Ke, conf | plaintext | pad, oldivec)
Cipher encCipher = getCipher(Ke, ivec, Cipher.ENCRYPT_MODE);
int blockSize = encCipher.getBlockSize();
byte[] confounder = Confounder.bytes(blockSize);
int plainSize = roundup(confounder.length + len, blockSize);
if (debug) {
System.err.println("confounder = " + confounder.length +
"; plaintext = " + len + "; padding = " +
(plainSize - confounder.length - len) + "; total = " +
plainSize);
traceOutput("confounder", confounder, 0, confounder.length);
}
byte[] toBeEncrypted = new byte[plainSize];
System.arraycopy(confounder, 0, toBeEncrypted,
0, confounder.length);
System.arraycopy(plaintext, start, toBeEncrypted,
confounder.length, len);
// Set padding bytes to zero
Arrays.fill(toBeEncrypted, confounder.length + len, plainSize,
(byte)0);
int cipherSize = encCipher.getOutputSize(plainSize);
int ccSize = cipherSize + getChecksumLength(); // cipher | hmac
byte[] ciphertext = new byte[ccSize];
encCipher.doFinal(toBeEncrypted, 0, plainSize, ciphertext, 0);
// Update ivec for next operation
// (last blockSize bytes of ciphertext)
// newstate.ivec = newIV
if (new_ivec != null && new_ivec.length == blockSize) {
System.arraycopy(ciphertext, cipherSize - blockSize,
new_ivec, 0, blockSize);
if (debug) {
traceOutput("new_ivec", new_ivec, 0, new_ivec.length);
}
}
// Derive integrity key
constant[4] = (byte) 0x55;
Ki = dk(baseKey, constant);
if (debug) {
traceOutput("constant", constant, 0, constant.length);
traceOutput("Ki", Ki, 0, Ke.length);
}
// Generate checksum
// H1 = HMAC(Ki, conf | plaintext | pad)
byte[] hmac = getHmac(Ki, toBeEncrypted);
if (debug) {
traceOutput("hmac", hmac, 0, hmac.length);
traceOutput("ciphertext", ciphertext, 0,
Math.min(ciphertext.length, 32));
}
// C1 | H1[1..h]
System.arraycopy(hmac, 0, ciphertext, cipherSize,
getChecksumLength());
return ciphertext;
} finally {
if (Ke != null) {
Arrays.fill(Ke, 0, Ke.length, (byte) 0);
}
if (Ki != null) {
Arrays.fill(Ki, 0, Ki.length, (byte) 0);
}
}
}
/**
* Performs encryption using given key only; does not add
* confounder, padding, or checksum. Incoming data to be encrypted
* assumed to have the correct blocksize.
* Ignore key usage.
*/
public byte[] encryptRaw(byte[] baseKey, int usage,
byte[] ivec, byte[] plaintext, int start, int len)
throws GeneralSecurityException, KrbCryptoException {
if (debug) {
System.err.println("usage: " + usage);
if (ivec != null) {
traceOutput("old_state.ivec", ivec, 0, ivec.length);
}
traceOutput("plaintext", plaintext, start, Math.min(len, 32));
traceOutput("baseKey", baseKey, 0, baseKey.length);
}
// Encrypt
Cipher encCipher = getCipher(baseKey, ivec, Cipher.ENCRYPT_MODE);
int blockSize = encCipher.getBlockSize();
if ((len % blockSize) != 0) {
throw new GeneralSecurityException(
"length of data to be encrypted (" + len +
") is not a multiple of the blocksize (" + blockSize + ")");
}
int cipherSize = encCipher.getOutputSize(len);
byte[] ciphertext = new byte[cipherSize];
encCipher.doFinal(plaintext, 0, len, ciphertext, 0);
return ciphertext;
}
/**
* Decrypts data using specified key and initial vector.
* @param baseKey encryption key to use
* @param ciphertext encrypted data to be decrypted
* @param usage ignored
*/
public byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len)
throws GeneralSecurityException {
if (debug) {
System.err.println("usage: " + usage);
if (ivec != null) {
traceOutput("old_state.ivec", ivec, 0, ivec.length);
}
traceOutput("ciphertext", ciphertext, start, Math.min(len, 32));
traceOutput("baseKey", baseKey, 0, baseKey.length);
}
Cipher decCipher = getCipher(baseKey, ivec, Cipher.DECRYPT_MODE);
int blockSize = decCipher.getBlockSize();
if ((len % blockSize) != 0) {
throw new GeneralSecurityException(
"length of data to be decrypted (" + len +
") is not a multiple of the blocksize (" + blockSize + ")");
}
byte[] decrypted = decCipher.doFinal(ciphertext, start, len);
if (debug) {
traceOutput("decrypted", decrypted, 0,
Math.min(decrypted.length, 32));
}
return decrypted;
}
/**
* @param baseKey key from which keys are to be derived using usage
* @param ciphertext E(Ke, conf | plaintext | padding, ivec) | H1[1..h]
*/
public byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
byte[] ciphertext, int start, int len) throws GeneralSecurityException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
byte[] Ke = null;
byte[] Ki = null;
try {
// Derive encryption key
byte[] constant = new byte[5];
constant[0] = (byte) ((usage>>24)&0xff);
constant[1] = (byte) ((usage>>16)&0xff);
constant[2] = (byte) ((usage>>8)&0xff);
constant[3] = (byte) (usage&0xff);
constant[4] = (byte) 0xaa;
Ke = dk(baseKey, constant); // Encryption key
if (debug) {
System.err.println("usage: " + usage);
if (ivec != null) {
traceOutput("old_state.ivec", ivec, 0, ivec.length);
}
traceOutput("ciphertext", ciphertext, start, Math.min(len, 32));
traceOutput("constant", constant, 0, constant.length);
traceOutput("baseKey", baseKey, 0, baseKey.length);
traceOutput("Ke", Ke, 0, Ke.length);
}
Cipher decCipher = getCipher(Ke, ivec, Cipher.DECRYPT_MODE);
int blockSize = decCipher.getBlockSize();
// Decrypt [confounder | plaintext | padding] (without checksum)
int cksumSize = getChecksumLength();
int cipherSize = len - cksumSize;
byte[] decrypted = decCipher.doFinal(ciphertext, start, cipherSize);
if (debug) {
traceOutput("decrypted", decrypted, 0,
Math.min(decrypted.length, 32));
}
// decrypted = [confounder | plaintext | padding]
// Derive integrity key
constant[4] = (byte) 0x55;
Ki = dk(baseKey, constant); // Integrity key
if (debug) {
traceOutput("constant", constant, 0, constant.length);
traceOutput("Ki", Ki, 0, Ke.length);
}
// Verify checksum
// H1 = HMAC(Ki, conf | plaintext | pad)
byte[] calculatedHmac = getHmac(Ki, decrypted);
if (debug) {
traceOutput("calculated Hmac", calculatedHmac, 0,
calculatedHmac.length);
traceOutput("message Hmac", ciphertext, cipherSize,
cksumSize);
}
boolean cksumFailed = false;
if (calculatedHmac.length >= cksumSize) {
for (int i = 0; i < cksumSize; i++) {
if (calculatedHmac[i] != ciphertext[cipherSize+i]) {
cksumFailed = true;
break;
}
}
}
if (cksumFailed) {
throw new GeneralSecurityException("Checksum failed");
}
// Prepare decrypted msg and ivec to be returned
// Last blockSize bytes of ciphertext without checksum
if (ivec != null && ivec.length == blockSize) {
System.arraycopy(ciphertext, start + cipherSize - blockSize,
ivec, 0, blockSize);
if (debug) {
traceOutput("new_state.ivec", ivec, 0, ivec.length);
}
}
// Get rid of confounder
// [plaintext | padding]
byte[] plaintext = new byte[decrypted.length - blockSize];
System.arraycopy(decrypted, blockSize, plaintext,
0, plaintext.length);
return plaintext; // padding still there
} finally {
if (Ke != null) {
Arrays.fill(Ke, 0, Ke.length, (byte) 0);
}
if (Ki != null) {
Arrays.fill(Ki, 0, Ki.length, (byte) 0);
}
}
}
// Round up to the next blocksize
int roundup(int n, int blocksize) {
return (((n + blocksize - 1) / blocksize) * blocksize);
}
public byte[] calculateChecksum(byte[] baseKey, int usage, byte[] input,
int start, int len) throws GeneralSecurityException {
if (!KeyUsage.isValid(usage)) {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
// Derive keys
byte[] constant = new byte[5];
constant[0] = (byte) ((usage>>24)&0xff);
constant[1] = (byte) ((usage>>16)&0xff);
constant[2] = (byte) ((usage>>8)&0xff);
constant[3] = (byte) (usage&0xff);
constant[4] = (byte) 0x99;
byte[] Kc = dk(baseKey, constant); // Checksum key
if (debug) {
System.err.println("usage: " + usage);
traceOutput("input", input, start, Math.min(len, 32));
traceOutput("constant", constant, 0, constant.length);
traceOutput("baseKey", baseKey, 0, baseKey.length);
traceOutput("Kc", Kc, 0, Kc.length);
}
try {
// Generate checksum
// H1 = HMAC(Kc, input)
byte[] hmac = getHmac(Kc, input);
if (debug) {
traceOutput("hmac", hmac, 0, hmac.length);
}
if (hmac.length == getChecksumLength()) {
return hmac;
} else if (hmac.length > getChecksumLength()) {
byte[] buf = new byte[getChecksumLength()];
System.arraycopy(hmac, 0, buf, 0, buf.length);
return buf;
} else {
throw new GeneralSecurityException("checksum size too short: " +
hmac.length + "; expecting : " + getChecksumLength());
}
} finally {
Arrays.fill(Kc, 0, Kc.length, (byte)0);
}
}
// DK(Key, Constant) = random-to-key(DR(Key, Constant))
byte[] dk(byte[] key, byte[] constant)
throws GeneralSecurityException {
return randomToKey(dr(key, constant));
}
/*
* From RFC 3961.
*
* DR(Key, Constant) = k-truncate(E(Key, Constant,
* initial-cipher-state))
*
* Here DR is the random-octet generation function described below, and
* DK is the key-derivation function produced from it. In this
* construction, E(Key, Plaintext, CipherState) is a cipher, Constant is
* a well-known constant determined by the specific usage of this
* function, and k-truncate truncates its argument by taking the first k
* bits. Here, k is the key generation seed length needed for the
* encryption system.
*
* The output of the DR function is a string of bits; the actual key is
* produced by applying the cryptosystem's random-to-key operation on
* this bitstring.
*
* If the Constant is smaller than the cipher block size of E, then it
* must be expanded with n-fold() so it can be encrypted. If the output
* of E is shorter than k bits it is fed back into the encryption as
* many times as necessary. The construct is as follows (where |
* indicates concatentation):
*
* K1 = E(Key, n-fold(Constant), initial-cipher-state)
* K2 = E(Key, K1, initial-cipher-state)
* K3 = E(Key, K2, initial-cipher-state)
* K4 = ...
*
* DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
*/
private byte[] dr(byte[] key, byte[] constant)
throws GeneralSecurityException {
Cipher encCipher = getCipher(key, null, Cipher.ENCRYPT_MODE);
int blocksize = encCipher.getBlockSize();
if (constant.length != blocksize) {
constant = nfold(constant, blocksize * 8);
}
byte[] toBeEncrypted = constant;
int keybytes = (getKeySeedLength()>>3); // from bits to bytes
byte[] rawkey = new byte[keybytes];
int posn = 0;
/* loop encrypting the blocks until enough key bytes are generated */
int n = 0, len;
while (n < keybytes) {
if (debug) {
System.err.println("Encrypting: " +
bytesToString(toBeEncrypted));
}
byte[] cipherBlock = encCipher.doFinal(toBeEncrypted);
if (debug) {
System.err.println("K: " + ++posn + " = " +
bytesToString(cipherBlock));
}
len = (keybytes - n <= cipherBlock.length ? (keybytes - n) :
cipherBlock.length);
if (debug) {
System.err.println("copying " + len + " key bytes");
}
System.arraycopy(cipherBlock, 0, rawkey, n, len);
n += len;
toBeEncrypted = cipherBlock;
}
return rawkey;
}
// ---------------------------------
// From MIT-1.3.1 distribution
/*
* n-fold(k-bits):
* l = lcm(n,k)
* r = l/k
* s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1)
* compute the 1's complement sum:
* n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1]
*/
/*
* representation: msb first, assume n and k are multiples of 8, and
* that k>=16. this is the case of all the cryptosystems which are
* likely to be used. this function can be replaced if that
* assumption ever fails.
*/
/* input length is in bits */
static byte[] nfold(byte[] in, int outbits) {
int inbits = in.length;
outbits >>= 3; // count in bytes
/* first compute lcm(n,k) */
int a, b, c, lcm;
a = outbits; // n
b = inbits; // k
while (b != 0) {
c = b;
b = a % b;
a = c;
}
lcm = outbits*inbits/a;
if (debug) {
System.err.println("k: " + inbits);
System.err.println("n: " + outbits);
System.err.println("lcm: " + lcm);
}
/* now do the real work */
byte[] out = new byte[outbits];
Arrays.fill(out, (byte)0);
int thisbyte = 0;
int msbit, i, bval, oval;
// this will end up cycling through k lcm(k,n)/k times, which
// is correct
for (i = lcm-1; i >= 0; i--) {
/* compute the msbit in k which gets added into this byte */
msbit = (/* first, start with msbit in the first, unrotated byte */
((inbits<<3)-1)
/* then, for each byte, shift to right for each repetition */
+ (((inbits<<3)+13)*(i/inbits))
/* last, pick out correct byte within that shifted repetition */
+ ((inbits-(i%inbits)) << 3)) % (inbits << 3);
/* pull out the byte value itself */
// Mask off values using &0xff to get only the lower byte
// Use >>> to avoid sign extension
bval = ((((in[((inbits-1)-(msbit>>>3))%inbits]&0xff)<<8)|
(in[((inbits)-(msbit>>>3))%inbits]&0xff))
>>>((msbit&7)+1))&0xff;
/*
System.err.println("((" +
((in[((inbits-1)-(msbit>>>3))%inbits]&0xff)<<8)
+ "|" + (in[((inbits)-(msbit>>>3))%inbits]&0xff) + ")"
+ ">>>" + ((msbit&7)+1) + ")&0xff = " + bval);
*/
thisbyte += bval;
/* do the addition */
// Mask off values using &0xff to get only the lower byte
oval = (out[i%outbits]&0xff);
thisbyte += oval;
out[i%outbits] = (byte) (thisbyte&0xff);
if (debug) {
System.err.println("msbit[" + i + "] = " + msbit + "\tbval=" +
Integer.toHexString(bval) + "\toval=" +
Integer.toHexString(oval)
+ "\tsum = " + Integer.toHexString(thisbyte));
}
/* keep around the carry bit, if any */
thisbyte >>>= 8;
if (debug) {
System.err.println("carry=" + thisbyte);
}
}
/* if there's a carry bit left over, add it back in */
if (thisbyte != 0) {
for (i = outbits-1; i >= 0; i--) {
/* do the addition */
thisbyte += (out[i]&0xff);
out[i] = (byte) (thisbyte&0xff);
/* keep around the carry bit, if any */
thisbyte >>>= 8;
}
}
return out;
}
// Routines used for debugging
static String bytesToString(byte[] digest) {
// Get character representation of digest
StringBuffer digestString = new StringBuffer();
for (int i = 0; i < digest.length; i++) {
if ((digest[i] & 0x000000ff) < 0x10) {
digestString.append("0" +
Integer.toHexString(digest[i] & 0x000000ff));
} else {
digestString.append(
Integer.toHexString(digest[i] & 0x000000ff));
}
}
return digestString.toString();
}
private static byte[] binaryStringToBytes(String str) {
char[] usageStr = str.toCharArray();
byte[] usage = new byte[usageStr.length/2];
for (int i = 0; i < usage.length; i++) {
byte a = Byte.parseByte(new String(usageStr, i*2, 1), 16);
byte b = Byte.parseByte(new String(usageStr, i*2 + 1, 1), 16);
usage[i] = (byte) ((a<<4)|b);
}
return usage;
}
static void traceOutput(String traceTag, byte[] output, int offset,
int len) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream(len);
new HexDumpEncoder().encodeBuffer(
new ByteArrayInputStream(output, offset, len), out);
System.err.println(traceTag + ":" + out.toString());
} catch (Exception e) {
}
}
// String.getBytes("UTF-8");
// Do this instead of using String to avoid making password immutable
static byte[] charToUtf8(char[] chars) {
Charset utf8 = Charset.forName("UTF-8");
CharBuffer cb = CharBuffer.wrap(chars);
ByteBuffer bb = utf8.encode(cb);
int len = bb.limit();
byte[] answer = new byte[len];
bb.get(answer, 0, len);
return answer;
}
static byte[] charToUtf16(char[] chars) {
Charset utf8 = Charset.forName("UTF-16LE");
CharBuffer cb = CharBuffer.wrap(chars);
ByteBuffer bb = utf8.encode(cb);
int len = bb.limit();
byte[] answer = new byte[len];
bb.get(answer, 0, len);
return answer;
}
}