# HG changeset patch # User weijun # Date 1516593641 -28800 # Node ID 67abfee27e6966cde1ce3babc4f2072c37a2d227 # Parent e7164f73c4d3ee9dfd342f7e105a5ae5face35d1 8014628: Support AES Encryption with HMAC-SHA2 for Kerberos 5 Reviewed-by: mullan diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java Mon Jan 22 12:00:41 2018 +0800 @@ -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 @@ -138,6 +138,12 @@ case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: return "aes256-cts-hmac-sha1-96"; + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + return "aes128-cts-hmac-sha256-128"; + + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: + return "aes256-cts-hmac-sha384-192"; + case EncryptedData.ETYPE_NULL: return "none"; diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java Mon Jan 22 12:00:41 2018 +0800 @@ -40,6 +40,8 @@ import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import sun.security.krb5.*; +import sun.security.krb5.internal.crypto.Aes128Sha2; +import sun.security.krb5.internal.crypto.Aes256Sha2; import sun.security.krb5.internal.crypto.Des3; import sun.security.krb5.internal.crypto.Aes128; import sun.security.krb5.internal.crypto.Aes256; @@ -101,6 +103,8 @@ case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: sgnAlg = -1; sealAlg = -1; break; @@ -365,6 +369,33 @@ throw ge; } + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + try { + byte[] answer = Aes128Sha2.calculateChecksum(keybytes, key_usage, + buf, 0, total); + return answer; + } catch (GeneralSecurityException e) { + GSSException ge = new GSSException(GSSException.FAILURE, -1, + "Could not use AES128 signing algorithm - " + + e.getMessage()); + ge.initCause(e); + throw ge; + } + + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: + try { + byte[] answer = Aes256Sha2.calculateChecksum(keybytes, key_usage, + buf, 0, total); + return answer; + } catch (GeneralSecurityException e) { + GSSException ge = new GSSException(GSSException.FAILURE, -1, + "Could not use AES256 signing algorithm - " + + e.getMessage()); + ge.initCause(e); + throw ge; + } + + default: throw new GSSException(GSSException.FAILURE, -1, "Unsupported encryption type: " + etype); @@ -517,6 +548,11 @@ case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: return Aes256.getChecksumLength(); + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + return Aes128Sha2.getChecksumLength(); + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: + return Aes256Sha2.getChecksumLength(); + case EncryptedData.ETYPE_ARCFOUR_HMAC: // only first 8 octets of HMAC Sgn_Cksum are used return HMAC_CHECKSUM_SIZE; @@ -574,6 +610,14 @@ aes256Decrypt(token, ciphertext, cStart, cLen, plaintext, pStart, key_usage); break; + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + aes128Sha2Decrypt(token, ciphertext, cStart, cLen, + plaintext, pStart, key_usage); + break; + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: + aes256Sha2Decrypt(token, ciphertext, cStart, cLen, + plaintext, pStart, key_usage); + break; default: throw new GSSException(GSSException.FAILURE, -1, "Unsupported etype: " + etype); @@ -654,6 +698,14 @@ aes256Decrypt(token, ciphertext, 0, cLen, plaintext, pStart, key_usage); break; + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + aes128Sha2Decrypt(token, ciphertext, 0, cLen, + plaintext, pStart, key_usage); + break; + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: + aes256Sha2Decrypt(token, ciphertext, 0, cLen, + plaintext, pStart, key_usage); + break; default: throw new GSSException(GSSException.FAILURE, -1, "Unsupported etype: " + etype); @@ -720,6 +772,12 @@ case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: return aes256Encrypt(confounder, tokenHeader, plaintext, start, len, key_usage); + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + return aes128Sha2Encrypt(confounder, tokenHeader, + plaintext, start, len, key_usage); + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: + return aes256Sha2Encrypt(confounder, tokenHeader, + plaintext, start, len, key_usage); default: throw new GSSException(GSSException.FAILURE, -1, "Unsupported etype: " + etype); @@ -796,6 +854,14 @@ ctext = aes256Encrypt(confounder, tokenHeader, plaintext, pStart, pLen, key_usage); break; + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + ctext = aes128Sha2Encrypt(confounder, tokenHeader, + plaintext, pStart, pLen, key_usage); + break; + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: + ctext = aes256Sha2Encrypt(confounder, tokenHeader, + plaintext, pStart, pLen, key_usage); + break; default: throw new GSSException(GSSException.FAILURE, -1, "Unsupported etype: " + etype); @@ -1317,6 +1383,38 @@ } } + private byte[] aes128Sha2Encrypt(byte[] confounder, byte[] tokenHeader, + byte[] plaintext, int start, int len, int key_usage) + throws GSSException { + + // encrypt { AES-plaintext-data | filler | header } + // AES-plaintext-data { confounder | plaintext } + // WrapToken = { tokenHeader | + // Encrypt (confounder | plaintext | tokenHeader ) | HMAC } + + byte[] all = new byte[confounder.length + len + tokenHeader.length]; + System.arraycopy(confounder, 0, all, 0, confounder.length); + System.arraycopy(plaintext, start, all, confounder.length, len); + System.arraycopy(tokenHeader, 0, all, confounder.length+len, + tokenHeader.length); + + // Krb5Token.debug("\naes128Sha2Encrypt:" + Krb5Token.getHexBytes(all)); + try { + byte[] answer = Aes128Sha2.encryptRaw(keybytes, key_usage, + ZERO_IV_AES, + all, 0, all.length); + // Krb5Token.debug("\naes128Sha2Encrypt encrypted:" + + // Krb5Token.getHexBytes(answer)); + return answer; + } catch (Exception e) { + // GeneralSecurityException, KrbCryptoException + GSSException ge = new GSSException(GSSException.FAILURE, -1, + "Could not use Aes128Sha2 Cipher - " + e.getMessage()); + ge.initCause(e); + throw ge; + } + } + private void aes128Decrypt(WrapToken_v2 token, byte[] ciphertext, int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) throws GSSException { @@ -1354,6 +1452,43 @@ */ } + private void aes128Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext, + int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) + throws GSSException { + + byte[] ptext = null; + + try { + ptext = Aes128Sha2.decryptRaw(keybytes, key_usage, + ZERO_IV_AES, ciphertext, cStart, cLen); + } catch (GeneralSecurityException e) { + GSSException ge = new GSSException(GSSException.FAILURE, -1, + "Could not use AES128Sha2 Cipher - " + e.getMessage()); + ge.initCause(e); + throw ge; + } + + /* + Krb5Token.debug("\naes128Sha2Decrypt in: " + + Krb5Token.getHexBytes(ciphertext, cStart, cLen)); + Krb5Token.debug("\naes128Sha2Decrypt plain: " + + Krb5Token.getHexBytes(ptext)); + Krb5Token.debug("\naes128Sha2Decrypt ptext: " + + Krb5Token.getHexBytes(ptext)); + */ + + // Strip out confounder and token header + int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE - + WrapToken_v2.TOKEN_HEADER_SIZE; + System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE, + plaintext, pStart, len); + + /* + Krb5Token.debug("\naes128Sha2Decrypt plaintext: " + + Krb5Token.getHexBytes(plaintext, pStart, len)); + */ + } + private byte[] aes256Encrypt(byte[] confounder, byte[] tokenHeader, byte[] plaintext, int start, int len, int key_usage) throws GSSException { @@ -1386,6 +1521,38 @@ } } + private byte[] aes256Sha2Encrypt(byte[] confounder, byte[] tokenHeader, + byte[] plaintext, int start, int len, int key_usage) + throws GSSException { + + // encrypt { AES-plaintext-data | filler | header } + // AES-plaintext-data { confounder | plaintext } + // WrapToken = { tokenHeader | + // Encrypt (confounder | plaintext | tokenHeader ) | HMAC } + + byte[] all = new byte[confounder.length + len + tokenHeader.length]; + System.arraycopy(confounder, 0, all, 0, confounder.length); + System.arraycopy(plaintext, start, all, confounder.length, len); + System.arraycopy(tokenHeader, 0, all, confounder.length+len, + tokenHeader.length); + + // Krb5Token.debug("\naes256Sha2Encrypt:" + Krb5Token.getHexBytes(all)); + + try { + byte[] answer = Aes256Sha2.encryptRaw(keybytes, key_usage, + ZERO_IV_AES, all, 0, all.length); + // Krb5Token.debug("\naes256Sha2Encrypt encrypted:" + + // Krb5Token.getHexBytes(answer)); + return answer; + } catch (Exception e) { + // GeneralSecurityException, KrbCryptoException + GSSException ge = new GSSException(GSSException.FAILURE, -1, + "Could not use Aes256Sha2 Cipher - " + e.getMessage()); + ge.initCause(e); + throw ge; + } + } + private void aes256Decrypt(WrapToken_v2 token, byte[] ciphertext, int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) throws GSSException { @@ -1423,6 +1590,43 @@ } + private void aes256Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext, + int cStart, int cLen, byte[] plaintext, int pStart, int key_usage) + throws GSSException { + + byte[] ptext; + try { + ptext = Aes256Sha2.decryptRaw(keybytes, key_usage, + ZERO_IV_AES, ciphertext, cStart, cLen); + } catch (GeneralSecurityException e) { + GSSException ge = new GSSException(GSSException.FAILURE, -1, + "Could not use AES256Sha2 Cipher - " + e.getMessage()); + ge.initCause(e); + throw ge; + } + + /* + Krb5Token.debug("\naes256Sha2Decrypt in: " + + Krb5Token.getHexBytes(ciphertext, cStart, cLen)); + Krb5Token.debug("\naes256Sha2Decrypt plain: " + + Krb5Token.getHexBytes(ptext)); + Krb5Token.debug("\naes256Sha2Decrypt ptext: " + + Krb5Token.getHexBytes(ptext)); + */ + + // Strip out confounder and token header + int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE - + WrapToken_v2.TOKEN_HEADER_SIZE; + System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE, + plaintext, pStart, len); + + /* + Krb5Token.debug("\naes256Sha2Decrypt plaintext: " + + Krb5Token.getHexBytes(plaintext, pStart, len)); + */ + + } + /** * This class provides a truncated inputstream needed by WrapToken. The * truncated inputstream is passed to CipherInputStream. It prevents diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java --- a/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java Mon Jan 22 12:00:41 2018 +0800 @@ -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 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; diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/Config.java --- a/src/java.security.jgss/share/classes/sun/security/krb5/Config.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Config.java Mon Jan 22 12:00:41 2018 +0800 @@ -1030,11 +1030,19 @@ } 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 @@ 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")) { diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/EncryptedData.java --- a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptedData.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptedData.java Mon Jan 22 12:00:41 2018 +0800 @@ -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 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() { } diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java --- a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java Mon Jan 22 12:00:41 2018 +0800 @@ -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 @@ 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 @@ 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"); diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java Mon Jan 22 12:00:41 2018 +0800 @@ -356,6 +356,8 @@ 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; diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/Aes128CtsHmacSha2EType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/Aes128CtsHmacSha2EType.java Mon Jan 22 12:00:41 2018 +0800 @@ -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; + } +} diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/Aes128Sha2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/Aes128Sha2.java Mon Jan 22 12:00:41 2018 +0800 @@ -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); + } +}; diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/Aes256CtsHmacSha2EType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/Aes256CtsHmacSha2EType.java Mon Jan 22 12:00:41 2018 +0800 @@ -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; + } +} diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/Aes256Sha2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/Aes256Sha2.java Mon Jan 22 12:00:41 2018 +0800 @@ -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); + } +}; diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java Mon Jan 22 12:00:41 2018 +0800 @@ -106,7 +106,19 @@ "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 @@ // 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 @@ 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 + ")"; } diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/HmacSha2Aes128CksumType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/HmacSha2Aes128CksumType.java Mon Jan 22 12:00:41 2018 +0800 @@ -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; + } + } +} diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/HmacSha2Aes256CksumType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/HmacSha2Aes256CksumType.java Mon Jan 22 12:00:41 2018 +0800 @@ -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; + } + } +} diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java Mon Jan 22 12:00:41 2018 +0800 @@ -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; + } + +} diff -r e7164f73c4d3 -r 67abfee27e69 src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java Fri Jan 19 15:05:18 2018 -0800 +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java Mon Jan 22 12:00:41 2018 +0800 @@ -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 @@ * * 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 @@ 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) { } } diff -r e7164f73c4d3 -r 67abfee27e69 test/jdk/sun/security/krb5/auto/BasicKrb5Test.java --- a/test/jdk/sun/security/krb5/auto/BasicKrb5Test.java Fri Jan 19 15:05:18 2018 -0800 +++ b/test/jdk/sun/security/krb5/auto/BasicKrb5Test.java Mon Jan 22 12:00:41 2018 +0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -23,44 +23,50 @@ /* * @test - * @bug 6706974 + * @bug 6706974 8014628 * @summary Add krb5 test infrastructure * @compile -XDignore.symbol.file BasicKrb5Test.java * @run main/othervm BasicKrb5Test * @run main/othervm BasicKrb5Test des-cbc-crc * @run main/othervm BasicKrb5Test des-cbc-md5 * @run main/othervm BasicKrb5Test des3-cbc-sha1 - * @run main/othervm BasicKrb5Test aes128-cts - * @run main/othervm BasicKrb5Test aes256-cts + * @run main/othervm BasicKrb5Test aes128-sha1 + * @run main/othervm BasicKrb5Test aes256-sha1 + * @run main/othervm BasicKrb5Test aes128-sha2 + * @run main/othervm BasicKrb5Test aes256-sha2 * @run main/othervm BasicKrb5Test rc4-hmac * @run main/othervm BasicKrb5Test -s * @run main/othervm BasicKrb5Test des-cbc-crc -s * @run main/othervm BasicKrb5Test des-cbc-md5 -s * @run main/othervm BasicKrb5Test des3-cbc-sha1 -s - * @run main/othervm BasicKrb5Test aes128-cts -s - * @run main/othervm BasicKrb5Test aes256-cts -s + * @run main/othervm BasicKrb5Test aes128-sha1 -s + * @run main/othervm BasicKrb5Test aes256-sha1 -s + * @run main/othervm BasicKrb5Test aes128-sha2 -s + * @run main/othervm BasicKrb5Test aes256-sha2 -s * @run main/othervm BasicKrb5Test rc4-hmac -s * @run main/othervm BasicKrb5Test -C * @run main/othervm BasicKrb5Test des-cbc-crc -C * @run main/othervm BasicKrb5Test des-cbc-md5 -C * @run main/othervm BasicKrb5Test des3-cbc-sha1 -C - * @run main/othervm BasicKrb5Test aes128-cts -C - * @run main/othervm BasicKrb5Test aes256-cts -C + * @run main/othervm BasicKrb5Test aes128-sha1 -C + * @run main/othervm BasicKrb5Test aes256-sha1 -C + * @run main/othervm BasicKrb5Test aes128-sha2 -C + * @run main/othervm BasicKrb5Test aes256-sha2 -C * @run main/othervm BasicKrb5Test rc4-hmac -C * @run main/othervm BasicKrb5Test -s -C * @run main/othervm BasicKrb5Test des-cbc-crc -s -C * @run main/othervm BasicKrb5Test des-cbc-md5 -s -C * @run main/othervm BasicKrb5Test des3-cbc-sha1 -s -C - * @run main/othervm BasicKrb5Test aes128-cts -s -C - * @run main/othervm BasicKrb5Test aes256-cts -s -C + * @run main/othervm BasicKrb5Test aes128-sha1 -s -C + * @run main/othervm BasicKrb5Test aes256-sha1 -s -C + * @run main/othervm BasicKrb5Test aes128-sha2 -s -C + * @run main/othervm BasicKrb5Test aes256-sha2 -s -C * @run main/othervm BasicKrb5Test rc4-hmac -s -C */ import org.ietf.jgss.GSSName; import sun.security.jgss.GSSUtil; -import sun.security.krb5.Config; import sun.security.krb5.KrbException; -import sun.security.krb5.internal.crypto.EType; /** * Basic JGSS/krb5 test with 3 parties: client, server, backend server. Each diff -r e7164f73c4d3 -r 67abfee27e69 test/jdk/sun/security/krb5/auto/KDC.java --- a/test/jdk/sun/security/krb5/auto/KDC.java Fri Jan 19 15:05:18 2018 -0800 +++ b/test/jdk/sun/security/krb5/auto/KDC.java Mon Jan 22 12:00:41 2018 +0800 @@ -604,19 +604,7 @@ */ private static EncryptionKey generateRandomKey(int eType) throws KrbException { - // Is 32 enough for AES256? I should have generated the keys directly - // but different cryptos have different rules on what keys are valid. - char[] pass = randomPassword(); - String algo; - switch (eType) { - case EncryptedData.ETYPE_DES_CBC_MD5: algo = "DES"; break; - case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD: algo = "DESede"; break; - case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: algo = "AES128"; break; - case EncryptedData.ETYPE_ARCFOUR_HMAC: algo = "ArcFourHMAC"; break; - case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: algo = "AES256"; break; - default: algo = "DES"; break; - } - return new EncryptionKey(pass, "NOTHING", algo); // Silly + return genKey0(randomPassword(), "NOTHING", null, eType, null); } /** @@ -680,6 +668,8 @@ switch (etype) { case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: String pn = p.toString(); if (p.getRealmString() == null) { pn = pn + "@" + getRealm(); @@ -687,7 +677,11 @@ if (s2kparamses.containsKey(pn)) { return s2kparamses.get(pn); } - return new byte[] {0, 0, 0x10, 0}; + if (etype < EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128) { + return new byte[]{0, 0, 0x10, 0}; + } else { + return new byte[]{0, 0, (byte) 0x80, 0}; + } default: return null; } @@ -715,9 +709,8 @@ kvno = pass[pass.length-1] - '0'; } } - return new EncryptionKey(EncryptionKeyDotStringToKey( - getPassword(p, server), getSalt(p), getParams(p, etype), etype), - etype, kvno); + return genKey0(getPassword(p, server), getSalt(p), + getParams(p, etype), etype, kvno); } catch (KrbException ke) { throw ke; } catch (Exception e) { @@ -735,6 +728,17 @@ } /** + * Generates key from password. + */ + private static EncryptionKey genKey0( + char[] pass, String salt, byte[] s2kparams, + int etype, Integer kvno) throws KrbException { + return new EncryptionKey(EncryptionKeyDotStringToKey( + pass, salt, s2kparams, etype), + etype, kvno); + } + + /** * Processes an incoming request and generates a response. * @param in the request * @return the response @@ -1181,8 +1185,8 @@ } boolean allOld = true; for (int i: eTypes) { - if (i == EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96 || - i == EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96) { + if (i >= EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96 && + i != EncryptedData.ETYPE_ARCFOUR_HMAC) { allOld = false; break; } diff -r e7164f73c4d3 -r 67abfee27e69 test/jdk/sun/security/krb5/auto/ReplayCacheTestProc.java --- a/test/jdk/sun/security/krb5/auto/ReplayCacheTestProc.java Fri Jan 19 15:05:18 2018 -0800 +++ b/test/jdk/sun/security/krb5/auto/ReplayCacheTestProc.java Mon Jan 22 12:00:41 2018 +0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 7152176 8168518 8172017 + * @bug 7152176 8168518 8172017 8014628 * @summary More krb5 tests * @library ../../../../java/security/testlibrary/ /test/lib * @build jdk.test.lib.Platform @@ -132,8 +132,13 @@ kdc.addPrincipalRandKey(service(i)); } + // Native lib might not support aes-sha2 + KDC.saveConfig(OneKDC.KRB5_CONF, kdc, + "default_tkt_enctypes = aes128-cts", + "default_tgs_enctypes = aes128-cts"); + + // Write KTAB after krb5.conf so it contains no aes-sha2 keys kdc.writeKtab(OneKDC.KTAB); - KDC.saveConfig(OneKDC.KRB5_CONF, kdc); // User-provided libs String userLibs = System.getProperty("test.libs"); diff -r e7164f73c4d3 -r 67abfee27e69 test/jdk/sun/security/krb5/etype/ETypeOrder.java --- a/test/jdk/sun/security/krb5/etype/ETypeOrder.java Fri Jan 19 15:05:18 2018 -0800 +++ b/test/jdk/sun/security/krb5/etype/ETypeOrder.java Mon Jan 22 12:00:41 2018 +0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -38,7 +38,7 @@ int[] etypes = EType.getBuiltInDefaults(); // Reference order, note that 2 is not implemented in Java - int correct[] = { 18, 17, 16, 23, 1, 3, 2 }; + int correct[] = { 18, 17, 20, 19, 16, 23, 1, 3, 2 }; int match = 0; loopi: for (int i=0; i= 256; + + // Sample results for string-to-key conversion: + char[] pass = "password".toCharArray(); + byte[] salt = cat( + hex("10 DF 9D D7 83 E5 BC 8A CE A1 73 0E 74 35 5F 61"), + "ATHENA.MIT.EDUraeburn".getBytes()); + + check(stringToKey(dk128, pass, salt, null), + hex("08 9B CA 48 B1 05 EA 6E A7 7C A5 D2 F3 9D C5 E7")); + + check(stringToKey(dk256, pass, salt, null), + hex("45 BD 80 6D BF 6A 83 3A 9C FF C1 C9 45 89 A2 22\n" + + "36 7A 79 BC 21 C4 13 71 89 06 E9 F5 78 A7 84 67")); + + // Sample results for key derivation: + byte[] bk16 = hex("37 05 D9 60 80 C1 77 28 A0 E8 00 EA B6 E0 D2 3C"); + + check(deriveKey(dk128, bk16, 2, (byte) 0x99), + hex("B3 1A 01 8A 48 F5 47 76 F4 03 E9 A3 96 32 5D C3")); + check(deriveKey(dk128, bk16, 2, (byte) 0xaa), + hex("9B 19 7D D1 E8 C5 60 9D 6E 67 C3 E3 7C 62 C7 2E")); + check(deriveKey(dk128, bk16, 2, (byte) 0x55), + hex("9F DA 0E 56 AB 2D 85 E1 56 9A 68 86 96 C2 6A 6C")); + + byte[] bk32 = hex( + "6D 40 4D 37 FA F7 9F 9D F0 D3 35 68 D3 20 66 98\n" + + "00 EB 48 36 47 2E A8 A0 26 D1 6B 71 82 46 0C 52"); + + check(deriveKey(dk256, bk32, 2, (byte) 0x99), hex( + "EF 57 18 BE 86 CC 84 96 3D 8B BB 50 31 E9 F5 C4\n" + + "BA 41 F2 8F AF 69 E7 3D")); + check(deriveKey(dk256, bk32, 2, (byte) 0xaa), hex( + "56 AB 22 BE E6 3D 82 D7 BC 52 27 F6 77 3F 8E A7\n" + + "A5 EB 1C 82 51 60 C3 83 12 98 0C 44 2E 5C 7E 49")); + check(deriveKey(dk256, bk32, 2, (byte) 0x55), hex( + "69 B1 65 14 E3 CD 8E 56 B8 20 10 D5 C7 30 12 B6\n" + + "22 C4 D0 0F FC 23 ED 1F")); + + // Sample encryptions (all using the default cipher state): + + check(enc(dk128, hex("7E 58 95 EA F2 67 24 35 BA D8 17 F5 45 A3 71 48"), + bk16, hex("")), + hex("EF 85 FB 89 0B B8 47 2F 4D AB 20 39 4D CA 78 1D\n" + + "AD 87 7E DA 39 D5 0C 87 0C 0D 5A 0A 8E 48 C7 18")); + + check(enc(dk128, hex("7B CA 28 5E 2F D4 13 0F B5 5B 1A 5C 83 BC 5B 24"), + bk16, hex("00 01 02 03 04 05")), + hex("84 D7 F3 07 54 ED 98 7B AB 0B F3 50 6B EB 09 CF\n" + + "B5 54 02 CE F7 E6 87 7C E9 9E 24 7E 52 D1 6E D4\n" + + "42 1D FD F8 97 6C")); + + check(enc(dk128, hex("56 AB 21 71 3F F6 2C 0A 14 57 20 0F 6F A9 94 8F"), + bk16, hex("00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F")), + hex("35 17 D6 40 F5 0D DC 8A D3 62 87 22 B3 56 9D 2A\n" + + "E0 74 93 FA 82 63 25 40 80 EA 65 C1 00 8E 8F C2\n" + + "95 FB 48 52 E7 D8 3E 1E 7C 48 C3 7E EB E6 B0 D3")); + + check(enc(dk128, hex("A7 A4 E2 9A 47 28 CE 10 66 4F B6 4E 49 AD 3F AC"), + bk16, hex("00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n" + + "10 11 12 13 14")), + hex("72 0F 73 B1 8D 98 59 CD 6C CB 43 46 11 5C D3 36\n" + + "C7 0F 58 ED C0 C4 43 7C 55 73 54 4C 31 C8 13 BC\n" + + "E1 E6 D0 72 C1 86 B3 9A 41 3C 2F 92 CA 9B 83 34\n" + + "A2 87 FF CB FC\n")); + + if (aes256ok) { + check(enc(dk256, hex("F7 64 E9 FA 15 C2 76 47 8B 2C 7D 0C 4E 5F 58 E4"), + bk32, hex("")), + hex("41 F5 3F A5 BF E7 02 6D 91 FA F9 BE 95 91 95 A0\n" + + "58 70 72 73 A9 6A 40 F0 A0 19 60 62 1A C6 12 74\n" + + "8B 9B BF BE 7E B4 CE 3C\n")); + + check(enc(dk256, hex("B8 0D 32 51 C1 F6 47 14 94 25 6F FE 71 2D 0B 9A"), + bk32, hex("00 01 02 03 04 05")), + hex("4E D7 B3 7C 2B CA C8 F7 4F 23 C1 CF 07 E6 2B C7\n" + + "B7 5F B3 F6 37 B9 F5 59 C7 F6 64 F6 9E AB 7B 60\n" + + "92 23 75 26 EA 0D 1F 61 CB 20 D6 9D 10 F2\n")); + + check(enc(dk256, hex("53 BF 8A 0D 10 52 65 D4 E2 76 42 86 24 CE 5E 63"), + bk32, hex("00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F")), + hex("BC 47 FF EC 79 98 EB 91 E8 11 5C F8 D1 9D AC 4B\n" + + "BB E2 E1 63 E8 7D D3 7F 49 BE CA 92 02 77 64 F6\n" + + "8C F5 1F 14 D7 98 C2 27 3F 35 DF 57 4D 1F 93 2E\n" + + "40 C4 FF 25 5B 36 A2 66\n")); + + check(enc(dk256, hex("76 3E 65 36 7E 86 4F 02 F5 51 53 C7 E3 B5 8A F1"), + bk32, hex("00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n" + + "10 11 12 13 14")), + hex("40 01 3E 2D F5 8E 87 51 95 7D 28 78 BC D2 D6 FE\n" + + "10 1C CF D5 56 CB 1E AE 79 DB 3C 3E E8 64 29 F2\n" + + "B2 A6 02 AC 86 FE F6 EC B6 47 D6 29 5F AE 07 7A\n" + + "1F EB 51 75 08 D2 C1 6B 41 92 E0 1F 62\n")); + } + + // Sample checksums: + + byte[] msg = hex( + "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n" + + "10 11 12 13 14"); + + check(checksum(dk128, bk16, msg), hex( + "D7 83 67 18 66 43 D6 7B 41 1C BA 91 39 FC 1D EE")); + + check(checksum(dk256, bk32, msg), hex( + "45 EE 79 15 67 EE FC A3 7F 4A C1 E0 22 2D E8 0D\n" + + "43 C3 BF A0 66 99 67 2A")); + + // Sample pseudorandom function (PRF) invocations: + // Java does not support PRF. Skipped. + } + + private static byte[] stringToKey(AesSha2DkCrypto dk, + char[] pass, byte[] salt, byte[] params) throws Exception { + Method m = AesSha2DkCrypto.class.getDeclaredMethod("stringToKey", + char[].class, byte[].class, byte[].class); + m.setAccessible(true); + return (byte[])m.invoke(dk, pass, salt, params); + } + + private static byte[] deriveKey(AesSha2DkCrypto dk, byte[] baseKey, + int usage, byte type) throws Exception { + Method m = AesSha2DkCrypto.class.getDeclaredMethod("deriveKey", + byte[].class, int.class, byte.class); + m.setAccessible(true); + return (byte[]) m.invoke(dk, baseKey, usage, type); + } + + private static byte[] cat(byte[] b1, byte[] b2) { + byte[] result = Arrays.copyOf(b1, b1.length + b2.length); + System.arraycopy(b2, 0, result, b1.length, b2.length); + return result; + } + + private static byte[] enc(AesSha2DkCrypto dk, byte[] confounder, + byte[] bk, byte[] text) throws Exception { + return dk.encryptRaw(bk, 2, new byte[16], cat(confounder, text), + 0, confounder.length + text.length); + } + + private static byte[] checksum(AesSha2DkCrypto dk, byte[] baseKey, byte[] text) + throws Exception { + return dk.calculateChecksum(baseKey, 2, text, 0, text.length); + } + + private static byte[] hex(String var) { + var = var.replaceAll("\\s", ""); + byte[] data = new byte[var.length()/2]; + for (int i=0; i