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