/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.harmony.xnet.provider.jsse; import java.security.GeneralSecurityException; import java.util.Hashtable; import javax.crypto.Cipher; /** * Represents Cipher Suite as defined in TLS 1.0 spec., * A.5. The CipherSuite; * C. CipherSuite definitions. * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec.</a> * */ public class CipherSuite { /** * true if this cipher suite is supported */ boolean supported = true; /** * cipher suite key exchange */ final int keyExchange; /** * cipher */ final String cipherName; /** * Cipher information */ final int keyMaterial; final int expandedKeyMaterial; final int effectiveKeyBytes; final int IVSize; final private int blockSize; // cipher suite code private final byte[] cipherSuiteCode; // cipher suite name private final String name; // true if cipher suite is exportable private final boolean isExportable; // Hash algorithm final private String hashName; // MAC algorithm final private String hmacName; // Hash size final private int hashSize; /** * key exchange values */ static int KeyExchange_RSA = 1; static int KeyExchange_RSA_EXPORT = 2; static int KeyExchange_DHE_DSS = 3; static int KeyExchange_DHE_DSS_EXPORT = 4; static int KeyExchange_DHE_RSA = 5; static int KeyExchange_DHE_RSA_EXPORT = 6; static int KeyExchange_DH_DSS = 7; static int KeyExchange_DH_RSA = 8; static int KeyExchange_DH_anon = 9; static int KeyExchange_DH_anon_EXPORT = 10; static int KeyExchange_DH_DSS_EXPORT = 11; static int KeyExchange_DH_RSA_EXPORT = 12; /** * TLS cipher suite codes */ static byte[] code_TLS_NULL_WITH_NULL_NULL = { 0x00, 0x00 }; static byte[] code_TLS_RSA_WITH_NULL_MD5 = { 0x00, 0x01 }; static byte[] code_TLS_RSA_WITH_NULL_SHA = { 0x00, 0x02 }; static byte[] code_TLS_RSA_EXPORT_WITH_RC4_40_MD5 = { 0x00, 0x03 }; static byte[] code_TLS_RSA_WITH_RC4_128_MD5 = { 0x00, 0x04 }; static byte[] code_TLS_RSA_WITH_RC4_128_SHA = { 0x00, 0x05 }; static byte[] code_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00, 0x06 }; static byte[] code_TLS_RSA_WITH_IDEA_CBC_SHA = { 0x00, 0x07 }; static byte[] code_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x08 }; static byte[] code_TLS_RSA_WITH_DES_CBC_SHA = { 0x00, 0x09 }; static byte[] code_TLS_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x0A }; static byte[] code_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x0B }; static byte[] code_TLS_DH_DSS_WITH_DES_CBC_SHA = { 0x00, 0x0C }; static byte[] code_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x0D }; static byte[] code_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x0E }; static byte[] code_TLS_DH_RSA_WITH_DES_CBC_SHA = { 0x00, 0x0F }; static byte[] code_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x10 }; static byte[] code_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x11 }; static byte[] code_TLS_DHE_DSS_WITH_DES_CBC_SHA = { 0x00, 0x12 }; static byte[] code_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x13 }; static byte[] code_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x14 }; static byte[] code_TLS_DHE_RSA_WITH_DES_CBC_SHA = { 0x00, 0x15 }; static byte[] code_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x16 }; static byte[] code_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00, 0x17 }; static byte[] code_TLS_DH_anon_WITH_RC4_128_MD5 = { 0x00, 0x18 }; static byte[] code_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x19 }; static byte[] code_TLS_DH_anon_WITH_DES_CBC_SHA = { 0x00, 0x1A }; static byte[] code_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x1B }; static CipherSuite TLS_NULL_WITH_NULL_NULL = new CipherSuite( "TLS_NULL_WITH_NULL_NULL", true, 0, null, null, code_TLS_NULL_WITH_NULL_NULL); static CipherSuite TLS_RSA_WITH_NULL_MD5 = new CipherSuite( "TLS_RSA_WITH_NULL_MD5", true, KeyExchange_RSA, null, "MD5", code_TLS_RSA_WITH_NULL_MD5); static CipherSuite TLS_RSA_WITH_NULL_SHA = new CipherSuite( "TLS_RSA_WITH_NULL_SHA", true, KeyExchange_RSA, null, "SHA", code_TLS_RSA_WITH_NULL_SHA); static CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = new CipherSuite( "TLS_RSA_EXPORT_WITH_RC4_40_MD5", true, KeyExchange_RSA_EXPORT, "RC4_40", "MD5", code_TLS_RSA_EXPORT_WITH_RC4_40_MD5); static CipherSuite TLS_RSA_WITH_RC4_128_MD5 = new CipherSuite( "TLS_RSA_WITH_RC4_128_MD5", false, KeyExchange_RSA, "RC4_128", "MD5", code_TLS_RSA_WITH_RC4_128_MD5); static CipherSuite TLS_RSA_WITH_RC4_128_SHA = new CipherSuite( "TLS_RSA_WITH_RC4_128_SHA", false, KeyExchange_RSA, "RC4_128", "SHA", code_TLS_RSA_WITH_RC4_128_SHA); static CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = new CipherSuite( "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", true, KeyExchange_RSA_EXPORT, "RC2_CBC_40", "MD5", code_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5); static CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = new CipherSuite( "TLS_RSA_WITH_IDEA_CBC_SHA", false, KeyExchange_RSA, "IDEA_CBC", "SHA", code_TLS_RSA_WITH_IDEA_CBC_SHA); static CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", true, KeyExchange_RSA_EXPORT, "DES40_CBC", "SHA", code_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA); static CipherSuite TLS_RSA_WITH_DES_CBC_SHA = new CipherSuite( "TLS_RSA_WITH_DES_CBC_SHA", false, KeyExchange_RSA, "DES_CBC", "SHA", code_TLS_RSA_WITH_DES_CBC_SHA); static CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = new CipherSuite( "TLS_RSA_WITH_3DES_EDE_CBC_SHA", false, KeyExchange_RSA, "3DES_EDE_CBC", "SHA", code_TLS_RSA_WITH_3DES_EDE_CBC_SHA); static CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", true, KeyExchange_DH_DSS_EXPORT, "DES40_CBC", "SHA", code_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA); static CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = new CipherSuite( "TLS_DH_DSS_WITH_DES_CBC_SHA", false, KeyExchange_DH_DSS, "DES_CBC", "SHA", code_TLS_DH_DSS_WITH_DES_CBC_SHA); static CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = new CipherSuite( "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", false, KeyExchange_DH_DSS, "3DES_EDE_CBC", "SHA", code_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA); static CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", true, KeyExchange_DH_RSA_EXPORT, "DES40_CBC", "SHA", code_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA); static CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = new CipherSuite( "TLS_DH_RSA_WITH_DES_CBC_SHA", false, KeyExchange_DH_RSA, "DES_CBC", "SHA", code_TLS_DH_RSA_WITH_DES_CBC_SHA); static CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = new CipherSuite( "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", false, KeyExchange_DH_RSA, "3DES_EDE_CBC", "SHA", code_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA); static CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", true, KeyExchange_DHE_DSS_EXPORT, "DES40_CBC", "SHA", code_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA); static CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = new CipherSuite( "TLS_DHE_DSS_WITH_DES_CBC_SHA", false, KeyExchange_DHE_DSS, "DES_CBC", "SHA", code_TLS_DHE_DSS_WITH_DES_CBC_SHA); static CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = new CipherSuite( "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", false, KeyExchange_DHE_DSS, "3DES_EDE_CBC", "SHA", code_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); static CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", true, KeyExchange_DHE_RSA_EXPORT, "DES40_CBC", "SHA", code_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA); static CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = new CipherSuite( "TLS_DHE_RSA_WITH_DES_CBC_SHA", false, KeyExchange_DHE_RSA, "DES_CBC", "SHA", code_TLS_DHE_RSA_WITH_DES_CBC_SHA); static CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = new CipherSuite( "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", false, KeyExchange_DHE_RSA, "3DES_EDE_CBC", "SHA", code_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); static CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = new CipherSuite( "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", true, KeyExchange_DH_anon_EXPORT, "RC4_40", "MD5", code_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5); static CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = new CipherSuite( "TLS_DH_anon_WITH_RC4_128_MD5", false, KeyExchange_DH_anon, "RC4_128", "MD5", code_TLS_DH_anon_WITH_RC4_128_MD5); static CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", true, KeyExchange_DH_anon_EXPORT, "DES40_CBC", "SHA", code_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA); static CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = new CipherSuite( "TLS_DH_anon_WITH_DES_CBC_SHA", false, KeyExchange_DH_anon, "DES_CBC", "SHA", code_TLS_DH_anon_WITH_DES_CBC_SHA); static CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = new CipherSuite( "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", false, KeyExchange_DH_anon, "3DES_EDE_CBC", "SHA", code_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA); // array for quick access to cipher suite by code private static CipherSuite[] cuitesByCode = { TLS_NULL_WITH_NULL_NULL, TLS_RSA_WITH_NULL_MD5, TLS_RSA_WITH_NULL_SHA, TLS_RSA_EXPORT_WITH_RC4_40_MD5, TLS_RSA_WITH_RC4_128_MD5, TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, TLS_RSA_WITH_IDEA_CBC_SHA, TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, TLS_RSA_WITH_DES_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_DH_DSS_WITH_DES_CBC_SHA, TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, TLS_DH_RSA_WITH_DES_CBC_SHA, TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_DHE_DSS_WITH_DES_CBC_SHA, TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, TLS_DH_anon_WITH_RC4_128_MD5, TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_DH_anon_WITH_DES_CBC_SHA, TLS_DH_anon_WITH_3DES_EDE_CBC_SHA }; // hash for quick access to cipher suite by name private static Hashtable<String, CipherSuite> cuitesByName; /** * array of supported cipher suites. * Set of supported suites is defined at the moment provider's start */ // TODO Dynamically supported suites: new providers may be dynamically // added/removed and the set of supported suites may be changed static CipherSuite[] supportedCipherSuites; /** * array of supported cipher suites names */ static String[] supportedCipherSuiteNames; /** * default cipher suites */ static CipherSuite[] defaultCipherSuites; static { int count = 0; cuitesByName = new Hashtable<String, CipherSuite>(); for (int i = 0; i < cuitesByCode.length; i++) { cuitesByName.put(cuitesByCode[i].getName(), cuitesByCode[i]); if (cuitesByCode[i].supported) { count++; } } supportedCipherSuites = new CipherSuite[count]; supportedCipherSuiteNames = new String[count]; count = 0; for (int i = 0; i < cuitesByCode.length; i++) { if (cuitesByCode[i].supported) { supportedCipherSuites[count] = cuitesByCode[i]; supportedCipherSuiteNames[count] = supportedCipherSuites[count].getName(); count++; } } CipherSuite[] defaultPretendent = { TLS_RSA_WITH_RC4_128_MD5, TLS_RSA_WITH_RC4_128_SHA, // TLS_RSA_WITH_AES_128_CBC_SHA, // TLS_DHE_RSA_WITH_AES_128_CBC_SHA, // LS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_RSA_WITH_DES_CBC_SHA, TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_DHE_DSS_WITH_DES_CBC_SHA, TLS_RSA_EXPORT_WITH_RC4_40_MD5, TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA }; count = 0; for (int i = 0; i < defaultPretendent.length; i++) { if (defaultPretendent[i].supported) { count++; } } defaultCipherSuites = new CipherSuite[count]; count = 0; for (int i = 0; i < defaultPretendent.length; i++) { if (defaultPretendent[i].supported) { defaultCipherSuites[count++] = defaultPretendent[i]; } } } /** * Returns CipherSuite by name * @param name * @return */ public static CipherSuite getByName(String name) { return cuitesByName.get(name); } /** * Returns CipherSuite based on TLS CipherSuite code * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., A.5. The CipherSuite</a> * @param b1 * @param b2 * @return */ public static CipherSuite getByCode(byte b1, byte b2) { if (b1 != 0 || (b2 & 0xFF) > cuitesByCode.length) { // Unknown return new CipherSuite("UNKNOUN_" + b1 + "_" + b2, false, 0, "", "", new byte[] { b1, b2 }); } return cuitesByCode[b2]; } /** * Returns CipherSuite based on V2CipherSpec code * as described in TLS 1.0 spec., E. Backward Compatibility With SSL * * @param b1 * @param b2 * @param b3 * @return CipherSuite */ public static CipherSuite getByCode(byte b1, byte b2, byte b3) { if (b1 == 0 && b2 == 0) { if ((b3 & 0xFF) <= cuitesByCode.length) { return cuitesByCode[b3]; } } // as TLSv1 equivalent of V2CipherSpec should be included in // V2ClientHello, ignore V2CipherSpec return new CipherSuite("UNKNOUN_" + b1 + "_" + b2 + "_" + b3, false, 0, "", "", new byte[] { b1, b2, b3 }); } /** * Creates CipherSuite * @param name * @param isExportable * @param keyExchange * @param cipherName * @param hash * @param code */ public CipherSuite(String name, boolean isExportable, int keyExchange, String cipherName, String hash, byte[] code) { this.name = name; this.keyExchange = keyExchange; this.isExportable = isExportable; if (cipherName == null) { this.cipherName = null; keyMaterial = 0; expandedKeyMaterial = 0; effectiveKeyBytes = 0; IVSize = 0; blockSize = 0; } else if ("IDEA_CBC".equals(cipherName)) { this.cipherName = "IDEA/CBC/NoPadding"; keyMaterial = 16; expandedKeyMaterial = 16; effectiveKeyBytes = 16; IVSize = 8; blockSize = 8; } else if ("RC2_CBC_40".equals(cipherName)) { this.cipherName = "RC2/CBC/NoPadding"; keyMaterial = 5; expandedKeyMaterial = 16; effectiveKeyBytes = 5; IVSize = 8; blockSize = 8; } else if ("RC4_40".equals(cipherName)) { this.cipherName = "RC4"; keyMaterial = 5; expandedKeyMaterial = 16; effectiveKeyBytes = 5; IVSize = 0; blockSize = 0; } else if ("RC4_128".equals(cipherName)) { this.cipherName = "RC4"; keyMaterial = 16; expandedKeyMaterial = 16; effectiveKeyBytes = 16; IVSize = 0; blockSize = 0; } else if ("DES40_CBC".equals(cipherName)) { this.cipherName = "DES/CBC/NoPadding"; keyMaterial = 5; expandedKeyMaterial = 8; effectiveKeyBytes = 5; IVSize = 8; blockSize = 8; } else if ("DES_CBC".equals(cipherName)) { this.cipherName = "DES/CBC/NoPadding"; keyMaterial = 8; expandedKeyMaterial = 8; effectiveKeyBytes = 7; IVSize = 8; blockSize = 8; } else if ("3DES_EDE_CBC".equals(cipherName)) { this.cipherName = "DESede/CBC/NoPadding"; keyMaterial = 24; expandedKeyMaterial = 24; effectiveKeyBytes = 24; IVSize = 8; blockSize = 8; } else { this.cipherName = cipherName; keyMaterial = 0; expandedKeyMaterial = 0; effectiveKeyBytes = 0; IVSize = 0; blockSize = 0; } if ("MD5".equals(hash)) { this.hmacName = "HmacMD5"; this.hashName = "MD5"; hashSize = 16; } else if ("SHA".equals(hash)) { this.hmacName = "HmacSHA1"; this.hashName = "SHA-1"; hashSize = 20; } else { this.hmacName = null; this.hashName = null; hashSize = 0; } cipherSuiteCode = code; if (this.cipherName != null) { try { Cipher.getInstance(this.cipherName); } catch (GeneralSecurityException e) { supported = false; } } } /** * Returns true if cipher suite is anonymous * @return */ public boolean isAnonymous() { if (keyExchange == KeyExchange_DH_anon || keyExchange == KeyExchange_DH_anon_EXPORT) { return true; } return false; } /** * Returns array of supported CipherSuites * @return */ public static CipherSuite[] getSupported() { return supportedCipherSuites; } /** * Returns array of supported cipher suites names * @return */ public static String[] getSupportedCipherSuiteNames() { return supportedCipherSuiteNames.clone(); } /** * Returns cipher suite name * @return */ public String getName() { return name; } /** * Returns cipher suite code as byte array * @return */ public byte[] toBytes() { return cipherSuiteCode; } /** * Returns cipher suite description */ @Override public String toString() { return name + ": " + cipherSuiteCode[0] + " " + cipherSuiteCode[1]; } /** * Compares this cipher suite to the specified object. */ @Override public boolean equals(Object obj) { if (obj instanceof CipherSuite && this.cipherSuiteCode[0] == ((CipherSuite) obj).cipherSuiteCode[0] && this.cipherSuiteCode[1] == ((CipherSuite) obj).cipherSuiteCode[1]) { return true; } return false; } /** * Returns cipher algorithm name * @return */ public String getBulkEncryptionAlgorithm() { return cipherName; } /** * Returns cipher block size * @return */ public int getBlockSize() { return blockSize; } /** * Returns MAC algorithm name * @return */ public String getHmacName() { return hmacName; } /** * Returns hash algorithm name * @return */ public String getHashName() { return hashName; } /** * Returns hash size * @return */ public int getMACLength() { return hashSize; } /** * Indicates whether this cipher suite is exportable * @return */ public boolean isExportable() { return isExportable; } }