1
2
3
4
5
6
7
8 package org.xwt.util;
9
10 import org.bouncycastle.crypto.AsymmetricBlockCipher;
11 import org.bouncycastle.crypto.Digest;
12 import org.bouncycastle.crypto.CipherParameters;
13 import org.bouncycastle.crypto.InvalidCipherTextException;
14 import org.bouncycastle.crypto.params.RSAKeyParameters;
15 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
16 import org.bouncycastle.crypto.params.KeyParameter;
17 import org.bouncycastle.crypto.digests.SHA1Digest;
18 import org.bouncycastle.crypto.digests.MD5Digest;
19 import org.bouncycastle.crypto.digests.MD2Digest;
20 import org.bouncycastle.crypto.engines.RSAEngine;
21 import org.bouncycastle.crypto.engines.RC4Engine;
22 import org.bouncycastle.util.encoders.Base64;
23 import org.bouncycastle.asn1.DERInputStream;
24 import org.bouncycastle.asn1.DEROutputStream;
25 import org.bouncycastle.asn1.DERSequence;
26 import org.bouncycastle.asn1.DERObject;
27 import org.bouncycastle.asn1.DEROctetString;
28 import org.bouncycastle.asn1.BERInputStream;
29 import org.bouncycastle.asn1.x509.X509CertificateStructure;
30 import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
31 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
32 import org.bouncycastle.asn1.x509.TBSCertificateStructure;
33 import org.bouncycastle.asn1.x509.X509Name;
34 import org.bouncycastle.asn1.x509.X509Extensions;
35 import org.bouncycastle.asn1.x509.X509Extension;
36 import org.bouncycastle.asn1.x509.BasicConstraints;
37 import org.xwt.util.Log;
38 import java.net.*;
39 import java.io.*;
40 import java.util.*;
41 import java.math.*;
42 import java.text.*;
43
44
93
94 public class SSL extends Socket {
95
96
97
98 public static void main(String[] args) {
99 Log.on = true;
100 try {
101 Socket s = new SSL("www.paypal.com", 443);
102 PrintWriter pw = new PrintWriter(s.getOutputStream());
103 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
104 pw.println("GET / HTTP/1.0");
105 pw.println("");
106 pw.flush();
107
108 while(true) {
109 String s2 = br.readLine();
110 if (s2 == null) return;
111 Log.info(SSL.class, s2);
112 }
113
114 } catch (Exception e) {
115 e.printStackTrace();
116 }
117 }
118
119
120
121 public static class SSLException extends IOException { public SSLException(String s) { super(s); } }
122 static SubjectPublicKeyInfo[] trusted_CA_public_keys;
123 static String[] trusted_CA_public_key_identifiers;
124 public static byte[] pad1 = new byte[48];
125 public static byte[] pad2 = new byte[48];
126 public static byte[] pad1_sha = new byte[40];
127 public static byte[] pad2_sha = new byte[40];
128 static byte[] randpool;
129 static long randcnt = 0;
130
131
132
133 public byte[] server_random = new byte[32];
134 public byte[] client_random = new byte[32];
135 public byte[] client_write_MAC_secret = new byte[16];
136 public byte[] server_write_MAC_secret = new byte[16];
137 public byte[] client_write_key = null;
138 public byte[] server_write_key = null;
139 public byte[] master_secret = null;
140
141
142 public byte[] serverKeyExchange = null;
143
144
145 public boolean cert_requested = false;
146
147 public X509CertificateStructure server_cert = null;
148
149 public SSLOutputStream os = null;
150 public SSLInputStream is = null;
151
152 String hostname;
153
154
155 boolean ignoreUntrustedCert = false;
156
157
158 public byte[] handshakes = new byte[] { };
159
160
161 boolean export = false;
162
163 public InputStream getInputStream() throws IOException { return is != null ? is : super.getInputStream(); }
164 public OutputStream getOutputStream() throws IOException { return os != null ? os : super.getOutputStream(); }
165
166 public SSL(String host, int port) throws IOException { this(host, port, true, false); }
167 public SSL(String host, int port, boolean negotiateImmediately) throws IOException { this(host, port, negotiateImmediately, false); }
168 public SSL(String host, int port, boolean negotiateImmediately, boolean ignoreUntrustedCert) throws IOException {
169 super(host, port);
170 if (!initializationFinished) {
171 synchronized(SSL.class) {
172 while (!initializationFinished)
173 try { SSL.class.wait(); } catch (Exception e) { }
174 }
175 }
176 hostname = host;
177 this.ignoreUntrustedCert = ignoreUntrustedCert;
178 if (negotiateImmediately) negotiate();
179 }
180
181
182 public void negotiate() throws IOException {
183 os = new SSLOutputStream(super.getOutputStream());
184 is = new SSLInputStream(super.getInputStream());
185 os.writeClientHello();
186 is.readServerHandshakes();
187 os.sendClientHandshakes();
188 is.readServerFinished();
189 }
190
191 class SSLInputStream extends InputStream {
192
193
194 DataInputStream raw;
195
196
197 public int seq_num = 0;
198
199
200 public RC4Engine rc4 = null;
201
202
203 byte[] pend = null;
204 int pendstart = 0;
205 int pendlen = 0;
206
207 public void mark() { }
208 public void reset() { }
209 public boolean markSupported() { return false; }
210 public long skip(long l) throws IOException { for(long i=0; i<l; i++) read(); return l; }
211 public SSLInputStream(InputStream raw) { this.raw = new DataInputStream(raw); }
212 public int available() throws IOException { return pendlen; }
213
214 public int read() throws IOException {
215 byte[] singlebyte = new byte[1];
216 int numread = read(singlebyte);
217 if (numread != 1) return -1;
218 return (int)singlebyte[0];
219 }
220
221 public int read(byte[] b, int off, int len) throws IOException {
222 if (pendlen == 0) {
223 pend = readRecord();
224 if (pend == null) return -1;
225 pendstart = 0;
226 pendlen = pend.length;
227 }
228 int ret = Math.min(len, pendlen);
229 System.arraycopy(pend, pendstart, b, off, ret);
230 pendlen -= ret;
231 pendstart += ret;
232 return ret;
233 }
234
235
236 public byte[] readRecord() throws IOException {
237
238
239
240
241 byte type;
242 try { type = raw.readByte();
243 } catch (EOFException e) {
244 if (Log.on) Log.info(this, "got EOFException reading packet type");
245 return null;
246 }
247
248 byte ver_major = raw.readByte();
249 byte ver_minor = raw.readByte();
250 short len = raw.readShort();
251 if (Log.on) Log.info(this, "got record of type " + type + ", SSLv" + ver_major + "." + ver_minor + ", length=" + len);
252
253 byte[] ret = new byte[len];
254 raw.readFully(ret);
255
256
257 if (type == 20) {
258 if (Log.on) Log.info(this, "got ChangeCipherSpec; ignoring");
259 seq_num = 0;
260 return readRecord();
261 }
262
263 byte[] decrypted_payload;
264
265
266 if (rc4 == null) decrypted_payload = ret;
267 else {
268
269 decrypted_payload = new byte[len - 16];
270 rc4.processBytes(ret, 0, len - 16, decrypted_payload, 0);
271
272
273 byte[] MAC = new byte[16];
274 rc4.processBytes(ret, len - 16, 16, MAC, 0);
275 byte[] ourMAC = computeMAC(type, decrypted_payload, 0, decrypted_payload.length, server_write_MAC_secret, seq_num++);
276 for(int i=0; i<MAC.length; i++)
277 if (MAC[i] != ourMAC[i])
278 throw new SSLException("MAC mismatch on byte " + i + ": got " + MAC[i] + ", expecting " + ourMAC[i]);
279 }
280
281 if (type == 21) {
282 if (decrypted_payload[1] > 1) {
283 throw new SSLException("got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
284 } else if (decrypted_payload[1] == 0) {
285 if (Log.on) Log.info(this, "server requested connection closure; returning null");
286 return null;
287 } else {
288 if (Log.on) Log.info(this, "got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
289 return readRecord();
290 }
291
292 } else if (type == 22) {
293 if (Log.on) Log.info(this, "read a handshake");
294
295 } else if (type != 23) {
296 if (Log.on) Log.info(this, "unexpected record type: " + type + "; skipping");
297 return readRecord();
298
299 }
300
301 if (Log.on) Log.info(this, " returning " + decrypted_payload.length + " byte record payload");
302 return decrypted_payload;
303 }
304
305 private byte[] readHandshake() throws IOException {
306
307 byte type = (byte)read();
308 int len = ((read() & 0xff) << 16) | ((read() & 0xff) << 8) | (read() & 0xff);
309 byte[] rec = new byte[len + 4];
310 rec[0] = type;
311 rec[1] = (byte)(((len & 0x00ff0000) >> 16) & 0xff);
312 rec[2] = (byte)(((len & 0x0000ff00) >> 8) & 0xff);
313 rec[3] = (byte)((len & 0x000000ff) & 0xff);
314 if (len > 0) read(rec, 4, len);
315 return rec;
316 }
317
318
319 public void readServerHandshakes() throws IOException {
320 for(;;) {
321
322 byte[] rec = readHandshake();
323 handshakes = concat(new byte[][] { handshakes, rec });
324 DataInputStream stream = new DataInputStream(new ByteArrayInputStream(rec, 4, rec.length - 4));
325
326 switch(rec[0]) {
327 case 2:
328 if (Log.on) Log.info(this, "got ServerHello");
329 byte ver_major = rec[4];
330 byte ver_minor = rec[5];
331 System.arraycopy(rec, 6, server_random, 0, server_random.length);
332 short cipher_high = rec[6 + server_random.length + rec[6 + server_random.length] + 1];
333 short cipher_low = rec[6 + server_random.length + rec[6 + server_random.length] + 2];
334
335 if (cipher_low == 0x04 || cipher_high != 0x00) {
336 export = false;
337 if (Log.on) Log.info(this, "using SSL_RSA_WITH_RC4_128_MD5");
338
339 } else if (cipher_low == 0x03 || cipher_high != 0x00) {
340 export = true;
341 if (Log.on) Log.info(this, "using SSL_RSA_EXPORT_WITH_RC4_40_MD5");
342
343 } else throw new SSLException("server asked for cipher " + ((cipher_high << 8) | cipher_low) +
344 " but we only do SSL_RSA_WITH_RC4_128_MD5 (0x0004) and " +
345 "SSL_RSA_EXPORT_WITH_RC4_40_MD5 (0x0003)");
346
347 byte compressionMethod = rec[6 + server_random.length + rec[6 + server_random.length] + 3];
348 if (compressionMethod != 0x0) throw new SSLException("server asked for compression method " + compressionMethod +
349 " but we don't support compression");
350 break;
351
352 case 11:
353 if (Log.on) Log.info(this, "got Server Certificate(s)");
354 int numcertbytes = ((rec[4] & 0xff) << 16) | ((rec[5] & 0xff) << 8) | (rec[6] & 0xff);
355 int numcerts = 0;
356 X509CertificateStructure last_cert = null;
357 X509CertificateStructure this_cert = null;
358
359 for(int i=0; i<numcertbytes;) {
360 int certlen = ((rec[7 + i] & 0xff) << 16) | ((rec[7 + i + 1] & 0xff) << 8) | (rec[7 + i + 2] & 0xff);
361 try {
362 DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(rec, 7 + i + 3, certlen));
363 this_cert = new X509CertificateStructure((DERSequence)dIn.readObject());
364 } catch (Exception e) {
365 SSLException t = new SSLException("error decoding server certificate: " + e);
366 t.fillInStackTrace();
367 throw t;
368 }
369
370 if (server_cert == null) {
371 server_cert = this_cert;
372 TBSCertificateStructure tbs = server_cert.getTBSCertificate();
373 X509Name subject = tbs.getSubject();
374
375
376 String CN = tbs.getSubject().toString() + " ";
377 boolean good = false;
378 for(int j=0; j<CN.length() - 3; j++)
379 if (CN.substring(j, j+3).equals("CN=")) {
380 good = true;
381 CN = CN.substring(j+3, CN.indexOf(' ', j+3));
382 break;
383 }
384
385 if (!good) throw new SSLException("server certificate does not seem to have a CN: " + CN);
386 if (!ignoreUntrustedCert && !CN.equalsIgnoreCase(hostname))
387 throw new SSLException("connecting to host " + hostname + " but server certificate was issued for " + CN);
388
389 SimpleDateFormat dateF = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss-z");
390
391
392 String s = tbs.getStartDate().getTime();
393 s = s.substring(0, 4) + "-" + s.substring(4, 6) + "-" + s.substring(6, 8) + "-" +
394 s.substring(8, 10) + "-" + s.substring(10, 12) + "-" +
395 s.substring(12, 14) + "-" + s.substring(14);
396
397 Date startDate = dateF.parse(s, new ParsePosition(0));
398
399 s = tbs.getEndDate().getTime();
400 s = s.substring(2, 4) + "-" + s.substring(4, 6) + "-" + s.substring(0, 2) + "-" + s.substring(6, 8) + "-" +
401 s.substring(8, 10) + "-" + s.substring(10, 12) + "-" + s.substring(12);
402 Date endDate = dateF.parse(s, new ParsePosition(0));
403
404 Date now = new Date();
405 if (!ignoreUntrustedCert && now.after(endDate))
406 throw new SSLException("server certificate expired on " + endDate);
407 if (!ignoreUntrustedCert && now.before(startDate))
408 throw new SSLException("server certificate will not be valid until " + startDate);
409
410 Log.info(this, "server cert (name, validity dates) checks out okay");
411
412 } else {
413
414
415 if (certlen + 3 + i < numcertbytes) {
416
417 X509Extension basicConstraints = this_cert.getTBSCertificate().getExtensions().getExtension(X509Extensions.BasicConstraints);
418 if (basicConstraints == null) throw new SSLException("certificate did not contain a basic constraints block");
419 DERInputStream dis = new DERInputStream(new ByteArrayInputStream(basicConstraints.getValue().getOctets()));
420 BasicConstraints bc = new BasicConstraints((DERSequence)dis.readObject());
421 if (!bc.isCA()) throw new SSLException("non-CA certificate used for signing");
422 }
423
424 if (!isSignedBy(last_cert, this_cert.getSubjectPublicKeyInfo()))
425 throw new SSLException("the server sent a broken chain of certificates");
426 }
427
428 last_cert = this_cert;
429 i += certlen + 3;
430 numcerts++;
431 }
432 if (Log.on) Log.info(this, " Certificate (" + numcerts + " certificates)");
433
434 if (ignoreUntrustedCert) break;
435
436 boolean good = false;
437
438
439 String subject = this_cert.getSubject().toString();
440 for(int i=0; i<trusted_CA_public_keys.length; i++) {
441 if (subject.indexOf(trusted_CA_public_key_identifiers[i]) != -1 && isSignedBy(this_cert, trusted_CA_public_keys[i])) {
442 if (Log.on) Log.info(this, "pass 1: server cert was signed by trusted CA " + i);
443 good = true;
444 break;
445 }
446 }
447
448
449 if (!good)
450 for(int i=0; i<trusted_CA_public_keys.length; i++) {
451 if (isSignedBy(this_cert, trusted_CA_public_keys[i])) {
452 if (Log.on) Log.info(this, "pass 2: server cert was signed by trusted CA " + i);
453 good = true;
454 break;
455 }
456 }
457
458 if (!good) throw new SSLException("server cert was not signed by a trusted CA");
459 break;
460
461 case 12:
462 if (Log.on) Log.info(this, "got ServerKeyExchange");
463 serverKeyExchange = rec;
464 break;
465
466 case 13:
467 if (Log.on) Log.info(this, "got Request for Client Certificates");
468 cert_requested = true;
469 break;
470
471 case 14: if (Log.on) Log.info(this, " ServerHelloDone"); return;
472 default: throw new SSLException("unknown handshake of type " + rec[0]);
473 }
474 }
475 }
476
477 public void readServerFinished() throws IOException {
478
479 byte[] rec = readHandshake();
480 if (rec[0] != 20) throw new SSLException("expecting server Finished message, but got message of type " + rec[0]);
481
482 byte[] expectedFinished = concat(new byte[][] {
483 md5(new byte[][] { master_secret, pad2,
484 md5(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
485 master_secret, pad1 }) }),
486 sha(new byte[][] { master_secret, pad2_sha,
487 sha(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
488 master_secret, pad1_sha } ) } ) } );
489
490 for(int i=0; i<expectedFinished.length; i++)
491 if (expectedFinished[i] != rec[i + 4])
492 throw new SSLException("server Finished message mismatch!");
493
494 if (Log.on) Log.info(this, "server finished message checked out okay!");
495 }
496
497 }
498
499 class SSLOutputStream extends OutputStream {
500
501
502 DataOutputStream raw;
503
504
505 public long seq_num = 0;
506
507
508 RC4Engine rc4 = null;
509
510 public SSLOutputStream(OutputStream raw) { this.raw = new DataOutputStream(raw); }
511 public void flush() throws IOException { raw.flush(); }
512 public void write(int b) throws IOException { write(new byte[] { (byte)b }, 0, 1); }
513 public void write(byte[] b, int off, int len) throws IOException { write(b, off, len, (byte)23); }
514 public void close() throws IOException {
515 write(new byte[] { 0x1, 0x0 }, 0, 2, (byte)21);
516 raw.close();
517 }
518
519
520 public void write(byte[] payload, int off, int len, byte type) throws IOException {
521
522
523 if (len > 1 << 14) {
524 write(payload, off, 1 << 14, type);
525 write(payload, off + 1 << 14, len - 1 << 14, type);
526 return;
527 }
528
529 raw.writeByte(type);
530 raw.writeShort(0x0300);
531
532 if (rc4 == null) {
533 raw.writeShort(len);
534 raw.write(payload, off, len);
535
536 } else {
537 byte[] MAC = computeMAC(type, payload, off, len, client_write_MAC_secret, seq_num);
538 byte[] encryptedPayload = new byte[MAC.length + len];
539 rc4.processBytes(payload, off, len, encryptedPayload, 0);
540 rc4.processBytes(MAC, 0, MAC.length, encryptedPayload, len);
541 raw.writeShort(encryptedPayload.length);
542 raw.write(encryptedPayload);
543
544 }
545
546 seq_num++;
547 }
548
549
550 public void writeHandshake(int type, byte[] payload) throws IOException {
551 byte[] real_payload = new byte[payload.length + 4];
552 System.arraycopy(payload, 0, real_payload, 4, payload.length);
553 real_payload[0] = (byte)(type & 0xFF);
554 intToBytes(payload.length, real_payload, 1, 3);
555 handshakes = concat(new byte[][] { handshakes, real_payload });
556 write(real_payload, 0, real_payload.length, (byte)22);
557 }
558
559 public void sendClientHandshakes() throws IOException {
560
561 if (Log.on) Log.info(this, "shaking hands");
562 if (cert_requested) {
563 if (Log.on) Log.info(this, "telling the server we have no certificates");
564 writeHandshake(11, new byte[] { 0x0, 0x0, 0x0 });
565 }
566
567
568 byte[] pre_master_secret = new byte[48];
569 pre_master_secret[0] = 0x03;
570 pre_master_secret[1] = 0x00;
571 getRandomBytes(pre_master_secret, 2, pre_master_secret.length - 2);
572
573
574 try {
575 byte[] encrypted_pre_master_secret;
576
577 SubjectPublicKeyInfo pki = server_cert.getSubjectPublicKeyInfo();
578 RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
579 BigInteger modulus = rsa_pks.getModulus();
580 BigInteger exponent = rsa_pks.getPublicExponent();
581
582 if (serverKeyExchange != null) {
583
584 AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
585 rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
586
587 int modulus_size = ((serverKeyExchange[4] & 0xff) << 8) | (serverKeyExchange[5] & 0xff);
588 byte[] b_modulus = new byte[modulus_size];
589 System.arraycopy(serverKeyExchange, 6, b_modulus, 0, modulus_size);
590 modulus = new BigInteger(1, b_modulus);
591
592 int exponent_size = ((serverKeyExchange[6 + modulus_size] & 0xff) << 8) | (serverKeyExchange[7 + modulus_size] & 0xff);
593 byte[] b_exponent = new byte[exponent_size];
594 System.arraycopy(serverKeyExchange, 8 + modulus_size, b_exponent, 0, exponent_size);
595 exponent = new BigInteger(1, b_exponent);
596
597 byte[] server_params = new byte[modulus_size + exponent_size + 4];
598 System.arraycopy(serverKeyExchange, 4, server_params, 0, server_params.length);
599
600 byte[] expectedSignature = concat(new byte[][] { md5(new byte[][] { client_random, server_random, server_params } ),
601 sha(new byte[][] { client_random, server_random, server_params } ) } );
602
603 byte[] recievedSignature = rsa.processBlock(serverKeyExchange, 6 + server_params.length,
604 serverKeyExchange.length - 6 - server_params.length);
605
606 for(int i=0; i<expectedSignature.length; i++)
607 if (expectedSignature[i] != recievedSignature[i])
608 throw new SSLException("ServerKeyExchange message had invalid signature " + i);
609
610 if (Log.on) Log.info(this, "ServerKeyExchange successfully processed");
611 }
612
613 AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
614 rsa.init(true, new RSAKeyParameters(false, modulus, exponent));
615
616 encrypted_pre_master_secret = rsa.processBlock(pre_master_secret, 0, pre_master_secret.length);
617 writeHandshake(16, encrypted_pre_master_secret);
618
619 } catch (Exception e) {
620 SSLException t = new SSLException("exception encrypting premaster secret");
621 t.fillInStackTrace();
622 throw t;
623 }
624
625
626 if (Log.on) Log.info(this, "Handshake complete; sending ChangeCipherSpec");
627 write(new byte[] { 0x01 }, 0, 1, (byte)20);
628 seq_num = 0;
629
630
631 master_secret = concat(new byte[][] {
632 md5(new byte[][] { pre_master_secret,
633 sha(new byte[][] { new byte[] { 0x41 }, pre_master_secret, client_random, server_random })}),
634 md5(new byte[][] { pre_master_secret,
635 sha(new byte[][] { new byte[] { 0x42, 0x42 }, pre_master_secret, client_random, server_random })}),
636 md5(new byte[][] { pre_master_secret,
637 sha(new byte[][] { new byte[] { 0x43, 0x43, 0x43 }, pre_master_secret, client_random, server_random })})
638 } );
639
640
641 byte[] key_material = new byte[] { };
642 for(int i=0; key_material.length < 72; i++) {
643 byte[] crap = new byte[i + 1];
644 for(int j=0; j<crap.length; j++) crap[j] = (byte)(((byte)0x41) + ((byte)i));
645 key_material = concat(new byte[][] { key_material,
646 md5(new byte[][] { master_secret,
647 sha(new byte[][] { crap, master_secret, server_random, client_random }) }) });
648 }
649
650 client_write_key = new byte[export ? 5 : 16];
651 server_write_key = new byte[export ? 5 : 16];
652
653 System.arraycopy(key_material, 0, client_write_MAC_secret, 0, 16);
654 System.arraycopy(key_material, 16, server_write_MAC_secret, 0, 16);
655 System.arraycopy(key_material, 32, client_write_key, 0, export ? 5 : 16);
656 System.arraycopy(key_material, export ? 37 : 48, server_write_key, 0, export ? 5 : 16);
657
658 if (export) {
659
660 byte[] client_untrimmed = md5(new byte[][] { concat(new byte[][] { client_write_key, client_random, server_random } ) });
661 byte[] server_untrimmed = md5(new byte[][] { concat(new byte[][] { server_write_key, server_random, client_random } ) });
662 client_write_key = new byte[16];
663 server_write_key = new byte[16];
664 System.arraycopy(client_untrimmed, 0, client_write_key, 0, 16);
665 System.arraycopy(server_untrimmed, 0, server_write_key, 0, 16);
666 }
667
668 rc4 = new RC4Engine();
669 rc4.init(true, new KeyParameter(client_write_key));
670 is.rc4 = new RC4Engine();
671 is.rc4.init(false, new KeyParameter(server_write_key));
672
673
674 writeHandshake(20, concat(new byte[][] {
675 md5(new byte[][] { master_secret, pad2,
676 md5(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
677 master_secret, pad1 }) }),
678 sha(new byte[][] { master_secret, pad2_sha,
679 sha(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
680 master_secret, pad1_sha } ) })
681 }));
682 raw.flush();
683 if (Log.on) Log.info(this, "wrote Finished message");
684
685 }
686
687 public void writeClientHello() throws IOException {
688
689 if (Log.on) Log.info(this, "sending ClientHello");
690 int unixtime = (int)(System.currentTimeMillis() / (long)1000);
691
692 byte[] out = new byte[] {
693 0x03, 0x00,
694
695
696 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
697 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
698 0x0, 0x0, 0x0, 0x0,
699
700 0x0,
701 0x0, 0x4, 0x0, 0x4, 0x0, 0x3,
702 0x1, 0x0
703 };
704
705
706 Random rand = new Random(System.currentTimeMillis());
707 rand.nextBytes(client_random);
708 intToBytes(unixtime, client_random, 0, 4);
709 System.arraycopy(client_random, 0, out, 2, client_random.length);
710
711 writeHandshake(1, out);
712 flush();
713 }
714 }
715
716
717
718
719 public static void intToBytes(long val, byte[] b, int offset, int num) {
720 for(int i=0; i<num; i++)
721 b[offset + num - i - 1] = (byte)((val & (0xFFL << (i * 8))) >> (i * 8));
722 }
723
724
725 public static synchronized void getRandomBytes(byte[] b, int offset, int len) {
726 MD5Digest md5 = new MD5Digest();
727 byte[] b2 = new byte[16];
728 while(len > 0) {
729 md5.reset();
730 md5.update(randpool, 0, randpool.length);
731 intToBytes(randcnt++, b2, 0, 8);
732 md5.update(b2, 0, 8);
733 md5.doFinal(b2, 0);
734 int n = len < 16 ? len : 16;
735 System.arraycopy(b2, 0, b, offset, n);
736 len -= n;
737 offset +=