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