diff --git a/src/crypto/public_key/elliptic/curves.js b/src/crypto/public_key/elliptic/curves.js
index c87c5bec..002837e4 100644
--- a/src/crypto/public_key/elliptic/curves.js
+++ b/src/crypto/public_key/elliptic/curves.js
@@ -110,25 +110,39 @@ const curves = {
}
};
-function Curve(name, params) {
+export default function Curve(oid_or_name, params) {
+ if (OID.prototype.isPrototypeOf(oid_or_name) &&
+ enums.curve[oid_or_name.toHex()]) {
+ this.name = oid_or_name.toHex(); // by curve OID
+ } else if (enums.curve[oid_or_name]) {
+ this.name = oid_or_name; // by curve name
+ } else if (enums.curve[util.hexstrdump(oid_or_name)]) {
+ this.name = util.hexstrdump(oid_or_name); // by oid string
+ } else {
+ throw new Error('Not valid curve');
+ }
+ this.name = enums.write(enums.curve, this.name);
+ this.oid = new OID(curves[this.name].oid);
+
+ params = params || curves[this.name];
+
this.keyType = params.keyType;
switch (this.keyType) {
case enums.publicKey.eddsa:
- this.curve = new EdDSA(name);
+ this.curve = new EdDSA(this.name);
break;
case enums.publicKey.ecdsa:
- this.curve = new EC(name);
+ this.curve = new EC(this.name);
break;
default:
throw new Error('Unknown elliptic key type;');
}
- this.name = name;
- this.oid = new OID(curves[name].oid);
+
this.hash = params.hash;
this.cipher = params.cipher;
- this.node = params.node && curves[name].node;
- this.web = params.web && curves[name].web;
- this.payloadSize = curves[name].payloadSize;
+ this.node = params.node && curves[this.name].node;
+ this.web = params.web && curves[this.name].web;
+ this.payloadSize = curves[this.name].payloadSize;
}
Curve.prototype.keyFromPrivate = function (priv) { // Not for ed25519
@@ -149,48 +163,28 @@ Curve.prototype.genKeyPair = async function () {
// If browser doesn't support a curve, we'll catch it
try {
keyPair = await webGenKeyPair(this.name);
- return new KeyPair(this.curve, keyPair);
} catch (err) {
util.print_debug("Browser did not support signing: " + err.message);
}
} else if (nodeCrypto && this.node) {
keyPair = await nodeGenKeyPair(this.name);
- return new KeyPair(this.curve, keyPair);
}
- const options = {
- entropy: util.Uint8Array2str(random.getRandomBytes(32)), // 32 = (192 + 64) / 8
- entropyEnc: 'string'
- };
- // TODO provide randomness to elliptic here
- const r = await this.curve.genKeyPair(options);
- const compact = this.curve.curve.type === 'edwards' || this.curve.curve.type === 'mont';
- if (this.keyType === enums.publicKey.eddsa) {
- keyPair = { secret: r.getSecret() };
- } else {
- keyPair = { pub: r.getPublic('array', compact), priv: r.getPrivate().toArray() };
+ if (!keyPair || !keyPair.priv) {
+ // elliptic fallback
+ const r = await this.curve.genKeyPair({ entropy: util.Uint8Array2str(random.getRandomBytes(32)) });
+ const compact = this.curve.curve.type === 'edwards' || this.curve.curve.type === 'mont';
+ if (this.keyType === enums.publicKey.eddsa) {
+ keyPair = { secret: r.getSecret() };
+ } else {
+ keyPair = { pub: r.getPublic('array', compact), priv: r.getPrivate().toArray() };
+ }
}
return new KeyPair(this.curve, keyPair);
};
-function getCurve(oid_or_name) {
- let name;
- if (OID.prototype.isPrototypeOf(oid_or_name) &&
- enums.curve[oid_or_name.toHex()]) {
- name = enums.write(enums.curve, oid_or_name.toHex()); // by curve OID
- return new Curve(name, curves[name]);
- } else if (enums.curve[oid_or_name]) {
- name = enums.write(enums.curve, oid_or_name); // by curve name
- return new Curve(name, curves[name]);
- } else if (enums.curve[util.hexstrdump(oid_or_name)]) {
- name = enums.write(enums.curve, util.hexstrdump(oid_or_name)); // by oid string
- return new Curve(name, curves[name]);
- }
- throw new Error('Not valid curve');
-}
-
async function generate(curve) {
- curve = getCurve(curve);
+ curve = new Curve(curve);
const keyPair = await curve.genKeyPair();
return {
oid: curve.oid,
@@ -205,10 +199,8 @@ function getPreferredHashAlgo(oid) {
return curves[enums.write(enums.curve, oid.toHex())].hash;
}
-export default Curve;
-
export {
- curves, webCurves, nodeCurves, getCurve, generate, getPreferredHashAlgo
+ curves, webCurves, nodeCurves, generate, getPreferredHashAlgo
};
diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js
index 911a6a83..f1fcd886 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 { getCurve } from './curves';
+import Curve 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 = getCurve(oid);
+ const curve = new Curve(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 = getCurve(oid);
+ const curve = new Curve(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 aa8907ba..c9b1549d 100644
--- a/src/crypto/public_key/elliptic/ecdsa.js
+++ b/src/crypto/public_key/elliptic/ecdsa.js
@@ -18,15 +18,13 @@
// Implementation of ECDSA following RFC6637 for Openpgpjs
/**
- * @requires util
* @requires crypto/hash
* @requires crypto/public_key/elliptic/curves
* @module crypto/public_key/elliptic/ecdsa
*/
-import util from '../../../util';
import hash from '../../hash';
-import { getCurve } from './curves';
+import Curve from './curves';
/**
* Sign a message using the provided key
@@ -38,7 +36,7 @@ import { getCurve } from './curves';
s: Uint8Array}} Signature of the message
*/
async function sign(oid, hash_algo, m, d) {
- const curve = getCurve(oid);
+ const curve = new Curve(oid);
const key = curve.keyFromPrivate(d);
const signature = await key.sign(m, hash_algo);
return { r: signature.r.toArrayLike(Uint8Array),
@@ -56,7 +54,7 @@ async function sign(oid, hash_algo, m, d) {
* @return {Boolean}
*/
async function verify(oid, hash_algo, signature, m, Q) {
- const curve = getCurve(oid);
+ const curve = new Curve(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 8d908313..4db75099 100644
--- a/src/crypto/public_key/elliptic/eddsa.js
+++ b/src/crypto/public_key/elliptic/eddsa.js
@@ -26,7 +26,7 @@
import BN from 'bn.js';
import hash from '../../hash';
-import { getCurve } from './curves';
+import Curve from './curves';
/**
* Sign a message using the provided key
@@ -38,7 +38,7 @@ import { getCurve } from './curves';
S: Uint8Array}} Signature of the message
*/
async function sign(oid, hash_algo, m, d) {
- const curve = getCurve(oid);
+ const curve = new Curve(oid);
const key = curve.keyFromSecret(d);
const signature = await key.sign(m, hash_algo);
// EdDSA signature params are returned in little-endian format
@@ -57,7 +57,7 @@ async function sign(oid, hash_algo, m, d) {
* @return {Boolean}
*/
async function verify(oid, hash_algo, signature, m, Q) {
- const curve = getCurve(oid);
+ const curve = new Curve(oid);
const key = curve.keyFromPublic(Q);
return key.verify(m, signature, hash_algo);
}
diff --git a/src/crypto/public_key/elliptic/index.js b/src/crypto/public_key/elliptic/index.js
index 4c1acb3c..cffe5dc4 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 { getCurve, generate, getPreferredHashAlgo } from './curves';
+import Curve, { generate, getPreferredHashAlgo } from './curves';
import ecdsa from './ecdsa';
import eddsa from './eddsa';
import ecdh from './ecdh';
export default {
- ecdh, ecdsa, eddsa, getCurve, generate, getPreferredHashAlgo
+ Curve, ecdh, ecdsa, eddsa, generate, getPreferredHashAlgo
};
diff --git a/src/packet/public_key.js b/src/packet/public_key.js
index d7b8ad59..ba51f487 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.getCurve(this.params[0]).name;
+ result.curve = this.params[0].getName();
}
return result;
};
diff --git a/src/type/oid.js b/src/type/oid.js
index 23e80d40..a8394874 100644
--- a/src/type/oid.js
+++ b/src/type/oid.js
@@ -16,14 +16,16 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
- * Wrapper to an OID value
+ * Wrapper to an OID value
*
* An object identifier type from {@link https://tools.ietf.org/html/rfc6637#section-11|RFC6637, section 11}.
* @requires util
+ * @requires enums
* @module type/oid
*/
-import util from '../util.js';
+import util from '../util';
+import enums from '../enums';
/**
* @constructor
@@ -73,6 +75,19 @@ OID.prototype.toHex = function() {
return util.hexstrdump(this.oid);
};
+/**
+ * If a known curve object identifier, return the canonical name of the curve
+ * @return {string} String with the canonical name of the curve
+ */
+OID.prototype.getName = function() {
+ const hex = this.toHex();
+ if (enums.curve[hex]) {
+ return enums.write(enums.curve, hex);
+ } else {
+ throw new Error('Unknown curve object identifier.');
+ }
+};
+
OID.fromClone = function (clone) {
const oid = new OID(clone.oid);
return oid;
diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js
index 5af35682..5f8c4b35 100644
--- a/test/crypto/elliptic.js
+++ b/test/crypto/elliptic.js
@@ -137,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.getCurve(name)).to.exist;
+ expect(new elliptic_curves.Curve(name)).to.exist;
});
done();
});
it('Creating curve from oid', function (done) {
const oids = ['2A8648CE3D030107', '2B81040022', '2B81040023', '2B8104000A'];
oids.forEach(function (oid) {
- expect(elliptic_curves.getCurve(openpgp.util.hex2bin(oid))).to.exist;
+ expect(new elliptic_curves.Curve(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.getCurve(name);
+ const curve = new elliptic_curves.Curve(name);
return curve.genKeyPair().then(keyPair => {
expect(keyPair).to.exist;
});
@@ -160,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.getCurve(name);
+ const curve = new elliptic_curves.Curve(name);
expect(curve).to.exist;
const keyPair = curve.keyFromPrivate(pair.priv);
expect(keyPair).to.exist;
@@ -171,19 +171,19 @@ describe('Elliptic Curve Cryptography', function () {
done();
});
it('Signature verification', function (done) {
- const curve = elliptic_curves.getCurve('p256');
+ const curve = new elliptic_curves.Curve('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.getCurve('p256');
+ const curve = new elliptic_curves.Curve('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.getCurve('p256');
+ const curve = new elliptic_curves.Curve('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);
@@ -191,7 +191,7 @@ describe('Elliptic Curve Cryptography', function () {
});
});
it('Shared secret generation', function (done) {
- const curve = elliptic_curves.getCurve('p256');
+ const curve = new elliptic_curves.Curve('p256');
let key1 = curve.keyFromPrivate(key_data.p256.priv);
let key2 = curve.keyFromPublic(signature_data.pub);
const shared1 = openpgp.util.hexidump(key1.derive(key2));
@@ -289,7 +289,7 @@ describe('Elliptic Curve Cryptography', function () {
.to.eventually.be.true.notify(done);
});
it('Sign and verify message', function () {
- const curve = elliptic_curves.getCurve('p521');
+ const curve = new elliptic_curves.Curve('p521');
return curve.genKeyPair().then(keyPair => {
const keyPublic = new Uint8Array(keyPair.getPublic());
const keyPrivate = new Uint8Array(keyPair.getPrivate());
@@ -310,7 +310,7 @@ describe('Elliptic Curve Cryptography', function () {
data = new Uint8Array(data);
}
return Promise.resolve().then(() => {
- const curve = elliptic_curves.getCurve(oid);
+ const curve = new elliptic_curves.Curve(oid);
return elliptic_curves.ecdh.decrypt(
curve.oid,
cipher,
diff --git a/test/general/x25519.js b/test/general/x25519.js
index 2e04c1d8..1d841ee2 100644
--- a/test/general/x25519.js
+++ b/test/general/x25519.js
@@ -238,9 +238,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.getCurve('ed25519').oid.toHex());
+ expect(primaryKey.params[0].getName()).to.equal("ed25519");
expect(primaryKey.algorithm).to.equal('eddsa');
- expect(subKey.params[0].toHex()).to.equal(elliptic.getCurve('curve25519').oid.toHex());
+ expect(subKey.params[0].getName()).to.equal('curve25519');
expect(subKey.algorithm).to.equal('ecdh');
// Self Certificate is valid
@@ -258,9 +258,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.getCurve('ed25519').oid.toHex());
+ expect(bye.primaryKey.params[0].getName()).to.equal('ed25519');
expect(bye.primaryKey.algorithm).to.equal('eddsa');
- expect(bye.subKeys[0].subKey.params[0].toHex()).to.equal(elliptic.getCurve('curve25519').oid.toHex());
+ expect(bye.subKeys[0].subKey.params[0].getName()).to.equal('curve25519');
expect(bye.subKeys[0].subKey.algorithm).to.equal('ecdh');
// Self Certificate is valid
@@ -338,7 +338,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.getCurve('ed25519');
+ const curve = new elliptic.Curve('ed25519');
const util = openpgp.util;
function testVector(vector) {
const S = curve.keyFromSecret(vector.SECRET_KEY);