diff --git a/src/crypto/public_key/dsa.js b/src/crypto/public_key/dsa.js index 16a1fff0..b6455e45 100644 --- a/src/crypto/public_key/dsa.js +++ b/src/crypto/public_key/dsa.js @@ -85,7 +85,8 @@ export default { } break; } - return { r: r.fromRed(), s: s.fromRed() }; + return { r: r.toArrayLike(Uint8Array), + s: s.toArrayLike(Uint8Array) }; }, /* diff --git a/src/crypto/public_key/elliptic/curves.js b/src/crypto/public_key/elliptic/curves.js index ede97dfc..85f80439 100644 --- a/src/crypto/public_key/elliptic/curves.js +++ b/src/crypto/public_key/elliptic/curves.js @@ -167,7 +167,7 @@ Curve.prototype.genKeyPair = async function () { return new KeyPair(this.curve, keyPair); }; -function get(oid_or_name) { +function getCurve(oid_or_name) { let name; if (OID.prototype.isPrototypeOf(oid_or_name) && enums.curve[oid_or_name.toHex()]) { @@ -184,7 +184,7 @@ function get(oid_or_name) { } async function generate(curve) { - curve = get(curve); + curve = getCurve(curve); const keyPair = await curve.genKeyPair(); return { oid: curve.oid, @@ -202,7 +202,7 @@ function getPreferredHashAlgo(oid) { export default Curve; export { - curves, webCurves, nodeCurves, get, generate, getPreferredHashAlgo + curves, webCurves, nodeCurves, getCurve, generate, getPreferredHashAlgo }; diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index 14217b1a..911a6a83 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -30,7 +30,7 @@ */ import BN from 'bn.js'; -import { get as curvesGet } from './curves'; +import { getCurve } from './curves'; import aes_kw from '../../aes_kw'; import cipher from '../../cipher'; import hash from '../../hash'; @@ -74,7 +74,7 @@ function kdf(hash_algo, X, length, param) { */ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { fingerprint = util.hex2Uint8Array(fingerprint); - const curve = curvesGet(oid); + const curve = getCurve(oid); const param = buildEcdhParam(enums.publicKey.ecdh, oid, cipher_algo, hash_algo, fingerprint); cipher_algo = enums.read(enums.symmetric, cipher_algo); const v = await curve.genKeyPair(); @@ -102,7 +102,7 @@ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { */ async function decrypt(oid, cipher_algo, hash_algo, V, C, d, fingerprint) { fingerprint = util.hex2Uint8Array(fingerprint); - const curve = curvesGet(oid); + const curve = getCurve(oid); const param = buildEcdhParam(enums.publicKey.ecdh, oid, cipher_algo, hash_algo, fingerprint); cipher_algo = enums.read(enums.symmetric, cipher_algo); V = curve.keyFromPublic(V); diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js index 948ffe59..aa8907ba 100644 --- a/src/crypto/public_key/elliptic/ecdsa.js +++ b/src/crypto/public_key/elliptic/ecdsa.js @@ -26,7 +26,7 @@ import util from '../../../util'; import hash from '../../hash'; -import { get as curvesGet } from './curves'; +import { getCurve } from './curves'; /** * Sign a message using the provided key @@ -34,25 +34,29 @@ import { get as curvesGet } from './curves'; * @param {enums.hash} hash_algo Hash algorithm used to sign * @param {Uint8Array} m Message to sign * @param {Uint8Array} d Private key used to sign the message - * @return {{r: BN, s: BN}} Signature of the message + * @return {{r: Uint8Array, + s: Uint8Array}} Signature of the message */ async function sign(oid, hash_algo, m, d) { - const curve = curvesGet(oid); + const curve = getCurve(oid); const key = curve.keyFromPrivate(d); - return key.sign(m, hash_algo); + const signature = await key.sign(m, hash_algo); + return { r: signature.r.toArrayLike(Uint8Array), + s: signature.s.toArrayLike(Uint8Array) }; } /** * Verifies if a signature is valid for a message * @param {module:type/oid} oid Elliptic curve object identifier * @param {enums.hash} hash_algo Hash algorithm used in the signature - * @param {{r: BN, s: BN}} signature Signature to verify + * @param {{r: Uint8Array, + s: Uint8Array}} signature Signature to verify * @param {Uint8Array} m Message to verify * @param {Uint8Array} Q Public key used to verify the message * @return {Boolean} */ async function verify(oid, hash_algo, signature, m, Q) { - const curve = curvesGet(oid); + const curve = getCurve(oid); const key = curve.keyFromPublic(Q); return key.verify(m, signature, hash_algo); } diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js index a0fc467d..8d908313 100644 --- a/src/crypto/public_key/elliptic/eddsa.js +++ b/src/crypto/public_key/elliptic/eddsa.js @@ -26,41 +26,40 @@ import BN from 'bn.js'; import hash from '../../hash'; -import { get as curvesGet } from './curves'; +import { getCurve } from './curves'; /** * Sign a message using the provided key * @param {module:type/oid} oid Elliptic curve object identifier * @param {enums.hash} hash_algo Hash algorithm used to sign * @param {Uint8Array} m Message to sign - * @param {BN} d Private key used to sign - * @return {{R: Array, S: Array}} Signature of the message + * @param {Uint8Array} d Private key used to sign + * @return {{R: Uint8Array, + S: Uint8Array}} Signature of the message */ async function sign(oid, hash_algo, m, d) { - const curve = curvesGet(oid); - const key = curve.keyFromSecret(d.toArray('be', 32)); + const curve = getCurve(oid); + const key = curve.keyFromSecret(d); const signature = await key.sign(m, hash_algo); // EdDSA signature params are returned in little-endian format - return { R: signature.Rencoded(), S: signature.Sencoded() }; + return { R: new Uint8Array(signature.Rencoded()), + S: new Uint8Array(signature.Sencoded()) }; } /** * Verifies if a signature is valid for a message * @param {module:type/oid} oid Elliptic curve object identifier * @param {enums.hash} hash_algo Hash algorithm used in the signature - * @param {{R: BN, S: BN}} signature Signature to verify the message + * @param {{R: Uint8Array, + S: Uint8Array}} signature Signature to verify the message * @param {Uint8Array} m Message to verify - * @param {BN} Q Public key used to verify the message + * @param {Uint8Array} Q Public key used to verify the message * @return {Boolean} */ async function verify(oid, hash_algo, signature, m, Q) { - const curve = curvesGet(oid); - const key = curve.keyFromPublic(Q.toArray('be', 33)); - // EdDSA signature params are expected in little-endian format - return key.verify(m, { - R: signature.R.toArray('le', 32), - S: signature.S.toArray('le', 32) - }, hash_algo); + const curve = getCurve(oid); + const key = curve.keyFromPublic(Q); + return key.verify(m, signature, hash_algo); } export default { sign, verify }; diff --git a/src/crypto/public_key/elliptic/index.js b/src/crypto/public_key/elliptic/index.js index 9599fc97..4c1acb3c 100644 --- a/src/crypto/public_key/elliptic/index.js +++ b/src/crypto/public_key/elliptic/index.js @@ -25,11 +25,11 @@ * @module crypto/public_key/elliptic */ -import { get, generate, getPreferredHashAlgo } from './curves'; +import { getCurve, generate, getPreferredHashAlgo } from './curves'; import ecdsa from './ecdsa'; import eddsa from './eddsa'; import ecdh from './ecdh'; export default { - ecdh, ecdsa, eddsa, get, generate, getPreferredHashAlgo + ecdh, ecdsa, eddsa, getCurve, generate, getPreferredHashAlgo }; diff --git a/src/crypto/signature.js b/src/crypto/signature.js index 32319a9b..aa33e984 100644 --- a/src/crypto/signature.js +++ b/src/crypto/signature.js @@ -55,8 +55,11 @@ export default { } case enums.publicKey.eddsa: { const oid = pub_MPIs[0]; - const signature = { R: msg_MPIs[0].toBN(), S: msg_MPIs[1].toBN() }; - const Q = pub_MPIs[1].toBN(); + // TODO refactor elliptic to accept Uint8Array + // EdDSA signature params are expected in little-endian format + const signature = { R: Array.from(msg_MPIs[0].toUint8Array('le', 32)), + S: Array.from(msg_MPIs[1].toUint8Array('le', 32)) }; + const Q = Array.from(pub_MPIs[1].toUint8Array('be', 33)); return publicKey.elliptic.eddsa.verify(oid, hash_algo, signature, data, Q); } default: @@ -95,8 +98,8 @@ export default { const x = key_params[4].toBN(); const signature = publicKey.dsa.sign(hash_algo, data, g, p, q, x); return util.concatUint8Array([ - util.Uint8Array2MPI(signature.r.toArrayLike(Uint8Array)), - util.Uint8Array2MPI(signature.s.toArrayLike(Uint8Array)) + util.Uint8Array2MPI(signature.r), + util.Uint8Array2MPI(signature.s) ]); } case enums.publicKey.elgamal: { @@ -107,17 +110,17 @@ export default { const d = key_params[2].toUint8Array(); const signature = await publicKey.elliptic.ecdsa.sign(oid, hash_algo, data, d); return util.concatUint8Array([ - util.Uint8Array2MPI(signature.r.toArrayLike(Uint8Array)), - util.Uint8Array2MPI(signature.s.toArrayLike(Uint8Array)) + util.Uint8Array2MPI(signature.r), + util.Uint8Array2MPI(signature.s) ]); } case enums.publicKey.eddsa: { const oid = key_params[0]; - const d = key_params[2].toBN(); + const d = Array.from(key_params[2].toUint8Array('be', 32)); const signature = await publicKey.elliptic.eddsa.sign(oid, hash_algo, data, d); return util.concatUint8Array([ - util.Uint8Array2MPI(Uint8Array.from(signature.R)), - util.Uint8Array2MPI(Uint8Array.from(signature.S)) + util.Uint8Array2MPI(signature.R), + util.Uint8Array2MPI(signature.S) ]); } default: diff --git a/src/packet/public_key.js b/src/packet/public_key.js index a8dbf8a2..d7b8ad59 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -201,7 +201,7 @@ PublicKey.prototype.getAlgorithmInfo = function () { if (this.params[0] instanceof type_mpi) { result.bits = this.params[0].byteLength() * 8; } else { - result.curve = crypto.publicKey.elliptic.get(this.params[0]).name; + result.curve = crypto.publicKey.elliptic.getCurve(this.params[0]).name; } return result; }; diff --git a/src/type/mpi.js b/src/type/mpi.js index 811b9873..f5797200 100644 --- a/src/type/mpi.js +++ b/src/type/mpi.js @@ -93,8 +93,8 @@ MPI.prototype.byteLength = function () { return this.write().length - 2; }; -MPI.prototype.toUint8Array = function () { - return this.write().slice(2); +MPI.prototype.toUint8Array = function (endian, length) { + return this.write(endian, length).slice(2); }; MPI.prototype.fromUint8Array = function (bytes) { diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js index b5bf328d..5af35682 100644 --- a/test/crypto/elliptic.js +++ b/test/crypto/elliptic.js @@ -1,5 +1,6 @@ const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp'); +const BN = require('bn.js'); const chai = require('chai'); chai.use(require('chai-as-promised')); @@ -136,21 +137,21 @@ describe('Elliptic Curve Cryptography', function () { it('Creating curve with name', function (done) { const names = ['p256', 'p384', 'p521', 'secp256k1', 'curve25519']; names.forEach(function (name) { - expect(elliptic_curves.get(name)).to.exist; + expect(elliptic_curves.getCurve(name)).to.exist; }); done(); }); it('Creating curve from oid', function (done) { const oids = ['2A8648CE3D030107', '2B81040022', '2B81040023', '2B8104000A']; oids.forEach(function (oid) { - expect(elliptic_curves.get(openpgp.util.hex2bin(oid))).to.exist; + expect(elliptic_curves.getCurve(openpgp.util.hex2bin(oid))).to.exist; }); done(); }); it('Creating KeyPair', function () { const names = ['p256', 'p384', 'p521', 'secp256k1', 'curve25519']; return Promise.all(names.map(function (name) { - const curve = elliptic_curves.get(name); + const curve = elliptic_curves.getCurve(name); return curve.genKeyPair().then(keyPair => { expect(keyPair).to.exist; }); @@ -159,7 +160,7 @@ describe('Elliptic Curve Cryptography', function () { it('Creating KeyPair from data', function (done) { for (const name in key_data) { const pair = key_data[name]; - const curve = elliptic_curves.get(name); + const curve = elliptic_curves.getCurve(name); expect(curve).to.exist; const keyPair = curve.keyFromPrivate(pair.priv); expect(keyPair).to.exist; @@ -170,19 +171,19 @@ describe('Elliptic Curve Cryptography', function () { done(); }); it('Signature verification', function (done) { - const curve = elliptic_curves.get('p256'); + const curve = elliptic_curves.getCurve('p256'); const key = curve.keyFromPublic(signature_data.pub); expect(key.verify(signature_data.message, signature_data.signature, 8)).to.eventually.be.true; done(); }); it('Invalid signature', function (done) { - const curve = elliptic_curves.get('p256'); + const curve = elliptic_curves.getCurve('p256'); const key = curve.keyFromPublic(key_data.p256.pub); expect(key.verify(signature_data.message, signature_data.signature, 8)).to.eventually.be.false; done(); }); it('Signature generation', function () { - const curve = elliptic_curves.get('p256'); + const curve = elliptic_curves.getCurve('p256'); let key = curve.keyFromPrivate(key_data.p256.priv); return key.sign(signature_data.message, 8).then(signature => { key = curve.keyFromPublic(key_data.p256.pub); @@ -190,7 +191,7 @@ describe('Elliptic Curve Cryptography', function () { }); }); it('Shared secret generation', function (done) { - const curve = elliptic_curves.get('p256'); + const curve = elliptic_curves.getCurve('p256'); let key1 = curve.keyFromPrivate(key_data.p256.priv); let key2 = curve.keyFromPublic(signature_data.pub); const shared1 = openpgp.util.hexidump(key1.derive(key2)); @@ -212,7 +213,7 @@ describe('Elliptic Curve Cryptography', function () { return ecdsa.verify( oid, hash, - {r: new Uint8Array(r), s: new Uint8Array(s)}, + {r: new BN(r), s: new BN(s)}, message, new Uint8Array(pub) ); @@ -288,7 +289,7 @@ describe('Elliptic Curve Cryptography', function () { .to.eventually.be.true.notify(done); }); it('Sign and verify message', function () { - const curve = elliptic_curves.get('p521'); + const curve = elliptic_curves.getCurve('p521'); return curve.genKeyPair().then(keyPair => { const keyPublic = new Uint8Array(keyPair.getPublic()); const keyPrivate = new Uint8Array(keyPair.getPrivate()); @@ -309,7 +310,7 @@ describe('Elliptic Curve Cryptography', function () { data = new Uint8Array(data); } return Promise.resolve().then(() => { - const curve = elliptic_curves.get(oid); + const curve = elliptic_curves.getCurve(oid); return elliptic_curves.ecdh.decrypt( curve.oid, cipher, diff --git a/test/general/x25519.js b/test/general/x25519.js index 0e6534c2..ac859525 100644 --- a/test/general/x25519.js +++ b/test/general/x25519.js @@ -235,9 +235,9 @@ describe('X25519 Cryptography', function () { const hi = firstKey.key; const primaryKey = hi.primaryKey; const subKey = hi.subKeys[0].subKey; - expect(primaryKey.params[0].toHex()).to.equal(elliptic.get('ed25519').oid.toHex()); + expect(primaryKey.params[0].toHex()).to.equal(elliptic.getCurve('ed25519').oid.toHex()); expect(primaryKey.algorithm).to.equal('eddsa'); - expect(subKey.params[0].toHex()).to.equal(elliptic.get('curve25519').oid.toHex()); + expect(subKey.params[0].toHex()).to.equal(elliptic.getCurve('curve25519').oid.toHex()); expect(subKey.algorithm).to.equal('ecdh'); // Self Certificate is valid @@ -255,9 +255,9 @@ describe('X25519 Cryptography', function () { }; return openpgp.generateKey(options).then(function (secondKey) { const bye = secondKey.key; - expect(bye.primaryKey.params[0].toHex()).to.equal(elliptic.get('ed25519').oid.toHex()); + expect(bye.primaryKey.params[0].toHex()).to.equal(elliptic.getCurve('ed25519').oid.toHex()); expect(bye.primaryKey.algorithm).to.equal('eddsa'); - expect(bye.subKeys[0].subKey.params[0].toHex()).to.equal(elliptic.get('curve25519').oid.toHex()); + expect(bye.subKeys[0].subKey.params[0].toHex()).to.equal(elliptic.getCurve('curve25519').oid.toHex()); expect(bye.subKeys[0].subKey.algorithm).to.equal('ecdh'); // Self Certificate is valid @@ -319,7 +319,7 @@ describe('X25519 Cryptography', function () { describe('Ed25519 Test Vectors from RFC8032', function () { // https://tools.ietf.org/html/rfc8032#section-7.1 const signature = openpgp.crypto.signature; - const curve = elliptic.get('ed25519'); + const curve = elliptic.getCurve('ed25519'); const util = openpgp.util; function testVector(vector) { const S = curve.keyFromSecret(vector.SECRET_KEY);