JavaScript RSA using bn.js, without asmcrypto.js

This commit is contained in:
Mahrud Sayrafi 2018-02-25 00:11:29 -05:00
parent 9943379cb7
commit 7a3a75a7df
No known key found for this signature in database
GPG Key ID: C24071B956C3245F
3 changed files with 35 additions and 40 deletions

View File

@ -53,7 +53,6 @@ export default {
let r; let r;
let s; let s;
let t; let t;
// TODO benchmark BN.mont vs BN.red
const redp = new BN.red(p); const redp = new BN.red(p);
const redq = new BN.red(q); const redq = new BN.red(q);
const gred = g.toRed(redp); const gred = g.toRed(redp);

View File

@ -8,7 +8,6 @@
/** @see module:crypto/public_key/rsa */ /** @see module:crypto/public_key/rsa */
import rsa from './rsa'; import rsa from './rsa';
import prime from './prime';
/** @see module:crypto/public_key/elgamal */ /** @see module:crypto/public_key/elgamal */
import elgamal from './elgamal'; import elgamal from './elgamal';
/** @see module:crypto/public_key/elliptic */ /** @see module:crypto/public_key/elliptic */
@ -18,7 +17,6 @@ import dsa from './dsa';
export default { export default {
rsa: rsa, rsa: rsa,
prime: prime,
elgamal: elgamal, elgamal: elgamal,
elliptic: elliptic, elliptic: elliptic,
dsa: dsa dsa: dsa

View File

@ -29,14 +29,12 @@
import BN from 'bn.js'; import BN from 'bn.js';
import { RSA_RAW } from 'asmcrypto.js/src/rsa/exports-raw';
import prime from './prime'; import prime from './prime';
import random from '../random'; import random from '../random';
import config from '../../config'; import config from '../../config';
import util from '../../util'; import util from '../../util';
const two = new BN(2); const two = new BN(2);
const zero = new BN(0);
// TODO use this is ../../encoding/base64.js and ./elliptic/{key,curve}.js // TODO use this is ../../encoding/base64.js and ./elliptic/{key,curve}.js
function b64toBN(base64url) { function b64toBN(base64url) {
@ -54,11 +52,11 @@ export default {
* @return BN * @return BN
*/ */
sign: function(m, n, e, d) { sign: function(m, n, e, d) {
m = m.toArrayLike(Uint8Array); if (n.cmp(m) <= 0) {
n = n.toArrayLike(Uint8Array); throw new Error('Data too large.');
e = e.toArrayLike(Uint8Array); }
d = d.toArrayLike(Uint8Array); const nred = new BN.red(n);
return RSA_RAW.sign(m, [n, e, d]); return m.toRed(nred).redPow(d).toArrayLike(Uint8Array, 'be', n.byteLength());
}, },
/** /**
@ -69,10 +67,11 @@ export default {
* @return BN * @return BN
*/ */
verify: function(s, n, e) { verify: function(s, n, e) {
s = s.toArrayLike(Uint8Array); if (n.cmp(s) <= 0) {
n = n.toArrayLike(Uint8Array); throw new Error('Data too large.');
e = e.toArrayLike(Uint8Array); }
return RSA_RAW.verify(s, [n, e]); const nred = new BN.red(n);
return s.toRed(nred).redPow(e).toArrayLike(Uint8Array, 'be', n.byteLength());
}, },
/** /**
@ -83,10 +82,11 @@ export default {
* @return BN * @return BN
*/ */
encrypt: function(m, n, e) { encrypt: function(m, n, e) {
m = m.toArrayLike(Uint8Array); if (n.cmp(m) <= 0) {
n = n.toArrayLike(Uint8Array); throw new Error('Data too large.');
e = e.toArrayLike(Uint8Array); }
return RSA_RAW.encrypt(m, [n, e]); const nred = new BN.red(n);
return m.toRed(nred).redPow(e).toArrayLike(Uint8Array, 'be', n.byteLength());
}, },
/** /**
@ -101,37 +101,35 @@ export default {
* @return {BN} The decrypted value of the message * @return {BN} The decrypted value of the message
*/ */
decrypt: function(m, n, e, d, p, q, u) { decrypt: function(m, n, e, d, p, q, u) {
let blinder = zero; if (n.cmp(m) <= 0) {
let unblinder = zero; throw new Error('Data too large.');
}
const dq = d.mod(q.subn(1)); // d mod (q-1)
const dp = d.mod(p.subn(1)); // d mod (p-1)
const pred = new BN.red(p);
const qred = new BN.red(q);
const nred = new BN.red(n); const nred = new BN.red(n);
config.rsa_blinding = false; // FIXME let blinder;
let unblinder;
if (config.rsa_blinding) { if (config.rsa_blinding) {
if (unblinder.bitLength() === n.bitLength()) { unblinder = random.getRandomBN(two, n).toRed(nred);
unblinder = unblinder.sqr().mod(n); blinder = unblinder.redInvm().redPow(e);
} else { m = m.toRed(nred).redMul(blinder).fromRed();
unblinder = random.getRandomBN(two, n);
}
blinder = unblinder.toRed(nred).redInvm().redPow(e).fromRed();
m = m.mul(blinder).mod(n);
} }
const dq = d.mod(q.subn(1)).toArrayLike(Uint8Array); // d mod (q-1) const mp = m.toRed(pred).redPow(dp);
const dp = d.mod(p.subn(1)).toArrayLike(Uint8Array); // d mod (p-1) const mq = m.toRed(qred).redPow(dq);
const nn = n.toArrayLike(Uint8Array); const t = mq.redSub(mp.fromRed().toRed(qred));
m = m.toArrayLike(Uint8Array); const h = u.toRed(qred).redMul(t).fromRed();
e = e.toArrayLike(Uint8Array);
d = d.toArrayLike(Uint8Array); let result = h.mul(p).add(mp).toRed(nred);
q = q.toArrayLike(Uint8Array);
p = p.toArrayLike(Uint8Array);
u = u.toArrayLike(Uint8Array);
let result = new BN(RSA_RAW.decrypt(m, [nn, e, d, q, p, dq, dp, u]).slice(1)); // FIXME remove slice
if (config.rsa_blinding) { if (config.rsa_blinding) {
result = result.mul(unblinder).mod(n); result = result.redMul(unblinder);
} }
return result; return result.toArrayLike(Uint8Array, 'be', n.byteLength());
}, },
/** /**