1 | define([ |
---|
2 | "dojo/_base/kernel", // dojo.experimental |
---|
3 | "dojo/_base/lang", // dojo.extend |
---|
4 | "./RSAKey", |
---|
5 | "../../math/BigInteger-ext" |
---|
6 | ], function(kernel, lang, RSAKey, BigInteger) { |
---|
7 | |
---|
8 | kernel.experimental("dojox.encoding.crypto.RSAKey-ext"); |
---|
9 | |
---|
10 | // Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext |
---|
11 | function pkcs1unpad2(d, n){ |
---|
12 | var b = d.toByteArray(); |
---|
13 | for(var i = 0, len = b.length; i < len && !b[i]; ++i); |
---|
14 | if(b.length - i !== n - 1 || b[i] !== 2){ |
---|
15 | return null; |
---|
16 | } |
---|
17 | for(++i; b[i];){ |
---|
18 | if(++i >= len){ |
---|
19 | return null; |
---|
20 | } |
---|
21 | } |
---|
22 | var ret = ""; |
---|
23 | while(++i < len){ |
---|
24 | ret += String.fromCharCode(b[i]); |
---|
25 | } |
---|
26 | return ret; |
---|
27 | } |
---|
28 | |
---|
29 | lang.extend(RSAKey, { |
---|
30 | setPrivate: function(N, E, D){ |
---|
31 | // summary: |
---|
32 | // Set the private key fields N, e, d and CRT params from hex strings |
---|
33 | if(N && E && N.length && E.length){ |
---|
34 | this.n = new BigInteger(N, 16); |
---|
35 | this.e = parseInt(E, 16); |
---|
36 | this.d = new BigInteger(D, 16); |
---|
37 | }else{ |
---|
38 | throw new Error("Invalid RSA private key"); |
---|
39 | } |
---|
40 | }, |
---|
41 | setPrivateEx: function(N, E, D, P, Q, DP, DQ, C) { |
---|
42 | // summary: |
---|
43 | // Set the private key fields N, e, d and CRT params from hex strings |
---|
44 | if(N && E && N.length && E.length){ |
---|
45 | this.n = new BigInteger(N, 16); |
---|
46 | this.e = parseInt(E, 16); |
---|
47 | this.d = new BigInteger(D, 16); |
---|
48 | this.p = new BigInteger(P, 16); |
---|
49 | this.q = new BigInteger(Q, 16); |
---|
50 | this.dmp1 = new BigInteger(DP, 16); |
---|
51 | this.dmq1 = new BigInteger(DQ, 16); |
---|
52 | this.coeff = new BigInteger(C, 16); |
---|
53 | }else{ |
---|
54 | throw new Error("Invalid RSA private key"); |
---|
55 | } |
---|
56 | }, |
---|
57 | generate: function(B, E){ |
---|
58 | // summary: |
---|
59 | // Generate a new random private key B bits long, using public expt E |
---|
60 | var rng = this.rngf(), qs = B >> 1; |
---|
61 | this.e = parseInt(E, 16); |
---|
62 | var ee = new BigInteger(E, 16); |
---|
63 | for(;;) { |
---|
64 | for(;;) { |
---|
65 | this.p = new BigInteger(B - qs, 1, rng); |
---|
66 | if(!this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) && this.p.isProbablePrime(10)){ |
---|
67 | break; |
---|
68 | } |
---|
69 | } |
---|
70 | for(;;) { |
---|
71 | this.q = new BigInteger(qs, 1, rng); |
---|
72 | if(!this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) && this.q.isProbablePrime(10)){ |
---|
73 | break; |
---|
74 | } |
---|
75 | } |
---|
76 | if(this.p.compareTo(this.q) <= 0) { |
---|
77 | var t = this.p; |
---|
78 | this.p = this.q; |
---|
79 | this.q = t; |
---|
80 | } |
---|
81 | var p1 = this.p.subtract(BigInteger.ONE); |
---|
82 | var q1 = this.q.subtract(BigInteger.ONE); |
---|
83 | var phi = p1.multiply(q1); |
---|
84 | if(!phi.gcd(ee).compareTo(BigInteger.ONE)) { |
---|
85 | this.n = this.p.multiply(this.q); |
---|
86 | this.d = ee.modInverse(phi); |
---|
87 | this.dmp1 = this.d.mod(p1); |
---|
88 | this.dmq1 = this.d.mod(q1); |
---|
89 | this.coeff = this.q.modInverse(this.p); |
---|
90 | break; |
---|
91 | } |
---|
92 | } |
---|
93 | rng.destroy(); |
---|
94 | }, |
---|
95 | |
---|
96 | decrypt: function(ctext){ |
---|
97 | // summary: |
---|
98 | // Return the PKCS#1 RSA decryption of "ctext". |
---|
99 | // ctext: String: |
---|
100 | // an even-length hex string |
---|
101 | // returns: a plain string. |
---|
102 | var c = new BigInteger(ctext, 16), m; |
---|
103 | if(!this.p || !this.q){ |
---|
104 | m = c.modPow(this.d, this.n); |
---|
105 | }else{ |
---|
106 | // TODO: re-calculate any missing CRT params |
---|
107 | var cp = c.mod(this.p).modPow(this.dmp1, this.p), |
---|
108 | cq = c.mod(this.q).modPow(this.dmq1, this.q); |
---|
109 | while(cp.compareTo(cq) < 0){ |
---|
110 | cp = cp.add(this.p); |
---|
111 | } |
---|
112 | m = cp.subtract(cq).multiply(this.coeff).mod(this.p).multiply(this.q).add(cq); |
---|
113 | } |
---|
114 | if(!m){ |
---|
115 | return null; |
---|
116 | } |
---|
117 | return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3); |
---|
118 | } |
---|
119 | }); |
---|
120 | |
---|
121 | return RSAKey; |
---|
122 | }); |
---|