diff --git a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java index c1cb1643595..f62bd421952 100644 --- a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java +++ b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java @@ -70,6 +70,9 @@ enum CipherSuite { TLS_AES_256_GCM_SHA384( 0x1302, true, "TLS_AES_256_GCM_SHA384", ProtocolVersion.PROTOCOLS_OF_13, B_AES_256_GCM_IV, H_SHA384), + TLS_CHACHA20_POLY1305_SHA256( + 0x1303, true, "TLS_CHACHA20_POLY1305_SHA256", + ProtocolVersion.PROTOCOLS_OF_13, B_CC20_P1305, H_SHA256), // Suite B compliant cipher suites, see RFC 6460. // @@ -87,11 +90,22 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_OF_12, K_ECDHE_ECDSA, B_AES_128_GCM, M_NULL, H_SHA256), + // Not suite B, but we want it to position the suite early in the list + // of 1.2 suites. + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256( + 0xCCA9, true, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDHE_ECDSA, B_CC20_P1305, M_NULL, H_SHA256), + // AES_256(GCM) TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384( 0xC030, true, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, K_ECDHE_RSA, B_AES_256_GCM, M_NULL, H_SHA384), + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256( + 0xCCA8, true, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDHE_RSA, B_CC20_P1305, M_NULL, H_SHA256), TLS_RSA_WITH_AES_256_GCM_SHA384( 0x009D, true, "TLS_RSA_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -108,6 +122,10 @@ enum CipherSuite { 0x009F, true, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, K_DHE_RSA, B_AES_256_GCM, M_NULL, H_SHA384), + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256( + 0xCCAA, true, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_DHE_RSA, B_CC20_P1305, M_NULL, H_SHA256), TLS_DHE_DSS_WITH_AES_256_GCM_SHA384( 0x00A3, true, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -480,8 +498,6 @@ enum CipherSuite { // Definition of the CipherSuites that are not supported but the names // are known. - TLS_CHACHA20_POLY1305_SHA256( // TLS 1.3 - "TLS_CHACHA20_POLY1305_SHA256", 0x1303), TLS_AES_128_CCM_SHA256( // TLS 1.3 "TLS_AES_128_CCM_SHA256", 0x1304), TLS_AES_128_CCM_8_SHA256( // TLS 1.3 diff --git a/src/java.base/share/classes/sun/security/ssl/JsseJce.java b/src/java.base/share/classes/sun/security/ssl/JsseJce.java index df9a863a199..be5934acd63 100644 --- a/src/java.base/share/classes/sun/security/ssl/JsseJce.java +++ b/src/java.base/share/classes/sun/security/ssl/JsseJce.java @@ -129,6 +129,11 @@ public Object run() { */ static final String CIPHER_AES_GCM = "AES/GCM/NoPadding"; + /** + * JCE transformation string for ChaCha20-Poly1305 + */ + static final String CIPHER_CHACHA20_POLY1305 = "ChaCha20-Poly1305"; + /** * JCA identifier string for DSA, i.e. a DSA with SHA-1. */ diff --git a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java index 338c4ac994f..267670e4a34 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java @@ -329,6 +329,32 @@ enum SSLCipher { new T13GcmWriteCipherGenerator(), ProtocolVersion.PROTOCOLS_OF_13 ) + })), + + @SuppressWarnings({"unchecked", "rawtypes"}) + B_CC20_P1305(CIPHER_CHACHA20_POLY1305, AEAD_CIPHER, 32, 32, 12, + 12, true, false, + (Map.Entry[])(new Map.Entry[] { + new SimpleImmutableEntry( + new T12CC20P1305ReadCipherGenerator(), + ProtocolVersion.PROTOCOLS_OF_12 + ), + new SimpleImmutableEntry( + new T13CC20P1305ReadCipherGenerator(), + ProtocolVersion.PROTOCOLS_OF_13 + ) + }), + (Map.Entry[])(new Map.Entry[] { + new SimpleImmutableEntry( + new T12CC20P1305WriteCipherGenerator(), + ProtocolVersion.PROTOCOLS_OF_12 + ), + new SimpleImmutableEntry( + new T13CC20P1305WriteCipherGenerator(), + ProtocolVersion.PROTOCOLS_OF_13 + ) })); // descriptive name including key size, e.g. AES/128 @@ -2082,6 +2108,549 @@ int calculatePacketSize(int fragmentSize, int headerSize) { } } + private static final class T12CC20P1305ReadCipherGenerator + implements ReadCipherGenerator { + + @Override + public SSLReadCipher createCipher(SSLCipher sslCipher, + Authenticator authenticator, ProtocolVersion protocolVersion, + String algorithm, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws GeneralSecurityException { + return new CC20P1305ReadCipher(authenticator, protocolVersion, + sslCipher, algorithm, key, params, random); + } + + static final class CC20P1305ReadCipher extends SSLReadCipher { + private final Cipher cipher; + private final int tagSize; + private final Key key; + private final byte[] iv; + private final SecureRandom random; + + CC20P1305ReadCipher(Authenticator authenticator, + ProtocolVersion protocolVersion, + SSLCipher sslCipher, String algorithm, + Key key, AlgorithmParameterSpec params, + SecureRandom random) throws GeneralSecurityException { + super(authenticator, protocolVersion); + this.cipher = JsseJce.getCipher(algorithm); + this.tagSize = sslCipher.tagSize; + this.key = key; + this.iv = ((IvParameterSpec)params).getIV(); + this.random = random; + + // DON'T initialize the cipher for AEAD! + } + + @Override + public Plaintext decrypt(byte contentType, ByteBuffer bb, + byte[] sequence) throws GeneralSecurityException { + if (bb.remaining() <= tagSize) { + throw new BadPaddingException( + "Insufficient buffer remaining for AEAD cipher " + + "fragment (" + bb.remaining() + "). Needs to be " + + "more than tag size (" + tagSize + ")"); + } + + byte[] sn = sequence; + if (sn == null) { + sn = authenticator.sequenceNumber(); + } + byte[] nonce = new byte[iv.length]; + System.arraycopy(sn, 0, nonce, nonce.length - sn.length, + sn.length); + for (int i = 0; i < nonce.length; i++) { + nonce[i] ^= iv[i]; + } + + // initialize the AEAD cipher with the unique IV + AlgorithmParameterSpec spec = new IvParameterSpec(nonce); + try { + cipher.init(Cipher.DECRYPT_MODE, key, spec, random); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException ikae) { + // unlikely to happen + throw new RuntimeException( + "invalid key or spec in AEAD mode", ikae); + } + + // update the additional authentication data + byte[] aad = authenticator.acquireAuthenticationBytes( + contentType, bb.remaining() - tagSize, sequence); + cipher.updateAAD(aad); + + // DON'T decrypt the nonce_explicit for AEAD mode. The buffer + // position has moved out of the nonce_explicit range. + int len = bb.remaining(); + int pos = bb.position(); + ByteBuffer dup = bb.duplicate(); + try { + len = cipher.doFinal(dup, bb); + } catch (IllegalBlockSizeException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode \"" + ibse.getMessage() + + " \"in JCE provider " + cipher.getProvider().getName()); + } catch (ShortBufferException sbe) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error in " + + "JCE provider " + cipher.getProvider().getName(), sbe); + } + // reset the limit to the end of the decrypted data + bb.position(pos); + bb.limit(pos + len); + + if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + SSLLogger.fine( + "Plaintext after DECRYPTION", bb.duplicate()); + } + + return new Plaintext(contentType, + ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, + -1, -1L, bb.slice()); + } + + @Override + void dispose() { + if (cipher != null) { + try { + cipher.doFinal(); + } catch (Exception e) { + // swallow all types of exceptions. + } + } + } + + @Override + int estimateFragmentSize(int packetSize, int headerSize) { + return packetSize - headerSize - tagSize; + } + } + } + + private static final class T12CC20P1305WriteCipherGenerator + implements WriteCipherGenerator { + @Override + public SSLWriteCipher createCipher(SSLCipher sslCipher, + Authenticator authenticator, ProtocolVersion protocolVersion, + String algorithm, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws GeneralSecurityException { + return new CC20P1305WriteCipher(authenticator, protocolVersion, + sslCipher, algorithm, key, params, random); + } + + private static final class CC20P1305WriteCipher extends SSLWriteCipher { + private final Cipher cipher; + private final int tagSize; + private final Key key; + private final byte[] iv; + private final SecureRandom random; + + CC20P1305WriteCipher(Authenticator authenticator, + ProtocolVersion protocolVersion, + SSLCipher sslCipher, String algorithm, + Key key, AlgorithmParameterSpec params, + SecureRandom random) throws GeneralSecurityException { + super(authenticator, protocolVersion); + this.cipher = JsseJce.getCipher(algorithm); + this.tagSize = sslCipher.tagSize; + this.key = key; + this.iv = ((IvParameterSpec)params).getIV(); + this.random = random; + + keyLimitCountdown = cipherLimits.getOrDefault( + algorithm.toUpperCase() + ":" + tag[0], 0L); + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.fine("algorithm = " + algorithm.toUpperCase() + + ":" + tag[0] + "\ncountdown value = " + + keyLimitCountdown); + } + if (keyLimitCountdown > 0) { + keyLimitEnabled = true; + } + + // DON'T initialize the cipher for AEAD! + } + + @Override + public int encrypt(byte contentType, + ByteBuffer bb) { + byte[] sn = authenticator.sequenceNumber(); + byte[] nonce = new byte[iv.length]; + System.arraycopy(sn, 0, nonce, nonce.length - sn.length, + sn.length); + for (int i = 0; i < nonce.length; i++) { + nonce[i] ^= iv[i]; + } + + // initialize the AEAD cipher for the unique IV + AlgorithmParameterSpec spec = new IvParameterSpec(nonce); + try { + cipher.init(Cipher.ENCRYPT_MODE, key, spec, random); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException ikae) { + // unlikely to happen + throw new RuntimeException( + "invalid key or spec in AEAD mode", ikae); + } + + // Update the additional authentication data, using the + // implicit sequence number of the authenticator. + byte[] aad = authenticator.acquireAuthenticationBytes( + contentType, bb.remaining(), null); + cipher.updateAAD(aad); + + // DON'T encrypt the nonce for AEAD mode. + int len = bb.remaining(); + int pos = bb.position(); + if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + SSLLogger.fine( + "Plaintext before ENCRYPTION", + bb.duplicate()); + } + + ByteBuffer dup = bb.duplicate(); + int outputSize = cipher.getOutputSize(dup.remaining()); + if (outputSize > bb.remaining()) { + // Need to expand the limit of the output buffer for + // the authentication tag. + // + // DON'T worry about the buffer's capacity, we have + // reserved space for the authentication tag. + bb.limit(pos + outputSize); + } + + try { + len = cipher.doFinal(dup, bb); + } catch (IllegalBlockSizeException | + BadPaddingException | ShortBufferException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode in JCE provider " + + cipher.getProvider().getName(), ibse); + } + + if (len != outputSize) { + throw new RuntimeException( + "Cipher buffering error in JCE provider " + + cipher.getProvider().getName()); + } + + return len; + } + + @Override + void dispose() { + if (cipher != null) { + try { + cipher.doFinal(); + } catch (Exception e) { + // swallow all types of exceptions. + } + } + } + + @Override + int getExplicitNonceSize() { + return 0; + } + + @Override + int calculateFragmentSize(int packetLimit, int headerSize) { + return packetLimit - headerSize - tagSize; + } + + @Override + int calculatePacketSize(int fragmentSize, int headerSize) { + return fragmentSize + headerSize + tagSize; + } + } + } + + private static final class T13CC20P1305ReadCipherGenerator + implements ReadCipherGenerator { + + @Override + public SSLReadCipher createCipher(SSLCipher sslCipher, + Authenticator authenticator, ProtocolVersion protocolVersion, + String algorithm, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws GeneralSecurityException { + return new CC20P1305ReadCipher(authenticator, protocolVersion, + sslCipher, algorithm, key, params, random); + } + + static final class CC20P1305ReadCipher extends SSLReadCipher { + private final Cipher cipher; + private final int tagSize; + private final Key key; + private final byte[] iv; + private final SecureRandom random; + + CC20P1305ReadCipher(Authenticator authenticator, + ProtocolVersion protocolVersion, + SSLCipher sslCipher, String algorithm, + Key key, AlgorithmParameterSpec params, + SecureRandom random) throws GeneralSecurityException { + super(authenticator, protocolVersion); + this.cipher = JsseJce.getCipher(algorithm); + this.tagSize = sslCipher.tagSize; + this.key = key; + this.iv = ((IvParameterSpec)params).getIV(); + this.random = random; + + // DON'T initialize the cipher for AEAD! + } + + @Override + public Plaintext decrypt(byte contentType, ByteBuffer bb, + byte[] sequence) throws GeneralSecurityException { + // An implementation may receive an unencrypted record of type + // change_cipher_spec consisting of the single byte value 0x01 + // at any time after the first ClientHello message has been + // sent or received and before the peer's Finished message has + // been received and MUST simply drop it without further + // processing. + if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) { + return new Plaintext(contentType, + ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, + -1, -1L, bb.slice()); + } + + if (bb.remaining() <= tagSize) { + throw new BadPaddingException( + "Insufficient buffer remaining for AEAD cipher " + + "fragment (" + bb.remaining() + "). Needs to be " + + "more than tag size (" + tagSize + ")"); + } + + byte[] sn = sequence; + if (sn == null) { + sn = authenticator.sequenceNumber(); + } + byte[] nonce = new byte[iv.length]; + System.arraycopy(sn, 0, nonce, nonce.length - sn.length, + sn.length); + for (int i = 0; i < nonce.length; i++) { + nonce[i] ^= iv[i]; + } + + // initialize the AEAD cipher with the unique IV + AlgorithmParameterSpec spec = new IvParameterSpec(nonce); + try { + cipher.init(Cipher.DECRYPT_MODE, key, spec, random); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException ikae) { + // unlikely to happen + throw new RuntimeException( + "invalid key or spec in AEAD mode", ikae); + } + + // Update the additional authentication data, using the + // implicit sequence number of the authenticator. + byte[] aad = authenticator.acquireAuthenticationBytes( + contentType, bb.remaining(), sn); + cipher.updateAAD(aad); + + int len = bb.remaining(); + int pos = bb.position(); + ByteBuffer dup = bb.duplicate(); + try { + len = cipher.doFinal(dup, bb); + } catch (IllegalBlockSizeException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode \"" + ibse.getMessage() + + " \"in JCE provider " + cipher.getProvider().getName()); + } catch (ShortBufferException sbe) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error in " + + "JCE provider " + cipher.getProvider().getName(), sbe); + } + // reset the limit to the end of the decrypted data + bb.position(pos); + bb.limit(pos + len); + + // remove inner plaintext padding + int i = bb.limit() - 1; + for (; i > 0 && bb.get(i) == 0; i--) { + // blank + } + if (i < (pos + 1)) { + throw new BadPaddingException( + "Incorrect inner plaintext: no content type"); + } + contentType = bb.get(i); + bb.limit(i); + + if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + SSLLogger.fine( + "Plaintext after DECRYPTION", bb.duplicate()); + } + + return new Plaintext(contentType, + ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, + -1, -1L, bb.slice()); + } + + @Override + void dispose() { + if (cipher != null) { + try { + cipher.doFinal(); + } catch (Exception e) { + // swallow all types of exceptions. + } + } + } + + @Override + int estimateFragmentSize(int packetSize, int headerSize) { + return packetSize - headerSize - tagSize; + } + } + } + + private static final class T13CC20P1305WriteCipherGenerator + implements WriteCipherGenerator { + @Override + public SSLWriteCipher createCipher(SSLCipher sslCipher, + Authenticator authenticator, ProtocolVersion protocolVersion, + String algorithm, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws GeneralSecurityException { + return new CC20P1305WriteCipher(authenticator, protocolVersion, + sslCipher, algorithm, key, params, random); + } + + private static final class CC20P1305WriteCipher extends SSLWriteCipher { + private final Cipher cipher; + private final int tagSize; + private final Key key; + private final byte[] iv; + private final SecureRandom random; + + CC20P1305WriteCipher(Authenticator authenticator, + ProtocolVersion protocolVersion, + SSLCipher sslCipher, String algorithm, + Key key, AlgorithmParameterSpec params, + SecureRandom random) throws GeneralSecurityException { + super(authenticator, protocolVersion); + this.cipher = JsseJce.getCipher(algorithm); + this.tagSize = sslCipher.tagSize; + this.key = key; + this.iv = ((IvParameterSpec)params).getIV(); + this.random = random; + + keyLimitCountdown = cipherLimits.getOrDefault( + algorithm.toUpperCase() + ":" + tag[0], 0L); + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.fine("algorithm = " + algorithm.toUpperCase() + + ":" + tag[0] + "\ncountdown value = " + + keyLimitCountdown); + } + if (keyLimitCountdown > 0) { + keyLimitEnabled = true; + } + + // DON'T initialize the cipher for AEAD! + } + + @Override + public int encrypt(byte contentType, + ByteBuffer bb) { + byte[] sn = authenticator.sequenceNumber(); + byte[] nonce = new byte[iv.length]; + System.arraycopy(sn, 0, nonce, nonce.length - sn.length, + sn.length); + for (int i = 0; i < nonce.length; i++) { + nonce[i] ^= iv[i]; + } + + // initialize the AEAD cipher for the unique IV + AlgorithmParameterSpec spec = new IvParameterSpec(nonce); + try { + cipher.init(Cipher.ENCRYPT_MODE, key, spec, random); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException ikae) { + // unlikely to happen + throw new RuntimeException( + "invalid key or spec in AEAD mode", ikae); + } + + // Update the additional authentication data, using the + // implicit sequence number of the authenticator. + int outputSize = cipher.getOutputSize(bb.remaining()); + byte[] aad = authenticator.acquireAuthenticationBytes( + contentType, outputSize, sn); + cipher.updateAAD(aad); + + int len = bb.remaining(); + int pos = bb.position(); + if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + SSLLogger.fine( + "Plaintext before ENCRYPTION", + bb.duplicate()); + } + + ByteBuffer dup = bb.duplicate(); + if (outputSize > bb.remaining()) { + // Need to expand the limit of the output buffer for + // the authentication tag. + // + // DON'T worry about the buffer's capacity, we have + // reserved space for the authentication tag. + bb.limit(pos + outputSize); + } + + try { + len = cipher.doFinal(dup, bb); + } catch (IllegalBlockSizeException | + BadPaddingException | ShortBufferException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode in JCE provider " + + cipher.getProvider().getName(), ibse); + } + + if (len != outputSize) { + throw new RuntimeException( + "Cipher buffering error in JCE provider " + + cipher.getProvider().getName()); + } + + if (keyLimitEnabled) { + keyLimitCountdown -= len; + } + return len; + } + + @Override + void dispose() { + if (cipher != null) { + try { + cipher.doFinal(); + } catch (Exception e) { + // swallow all types of exceptions. + } + } + } + + @Override + int getExplicitNonceSize() { + return 0; + } + + @Override + int calculateFragmentSize(int packetLimit, int headerSize) { + return packetLimit - headerSize - tagSize; + } + + @Override + int calculatePacketSize(int fragmentSize, int headerSize) { + return fragmentSize + headerSize + tagSize; + } + } + } + private static void addMac(MAC signer, ByteBuffer destination, byte contentType) { if (signer.macAlg().size != 0) { @@ -2367,4 +2936,3 @@ private static int[] checkPadding(ByteBuffer bb, byte pad) { return results; } } - diff --git a/test/jdk/javax/net/ssl/TLSCommon/CipherSuite.java b/test/jdk/javax/net/ssl/TLSCommon/CipherSuite.java index f963cabbbb6..54497753c90 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/CipherSuite.java +++ b/test/jdk/javax/net/ssl/TLSCommon/CipherSuite.java @@ -27,6 +27,8 @@ public enum CipherSuite { 0x1302, Protocol.TLSV1_3, Protocol.TLSV1_3), TLS_AES_128_GCM_SHA256( 0x1301, Protocol.TLSV1_3, Protocol.TLSV1_3), + TLS_CHACHA20_POLY1305_SHA256( + 0x1303, Protocol.TLSV1_3, Protocol.TLSV1_3), TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256( 0xCCAA, Protocol.TLSV1_2, Protocol.TLSV1_2), TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256( diff --git a/test/jdk/javax/net/ssl/TLSCommon/SSLEngineTestCase.java b/test/jdk/javax/net/ssl/TLSCommon/SSLEngineTestCase.java index 81ce3d324e3..57548ce750d 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/SSLEngineTestCase.java +++ b/test/jdk/javax/net/ssl/TLSCommon/SSLEngineTestCase.java @@ -182,7 +182,8 @@ public enum HandshakeMode { private static final String[] TLS13_CIPHERS = { "TLS_AES_256_GCM_SHA384", - "TLS_AES_128_GCM_SHA256" + "TLS_AES_128_GCM_SHA256", + "TLS_CHACHA20_POLY1305_SHA256" }; private static final String[] SUPPORTED_NON_KRB_CIPHERS;