1 package org.cacert.gigi.util;
3 import java.lang.reflect.Field;
4 import java.lang.reflect.Method;
5 import java.util.Arrays;
6 import java.util.Collection;
7 import java.util.HashMap;
8 import java.util.TreeSet;
10 import sun.security.ssl.SSLContextImpl;
12 public class CipherInfo implements Comparable<CipherInfo> {
13 private static class CipherInfoGenerator {
14 private Class<?> cipherSuite;
15 private Field cipherSuiteNameMap;
16 private Field exchange;
18 private Field keySize;
19 private Field algortihm;
20 private Field transformation;
21 private HashMap<?, ?> names;
23 private Field macName;
24 private Field macSize;
26 public CipherInfoGenerator() throws ReflectiveOperationException {
27 SSLContextImpl sc = new SSLContextImpl.TLS12Context();
28 Method m = SSLContextImpl.class
29 .getDeclaredMethod("getSupportedCipherSuiteList");
30 m.setAccessible(true);
31 Object o = m.invoke(sc);
32 Class<?> cipherSuiteList = o.getClass();
33 Method collection = cipherSuiteList.getDeclaredMethod("collection");
34 collection.setAccessible(true);
35 Collection<?> suites = (Collection<?>) collection.invoke(o);
36 Object oneSuite = suites.iterator().next();
37 cipherSuite = oneSuite.getClass();
38 cipherSuiteNameMap = cipherSuite.getDeclaredField("nameMap");
39 cipherSuiteNameMap.setAccessible(true);
40 names = (HashMap<?, ?>) cipherSuiteNameMap.get(null);
41 exchange = cipherSuite.getDeclaredField("keyExchange");
42 exchange.setAccessible(true);
43 cipher = cipherSuite.getDeclaredField("cipher");
44 cipher.setAccessible(true);
45 Class<?> bulkCipher = cipher.getType();
46 keySize = bulkCipher.getDeclaredField("keySize");
47 keySize.setAccessible(true);
48 algortihm = bulkCipher.getDeclaredField("algorithm");
49 algortihm.setAccessible(true);
50 transformation = bulkCipher.getDeclaredField("transformation");
51 transformation.setAccessible(true);
53 macAlg = cipherSuite.getDeclaredField("macAlg");
54 macAlg.setAccessible(true);
55 Class<?> mac = macAlg.getType();
56 macName = mac.getDeclaredField("name");
57 macName.setAccessible(true);
58 macSize = mac.getDeclaredField("size");
59 macSize.setAccessible(true);
61 public CipherInfo generateInfo(String suiteName)
62 throws IllegalArgumentException, IllegalAccessException {
63 Object suite = names.get(suiteName);
64 String keyExchange = exchange.get(suite).toString();
65 Object bulkCipher = cipher.get(suite);
66 Object mac = macAlg.get(suite);
68 String transform = (String) transformation.get(bulkCipher);
69 String[] transformationParts = transform.split("/");
70 int keysize = keySize.getInt(bulkCipher);
72 String macNam = (String) macName.get(mac);
73 int macSiz = macSize.getInt(mac);
75 String chaining = null;
76 String padding = null;
77 if (transformationParts.length > 1) {
78 chaining = transformationParts[1];
79 padding = transformationParts[2];
82 return new CipherInfo(suiteName, keyExchange,
83 transformationParts[0], keysize * 8, chaining, padding,
91 String cipherChaining;
97 private CipherInfo(String suiteName, String keyExchange, String cipher,
98 int keySize, String cipherChaining, String cipherPadding,
99 String macName, int macSize) {
100 this.suiteName = suiteName;
101 this.keyExchange = keyExchange;
102 this.cipher = cipher;
103 this.keySize = keySize;
104 this.cipherChaining = cipherChaining;
105 this.cipherPadding = cipherPadding;
106 this.macName = macName;
107 this.macSize = macSize;
110 static CipherInfoGenerator cig;
113 cig = new CipherInfoGenerator();
114 } catch (ReflectiveOperationException e) {
119 public static CipherInfo generateInfo(String name) {
124 return cig.generateInfo(name);
125 } catch (IllegalArgumentException e) {
127 } catch (IllegalAccessException e) {
132 public String getSuiteName() {
136 * 5: ECDHE, AES||CAMELLIA, keysize >=256 <br>
137 * 4: DHE, AES||CAMELLIA, keysize >= 256<br>
138 * 3: ECDHE|| DHE, AES||CAMELLIA<br>
143 * @return the strength
145 public int getStrength() {
146 if (cipher.equals("NULL") || cipher.equals("RC4")
147 || cipher.contains("DES")) {
150 boolean ecdhe = keyExchange.startsWith("ECDHE");
151 boolean dhe = keyExchange.startsWith("DHE");
152 boolean pfs = ecdhe || dhe;
153 boolean goodCipher = cipher.equals("AES") || cipher.equals("CAMELLIA");
154 if (ecdhe && goodCipher && keySize >= 256) {
157 if (dhe && goodCipher && keySize >= 256) {
160 if (pfs && goodCipher) {
166 if (keyExchange.equals("RSA") || keyExchange.equals("DSA")) {
171 private static final String[] CIPHER_RANKING = new String[]{"CAMELLIA",
172 "AES", "RC4", "3DES", "DES", "DES40"};
175 public String toString() {
176 return "CipherInfo [keyExchange=" + keyExchange + ", cipher=" + cipher
177 + ", keySize=" + keySize + ", cipherChaining=" + cipherChaining
178 + ", cipherPadding=" + cipherPadding + ", macName=" + macName
179 + ", macSize=" + macSize + "]";
184 * Cipher {@link #CIPHER_RANKING}<br>
185 * Cipher {@link #keySize}<br>
192 public int compareTo(CipherInfo o) {
193 int myStrength = getStrength();
194 int oStrength = o.getStrength();
195 if (myStrength > oStrength) {
198 if (myStrength < oStrength) {
202 boolean myEcdhe = keyExchange.startsWith("ECDHE");
203 boolean oEcdhe = o.keyExchange.startsWith("ECDHE");
204 if (myEcdhe && !oEcdhe) {
207 if (!myEcdhe && oEcdhe) {
210 boolean myGCM = "GCM".equals(cipherChaining);
211 boolean oGCM = "GCM".equals(o.cipherChaining);
212 if (myGCM && !oGCM) {
215 if (!myGCM && oGCM) {
218 if (!cipher.equals(o.cipher)) {
220 for (String testCipher : CIPHER_RANKING) {
221 if (cipher.equals(testCipher)) {
224 if (o.cipher.equals(testCipher)) {
228 if (cipher.equals("NULL")) {
231 if (o.cipher.equals("NULL")) {
235 if (keySize > o.keySize) {
238 if (keySize < o.keySize) {
241 boolean mySHA = macName.startsWith("SHA");
242 boolean oSHA = o.macName.startsWith("SHA");
243 if (mySHA && !oSHA) {
246 if (mySHA && !oSHA) {
249 if (macSize > o.macSize) {
252 if (macSize < o.macSize) {
256 return suiteName.compareTo(o.suiteName);
258 static String[] cipherRanking = null;
259 public static String[] getCompleteRanking() {
260 if (cipherRanking == null) {
261 String[] ciphers = filterCiphers((Iterable<String>) cig.names
263 cipherRanking = ciphers;
265 return cipherRanking;
267 private static String[] filterCiphers(Iterable<String> toFilter) {
268 TreeSet<CipherInfo> chosenCiphers = new TreeSet<CipherInfo>();
269 for (String o : toFilter) {
271 CipherInfo info = CipherInfo.generateInfo(s);
273 if (info.getStrength() > 1) {
274 chosenCiphers.add(info);
278 String[] ciphers = new String[chosenCiphers.size()];
280 for (CipherInfo i : chosenCiphers) {
281 ciphers[counter++] = i.getSuiteName();
285 public static String[] filter(String[] supportedCipherSuites) {
286 return filterCiphers(Arrays.asList(supportedCipherSuites));