mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8014628: Support AES Encryption with HMAC-SHA2 for Kerberos 5
Reviewed-by: mullan
This commit is contained in:
parent
c1700dddf5
commit
724d1916fe
21 changed files with 1703 additions and 58 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, 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
|
||||
|
@ -66,6 +66,10 @@ public class Checksum {
|
|||
public static final int CKSUMTYPE_HMAC_SHA1_96_AES128 = 15; // 96
|
||||
public static final int CKSUMTYPE_HMAC_SHA1_96_AES256 = 16; // 96
|
||||
|
||||
// rfc8009
|
||||
public static final int CKSUMTYPE_HMAC_SHA256_128_AES128 = 19; // 96
|
||||
public static final int CKSUMTYPE_HMAC_SHA384_192_AES256 = 20; // 96
|
||||
|
||||
// draft-brezak-win2k-krb-rc4-hmac-04.txt
|
||||
public static final int CKSUMTYPE_HMAC_MD5_ARCFOUR = -138;
|
||||
|
||||
|
|
|
@ -1030,11 +1030,19 @@ public class Config {
|
|||
} else if (input.startsWith("a") || (input.startsWith("A"))) {
|
||||
// AES
|
||||
if (input.equalsIgnoreCase("aes128-cts") ||
|
||||
input.equalsIgnoreCase("aes128-cts-hmac-sha1-96")) {
|
||||
input.equalsIgnoreCase("aes128-sha1") ||
|
||||
input.equalsIgnoreCase("aes128-cts-hmac-sha1-96")) {
|
||||
result = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96;
|
||||
} else if (input.equalsIgnoreCase("aes256-cts") ||
|
||||
input.equalsIgnoreCase("aes256-cts-hmac-sha1-96")) {
|
||||
input.equalsIgnoreCase("aes256-sha1") ||
|
||||
input.equalsIgnoreCase("aes256-cts-hmac-sha1-96")) {
|
||||
result = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96;
|
||||
} else if (input.equalsIgnoreCase("aes128-sha2") ||
|
||||
input.equalsIgnoreCase("aes128-cts-hmac-sha256-128")) {
|
||||
result = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128;
|
||||
} else if (input.equalsIgnoreCase("aes256-sha2") ||
|
||||
input.equalsIgnoreCase("aes256-cts-hmac-sha384-192")) {
|
||||
result = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192;
|
||||
// ARCFOUR-HMAC
|
||||
} else if (input.equalsIgnoreCase("arcfour-hmac") ||
|
||||
input.equalsIgnoreCase("arcfour-hmac-md5")) {
|
||||
|
@ -1057,6 +1065,10 @@ public class Config {
|
|||
result = Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128;
|
||||
} else if (input.equalsIgnoreCase("hmac-sha1-96-aes256")) {
|
||||
result = Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256;
|
||||
} else if (input.equalsIgnoreCase("hmac-sha256-128-aes128")) {
|
||||
result = Checksum.CKSUMTYPE_HMAC_SHA256_128_AES128;
|
||||
} else if (input.equalsIgnoreCase("hmac-sha384-192-aes256")) {
|
||||
result = Checksum.CKSUMTYPE_HMAC_SHA384_192_AES256;
|
||||
} else if (input.equalsIgnoreCase("hmac-md5-rc4") ||
|
||||
input.equalsIgnoreCase("hmac-md5-arcfour") ||
|
||||
input.equalsIgnoreCase("hmac-md5-enc")) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, 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
|
||||
|
@ -79,6 +79,12 @@ public class EncryptedData implements Cloneable {
|
|||
public static final int
|
||||
ETYPE_AES256_CTS_HMAC_SHA1_96 = 18; // 16 0 16
|
||||
|
||||
// rfc8009
|
||||
public static final int
|
||||
ETYPE_AES128_CTS_HMAC_SHA256_128 = 19; // 16 0 16
|
||||
public static final int
|
||||
ETYPE_AES256_CTS_HMAC_SHA384_192 = 20; // 16 0 16
|
||||
|
||||
/* used by self */
|
||||
private EncryptedData() {
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, 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
|
||||
|
@ -252,6 +252,12 @@ public class EncryptionKey
|
|||
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
|
||||
return Aes256.stringToKey(password, salt, s2kparams);
|
||||
|
||||
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
|
||||
return Aes128Sha2.stringToKey(password, salt, s2kparams);
|
||||
|
||||
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
|
||||
return Aes256Sha2.stringToKey(password, salt, s2kparams);
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("encryption type " +
|
||||
EType.toString(keyType) + " not supported");
|
||||
|
@ -293,6 +299,15 @@ public class EncryptionKey
|
|||
throw new IllegalArgumentException("Algorithm " + algorithm +
|
||||
" not enabled");
|
||||
}
|
||||
} else if (algorithm.equalsIgnoreCase("aes128-cts-hmac-sha256-128")) {
|
||||
keyType = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128;
|
||||
} else if (algorithm.equalsIgnoreCase("aes256-cts-hmac-sha384-192")) {
|
||||
keyType = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192;
|
||||
// validate if AES256 is enabled
|
||||
if (!EType.isSupported(keyType)) {
|
||||
throw new IllegalArgumentException("Algorithm " + algorithm +
|
||||
" not enabled");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Algorithm " + algorithm +
|
||||
" not supported");
|
||||
|
|
|
@ -356,6 +356,8 @@ public class KrbTgsReq {
|
|||
case Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR:
|
||||
case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128:
|
||||
case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256:
|
||||
case Checksum.CKSUMTYPE_HMAC_SHA256_128_AES128:
|
||||
case Checksum.CKSUMTYPE_HMAC_SHA384_192_AES256:
|
||||
cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp, key,
|
||||
KeyUsage.KU_PA_TGS_REQ_CKSUM);
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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-cts-hmac-sha256-128
|
||||
*/
|
||||
|
||||
public final class Aes128CtsHmacSha2EType extends EType {
|
||||
|
||||
public int eType() {
|
||||
return EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128;
|
||||
}
|
||||
|
||||
public int minimumPadSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int confounderSize() {
|
||||
return blockSize();
|
||||
}
|
||||
|
||||
public int checksumType() {
|
||||
return Checksum.CKSUMTYPE_HMAC_SHA256_128_AES128;
|
||||
}
|
||||
|
||||
public int checksumSize() {
|
||||
return Aes128Sha2.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 Aes128Sha2.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 Aes128Sha2.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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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.AesSha2DkCrypto;
|
||||
import sun.security.krb5.KrbCryptoException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Class with static methods for doing aes128-cts-hmac-sha256-128 operations.
|
||||
*/
|
||||
|
||||
public class Aes128Sha2 {
|
||||
private static final AesSha2DkCrypto CRYPTO = new AesSha2DkCrypto(128);
|
||||
|
||||
private Aes128Sha2() {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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-cts-hmac-sha384-192
|
||||
*/
|
||||
|
||||
public final class Aes256CtsHmacSha2EType extends EType {
|
||||
|
||||
public int eType() {
|
||||
return EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192;
|
||||
}
|
||||
|
||||
public int minimumPadSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int confounderSize() {
|
||||
return blockSize();
|
||||
}
|
||||
|
||||
public int checksumType() {
|
||||
return Checksum.CKSUMTYPE_HMAC_SHA384_192_AES256;
|
||||
}
|
||||
|
||||
public int checksumSize() {
|
||||
return Aes256Sha2.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 Aes256Sha2.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 Aes256Sha2.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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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.AesSha2DkCrypto;
|
||||
import sun.security.krb5.KrbCryptoException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Class with static methods for doing aes256-cts-hmac-sha384-192 operations.
|
||||
*/
|
||||
|
||||
public class Aes256Sha2 {
|
||||
private static final AesSha2DkCrypto CRYPTO = new AesSha2DkCrypto(256);
|
||||
|
||||
private Aes256Sha2() {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
|
@ -106,7 +106,19 @@ public abstract class EType {
|
|||
"sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType";
|
||||
break;
|
||||
|
||||
case EncryptedData.ETYPE_ARCFOUR_HMAC:
|
||||
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
|
||||
eType = new Aes128CtsHmacSha2EType();
|
||||
eTypeName =
|
||||
"sun.security.krb5.internal.crypto.Aes128CtsHmacSha2EType";
|
||||
break;
|
||||
|
||||
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
|
||||
eType = new Aes256CtsHmacSha2EType();
|
||||
eTypeName =
|
||||
"sun.security.krb5.internal.crypto.Aes256CtsHmacSha2EType";
|
||||
break;
|
||||
|
||||
case EncryptedData.ETYPE_ARCFOUR_HMAC:
|
||||
eType = new ArcFourHmacEType();
|
||||
eTypeName = "sun.security.krb5.internal.crypto.ArcFourHmacEType";
|
||||
break;
|
||||
|
@ -189,20 +201,23 @@ public abstract class EType {
|
|||
// 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,
|
||||
EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
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,
|
||||
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
|
||||
EncryptedData.ETYPE_ARCFOUR_HMAC,
|
||||
EncryptedData.ETYPE_DES_CBC_CRC,
|
||||
EncryptedData.ETYPE_DES_CBC_MD5,
|
||||
};
|
||||
|
||||
|
||||
|
@ -363,7 +378,10 @@ public abstract class EType {
|
|||
return "RC4 with HMAC";
|
||||
case 24:
|
||||
return "RC4 with HMAC EXP";
|
||||
|
||||
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
|
||||
return "AES128 CTS mode with HMAC SHA256-128";
|
||||
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
|
||||
return "AES256 CTS mode with HMAC SHA384-192";
|
||||
}
|
||||
return "Unknown (" + type + ")";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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-cts-sha256
|
||||
*/
|
||||
|
||||
public class HmacSha2Aes128CksumType extends CksumType {
|
||||
|
||||
public HmacSha2Aes128CksumType() {
|
||||
}
|
||||
|
||||
public int confounderSize() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
public int cksumType() {
|
||||
return Checksum.CKSUMTYPE_HMAC_SHA256_128_AES128;
|
||||
}
|
||||
|
||||
public boolean isSafe() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int cksumSize() {
|
||||
return 16; // bytes
|
||||
}
|
||||
|
||||
public int keyType() {
|
||||
return Krb5.KEYTYPE_AES;
|
||||
}
|
||||
|
||||
public int keySize() {
|
||||
return 16; // bytes
|
||||
}
|
||||
|
||||
public byte[] calculateChecksum(byte[] data, int size) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[] calculateKeyedChecksum(byte[] data, int size, byte[] key,
|
||||
int usage) throws KrbCryptoException {
|
||||
|
||||
try {
|
||||
return Aes128Sha2.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 verifyKeyedChecksum(byte[] data, int size,
|
||||
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
|
||||
|
||||
try {
|
||||
byte[] newCksum = Aes128Sha2.calculateChecksum(key, usage,
|
||||
data, 0, size);
|
||||
return isChecksumEqual(checksum, newCksum);
|
||||
} catch (GeneralSecurityException e) {
|
||||
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
|
||||
ke.initCause(e);
|
||||
throw ke;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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-cts-sha384
|
||||
*/
|
||||
|
||||
public class HmacSha2Aes256CksumType extends CksumType {
|
||||
|
||||
public HmacSha2Aes256CksumType() {
|
||||
}
|
||||
|
||||
public int confounderSize() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
public int cksumType() {
|
||||
return Checksum.CKSUMTYPE_HMAC_SHA384_192_AES256;
|
||||
}
|
||||
|
||||
public boolean isSafe() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int cksumSize() {
|
||||
return 24; // bytes
|
||||
}
|
||||
|
||||
public int keyType() {
|
||||
return Krb5.KEYTYPE_AES;
|
||||
}
|
||||
|
||||
public int keySize() {
|
||||
return 32; // bytes
|
||||
}
|
||||
|
||||
public byte[] calculateChecksum(byte[] data, int size) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[] calculateKeyedChecksum(byte[] data, int size, byte[] key,
|
||||
int usage) throws KrbCryptoException {
|
||||
|
||||
try {
|
||||
return Aes256Sha2.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 verifyKeyedChecksum(byte[] data, int size,
|
||||
byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
|
||||
|
||||
try {
|
||||
byte[] newCksum = Aes256Sha2.calculateChecksum(key, usage, data,
|
||||
0, size);
|
||||
return isChecksumEqual(checksum, newCksum);
|
||||
} catch (GeneralSecurityException e) {
|
||||
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
|
||||
ke.initCause(e);
|
||||
throw ke;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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.IvParameterSpec;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
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 with
|
||||
* HMAC-SHA2 for Kerberos 5
|
||||
* https://tools.ietf.org/html/rfc8009
|
||||
*
|
||||
* 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 80 00 |
|
||||
* | |
|
||||
* | key-generation seed length key size |
|
||||
* | |
|
||||
* | random-to-key function identity function |
|
||||
* | |
|
||||
* | hash function, H SHA-256 / SHA-384 |
|
||||
* | |
|
||||
* | HMAC output size, h 16/24 octets |
|
||||
* | |
|
||||
* | 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-cts-hmac-sha256-128 and aes256-cts-hmac-sha384-192
|
||||
*/
|
||||
|
||||
public class AesSha2DkCrypto extends DkCrypto {
|
||||
|
||||
private static final boolean debug = false;
|
||||
|
||||
private static final int BLOCK_SIZE = 16;
|
||||
private static final int DEFAULT_ITERATION_COUNT = 32768;
|
||||
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 byte[] ETYPE_NAME_128 =
|
||||
"aes128-cts-hmac-sha256-128".getBytes();
|
||||
private static final byte[] ETYPE_NAME_256 =
|
||||
"aes256-cts-hmac-sha384-192".getBytes();
|
||||
|
||||
private final int hashSize;
|
||||
private final int keyLength;
|
||||
|
||||
public AesSha2DkCrypto(int length) {
|
||||
keyLength = length;
|
||||
hashSize = (length == 128?128:192)/8;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc8009#section-4
|
||||
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[] saltp = new byte[26 + 1 + salt.length];
|
||||
if (keyLength == 128) {
|
||||
System.arraycopy(ETYPE_NAME_128, 0, saltp, 0, 26);
|
||||
} else {
|
||||
System.arraycopy(ETYPE_NAME_256, 0, saltp, 0, 26);
|
||||
}
|
||||
System.arraycopy(salt, 0, saltp, 27, salt.length);
|
||||
byte[] tmpKey = randomToKey(PBKDF2(secret, saltp, iter_count,
|
||||
getKeySeedLength()));
|
||||
byte[] result = dk(tmpKey, KERBEROS_CONSTANT);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected byte[] randomToKey(byte[] in) {
|
||||
// simple identity operation
|
||||
return in;
|
||||
}
|
||||
|
||||
/*
|
||||
* https://tools.ietf.org/html/rfc8009#section-3 defines
|
||||
* a new key derivation function:
|
||||
*
|
||||
* KDF-HMAC-SHA2(key, label, k) = k-truncate(K1)
|
||||
* K1 = HMAC-SHA-256(key, 0x00000001 | label | 0x00 | k) or
|
||||
* K1 = HMAC-SHA-384(key, 0x00000001 | label | 0x00 | k)
|
||||
*
|
||||
* where label is constant below.
|
||||
*/
|
||||
protected byte[] dr(byte[] key, byte[] constant)
|
||||
throws GeneralSecurityException {
|
||||
byte[] result;
|
||||
byte[] input = new byte[constant.length + 9];
|
||||
// 0x00000001 at the beginning
|
||||
input[3] = 1;
|
||||
// label follows
|
||||
System.arraycopy(constant, 0, input, 4, constant.length);
|
||||
SecretKeySpec tkey = new SecretKeySpec(key, "HMAC");
|
||||
Mac mac = Mac.getInstance(
|
||||
keyLength == 128? "HmacSHA256": "HmacSHA384");
|
||||
mac.init(tkey);
|
||||
|
||||
int k;
|
||||
if (keyLength == 128) {
|
||||
// key length for enc and hmac both 128
|
||||
k = 128;
|
||||
} else {
|
||||
byte last = constant[constant.length-1];
|
||||
if (last == (byte)0x99 || last == (byte)0x55) {
|
||||
// 192 for hmac
|
||||
k = 192;
|
||||
} else {
|
||||
// 256 for enc
|
||||
k = 256;
|
||||
}
|
||||
}
|
||||
// 0x00 and k at the end
|
||||
input[input.length - 1] = (byte)(k);
|
||||
input[input.length - 2] = (byte)(k / 256);
|
||||
|
||||
result = mac.doFinal(input);
|
||||
return Arrays.copyOf(result, k / 8);
|
||||
}
|
||||
|
||||
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(keyLength == 128 ? "HmacSHA256" : "HmacSHA384");
|
||||
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;
|
||||
}
|
||||
|
||||
private byte[] deriveKey(byte[] baseKey, int usage, byte type)
|
||||
throws GeneralSecurityException {
|
||||
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] = type;
|
||||
return dk(baseKey, constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
byte[] Kc = deriveKey(baseKey, usage, (byte) 0x99); // Checksum key
|
||||
if (debug) {
|
||||
System.err.println("usage: " + usage);
|
||||
traceOutput("input", input, start, Math.min(len, 32));
|
||||
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 {
|
||||
Ke = deriveKey(baseKey, usage, (byte) 0xaa); // 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);
|
||||
|
||||
Ki = deriveKey(baseKey, usage, (byte) 0x55);
|
||||
if (debug) {
|
||||
traceOutput("Ki", Ki, 0, Ke.length);
|
||||
}
|
||||
|
||||
// Generate checksum
|
||||
// H = HMAC(Ki, IV | C)
|
||||
byte[] msg = Arrays.copyOf(ivec, ivec.length + toBeEncrypted.length);
|
||||
System.arraycopy(output, 0, msg, ivec.length, toBeEncrypted.length);
|
||||
byte[] hmac = getHmac(Ki, msg);
|
||||
|
||||
// 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 {
|
||||
Ke = deriveKey(baseKey, usage, (byte) 0xaa); // 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("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));
|
||||
}
|
||||
|
||||
Ki = deriveKey(baseKey, usage, (byte) 0x55); // Integrity key
|
||||
if (debug) {
|
||||
traceOutput("Ki", Ki, 0, Ke.length);
|
||||
}
|
||||
|
||||
// Verify checksum
|
||||
// H = HMAC(Ki, IV | C)
|
||||
byte[] msg = Arrays.copyOf(ivec, ivec.length + len-hashSize);
|
||||
System.arraycopy(ciphertext, start, msg, ivec.length, len-hashSize);
|
||||
byte[] calculatedHmac = getHmac(Ki, msg);
|
||||
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(keyLength == 128 ?
|
||||
"PBKDF2WithHmacSHA256" : "PBKDF2WithHmacSHA384");
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -478,7 +478,7 @@ public abstract class DkCrypto {
|
|||
*
|
||||
* DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
|
||||
*/
|
||||
private byte[] dr(byte[] key, byte[] constant)
|
||||
protected byte[] dr(byte[] key, byte[] constant)
|
||||
throws GeneralSecurityException {
|
||||
|
||||
Cipher encCipher = getCipher(key, null, Cipher.ENCRYPT_MODE);
|
||||
|
@ -667,7 +667,7 @@ public abstract class DkCrypto {
|
|||
new HexDumpEncoder().encodeBuffer(
|
||||
new ByteArrayInputStream(output, offset, len), out);
|
||||
|
||||
System.err.println(traceTag + ":" + out.toString());
|
||||
System.err.println(traceTag + ":\n" + out.toString());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue