public enum HandshakeType { HELLO_REQUEST(0), CLIENT_HELLO(1), SERVER_HELLO(2), // certificate CERTIFICATE(3), // server_key_exchange (12) SERVER_KEY_EXCHANGE(12), // certificate_request(13) CERTIFICATE_REQUEST(13), // server_hello_done(14) SERVER_HELLO_DONE(14), // certificate_verify(15) CERTIFICATE_VERIFY(15), // client_key_exchange(16) CLIENT_KEY_EXCHANGE(16), // finished(20) FINISHED(20); private int value; private HandshakeType(int value) { this.value = value; } public int value() { return value; } }
public abstract class Handshake { public abstract ByteArrayOutputStream body() throws IOException; }
public enum ContentType { CHANGE_CIPHER_SPEC(20), ALERT(21), HANDSHAKE(22), APPLICATION_DATA(23); private int value; private ContentType(int value) { this.value = value; } public int value() { return value; } }
public enum CipherSuite { TLS_NULL_WITH_NULL_NULL((byte) 0x00, (byte) 0x00), TLS_RSA_WITH_NULL_MD5((byte) 0x00, (byte) 0x01), TLS_RSA_WITH_NULL_SHA((byte) 0x00, (byte) 0x02), TLS_RSA_EXPORT_WITH_RC4_40_MD5((byte) 0x00, (byte) 0x03), TLS_RSA_WITH_RC4_128_MD5((byte) 0x00, (byte) 0x04), TLS_RSA_WITH_RC4_128_SHA((byte) 0x00, (byte) 0x05), TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5((byte) 0x00, (byte) 0x06), TLS_RSA_WITH_IDEA_CBC_SHA((byte) 0x00, (byte) 0x07), TLS_RSA_EXPORT_WITH_DES40_CBC_SHA((byte) 0x00, (byte) 0x08), TLS_RSA_WITH_DES_CBC_SHA((byte) 0x00, (byte) 0x09), TLS_RSA_WITH_3DES_EDE_CBC_SHA((byte) 0x00, (byte) 0x0A), TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA((byte) 0x00, (byte) 0x0B), TLS_DH_DSS_WITH_DES_CBC_SHA((byte) 0x00, (byte) 0x0C), TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA((byte) 0x00, (byte) 0x0D), TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA((byte) 0x00, (byte) 0x0E), TLS_DH_RSA_WITH_DES_CBC_SHA((byte) 0x00, (byte) 0x0F), TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA((byte) 0x00, (byte) 0x10), TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA((byte) 0x00, (byte) 0x11), TLS_DHE_DSS_WITH_DES_CBC_SHA((byte) 0x00, (byte) 0x12), TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA((byte) 0x00, (byte) 0x13), TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA((byte) 0x00, (byte) 0x14), TLS_DHE_RSA_WITH_DES_CBC_SHA((byte) 0x00, (byte) 0x15), TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA((byte) 0x00, (byte) 0x16), TLS_DH_anon_EXPORT_WITH_RC4_40_MD5((byte) 0x00, (byte) 0x17), TLS_DH_anon_WITH_RC4_128_MD5((byte) 0x00, (byte) 0x18), TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA((byte) 0x00, (byte) 0x19), TLS_DH_anon_WITH_DES_CBC_SHA((byte) 0x00, (byte) 0x1A), TLS_DH_anon_WITH_3DES_EDE_CBC_SHA((byte) 0x00, (byte) 0x1B); private byte hb; private byte lb; private CipherSuite(byte high, byte low) { this.hb = high; this.lb = low; } public byte high() { return hb; } public byte low() { return lb; } }
public class ClientHello extends Handshake { // 23 * 16 + 3 public ByteArrayOutputStream body() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write(Test.MAJOR); bos.write(Test.MINOR); long ms = System.currentTimeMillis(); ms = ms / 1000; bos.write((int) ((ms << 32) >> 56)); bos.write((int) ((ms << 40) >> 56)); bos.write((int) ((ms << 48) >> 56)); bos.write((int) ((ms << 56) >> 56)); Random random = new Random(ms); byte[] random_bytes = new byte[28]; random.nextBytes(random_bytes); bos.write(random_bytes); // bos.write(0); // the length of session id, this value indicates the bytes of length // // if session id is empty, then the length of session id is zero // // and so here do not write session id byte[] sessionId = new byte[32]; Random sessionIdGenerator = new Random(System.currentTimeMillis()); sessionIdGenerator.nextBytes(sessionId); bos.write(sessionId.length); bos.write(sessionId); // // the length of cipher suite, this value indicates the bytes of cipher suite // bos.write(0); // bos.write(0); // // if doe's contains cipher suite, do not write cipher suites // the length of cipher suite, this value indicates the bytes of cipher suite bos.write(0); bos.write(2); bos.write(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.high()); bos.write(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.low()); bos.write(1); bos.write(0); return bos; } }
public class ClientHello extends Handshake { // 23 * 16 + 3 public ByteArrayOutputStream body() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write(Test.MAJOR); bos.write(Test.MINOR); long ms = System.currentTimeMillis(); ms = ms / 1000; bos.write((int) ((ms << 32) >> 56)); bos.write((int) ((ms << 40) >> 56)); bos.write((int) ((ms << 48) >> 56)); bos.write((int) ((ms << 56) >> 56)); Random random = new Random(ms); byte[] random_bytes = new byte[28]; random.nextBytes(random_bytes); bos.write(random_bytes); // bos.write(0); // the length of session id, this value indicates the bytes of length // // if session id is empty, then the length of session id is zero // // and so here do not write session id byte[] sessionId = new byte[32]; Random sessionIdGenerator = new Random(System.currentTimeMillis()); sessionIdGenerator.nextBytes(sessionId); bos.write(sessionId.length); bos.write(sessionId); // // the length of cipher suite, this value indicates the bytes of cipher suite // bos.write(0); // bos.write(0); // // if doe's contains cipher suite, do not write cipher suites // // the length of cipher suite, this value indicates the bytes of cipher suite // bos.write(0); // bos.write(2); // bos.write(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.high()); // bos.write(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.low()); // the length of cipher suite, this value indicates the bytes of cipher suite bos.write(0x00); bos.write(0x38); byte[] cipherSuites = new byte[] {(byte)0xc0, (byte)0x14, (byte)0x00, (byte)0x88, (byte)0x00, (byte)0x87, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x38, (byte)0xc0, (byte)0x0f, (byte)0x00, (byte)0x84, (byte)0x00, (byte)0x35, (byte)0xc0, (byte)0x11, (byte)0xc0, (byte)0x13, (byte)0x00, (byte)0x45, (byte)0x00, (byte)0x44, (byte)0x00, (byte)0x66, (byte)0x00, (byte)0x33, (byte)0x00, (byte)0x32, (byte)0xc0, (byte)0x0c, (byte)0xc0, (byte)0x0e, (byte)0x00, (byte)0x96, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x2f, (byte)0xc0, (byte)0x12, (byte)0x00, (byte)0x16, (byte)0x00, (byte)0x13, (byte)0xc0, (byte)0x0d, (byte) 0xfe, (byte) 0xff, (byte) 0x00, (byte) 0x0a}; bos.write(cipherSuites); bos.write(1); bos.write(0); return bos; } }
public class Test { // The version consists of a major version and a minor version: major.minor, such as 3.2, 3 means the major version, 2 means the minor version // Current versions include 3.1, 3.2 // Major version, 3 means version 3.x, versions above 3.0. public static final int MAJOR = 0x03; // small version public static final int MINOR = 0x02; public static final int DEFAULT_PORT = 443; private Socket socket; public Test(String host) throws IOException { this(host, DEFAULT_PORT); } public Test(String host, int port) throws IOException { socket = new Socket(host, port); } public void handshake() throws IOException { OutputStream os = socket.getOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write(ContentType.HANDSHAKE.value()); bos.write(MAJOR); bos.write(MINOR); ByteArrayOutputStream bbos = hello(); int length = bbos.size(); bos.write((int) ((length << 16) >> 24)); bos.write((int) ((length << 24) >> 24)); bos.write (bbos.toByteArray ()); os.write(bos.toByteArray()); InputStream is = socket.getInputStream(); } public ByteArrayOutputStream hello() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write(HandshakeType.CLIENT_HELLO.value()); ClientHello client_hello = new ClientHello(); ByteArrayOutputStream bbos = client_hello.body(); int length = bbos.size(); bos.write((int) ((length << 8) >> 24)); bos.write((int) ((length << 16) >> 24)); bos.write((int) ((length << 24) >> 24)); bos.write (bbos.toByteArray ()); return bos; } }
public class TestTest { private static final String DEFAULT_HOST = "112.65.203.33"; private static com.chos.tls.Test test; @BeforeClass public static void initialize() throws IOException { test = new com.chos.tls.Test(DEFAULT_HOST); } @Test public void handshake() throws IOException { test.handshake(); } }