124 lines
3.4 KiB
JavaScript
124 lines
3.4 KiB
JavaScript
//>>built
|
|
define("dojox/encoding/crypto/RSAKey-ext", [
|
|
"dojo/_base/kernel", // dojo.experimental
|
|
"dojo/_base/lang", // dojo.extend
|
|
"./RSAKey",
|
|
"../../math/BigInteger-ext"
|
|
], function(kernel, lang, RSAKey, BigInteger) {
|
|
|
|
kernel.experimental("dojox.encoding.crypto.RSAKey-ext");
|
|
|
|
// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
|
|
function pkcs1unpad2(d, n){
|
|
var b = d.toByteArray();
|
|
for(var i = 0, len = b.length; i < len && !b[i]; ++i);
|
|
if(b.length - i !== n - 1 || b[i] !== 2){
|
|
return null;
|
|
}
|
|
for(++i; b[i];){
|
|
if(++i >= len){
|
|
return null;
|
|
}
|
|
}
|
|
var ret = "";
|
|
while(++i < len){
|
|
ret += String.fromCharCode(b[i]);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
lang.extend(RSAKey, {
|
|
setPrivate: function(N, E, D){
|
|
// summary:
|
|
// Set the private key fields N, e, d and CRT params from hex strings
|
|
if(N && E && N.length && E.length){
|
|
this.n = new BigInteger(N, 16);
|
|
this.e = parseInt(E, 16);
|
|
this.d = new BigInteger(D, 16);
|
|
}else{
|
|
throw new Error("Invalid RSA private key");
|
|
}
|
|
},
|
|
setPrivateEx: function(N, E, D, P, Q, DP, DQ, C) {
|
|
// summary:
|
|
// Set the private key fields N, e, d and CRT params from hex strings
|
|
if(N && E && N.length && E.length){
|
|
this.n = new BigInteger(N, 16);
|
|
this.e = parseInt(E, 16);
|
|
this.d = new BigInteger(D, 16);
|
|
this.p = new BigInteger(P, 16);
|
|
this.q = new BigInteger(Q, 16);
|
|
this.dmp1 = new BigInteger(DP, 16);
|
|
this.dmq1 = new BigInteger(DQ, 16);
|
|
this.coeff = new BigInteger(C, 16);
|
|
}else{
|
|
throw new Error("Invalid RSA private key");
|
|
}
|
|
},
|
|
generate: function(B, E){
|
|
// summary:
|
|
// Generate a new random private key B bits long, using public expt E
|
|
var rng = this.rngf(), qs = B >> 1;
|
|
this.e = parseInt(E, 16);
|
|
var ee = new BigInteger(E, 16);
|
|
for(;;) {
|
|
for(;;) {
|
|
this.p = new BigInteger(B - qs, 1, rng);
|
|
if(!this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) && this.p.isProbablePrime(10)){
|
|
break;
|
|
}
|
|
}
|
|
for(;;) {
|
|
this.q = new BigInteger(qs, 1, rng);
|
|
if(!this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) && this.q.isProbablePrime(10)){
|
|
break;
|
|
}
|
|
}
|
|
if(this.p.compareTo(this.q) <= 0) {
|
|
var t = this.p;
|
|
this.p = this.q;
|
|
this.q = t;
|
|
}
|
|
var p1 = this.p.subtract(BigInteger.ONE);
|
|
var q1 = this.q.subtract(BigInteger.ONE);
|
|
var phi = p1.multiply(q1);
|
|
if(!phi.gcd(ee).compareTo(BigInteger.ONE)) {
|
|
this.n = this.p.multiply(this.q);
|
|
this.d = ee.modInverse(phi);
|
|
this.dmp1 = this.d.mod(p1);
|
|
this.dmq1 = this.d.mod(q1);
|
|
this.coeff = this.q.modInverse(this.p);
|
|
break;
|
|
}
|
|
}
|
|
rng.destroy();
|
|
},
|
|
|
|
decrypt: function(ctext){
|
|
// summary:
|
|
// Return the PKCS#1 RSA decryption of "ctext".
|
|
// ctext: String:
|
|
// an even-length hex string
|
|
// returns: a plain string.
|
|
var c = new BigInteger(ctext, 16), m;
|
|
if(!this.p || !this.q){
|
|
m = c.modPow(this.d, this.n);
|
|
}else{
|
|
// TODO: re-calculate any missing CRT params
|
|
var cp = c.mod(this.p).modPow(this.dmp1, this.p),
|
|
cq = c.mod(this.q).modPow(this.dmq1, this.q);
|
|
while(cp.compareTo(cq) < 0){
|
|
cp = cp.add(this.p);
|
|
}
|
|
m = cp.subtract(cq).multiply(this.coeff).mod(this.p).multiply(this.q).add(cq);
|
|
}
|
|
if(!m){
|
|
return null;
|
|
}
|
|
return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3);
|
|
}
|
|
});
|
|
|
|
return RSAKey;
|
|
});
|