millerRabin set to 40 iterations; doc fixes
This commit is contained in:
parent
7a3a75a7df
commit
2e95335825
|
@ -280,7 +280,7 @@ export default {
|
||||||
return constructParams(types, [keyObject.oid, keyObject.Q, [keyObject.hash, keyObject.cipher], keyObject.d]);
|
return constructParams(types, [keyObject.oid, keyObject.Q, [keyObject.hash, keyObject.cipher], keyObject.d]);
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
throw new Error('Invalid public key encryption algorithm.');
|
throw new Error('Invalid public key algorithm.');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
// Algorithms for probabilistic prime generation
|
// Algorithms for probabilistic random prime generation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires bn.js
|
* @requires bn.js
|
||||||
|
@ -30,7 +30,14 @@ export default {
|
||||||
randomProbablePrime, isProbablePrime, fermat, millerRabin
|
randomProbablePrime, isProbablePrime, fermat, millerRabin
|
||||||
};
|
};
|
||||||
|
|
||||||
function randomProbablePrime(bits, e) {
|
/**
|
||||||
|
* Probabilistic random number generator
|
||||||
|
* @param {Integer} bits Bit length of the prime
|
||||||
|
* @param {BN} e Optional RSA exponent to check against the prime
|
||||||
|
* @param {Integer} k Optional number of iterations of Miller-Rabin test
|
||||||
|
* @return BN
|
||||||
|
*/
|
||||||
|
function randomProbablePrime(bits, e, k) {
|
||||||
const min = new BN(1).shln(bits - 1);
|
const min = new BN(1).shln(bits - 1);
|
||||||
|
|
||||||
let n = random.getRandomBN(min, min.shln(1));
|
let n = random.getRandomBN(min, min.shln(1));
|
||||||
|
@ -38,7 +45,7 @@ function randomProbablePrime(bits, e) {
|
||||||
n.iaddn(1); // force odd
|
n.iaddn(1); // force odd
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!isProbablePrime(n, e)) {
|
while (!isProbablePrime(n, e, k)) {
|
||||||
n.iaddn(2);
|
n.iaddn(2);
|
||||||
// If reached the maximum, go back to the minimum.
|
// If reached the maximum, go back to the minimum.
|
||||||
if (n.bitLength() > bits) {
|
if (n.bitLength() > bits) {
|
||||||
|
@ -48,14 +55,21 @@ function randomProbablePrime(bits, e) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isProbablePrime(n, e) {
|
/**
|
||||||
|
* Probabilistic primality testing
|
||||||
|
* @param {BN} n Number to test
|
||||||
|
* @param {BN} e Optional RSA exponent to check against the prime
|
||||||
|
* @param {Integer} k Optional number of iterations of Miller-Rabin test
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
function isProbablePrime(n, e, k) {
|
||||||
if (e && !n.subn(1).gcd(e).eqn(1)) {
|
if (e && !n.subn(1).gcd(e).eqn(1)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!fermat(n)) {
|
if (!fermat(n)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!millerRabin(n)) {
|
if (!millerRabin(n, k)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -64,6 +78,9 @@ function isProbablePrime(n, e) {
|
||||||
/**
|
/**
|
||||||
* Tests whether n is probably prime or not using Fermat's test with b = 2.
|
* Tests whether n is probably prime or not using Fermat's test with b = 2.
|
||||||
* Fails if b^(n-1) mod n === 1.
|
* Fails if b^(n-1) mod n === 1.
|
||||||
|
* @param {BN} n Number to test
|
||||||
|
* @param {Integer} b Optional Fermat test base
|
||||||
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
function fermat(n, b) {
|
function fermat(n, b) {
|
||||||
b = b || new BN(2);
|
b = b || new BN(2);
|
||||||
|
@ -103,33 +120,38 @@ function fermat(n, b) {
|
||||||
/**
|
/**
|
||||||
* Tests whether n is probably prime or not using the Miller-Rabin test.
|
* Tests whether n is probably prime or not using the Miller-Rabin test.
|
||||||
* See HAC Remark 4.28.
|
* See HAC Remark 4.28.
|
||||||
|
* @param {BN} n Number to test
|
||||||
|
* @param {Integer} k Optional number of iterations of Miller-Rabin test
|
||||||
|
* @param {Function} cb Optional callback function to call with random witnesses
|
||||||
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
function millerRabin(n, k, cb) {
|
function millerRabin(n, k, cb) {
|
||||||
var len = n.bitLength();
|
const len = n.bitLength();
|
||||||
var red = BN.mont(n);
|
const red = BN.mont(n);
|
||||||
var rone = new BN(1).toRed(red);
|
const rone = new BN(1).toRed(red);
|
||||||
|
|
||||||
if (!k)
|
if (!k)
|
||||||
k = Math.max(1, (len / 48) | 0);
|
k = Math.max(1, (len / 48) | 0);
|
||||||
|
|
||||||
// Find d and s, (n - 1) = (2 ^ s) * d;
|
// Find d and s, (n - 1) = (2 ^ s) * d;
|
||||||
var n1 = n.subn(1);
|
const n1 = n.subn(1);
|
||||||
for (var s = 0; !n1.testn(s); s++) {}
|
let s = 0;
|
||||||
var d = n.shrn(s);
|
while (!n1.testn(s)) { s++; }
|
||||||
|
const d = n.shrn(s);
|
||||||
|
|
||||||
var rn1 = n1.toRed(red);
|
const rn1 = n1.toRed(red);
|
||||||
|
|
||||||
var prime = true;
|
|
||||||
for (; k > 0; k--) {
|
for (; k > 0; k--) {
|
||||||
var a = random.getRandomBN(new BN(2), n1);
|
let a = random.getRandomBN(new BN(2), n1);
|
||||||
if (cb)
|
if (cb)
|
||||||
cb(a);
|
cb(a);
|
||||||
|
|
||||||
var x = a.toRed(red).redPow(d);
|
let x = a.toRed(red).redPow(d);
|
||||||
if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
|
if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (var i = 1; i < s; i++) {
|
let i;
|
||||||
|
for (i = 1; i < s; i++) {
|
||||||
x = x.redSqr();
|
x = x.redSqr();
|
||||||
|
|
||||||
if (x.cmp(rone) === 0)
|
if (x.cmp(rone) === 0)
|
||||||
|
@ -142,5 +164,5 @@ function millerRabin(n, k, cb) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return prime;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires bn.js
|
* @requires bn.js
|
||||||
* @requires asmcrypto.js
|
|
||||||
* @requires crypto/public_key/prime
|
* @requires crypto/public_key/prime
|
||||||
* @requires crypto/random
|
* @requires crypto/random
|
||||||
* @requires config
|
* @requires config
|
||||||
|
@ -135,7 +134,10 @@ export default {
|
||||||
/**
|
/**
|
||||||
* Generate a new random private key B bits long with public exponent E
|
* Generate a new random private key B bits long with public exponent E
|
||||||
* @param {Integer} B RSA bit length
|
* @param {Integer} B RSA bit length
|
||||||
* @param {String} E RSA public exponent in hex
|
* @param {String} E RSA public exponent in hex string
|
||||||
|
* @return {{n: BN, e: BN, d: BN,
|
||||||
|
p: BN, q: BN, u: BN}} RSA public modulus, RSA public exponent, RSA private exponent,
|
||||||
|
RSA private prime p, RSA private prime q, u = q ** -1 mod p
|
||||||
*/
|
*/
|
||||||
generate: async function(B, E) {
|
generate: async function(B, E) {
|
||||||
let key;
|
let key;
|
||||||
|
@ -193,13 +195,13 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
let p = prime.randomProbablePrime(B - (B >> 1), E);
|
// 40 iterations of the Miller-Rabin test
|
||||||
let q = prime.randomProbablePrime(B >> 1, E);
|
// See https://stackoverflow.com/a/6330138 for justification
|
||||||
|
let p = prime.randomProbablePrime(B - (B >> 1), E, 40);
|
||||||
|
let q = prime.randomProbablePrime(B >> 1, E, 40);
|
||||||
|
|
||||||
if (p.cmp(q) < 0) {
|
if (p.cmp(q) < 0) {
|
||||||
const t = p;
|
[p, q] = [q, p];
|
||||||
p = q;
|
|
||||||
q = t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const phi = p.subn(1).mul(q.subn(1));
|
const phi = p.subn(1).mul(q.subn(1));
|
||||||
|
@ -214,5 +216,7 @@ export default {
|
||||||
u: p.invm(q)
|
u: p.invm(q)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
prime: prime
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
|
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
|
||||||
const AES_CFB = require('asmcrypto.js/asmcrypto.all.js').AES_CFB;
|
|
||||||
|
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
chai.use(require('chai-as-promised'));
|
chai.use(require('chai-as-promised'));
|
||||||
|
@ -297,11 +296,7 @@ describe('API functional testing', function() {
|
||||||
const prefix = util.concatUint8Array([rndm, repeat]);
|
const prefix = util.concatUint8Array([rndm, repeat]);
|
||||||
|
|
||||||
const symmencData = crypto.cfb.encrypt(rndm, algo, util.str2Uint8Array(plaintext), symmKey, false);
|
const symmencData = crypto.cfb.encrypt(rndm, algo, util.str2Uint8Array(plaintext), symmKey, false);
|
||||||
const symmencData2 = AES_CFB.encrypt(util.concatUint8Array([prefix, util.str2Uint8Array(plaintext)]), symmKey);
|
const decrypted = crypto.cfb.decrypt(algo, symmKey, symmencData, false);
|
||||||
|
|
||||||
let decrypted = AES_CFB.decrypt(symmencData, symmKey);
|
|
||||||
decrypted = decrypted.subarray(crypto.cipher[algo].blockSize + 2, decrypted.length);
|
|
||||||
expect(util.Uint8Array2str(symmencData)).to.equal(util.Uint8Array2str(symmencData2));
|
|
||||||
|
|
||||||
const text = util.Uint8Array2str(decrypted);
|
const text = util.Uint8Array2str(decrypted);
|
||||||
expect(text).to.equal(plaintext);
|
expect(text).to.equal(plaintext);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user