diff --git a/src/crypto/public_key/index.js b/src/crypto/public_key/index.js index ae4aac89..384dff82 100644 --- a/src/crypto/public_key/index.js +++ b/src/crypto/public_key/index.js @@ -7,16 +7,18 @@ */ /** @see module:crypto/public_key/rsa */ -import rsa from './rsa.js'; +import rsa from './rsa'; +import prime from './prime'; /** @see module:crypto/public_key/elgamal */ -import elgamal from './elgamal.js'; +import elgamal from './elgamal'; /** @see module:crypto/public_key/elliptic */ import elliptic from './elliptic'; /** @see module:crypto/public_key/dsa */ -import dsa from './dsa.js'; +import dsa from './dsa'; export default { rsa: rsa, + prime: prime, elgamal: elgamal, elliptic: elliptic, dsa: dsa diff --git a/src/crypto/public_key/prime.js b/src/crypto/public_key/prime.js index 75cec019..a35743b9 100644 --- a/src/crypto/public_key/prime.js +++ b/src/crypto/public_key/prime.js @@ -15,7 +15,7 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// Algorithms for probabilistic primality testing +// Algorithms for probabilistic prime generation /** * @requires bn.js @@ -26,21 +26,32 @@ import BN from 'bn.js'; import random from '../random'; -function randomProbablePrime(b) { - let n; - const min = new BN(1).shln(b-1); - do { - n = random.getRandomBN(min, min.shln(1)); - if (n.isEven()) { - n.iaddn(1); // force odd +export default { + randomProbablePrime, isProbablePrime, fermat, millerRabin +}; + +function randomProbablePrime(bits, e) { + const min = new BN(1).shln(bits - 1); + + let n = random.getRandomBN(min, min.shln(1)); + if (n.isEven()) { + n.iaddn(1); // force odd + } + + while (!isProbablePrime(n, e)) { + n.iaddn(2); + // If reached the maximum, go back to the minimum. + if (n.bitLength() > bits) { + n = n.mod(min.shln(1)).iadd(min); } - } while (!isProbablePrime(n)); -// this.dAddOffset(2, 0); -// if (this.bitLength() > b) -// this.subTo(BigInteger.ONE.shiftLeft(b - 1), this); + } + return n; } -function isProbablePrime(n) { +function isProbablePrime(n, e) { + if (e && !n.subn(1).gcd(e).eqn(1)) { + return false; + } if (!fermat(n)) { return false; } @@ -54,9 +65,9 @@ function isProbablePrime(n) { * Tests whether n is probably prime or not using Fermat's test with b = 2. * Fails if b^(n-1) mod n === 1. */ -export function fermat(n, b) { +function fermat(n, b) { b = b || new BN(2); - return b.toRed(BN.mont(n)).redPow(n.subn(1)).cmpn(1) === 0; + return b.toRed(BN.mont(n)).redPow(n.subn(1)).fromRed().cmpn(1) === 0; } @@ -93,7 +104,7 @@ export function fermat(n, b) { * Tests whether n is probably prime or not using the Miller-Rabin test. * See HAC Remark 4.28. */ -export function millerRabin(n, k, cb) { +function millerRabin(n, k, cb) { var len = n.bitLength(); var red = BN.mont(n); var rone = new BN(1).toRed(red); diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js index 2e86b7d5..3792f1ea 100644 --- a/src/crypto/public_key/rsa.js +++ b/src/crypto/public_key/rsa.js @@ -29,9 +29,7 @@ import BN from 'bn.js'; -import { RSA } from 'asmcrypto.js/src/rsa/exports-keygen'; import { RSA_RAW } from 'asmcrypto.js/src/rsa/exports-raw'; -import { random as asmcrypto_random } from 'asmcrypto.js/src/random/exports'; import prime from './prime'; import random from '../random'; import config from '../../config'; @@ -40,6 +38,13 @@ import util from '../../util'; const two = new BN(2); const zero = new BN(0); +// TODO use this is ../../encoding/base64.js and ./elliptic/{key,curve}.js +function b64toBN(base64url) { + const base64 = base64url.replace(/\-/g, '+').replace(/_/g, '/'); + const hex = util.hexstrdump(atob(base64)); + return new BN(hex, 16); +} + export default { /** Create signature * @param m message as BN @@ -189,25 +194,27 @@ export default { return key; } - // TODO use this is ../../encoding/base64.js and ./elliptic/{key,curve}.js - function b64toBN(base64url) { - const base64 = base64url.replace(/\-/g, '+').replace(/_/g, '/'); - const hex = util.hexstrdump(atob(base64)); - return new BN(hex, 16); - } + while (true) { + let p = prime.randomProbablePrime(B - (B >> 1), E); + let q = prime.randomProbablePrime(B >> 1, E); - // asmcrypto fallback - await asmcrypto_random.seed(await random.getRandomBytes(1024)); // FIXME how much randomness? - key = await RSA.generateKey(B, E.toArrayLike(Uint8Array)); - return { - n: new BN(key[0]), - e: new BN(key[1]), - d: new BN(key[2]), - q: new BN(key[3]), - p: new BN(key[4]), - // dq: new BN(key[5]), - // dp: new BN(key[6]), - u: new BN(key[7]) - }; + if (p.cmp(q) < 0) { + const t = p; + p = q; + q = t; + } + + const phi = p.subn(1).mul(q.subn(1)); + return { + n: p.mul(q), + e: E, + d: E.invm(phi), + q: q, + p: p, + // dq: d.mod(q.subn(1)), + // dp: d.mod(p.subn(1)), + u: p.invm(q) + }; + } } };