// Copyright (c) 2011 Kevin M Burns Jr. // All Rights Reserved. // See "LICENSE" for details. // // Extension to jsbn which adds facilities for asynchronous RSA key generation // Primarily created to avoid execution timeout on mobile devices // // http://www-cs-students.stanford.edu/~tjw/jsbn/ // // --- (function(){ // Generate a new random private key B bits long, using public expt E var RSAGenerateAsync = function (B, E, callback) { //var rng = new SeededRandom(); var rng = new SecureRandom(); var qs = B >> 1; this.e = parseInt(E, 16); var ee = new BigInteger(E, 16); var rsa = this; // These functions have non-descript names because they were originally for(;;) loops. // I don't know about cryptography to give them better names than loop1-4. var loop1 = function() { var loop4 = function() { if (rsa.p.compareTo(rsa.q) <= 0) { var t = rsa.p; rsa.p = rsa.q; rsa.q = t; } var p1 = rsa.p.subtract(BigInteger.ONE); var q1 = rsa.q.subtract(BigInteger.ONE); var phi = p1.multiply(q1); if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { rsa.n = rsa.p.multiply(rsa.q); rsa.d = ee.modInverse(phi); rsa.dmp1 = rsa.d.mod(p1); rsa.dmq1 = rsa.d.mod(q1); rsa.coeff = rsa.q.modInverse(rsa.p); setTimeout(function(){callback()},0); // escape } else { setTimeout(loop1,0); } }; var loop3 = function() { rsa.q = nbi(); rsa.q.fromNumberAsync(qs, 1, rng, function(){ rsa.q.subtract(BigInteger.ONE).gcda(ee, function(r){ if (r.compareTo(BigInteger.ONE) == 0 && rsa.q.isProbablePrime(10)) { setTimeout(loop4,0); } else { setTimeout(loop3,0); } }); }); }; var loop2 = function() { rsa.p = nbi(); rsa.p.fromNumberAsync(B - qs, 1, rng, function(){ rsa.p.subtract(BigInteger.ONE).gcda(ee, function(r){ if (r.compareTo(BigInteger.ONE) == 0 && rsa.p.isProbablePrime(10)) { setTimeout(loop3,0); } else { setTimeout(loop2,0); } }); }); }; setTimeout(loop2,0); }; setTimeout(loop1,0); }; RSAKey.prototype.generateAsync = RSAGenerateAsync; // Public API method var bnGCDAsync = function (a, callback) { var x = (this.s < 0) ? this.negate() : this.clone(); var y = (a.s < 0) ? a.negate() : a.clone(); if (x.compareTo(y) < 0) { var t = x; x = y; y = t; } var i = x.getLowestSetBit(), g = y.getLowestSetBit(); if (g < 0) { callback(x); return; } if (i < g) g = i; if (g > 0) { x.rShiftTo(g, x); y.rShiftTo(g, y); } // Workhorse of the algorithm, gets called 200 - 800 times per 512 bit keygen. var gcda1 = function() { if ((i = x.getLowestSetBit()) > 0){ x.rShiftTo(i, x); } if ((i = y.getLowestSetBit()) > 0){ y.rShiftTo(i, y); } if (x.compareTo(y) >= 0) { x.subTo(y, x); x.rShiftTo(1, x); } else { y.subTo(x, y); y.rShiftTo(1, y); } if(!(x.signum() > 0)) { if (g > 0) y.lShiftTo(g, y); setTimeout(function(){callback(y)},0); // escape } else { setTimeout(gcda1,0); } }; setTimeout(gcda1,10); }; BigInteger.prototype.gcda = bnGCDAsync; // (protected) alternate constructor var bnpFromNumberAsync = function (a,b,c,callback) { if("number" == typeof b) { if(a < 2) { this.fromInt(1); } else { this.fromNumber(a,c); if(!this.testBit(a-1)){ this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); } if(this.isEven()) { this.dAddOffset(1,0); } var bnp = this; var bnpfn1 = function(){ bnp.dAddOffset(2,0); if(bnp.bitLength() > a) bnp.subTo(BigInteger.ONE.shiftLeft(a-1),bnp); if(bnp.isProbablePrime(b)) { setTimeout(function(){callback()},0); // escape } else { setTimeout(bnpfn1,0); } }; setTimeout(bnpfn1,0); } } else { var x = new Array(), t = a&7; x.length = (a>>3)+1; b.nextBytes(x); if(t > 0) x[0] &= ((1<