PageRenderTime 167ms CodeModel.GetById 93ms app.highlight 53ms RepoModel.GetById 3ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/socket.io-client/lib/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLSecurityParameters.as

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
ActionScript | 340 lines | 212 code | 66 blank | 62 comment | 14 complexity | b758ef5891f2dba0fb4b71b48e3613a0 MD5 | raw file
  1/**
  2 * TLSSecurityParameters
  3 * 
  4 * This class encapsulates all the security parameters that get negotiated
  5 * during the TLS handshake. It also holds all the key derivation methods.
  6 * Copyright (c) 2007 Henri Torgemane
  7 * 
  8 * See LICENSE.txt for full license information.
  9 */
 10package com.hurlant.crypto.tls {
 11	import com.hurlant.crypto.hash.MD5;
 12	import com.hurlant.crypto.hash.SHA1;
 13	import com.hurlant.util.Hex;
 14	
 15	import flash.utils.ByteArray;
 16	
 17	public class SSLSecurityParameters implements ISecurityParameters {
 18		
 19		// COMPRESSION
 20		public static const COMPRESSION_NULL:uint = 0;
 21		
 22		private var entity:uint; // SERVER | CLIENT
 23		private var bulkCipher:uint; // BULK_CIPHER_*
 24		private var cipherType:uint; // STREAM_CIPHER | BLOCK_CIPHER
 25		private var keySize:uint;
 26		private var keyMaterialLength:uint;
 27		private var keyBlock:ByteArray;
 28		private var IVSize:uint;
 29		private var MAC_length:uint;
 30		private var macAlgorithm:uint; // MAC_*
 31		private var hashSize:uint;
 32		private var compression:uint; // COMPRESSION_NULL
 33		private var masterSecret:ByteArray; // 48 bytes
 34		private var clientRandom:ByteArray; // 32 bytes
 35		private var serverRandom:ByteArray; // 32 bytes
 36		private var pad_1:ByteArray; // varies
 37		private var pad_2:ByteArray; // varies
 38		private var ignoreCNMismatch:Boolean = true;
 39		private var trustAllCerts:Boolean = false;
 40		private var trustSelfSigned:Boolean = false;
 41		public static const PROTOCOL_VERSION:uint = 0x0300;
 42		
 43		// not strictly speaking part of this, but yeah.
 44		public var keyExchange:uint;
 45		
 46		public function get version() : uint { 
 47			return PROTOCOL_VERSION;
 48		}
 49		public function SSLSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:ByteArray = null) {
 50			this.entity = entity;
 51			reset();
 52		}
 53		
 54		public function reset():void {
 55			bulkCipher = BulkCiphers.NULL;
 56			cipherType = BulkCiphers.BLOCK_CIPHER;
 57			macAlgorithm = MACs.NULL;
 58			compression = COMPRESSION_NULL;
 59			masterSecret = null;
 60		}
 61		
 62		public function getBulkCipher():uint {
 63			return bulkCipher;
 64		}
 65		public function getCipherType():uint {
 66			return cipherType;
 67		}
 68		public function getMacAlgorithm():uint {
 69			return macAlgorithm;
 70		}
 71		
 72		public function setCipher(cipher:uint):void {
 73			bulkCipher = CipherSuites.getBulkCipher(cipher);
 74			cipherType = BulkCiphers.getType(bulkCipher);
 75			keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher);   // 8
 76			keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); // 5
 77			IVSize = BulkCiphers.getIVSize(bulkCipher);
 78
 79
 80			keyExchange = CipherSuites.getKeyExchange(cipher);
 81			
 82			macAlgorithm = CipherSuites.getMac(cipher);
 83			hashSize = MACs.getHashSize(macAlgorithm);
 84			pad_1 = new ByteArray();
 85			pad_2 = new ByteArray();
 86			for (var x:int = 0; x < 48; x++) {
 87				pad_1.writeByte(0x36);
 88				pad_2.writeByte(0x5c);
 89			}			
 90		}
 91		public function setCompression(algo:uint):void {
 92			compression = algo;
 93		}
 94		
 95		public function setPreMasterSecret(secret:ByteArray):void {
 96			/* Warning! Following code may cause madness
 97				 Tread not here, unless ye be men of valor.
 98			
 99			***** Official Prophylactic Comment ******
100				(to protect the unwary...this code actually works, that's all you need to know)
101			
102			This does two things, computes the master secret, and generates the keyBlock
103			
104			
105			To compute the master_secret, the following algorithm is used.
106			 for SSL 3, this means
107			 master = MD5( premaster + SHA1('A' + premaster + client_random + server_random ) ) +
108						MD5( premaster + SHA1('BB' + premaster + client_random + server_random ) ) +
109						MD5( premaster + SHA1('CCC' + premaster + client_random + server_random ) )
110			*/		
111			var tempHashA:ByteArray = new ByteArray(); // temporary hash, gets reused a lot
112			var tempHashB:ByteArray = new ByteArray(); // temporary hash, gets reused a lot
113			
114			var shaHash:ByteArray;
115			var mdHash:ByteArray;
116			
117			var i:int;
118			var j:int;
119			
120			var sha:SHA1 = new SHA1();
121			var md:MD5 = new MD5();
122					
123			var k:ByteArray = new ByteArray();
124			
125			k.writeBytes(secret);
126			k.writeBytes(clientRandom);
127			k.writeBytes(serverRandom);
128			
129			masterSecret = new ByteArray();
130			var pad_char:uint = 0x41;
131			
132			for ( i = 0; i < 3; i++) {
133				// SHA portion
134				tempHashA.position = 0;
135								
136				for ( j = 0; j < i + 1; j++) {
137					tempHashA.writeByte(pad_char);
138				}
139				pad_char++;
140				
141				tempHashA.writeBytes(k);
142				shaHash = sha.hash(tempHashA);
143				
144				// MD5 portion
145				tempHashB.position = 0;
146				tempHashB.writeBytes(secret); 
147				tempHashB.writeBytes(shaHash); 
148				mdHash = md.hash(tempHashB);
149				
150				// copy into my key
151				masterSecret.writeBytes(mdHash);
152			}
153			
154			// *************** END MASTER SECRET **************
155			
156			// More prophylactic comments
157			// *************** START KEY BLOCK ****************
158			
159			// So here, I'm setting up the keyBlock array that I will derive MACs, keys, and IVs from.
160			// Rebuild k (hash seed)
161			 
162			k.position = 0; 
163			k.writeBytes(masterSecret);
164			k.writeBytes(serverRandom);
165			k.writeBytes(clientRandom);
166			
167			keyBlock = new ByteArray(); 
168			
169			tempHashA = new ByteArray();
170			tempHashB = new ByteArray();
171			// now for 16 iterations to get 256 bytes (16 * 16), better to have more than not enough
172			pad_char = 0x41;
173			for ( i = 0; i < 16; i++) {
174				tempHashA.position = 0; 
175				
176				for ( j = 0; j < i + 1; j++) {
177					tempHashA.writeByte(pad_char);
178				}
179				pad_char++;
180				tempHashA.writeBytes(k);
181				shaHash = sha.hash(tempHashA);	
182				
183				tempHashB.position = 0; 
184				tempHashB.writeBytes(masterSecret);
185				tempHashB.writeBytes(shaHash, 0);
186				mdHash = md.hash(tempHashB);
187				
188				keyBlock.writeBytes(mdHash); 
189			}
190		}
191		
192		public function setClientRandom(secret:ByteArray):void {
193			clientRandom = secret;
194		}
195		public function setServerRandom(secret:ByteArray):void {
196			serverRandom = secret;
197		}
198		
199		public function get useRSA():Boolean {
200			return KeyExchanges.useRSA(keyExchange);
201		}
202		
203		// This is the Finished message
204		// if you value your sanity, stay away...far away
205		public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {
206			// for SSL 3.0, this consists of
207			// 	finished = md5( masterSecret + pad2 + md5( handshake + sender + masterSecret + pad1 ) ) +
208			//			   sha1( masterSecret + pad2 + sha1( handshake + sender + masterSecret + pad1 ) )
209			
210			// trace("Handshake messages: " + Hex.fromArray(handshakeMessages));
211			var sha:SHA1 = new SHA1();
212			var md:MD5 = new MD5();
213			var k:ByteArray = new ByteArray(); // handshake + sender + masterSecret + pad1
214			var j:ByteArray = new ByteArray(); // masterSecret + pad2 + k
215			
216			var innerKey:ByteArray;
217			var outerKey:ByteArray = new ByteArray();
218			
219			var hashSha:ByteArray;
220			var hashMD:ByteArray;
221			
222			var sideBytes:ByteArray = new ByteArray();
223			if (side == TLSEngine.CLIENT) {
224			 	sideBytes.writeUnsignedInt(0x434C4E54);
225			 } else {
226				sideBytes.writeUnsignedInt(0x53525652);
227			}
228			
229			// Do the SHA1 part of the routine first
230			masterSecret.position = 0;
231			k.writeBytes(handshakeMessages);
232			k.writeBytes(sideBytes);
233			k.writeBytes(masterSecret);
234			k.writeBytes(pad_1, 0, 40); // limited to 40 chars for SHA1
235				
236			innerKey = sha.hash(k);
237			// trace("Inner SHA Key: " + Hex.fromArray(innerKey));
238			
239			j.writeBytes(masterSecret);
240			j.writeBytes(pad_2, 0, 40); // limited to 40 chars for SHA1
241			j.writeBytes(innerKey);
242			
243			hashSha = sha.hash(j);
244			// trace("Outer SHA Key: " + Hex.fromArray(hashSha));
245			
246			// Rebuild k for MD5
247			k = new ByteArray();
248			
249			k.writeBytes(handshakeMessages);
250			k.writeBytes(sideBytes);
251			k.writeBytes(masterSecret);
252			k.writeBytes(pad_1); // Take the whole length of pad_1 & pad_2 for MD5
253			
254			innerKey = md.hash(k);
255			// trace("Inner MD5 Key: " + Hex.fromArray(innerKey));
256			
257			j = new ByteArray();
258			j.writeBytes(masterSecret);
259			j.writeBytes(pad_2); // see above re: 48 byte pad
260			j.writeBytes(innerKey); 
261			
262			hashMD = md.hash(j);
263			// trace("Outer MD5 Key: " + Hex.fromArray(hashMD));
264			
265			outerKey.writeBytes(hashMD, 0, hashMD.length);
266			outerKey.writeBytes(hashSha, 0, hashSha.length);
267			var out:String = Hex.fromArray(outerKey);
268			// trace("Finished Message: " + out);
269			outerKey.position = 0;
270			
271			return outerKey;
272		
273		}
274		
275		public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {
276			// TODO: Implement this, but I don't forsee it being necessary at this point in time, since for purposes
277			// of the override, I'm only going to use TLS
278			return null;  
279		}
280		
281		public function getConnectionStates():Object {
282			
283			if (masterSecret != null) {
284				// so now, I have to derive the actual keys from the keyblock that I generated in setPremasterSecret.
285				// for MY purposes, I need RSA-AES 128/256 + SHA
286				// so I'm gonna have keylen = 32, minlen = 32, mac_length = 20, iv_length = 16
287				// but...I can get this data from the settings returned in the constructor when this object is 
288				// It strikes me that TLS does this more elegantly...
289				
290				var mac_length:int = hashSize as Number;
291				var key_length:int = keySize as Number;
292				var iv_length:int = IVSize as Number;
293				
294				var client_write_MAC:ByteArray = new ByteArray();
295				var server_write_MAC:ByteArray = new ByteArray();
296				var client_write_key:ByteArray = new ByteArray();
297				var server_write_key:ByteArray = new ByteArray();
298				var client_write_IV:ByteArray = new ByteArray();
299				var server_write_IV:ByteArray = new ByteArray();
300		
301				// Derive the keys from the keyblock
302				// Get the MACs first
303				keyBlock.position = 0;
304				keyBlock.readBytes(client_write_MAC, 0, mac_length);
305				keyBlock.readBytes(server_write_MAC, 0, mac_length);
306				
307				// keyBlock.position is now at MAC_length * 2
308				// then get the keys
309				keyBlock.readBytes(client_write_key, 0, key_length);
310				keyBlock.readBytes(server_write_key, 0, key_length);
311				
312				// keyBlock.position is now at (MAC_length * 2) + (keySize * 2) 
313				// and then the IVs
314				keyBlock.readBytes(client_write_IV, 0, iv_length);
315				keyBlock.readBytes(server_write_IV, 0, iv_length);
316				
317				// reset this in case it's needed, for some reason or another, but I doubt it
318				keyBlock.position = 0;
319				
320				var client_write:SSLConnectionState = new SSLConnectionState(
321						bulkCipher, cipherType, macAlgorithm,
322						client_write_MAC, client_write_key, client_write_IV);
323				var server_write:SSLConnectionState = new SSLConnectionState(
324						bulkCipher, cipherType, macAlgorithm,
325						server_write_MAC, server_write_key, server_write_IV);
326				
327				if (entity == TLSEngine.CLIENT) {
328					return {read:server_write, write:client_write};
329				} else {
330					return {read:client_write, write:server_write};
331				}
332
333
334			} else {
335				return {read:new SSLConnectionState, write:new SSLConnectionState};
336			}
337		}
338		
339	}
340}