4 * This class encapsulates the read or write state of a TLS connection,
\r
5 * and implementes the encrypting and hashing of packets.
\r
6 * Copyright (c) 2007 Henri Torgemane
\r
8 * See LICENSE.txt for full license information.
\r
10 package com.hurlant.crypto.tls {
\r
11 import flash.utils.IDataInput;
\r
12 import flash.utils.ByteArray;
\r
13 import com.hurlant.crypto.hash.MD5;
\r
14 import com.hurlant.crypto.hash.HMAC;
\r
15 import com.hurlant.crypto.hash.IHash;
\r
16 import com.hurlant.crypto.symmetric.ICipher;
\r
17 import com.hurlant.crypto.symmetric.IVMode;
\r
18 import com.hurlant.util.Hex;
\r
19 import com.hurlant.util.ArrayUtil;
\r
21 public class TLSConnectionState implements IConnectionState {
\r
24 // compression state
\r
27 private var bulkCipher:uint;
\r
28 private var cipherType:uint;
\r
29 private var CIPHER_key:ByteArray;
\r
30 private var CIPHER_IV:ByteArray;
\r
31 private var cipher:ICipher;
\r
32 private var ivmode:IVMode;
\r
35 private var macAlgorithm:uint;
\r
36 private var MAC_write_secret:ByteArray;
\r
37 private var hmac:HMAC;
\r
39 // sequence number. uint64
\r
40 private var seq_lo:uint;
\r
41 private var seq_hi:uint;
\r
45 public function TLSConnectionState(
\r
46 bulkCipher:uint=0, cipherType:uint=0, macAlgorithm:uint=0,
\r
47 mac:ByteArray=null, key:ByteArray=null, IV:ByteArray=null) {
\r
48 this.bulkCipher = bulkCipher;
\r
49 this.cipherType = cipherType;
\r
50 this.macAlgorithm = macAlgorithm;
\r
51 MAC_write_secret = mac;
\r
52 hmac = MACs.getHMAC(macAlgorithm);
\r
55 cipher = BulkCiphers.getCipher(bulkCipher, key, 0x0301);
\r
56 if (cipher is IVMode) {
\r
57 ivmode = cipher as IVMode;
\r
62 public function decrypt(type:uint, length:uint, p:ByteArray):ByteArray {
\r
63 // decompression is a nop.
\r
65 if (cipherType == BulkCiphers.STREAM_CIPHER) {
\r
66 if (bulkCipher == BulkCiphers.NULL) {
\r
73 var nextIV:ByteArray = new ByteArray;
\r
74 nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
\r
82 if (macAlgorithm!=MACs.NULL) {
\r
83 var data:ByteArray = new ByteArray;
\r
84 var len:uint = p.length - hmac.getHashSize();
\r
85 data.writeUnsignedInt(seq_hi);
\r
86 data.writeUnsignedInt(seq_lo);
\r
87 data.writeByte(type);
\r
88 data.writeShort(TLSSecurityParameters.PROTOCOL_VERSION);
\r
89 data.writeShort(len);
\r
91 data.writeBytes(p, 0, len);
\r
93 var mac:ByteArray = hmac.compute(MAC_write_secret, data);
\r
94 // compare "mac" with the last X bytes of p.
\r
95 var mac_received:ByteArray = new ByteArray;
\r
96 mac_received.writeBytes(p, len, hmac.getHashSize());
\r
97 if (ArrayUtil.equals(mac, mac_received)) {
\r
98 // happy happy joy joy
\r
100 throw new TLSError("Bad Mac Data", TLSError.bad_record_mac);
\r
107 if (seq_lo==0) seq_hi++;
\r
110 public function encrypt(type:uint, p:ByteArray):ByteArray {
\r
111 var mac:ByteArray = null;
\r
112 if (macAlgorithm!=MACs.NULL) {
\r
113 var data:ByteArray = new ByteArray;
\r
114 data.writeUnsignedInt(seq_hi);
\r
115 data.writeUnsignedInt(seq_lo);
\r
116 data.writeByte(type);
\r
117 data.writeShort(TLSSecurityParameters.PROTOCOL_VERSION);
\r
118 data.writeShort(p.length);
\r
120 data.writeBytes(p, 0, p.length);
\r
122 mac = hmac.compute(MAC_write_secret, data);
\r
123 p.position = p.length;
\r
127 if (cipherType == BulkCiphers.STREAM_CIPHER) {
\r
129 if (bulkCipher == BulkCiphers.NULL) {
\r
138 var nextIV:ByteArray = new ByteArray;
\r
139 nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
\r
140 CIPHER_IV = nextIV;
\r
141 ivmode.IV = nextIV;
\r
145 if (seq_lo==0) seq_hi++;
\r
146 // compression is a nop.
\r