PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

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

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
ActionScript | 339 lines | 256 code | 31 blank | 52 comment | 42 complexity | d7a68d698220691be6776b1ca97e1049 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /**
  2. * RSAKey
  3. *
  4. * An ActionScript 3 implementation of RSA + PKCS#1 (light version)
  5. * Copyright (c) 2007 Henri Torgemane
  6. *
  7. * Derived from:
  8. * The jsbn library, Copyright (c) 2003-2005 Tom Wu
  9. *
  10. * See LICENSE.txt for full license information.
  11. */
  12. package com.hurlant.crypto.rsa
  13. {
  14. import com.hurlant.crypto.prng.Random;
  15. import com.hurlant.math.BigInteger;
  16. import com.hurlant.util.Memory;
  17. import flash.utils.ByteArray;
  18. import com.hurlant.crypto.hash.IHash;
  19. import com.hurlant.util.Hex;
  20. import com.hurlant.util.der.DER;
  21. import com.hurlant.util.der.OID;
  22. import com.hurlant.util.ArrayUtil;
  23. import com.hurlant.util.der.Type;
  24. import com.hurlant.util.der.Sequence;
  25. import com.hurlant.util.der.ObjectIdentifier;
  26. import com.hurlant.util.der.ByteString;
  27. import com.hurlant.crypto.tls.TLSError;
  28. /**
  29. * Current limitations:
  30. * exponent must be smaller than 2^31.
  31. */
  32. public class RSAKey
  33. {
  34. // public key
  35. public var e:int; // public exponent. must be <2^31
  36. public var n:BigInteger; // modulus
  37. // private key
  38. public var d:BigInteger;
  39. // extended private key
  40. public var p:BigInteger;
  41. public var q:BigInteger;
  42. public var dmp1:BigInteger
  43. public var dmq1:BigInteger;
  44. public var coeff:BigInteger;
  45. // flags. flags are cool.
  46. protected var canDecrypt:Boolean;
  47. protected var canEncrypt:Boolean;
  48. public function RSAKey(N:BigInteger, E:int,
  49. D:BigInteger=null,
  50. P:BigInteger = null, Q:BigInteger=null,
  51. DP:BigInteger=null, DQ:BigInteger=null,
  52. C:BigInteger=null) {
  53. this.n = N;
  54. this.e = E;
  55. this.d = D;
  56. this.p = P;
  57. this.q = Q;
  58. this.dmp1 = DP;
  59. this.dmq1 = DQ;
  60. this.coeff = C;
  61. // adjust a few flags.
  62. canEncrypt = (n!=null&&e!=0);
  63. canDecrypt = (canEncrypt&&d!=null);
  64. }
  65. public static function parsePublicKey(N:String, E:String):RSAKey {
  66. return new RSAKey(new BigInteger(N, 16, true), parseInt(E,16));
  67. }
  68. public static function parsePrivateKey(N:String, E:String, D:String,
  69. P:String=null,Q:String=null, DMP1:String=null, DMQ1:String=null, IQMP:String=null):RSAKey {
  70. if (P==null) {
  71. return new RSAKey(new BigInteger(N,16, true), parseInt(E,16), new BigInteger(D,16, true));
  72. } else {
  73. return new RSAKey(new BigInteger(N,16, true), parseInt(E,16), new BigInteger(D,16, true),
  74. new BigInteger(P,16, true), new BigInteger(Q,16, true),
  75. new BigInteger(DMP1,16, true), new BigInteger(DMQ1, 16, true),
  76. new BigInteger(IQMP, 16, true));
  77. }
  78. }
  79. public function getBlockSize():uint {
  80. return (n.bitLength()+7)/8;
  81. }
  82. public function dispose():void {
  83. e = 0;
  84. n.dispose();
  85. n = null;
  86. Memory.gc();
  87. }
  88. public function encrypt(src:ByteArray, dst:ByteArray, length:uint, pad:Function=null):void {
  89. _encrypt(doPublic, src, dst, length, pad, 0x02);
  90. }
  91. public function decrypt(src:ByteArray, dst:ByteArray, length:uint, pad:Function=null):void {
  92. _decrypt(doPrivate2, src, dst, length, pad, 0x02);
  93. }
  94. public function sign(src:ByteArray, dst:ByteArray, length:uint, pad:Function = null):void {
  95. _encrypt(doPrivate2, src, dst, length, pad, 0x01);
  96. }
  97. public function verify(src:ByteArray, dst:ByteArray, length:uint, pad:Function = null):void {
  98. _decrypt(doPublic, src, dst, length, pad, 0x01);
  99. }
  100. private function _encrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int):void {
  101. // adjust pad if needed
  102. if (pad==null) pad = pkcs1pad;
  103. // convert src to BigInteger
  104. if (src.position >= src.length) {
  105. src.position = 0;
  106. }
  107. var bl:uint = getBlockSize();
  108. var end:int = src.position + length;
  109. while (src.position<end) {
  110. var block:BigInteger = new BigInteger(pad(src, end, bl, padType), bl, true);
  111. var chunk:BigInteger = op(block);
  112. chunk.toArray(dst);
  113. }
  114. }
  115. private function _decrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int):void {
  116. // adjust pad if needed
  117. if (pad==null) pad = pkcs1unpad;
  118. // convert src to BigInteger
  119. if (src.position >= src.length) {
  120. src.position = 0;
  121. }
  122. var bl:uint = getBlockSize();
  123. var end:int = src.position + length;
  124. while (src.position<end) {
  125. var block:BigInteger = new BigInteger(src, bl, true);
  126. var chunk:BigInteger = op(block);
  127. var b:ByteArray = pad(chunk, bl, padType);
  128. if (b == null)
  129. throw new TLSError( "Decrypt error - padding function returned null!", TLSError.decode_error );
  130. // if (b != null)
  131. dst.writeBytes(b);
  132. }
  133. }
  134. /**
  135. * PKCS#1 pad. type 1 (0xff) or 2, random.
  136. * puts as much data from src into it, leaves what doesn't fit alone.
  137. */
  138. private function pkcs1pad(src:ByteArray, end:int, n:uint, type:uint = 0x02):ByteArray {
  139. var out:ByteArray = new ByteArray;
  140. var p:uint = src.position;
  141. end = Math.min(end, src.length, p+n-11);
  142. src.position = end;
  143. var i:int = end-1;
  144. while (i>=p && n>11) {
  145. out[--n] = src[i--];
  146. }
  147. out[--n] = 0;
  148. if (type==0x02) { // type 2
  149. var rng:Random = new Random;
  150. var x:int = 0;
  151. while (n>2) {
  152. do {
  153. x = rng.nextByte();
  154. } while (x==0);
  155. out[--n] = x;
  156. }
  157. } else { // type 1
  158. while (n>2) {
  159. out[--n] = 0xFF;
  160. }
  161. }
  162. out[--n] = type;
  163. out[--n] = 0;
  164. return out;
  165. }
  166. /**
  167. *
  168. * @param src
  169. * @param n
  170. * @param type Not used.
  171. * @return
  172. *
  173. */
  174. private function pkcs1unpad(src:BigInteger, n:uint, type:uint = 0x02):ByteArray {
  175. var b:ByteArray = src.toByteArray();
  176. var out:ByteArray = new ByteArray;
  177. b.position = 0;
  178. var i:int = 0;
  179. while (i<b.length && b[i]==0) ++i;
  180. if (b.length-i != n-1 || b[i]!=type) {
  181. trace("PKCS#1 unpad: i="+i+", expected b[i]=="+type+", got b[i]="+b[i].toString(16));
  182. return null;
  183. }
  184. ++i;
  185. while (b[i]!=0) {
  186. if (++i>=b.length) {
  187. trace("PKCS#1 unpad: i="+i+", b[i-1]!=0 (="+b[i-1].toString(16)+")");
  188. return null;
  189. }
  190. }
  191. while (++i < b.length) {
  192. out.writeByte(b[i]);
  193. }
  194. out.position = 0;
  195. return out;
  196. }
  197. /**
  198. * Raw pad.
  199. */
  200. public function rawpad(src:ByteArray, end:int, n:uint, type:uint = 0):ByteArray {
  201. return src;
  202. }
  203. public function rawunpad(src:BigInteger, n:uint, type:uint = 0):ByteArray {
  204. return src.toByteArray();
  205. }
  206. public function toString():String {
  207. return "rsa";
  208. }
  209. public function dump():String {
  210. var s:String= "N="+n.toString(16)+"\n"+
  211. "E="+e.toString(16)+"\n";
  212. if (canDecrypt) {
  213. s+="D="+d.toString(16)+"\n";
  214. if (p!=null && q!=null) {
  215. s+="P="+p.toString(16)+"\n";
  216. s+="Q="+q.toString(16)+"\n";
  217. s+="DMP1="+dmp1.toString(16)+"\n";
  218. s+="DMQ1="+dmq1.toString(16)+"\n";
  219. s+="IQMP="+coeff.toString(16)+"\n";
  220. }
  221. }
  222. return s;
  223. }
  224. /**
  225. *
  226. * note: We should have a "nice" variant of this function that takes a callback,
  227. * and perform the computation is small fragments, to keep the web browser
  228. * usable.
  229. *
  230. * @param B
  231. * @param E
  232. * @return a new random private key B bits long, using public expt E
  233. *
  234. */
  235. public static function generate(B:uint, E:String):RSAKey {
  236. var rng:Random = new Random;
  237. var qs:uint = B>>1;
  238. var key:RSAKey = new RSAKey(null,0,null);
  239. key.e = parseInt(E, 16);
  240. var ee:BigInteger = new BigInteger(E,16, true);
  241. for (;;) {
  242. for (;;) {
  243. key.p = bigRandom(B-qs, rng);
  244. if (key.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE)==0 &&
  245. key.p.isProbablePrime(10)) break;
  246. }
  247. for (;;) {
  248. key.q = bigRandom(qs, rng);
  249. if (key.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE)==0 &&
  250. key.q.isProbablePrime(10)) break;
  251. }
  252. if (key.p.compareTo(key.q)<=0) {
  253. var t:BigInteger = key.p;
  254. key.p = key.q;
  255. key.q = t;
  256. }
  257. var p1:BigInteger = key.p.subtract(BigInteger.ONE);
  258. var q1:BigInteger = key.q.subtract(BigInteger.ONE);
  259. var phi:BigInteger = p1.multiply(q1);
  260. if (phi.gcd(ee).compareTo(BigInteger.ONE)==0) {
  261. key.n = key.p.multiply(key.q);
  262. key.d = ee.modInverse(phi);
  263. key.dmp1 = key.d.mod(p1);
  264. key.dmq1 = key.d.mod(q1);
  265. key.coeff = key.q.modInverse(key.p);
  266. break;
  267. }
  268. }
  269. return key;
  270. }
  271. protected static function bigRandom(bits:int, rnd:Random):BigInteger {
  272. if (bits<2) return BigInteger.nbv(1);
  273. var x:ByteArray = new ByteArray;
  274. rnd.nextBytes(x, (bits>>3));
  275. x.position = 0;
  276. var b:BigInteger = new BigInteger(x,0,true);
  277. b.primify(bits, 1);
  278. return b;
  279. }
  280. protected function doPublic(x:BigInteger):BigInteger {
  281. return x.modPowInt(e, n);
  282. }
  283. protected function doPrivate2(x:BigInteger):BigInteger {
  284. if (p==null && q==null) {
  285. return x.modPow(d,n);
  286. }
  287. var xp:BigInteger = x.mod(p).modPow(dmp1, p);
  288. var xq:BigInteger = x.mod(q).modPow(dmq1, q);
  289. while (xp.compareTo(xq)<0) {
  290. xp = xp.add(p);
  291. }
  292. var r:BigInteger = xp.subtract(xq).multiply(coeff).mod(p).multiply(q).add(xq);
  293. return r;
  294. }
  295. protected function doPrivate(x:BigInteger):BigInteger {
  296. if (p==null || q==null) {
  297. return x.modPow(d, n);
  298. }
  299. // TODO: re-calculate any missing CRT params
  300. var xp:BigInteger = x.mod(p).modPow(dmp1, p);
  301. var xq:BigInteger = x.mod(q).modPow(dmq1, q);
  302. while (xp.compareTo(xq)<0) {
  303. xp = xp.add(p);
  304. }
  305. return xp.subtract(xq).multiply(coeff).mod(p).multiply(q).add(xq);
  306. }
  307. }
  308. }