Addresses various review comments by @sanjanarajan

* Various FIXME tags are removed
 * In curve.js:
  - webCrypto/nodeCrypto fallback bug is fixed
  - Curve25519 has keyType ecdsa (won't be used for signing, but technically can be)
  - webGenKeyPair is simplifed
 * In base64.js:
  - documentation added and arguments simplified
 * In ecdsa.js and eddsa.js:
  - hash_algo is now at least as strong as the default curve hash
  - simplified the code by moving webSign/nodeSign and webVerify/nodeVerify to live in key.js (ht @ismaelbej)
 * In message.js:
  - in decryptSessionKey, loops break once a key packet is decrypted
 * In key.js:
  - getPreferredHashAlgorithm returns the best hash algorithm
  - enums are used for curve selection
This commit is contained in:
Mahrud Sayrafi 2018-01-18 00:34:03 -08:00 committed by Sanjana Rajan
parent 3129e7c4e3
commit 5cb89f4f25
11 changed files with 278 additions and 259 deletions

View File

@ -34,19 +34,19 @@ import random from '../../random';
import config from '../../../config';
import enums from '../../../enums';
import util from '../../../util';
import OID from '../../../type/oid';
import base64 from '../../../encoding/base64';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
var webCurves = {}, nodeCurves = {};
if (webCrypto && config.use_native) {
webCurves = {
'p256': 'P-256',
'p384': 'P-384',
'p521': 'P-521'
};
} else if (nodeCrypto && config.use_native) {
webCurves = {
'p256': 'P-256',
'p384': 'P-384',
'p521': 'P-521'
};
if (nodeCrypto && config.use_native) {
var knownCurves = nodeCrypto.getCurves();
nodeCurves = {
'secp256k1': knownCurves.includes('secp256k1') ? 'secp256k1' : undefined,
@ -63,8 +63,8 @@ const curves = {
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha256,
cipher: enums.symmetric.aes128,
node: nodeCurves.secp256r1,
web: webCurves.secp256r1,
node: nodeCurves.p256,
web: webCurves.p256,
payloadSize: 32
},
p384: {
@ -72,8 +72,8 @@ const curves = {
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha384,
cipher: enums.symmetric.aes192,
node: nodeCurves.secp384r1,
web: webCurves.secp384r1,
node: nodeCurves.p384,
web: webCurves.p384,
payloadSize: 48
},
p521: {
@ -81,8 +81,8 @@ const curves = {
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha512,
cipher: enums.symmetric.aes256,
node: nodeCurves.secp521r1,
web: webCurves.secp521r1,
node: nodeCurves.p521,
web: webCurves.p521,
payloadSize: 66
},
secp256k1: {
@ -99,13 +99,16 @@ const curves = {
},
curve25519: {
oid: util.bin2str([0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01]),
keyType: enums.publicKey.ecdh,
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha256,
cipher: enums.symmetric.aes128
},
brainpoolP256r1: { // TODO 1.3.36.3.3.2.8.1.1.7
oid: util.bin2str([0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07])
},
brainpoolP384r1: { // TODO 1.3.36.3.3.2.8.1.1.11
oid: util.bin2str([0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B])
},
brainpoolP512r1: { // TODO 1.3.36.3.3.2.8.1.1.13
oid: util.bin2str([0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D])
}
@ -118,12 +121,12 @@ function Curve(name, params) {
this.curve = new EdDSA(name);
break;
case enums.publicKey.ecdsa:
case enums.publicKey.ecdh:
this.curve = new EC(name);
break;
default:
throw new Error('Unknown elliptic key type;');
}
this.name = name;
this.oid = curves[name].oid;
this.hash = params.hash;
this.cipher = params.cipher;
@ -145,14 +148,14 @@ Curve.prototype.keyFromPublic = function (pub) {
};
Curve.prototype.genKeyPair = async function () {
var r, keyPair;
var keyPair;
if (webCrypto && config.use_native && this.web) {
keyPair = await webGenKeyPair(this.name, "ECDSA"); // FIXME is ECDH different?
keyPair = await webGenKeyPair(this.name);
} else if (nodeCrypto && config.use_native && this.node) {
keyPair = await nodeGenKeyPair(this.name);
} else {
var compact = this.curve.curve.type === 'edwards' || this.curve.curve.type === 'mont';
r = await this.curve.genKeyPair();
var r = await this.curve.genKeyPair();
if (this.keyType === enums.publicKey.eddsa) {
keyPair = { secret: r.getSecret() };
} else {
@ -162,17 +165,18 @@ Curve.prototype.genKeyPair = async function () {
return new KeyPair(this.curve, keyPair);
};
function get(oid_or_name) {
var name;
if (enums.curve[oid_or_name]) {
name = enums.write(enums.curve, oid_or_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]);
}
for (name in curves) {
if (curves[name].oid === oid_or_name) {
return new Curve(name, curves[name]);
}
}
throw new Error('Not valid curve');
}
@ -189,8 +193,16 @@ async function generate(curve) {
};
}
function getPreferredHashAlgorithm(oid) {
return curves[enums.write(enums.curve, oid.toHex())].hash;
}
module.exports = {
Curve: Curve,
curves: curves,
webCurves: webCurves,
nodeCurves: nodeCurves,
getPreferredHashAlgorithm: getPreferredHashAlgorithm,
generate: generate,
get: get
};
@ -203,14 +215,10 @@ module.exports = {
//////////////////////////
async function webGenKeyPair(name, algorithm) {
async function webGenKeyPair(name) {
// Note: keys generated with ECDSA and ECDH are structurally equivalent
var webCryptoKey = await webCrypto.generateKey(
{
name: algorithm === "ECDH" ? "ECDH" : "ECDSA",
namedCurve: webCurves[name]
},
true,
algorithm === "ECDH" ? ["deriveKey", "deriveBits"] : ["sign", "verify"]
{ name: "ECDSA", namedCurve: webCurves[name] }, true, ["sign", "verify"]
);
var privateKey = await webCrypto.exportKey("jwk", webCryptoKey.privateKey);
@ -218,15 +226,15 @@ async function webGenKeyPair(name, algorithm) {
return {
pub: {
x: base64.decode(publicKey.x, 'base64url'),
y: base64.decode(publicKey.y, 'base64url')
x: base64.decode(publicKey.x, true),
y: base64.decode(publicKey.y, true)
},
priv: base64.decode(privateKey.d, 'base64url')
priv: base64.decode(privateKey.d, true)
};
}
async function nodeGenKeyPair(name) {
var ecdh = nodeCrypto.createECDH(name === "secp256r1" ? "prime256v1" : name);
var ecdh = nodeCrypto.createECDH(nodeCurves[name]);
await ecdh.generateKeys();
return {

View File

@ -25,28 +25,9 @@
'use strict';
import BN from 'bn.js';
import ASN1 from 'asn1.js';
import jwkToPem from 'jwk-to-pem';
import hash from '../../hash';
import curves from './curves.js';
import BigInteger from '../jsbn.js';
import config from '../../../config';
import enums from '../../../enums.js';
import util from '../../../util.js';
import base64 from '../../../encoding/base64.js';
const webCrypto = util.getWebCrypto();
const webCurves = curves.webCurves;
const nodeCrypto = util.getNodeCrypto();
const nodeCurves = curves.nodeCurves;
var ECDSASignature = ASN1.define('ECDSASignature', function() {
this.seq().obj(
this.key('r').int(), // FIXME int or BN?
this.key('s').int() // FIXME int or BN?
);
});
/**
* Sign a message using the provided key
@ -57,17 +38,9 @@ var ECDSASignature = ASN1.define('ECDSASignature', function() {
* @return {{r: BigInteger, s: BigInteger}} Signature of the message
*/
async function sign(oid, hash_algo, m, d) {
var signature;
const curve = curves.get(oid);
hash_algo = hash_algo ? hash_algo : curve.hash;
const key = curve.keyFromPrivate(d.toByteArray());
if (webCrypto && config.use_native && curve.web) {
signature = await webSign(curve, hash_algo, m, key.keyPair);
} else if (nodeCrypto && config.use_native && curve.node) {
signature = await nodeSign(curve, hash_algo, m, key.keyPair);
} else {
signature = await key.sign(m, hash_algo);
}
const signature = await key.sign(m, hash_algo);
return {
r: new BigInteger(signature.r.toArray()),
s: new BigInteger(signature.s.toArray())
@ -84,168 +57,14 @@ async function sign(oid, hash_algo, m, d) {
* @return {Boolean}
*/
async function verify(oid, hash_algo, signature, m, Q) {
var result;
const curve = curves.get(oid);
hash_algo = hash_algo ? hash_algo : curve.hash; // FIXME is this according to the RFC?
const key = curve.keyFromPublic(Q.toByteArray());
if (webCrypto && config.use_native && curve.web) {
result = await webVerify(curve, hash_algo, signature, m, key.keyPair.getPublic());
} else if (nodeCrypto && config.use_native && curve.node) {
result = await nodeVerify(curve, hash_algo, signature, m, key.keyPair.getPublic());
} else {
result = await key.verify(
m, {r: signature.r.toByteArray(), s: signature.s.toByteArray()}, hash_algo
);
}
return result;
return key.verify(
m, { r: signature.r.toByteArray(), s: signature.s.toByteArray() }, hash_algo
);
}
module.exports = {
sign: sign,
verify: verify
};
//////////////////////////
// //
// Helper functions //
// //
//////////////////////////
async function webSign(curve, hash_algo, message, keyPair) {
var l = curve.payloadSize;
if (typeof message === 'string') {
message = util.str2Uint8Array(message);
}
const key = await webCrypto.importKey(
"jwk",
{
"kty": "EC",
"crv": webCurves[curve.name],
"x": base64.encode(new Uint8Array(keyPair.getPublic().getX().toArray('be', l)), null, 'base64url'),
"y": base64.encode(new Uint8Array(keyPair.getPublic().getY().toArray('be', l)), null, 'base64url'),
"d": base64.encode(new Uint8Array(keyPair.getPrivate().toArray('be', l)), null, 'base64url'),
"use": "sig",
"kid": "ECDSA Private Key"
},
{
"name": "ECDSA",
"namedCurve": webCurves[curve.name],
"hash": { name: enums.read(enums.webHash, curve.hash) }
},
false,
["sign"]
);
const signature = new Uint8Array(await webCrypto.sign(
{
"name": 'ECDSA',
"namedCurve": webCurves[curve.name],
"hash": { name: enums.read(enums.webHash, hash_algo) }
},
key,
message
));
return {
r: signature.slice(0, l),
s: signature.slice(l, 2 * l)
};
}
async function webVerify(curve, hash_algo, signature, message, publicKey) {
var r = signature.r.toByteArray(), s = signature.s.toByteArray(), l = curve.payloadSize;
r = (r.length === l) ? r : [0].concat(r);
s = (s.length === l) ? s : [0].concat(s);
signature = new Uint8Array(r.concat(s)).buffer;
if (typeof message === 'string') {
message = util.str2Uint8Array(message);
}
const key = await webCrypto.importKey(
"jwk",
{
"kty": "EC",
"crv": webCurves[curve.name],
"x": base64.encode(new Uint8Array(publicKey.getX().toArray('be', l)), null, 'base64url'),
"y": base64.encode(new Uint8Array(publicKey.getY().toArray('be', l)), null, 'base64url'),
"use": "sig",
"kid": "ECDSA Public Key"
},
{
"name": "ECDSA",
"namedCurve": webCurves[curve.name],
"hash": { name: enums.read(enums.webHash, curve.hash) }
},
false,
["verify"]
);
return webCrypto.verify(
{
"name": 'ECDSA',
"namedCurve": webCurves[curve.name],
"hash": { name: enums.read(enums.webHash, hash_algo) }
},
key,
signature,
message
);
}
async function nodeSign(curve, hash_algo, message, keyPair) {
if (typeof message === 'string') {
message = util.str2Uint8Array(message);
}
const key = jwkToPem(
{
"kty": "EC",
"crv": nodeCurves[curve.name],
"x": base64.encode(new Uint8Array(keyPair.getPublic().getX().toArray())),
"y": base64.encode(new Uint8Array(keyPair.getPublic().getY().toArray())),
"d": base64.encode(new Uint8Array(keyPair.getPrivate().toArray())),
"use": "sig",
"kid": "ECDSA Private Key"
},
{ private: true }
);
const sign = nodeCrypto.createSign(enums.read(enums.hash, hash_algo));
sign.write(message);
sign.end();
const signature = await ECDSASignature.decode(sign.sign(key), 'der');
return {
r: signature.r.toArray(),
s: signature.s.toArray()
};
}
async function nodeVerify(curve, hash_algo, signature, message, publicKey) {
signature = ECDSASignature.encode(
{
r: new BN(signature.r.toByteArray()),
s: new BN(signature.s.toByteArray())
},
'der');
if (typeof message === 'string') {
message = util.str2Uint8Array(message);
}
const key = jwkToPem(
{
"kty": "EC",
"crv": nodeCurves[curve.name],
"x": base64.encode(new Uint8Array(publicKey.getX().toArray())),
"y": base64.encode(new Uint8Array(publicKey.getY().toArray())),
"use": "sig",
"kid": "ECDSA Public Key"
},
{ private: false }
);
// FIXME what happens when hash_algo = undefined?
const verify = nodeCrypto.createVerify(enums.read(enums.hash, hash_algo));
verify.write(message);
verify.end();
const result = await verify.verify(key, signature);
return result;
}

View File

@ -2,6 +2,7 @@
'use strict';
import hash from '../../hash';
import curves from './curves.js';
import BigInteger from '../jsbn.js';
@ -14,11 +15,9 @@ import BigInteger from '../jsbn.js';
* @return {{r: BigInteger, s: BigInteger}} Signature of the message
*/
async function sign(oid, hash_algo, m, d) {
var signature;
const curve = curves.get(oid);
hash_algo = hash_algo ? hash_algo : curve.hash;
const key = curve.keyFromSecret(d.toByteArray());
signature = await key.sign(m, hash_algo);
const signature = await key.sign(m, hash_algo);
return {
r: new BigInteger(signature.Rencoded()),
s: new BigInteger(signature.Sencoded())
@ -35,12 +34,10 @@ async function sign(oid, hash_algo, m, d) {
* @return {Boolean}
*/
async function verify(oid, hash_algo, signature, m, Q) {
var result;
const curve = curves.get(oid);
hash_algo = hash_algo ? hash_algo : curve.hash; // FIXME is this according to the RFC?
const key = curve.keyFromPublic(Q.toByteArray());
return key.verify(
m, {R: signature.r.toByteArray(), S: signature.s.toByteArray()}, hash_algo
m, { R: signature.r.toByteArray(), S: signature.s.toByteArray() }, hash_algo
);
}

View File

@ -27,7 +27,7 @@
'use strict';
import {get, generate} from './curves';
import {get, generate, getPreferredHashAlgorithm} from './curves';
import ecdsa from './ecdsa';
import eddsa from './eddsa';
import ecdh from './ecdh';
@ -37,5 +37,6 @@ module.exports = {
eddsa: eddsa,
ecdh: ecdh,
get: get,
generate: generate
generate: generate,
getPreferredHashAlgorithm: getPreferredHashAlgorithm
};

View File

@ -25,9 +25,28 @@
'use strict';
import BN from 'bn.js';
import ASN1 from 'asn1.js';
import jwkToPem from 'jwk-to-pem';
import curves from './curves';
import hash from '../../hash';
import util from '../../../util';
import enums from '../../../enums';
import config from '../../../config';
import base64 from '../../../encoding/base64';
const webCrypto = util.getWebCrypto();
const webCurves = curves.webCurves;
const nodeCrypto = util.getNodeCrypto();
const nodeCurves = curves.nodeCurves;
var ECDSASignature = ASN1.define('ECDSASignature', function() {
this.seq().obj(
this.key('r').int(),
this.key('s').int()
);
});
function KeyPair(curve, options) {
this.curve = curve;
@ -35,20 +54,32 @@ function KeyPair(curve, options) {
this.keyPair = this.curve.keyPair(options);
}
KeyPair.prototype.sign = function (message, hash_algo) {
KeyPair.prototype.sign = async function (message, hash_algo) {
if (typeof message === 'string') {
message = util.str2Uint8Array(message);
}
const digest = (typeof hash_algo === 'undefined') ? message : hash.digest(hash_algo, message);
return this.keyPair.sign(digest);
if (webCrypto && config.use_native && this.curve.web) {
return webSign(this.curve, hash_algo, message, this.keyPair);
} else if (nodeCrypto && config.use_native && this.curve.node) {
return nodeSign(this.curve, hash_algo, message, this.keyPair);
} else {
const digest = (typeof hash_algo === 'undefined') ? message : hash.digest(hash_algo, message);
return this.keyPair.sign(digest);
}
};
KeyPair.prototype.verify = function (message, signature, hash_algo) {
KeyPair.prototype.verify = async function (message, signature, hash_algo) {
if (typeof message === 'string') {
message = util.str2Uint8Array(message);
}
const digest = (typeof hash_algo === 'undefined') ? message : hash.digest(hash_algo, message);
return this.keyPair.verify(digest, signature);
if (webCrypto && config.use_native && this.curve.web) {
return webVerify(this.curve, hash_algo, signature, message, this.keyPair.getPublic());
} else if (nodeCrypto && config.use_native && this.curve.node) {
return nodeVerify(this.curve, hash_algo, signature, message, this.keyPair.getPublic());
} else {
const digest = (typeof hash_algo === 'undefined') ? message : hash.digest(hash_algo, message);
return this.keyPair.verify(digest, signature);
}
};
KeyPair.prototype.derive = function (pub) {
@ -81,3 +112,131 @@ KeyPair.prototype.isValid = function () {
module.exports = {
KeyPair: KeyPair
};
//////////////////////////
// //
// Helper functions //
// //
//////////////////////////
async function webSign(curve, hash_algo, message, keyPair) {
var l = curve.payloadSize;
const key = await webCrypto.importKey(
"jwk",
{
"kty": "EC",
"crv": webCurves[curve.name],
"x": base64.encode(new Uint8Array(keyPair.getPublic().getX().toArray('be', l)), true),
"y": base64.encode(new Uint8Array(keyPair.getPublic().getY().toArray('be', l)), true),
"d": base64.encode(new Uint8Array(keyPair.getPrivate().toArray('be', l)), true),
"use": "sig",
"kid": "ECDSA Private Key"
},
{
"name": "ECDSA",
"namedCurve": webCurves[curve.name],
"hash": { name: enums.read(enums.webHash, curve.hash) }
},
false,
["sign"]
);
const signature = new Uint8Array(await webCrypto.sign(
{
"name": 'ECDSA',
"namedCurve": webCurves[curve.name],
"hash": { name: enums.read(enums.webHash, hash_algo) }
},
key,
message
));
return {
r: signature.slice(0, l),
s: signature.slice(l, 2 * l)
};
}
async function webVerify(curve, hash_algo, {r, s}, message, publicKey) {
var l = curve.payloadSize;
r = (r.length === l) ? r : [0].concat(r);
s = (s.length === l) ? s : [0].concat(s);
var signature = new Uint8Array(r.concat(s)).buffer;
const key = await webCrypto.importKey(
"jwk",
{
"kty": "EC",
"crv": webCurves[curve.name],
"x": base64.encode(new Uint8Array(publicKey.getX().toArray('be', l)), true),
"y": base64.encode(new Uint8Array(publicKey.getY().toArray('be', l)), true),
"use": "sig",
"kid": "ECDSA Public Key"
},
{
"name": "ECDSA",
"namedCurve": webCurves[curve.name],
"hash": { name: enums.read(enums.webHash, curve.hash) }
},
false,
["verify"]
);
return webCrypto.verify(
{
"name": 'ECDSA',
"namedCurve": webCurves[curve.name],
"hash": { name: enums.read(enums.webHash, hash_algo) }
},
key,
signature,
message
);
}
async function nodeSign(curve, hash_algo, message, keyPair) {
const key = jwkToPem(
{
"kty": "EC",
"crv": webCurves[curve.name],
"x": base64.encode(new Uint8Array(keyPair.getPublic().getX().toArray())),
"y": base64.encode(new Uint8Array(keyPair.getPublic().getY().toArray())),
"d": base64.encode(new Uint8Array(keyPair.getPrivate().toArray())),
"use": "sig",
"kid": "ECDSA Private Key"
},
{ private: true }
);
const sign = nodeCrypto.createSign(enums.read(enums.hash, hash_algo));
sign.write(message);
sign.end();
const signature = await ECDSASignature.decode(sign.sign(key), 'der');
return {
r: signature.r.toArray(),
s: signature.s.toArray()
};
}
async function nodeVerify(curve, hash_algo, {r, s}, message, publicKey) {
var signature = ECDSASignature.encode({ r: new BN(r), s: new BN(s) }, 'der');
const key = jwkToPem(
{
"kty": "EC",
"crv": webCurves[curve.name],
"x": base64.encode(new Uint8Array(publicKey.getX().toArray())),
"y": base64.encode(new Uint8Array(publicKey.getY().toArray())),
"use": "sig",
"kid": "ECDSA Public Key"
},
{ private: false }
);
// FIXME what happens when hash_algo = undefined?
const verify = nodeCrypto.createVerify(enums.read(enums.hash, hash_algo));
verify.write(message);
verify.end();
const result = await verify.verify(key, signature);
return result;
}

View File

@ -17,20 +17,21 @@
'use strict';
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var b64u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; // Standard radix-64
var b64u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; // URL-safe radix-64
/**
* Convert binary array to radix-64
* @param {Uint8Array} t Uint8Array to convert
* @param {bool} u if true, output is URL-safe
* @returns {string} radix-64 version of input string
* @static
*/
function s2r(t, o, u) {
function s2r(t, u = false) {
// TODO check btoa alternative
var b64 = (u === "base64url") ? b64u : b64s;
var b64 = u ? b64u : b64s;
var a, c, n;
var r = o ? o : [],
var r = [],
l = 0,
s = 0;
var tl = t.length;
@ -67,33 +68,30 @@ function s2r(t, o, u) {
if ((l % 60) === 0 && !u) {
r.push("\n");
}
if (u !== 'base64url') {
if (!u) {
r.push('=');
l += 1;
}
}
if (s === 1 && u !== 'base64url') {
if (s === 1 && !u) {
if ((l % 60) === 0 && !u) {
r.push("\n");
}
r.push('=');
}
if (o)
{
return;
}
return r.join('');
}
/**
* Convert radix-64 to binary array
* @param {String} t radix-64 string to convert
* @param {bool} u if true, input is interpreted as URL-safe
* @returns {Uint8Array} binary array version of input string
* @static
*/
function r2s(t, u) {
// TODO check atob alternative
var b64 = (u === "base64url") ? b64u : b64s;
var b64 = u ? b64u : b64s;
var c, n;
var r = [],
s = 0,

View File

@ -16,25 +16,40 @@ export default {
"secp256r1": "p256",
"prime256v1": "p256",
"1.2.840.10045.3.1.7": "p256",
"2a8648ce3d030107": "p256",
"2A8648CE3D030107": "p256",
"p384": "p384",
"P-384": "p384",
"secp384r1": "p384",
"1.3.132.0.34": "p384",
"2b81040022": "p384",
"2B81040022": "p384",
"p521": "p521",
"P-521": "p521",
"secp521r1": "p521",
"1.3.132.0.35": "p521",
"2b81040023": "p521",
"2B81040023": "p521",
"secp256k1": "secp256k1",
"1.3.132.0.10": "secp256k1",
"2b8104000a": "secp256k1",
"2B8104000A": "secp256k1",
"ed25519": "ed25519",
"Ed25519": "ed25519",
"1.3.6.1.4.1.11591.15.1": "ed25519",
"2b06010401da470f01": "ed25519",
"2B06010401DA470F01": "ed25519",
"cv25519": "curve25519",
"curve25519": "curve25519",
"1.3.6.1.4.1.3029.1.5.1": "curve25519"
"Curve25519": "curve25519",
"1.3.6.1.4.1.3029.1.5.1": "curve25519",
"2b060104019755010501": "curve25519",
"2B060104019755010501": "curve25519"
},
/** A string to key specifier type

View File

@ -145,7 +145,7 @@ Packetlist.prototype.filterByTag = function () {
*/
Packetlist.prototype.forEach = function (callback) {
for (var i = 0; i < this.length; i++) {
callback(this[i]);
callback(this[i], i, this);
}
};
@ -163,6 +163,20 @@ Packetlist.prototype.map = function (callback) {
return packetArray;
};
/**
* Executes the callback function once for each element
* until it finds one where callback returns a truthy value
*/
Packetlist.prototype.some = async function (callback) {
for (var i = 0; i < this.length; i++) {
// eslint-disable-next-line no-await-in-loop
if (await callback(this[i], i, this)) {
return true;
}
}
return false;
};
/**
* Traverses packet tree and returns first matching packet
* @param {module:enums.packet} type The packet type

View File

@ -68,6 +68,14 @@ OID.prototype.write = function () {
String.fromCharCode(this.oid.length)+this.oid);
};
/**
* Serialize an OID object as a hex string
* @return {string} String with the hex value of the OID
*/
OID.prototype.toHex = function() {
return util.hexstrdump(this.oid);
};
OID.fromClone = function (clone) {
var oid = new OID(clone.oid);
return oid;

View File

@ -175,22 +175,22 @@ describe('Elliptic Curve Cryptography', function () {
it('Signature verification', function (done) {
var curve = elliptic_curves.get('p256');
var key = curve.keyFromPublic(signature_data.pub);
expect(key.verify(signature_data.message, signature_data.signature, 8)).to.be.true;
expect(key.verify(signature_data.message, signature_data.signature, 8)).to.eventually.be.true;
done();
});
it('Invalid signature', function (done) {
var curve = elliptic_curves.get('p256');
var key = curve.keyFromPublic(key_data.p256.pub);
expect(key.verify(signature_data.message, signature_data.signature, 8)).to.be.false;
expect(key.verify(signature_data.message, signature_data.signature, 8)).to.eventually.be.false;
done();
});
it('Signature generation', function (done) {
it('Signature generation', function () {
var curve = elliptic_curves.get('p256');
var key = curve.keyFromPrivate(key_data.p256.priv);
var signature = key.sign(signature_data.message, 8);
key = curve.keyFromPublic(key_data.p256.pub);
expect(key.verify(signature_data.message, signature, 8)).to.be.true;
done();
return key.sign(signature_data.message, 8).then(signature => {
key = curve.keyFromPublic(key_data.p256.pub);
expect(key.verify(signature_data.message, signature, 8)).to.eventually.be.true;
});
});
it('Shared secret generation', function (done) {
var curve = elliptic_curves.get('p256');

View File

@ -200,7 +200,7 @@ describe('Elliptic Curve Cryptography', function () {
var romeo = load_priv_key('romeo');
var juliet = load_pub_key('juliet');
expect(romeo.decrypt(data['romeo'].pass)).to.be.true;
openpgp.encrypt(
return openpgp.encrypt(
{publicKeys: [juliet], privateKeys: [romeo], data: data.romeo.message + "\n"}
).then(function (encrypted) {
var message = openpgp.message.readArmored(encrypted.data);