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:
parent
3129e7c4e3
commit
5cb89f4f25
|
@ -34,19 +34,19 @@ import random from '../../random';
|
||||||
import config from '../../../config';
|
import config from '../../../config';
|
||||||
import enums from '../../../enums';
|
import enums from '../../../enums';
|
||||||
import util from '../../../util';
|
import util from '../../../util';
|
||||||
|
import OID from '../../../type/oid';
|
||||||
import base64 from '../../../encoding/base64';
|
import base64 from '../../../encoding/base64';
|
||||||
|
|
||||||
const webCrypto = util.getWebCrypto();
|
const webCrypto = util.getWebCrypto();
|
||||||
const nodeCrypto = util.getNodeCrypto();
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
|
|
||||||
var webCurves = {}, nodeCurves = {};
|
var webCurves = {}, nodeCurves = {};
|
||||||
if (webCrypto && config.use_native) {
|
webCurves = {
|
||||||
webCurves = {
|
'p256': 'P-256',
|
||||||
'p256': 'P-256',
|
'p384': 'P-384',
|
||||||
'p384': 'P-384',
|
'p521': 'P-521'
|
||||||
'p521': 'P-521'
|
};
|
||||||
};
|
if (nodeCrypto && config.use_native) {
|
||||||
} else if (nodeCrypto && config.use_native) {
|
|
||||||
var knownCurves = nodeCrypto.getCurves();
|
var knownCurves = nodeCrypto.getCurves();
|
||||||
nodeCurves = {
|
nodeCurves = {
|
||||||
'secp256k1': knownCurves.includes('secp256k1') ? 'secp256k1' : undefined,
|
'secp256k1': knownCurves.includes('secp256k1') ? 'secp256k1' : undefined,
|
||||||
|
@ -63,8 +63,8 @@ const curves = {
|
||||||
keyType: enums.publicKey.ecdsa,
|
keyType: enums.publicKey.ecdsa,
|
||||||
hash: enums.hash.sha256,
|
hash: enums.hash.sha256,
|
||||||
cipher: enums.symmetric.aes128,
|
cipher: enums.symmetric.aes128,
|
||||||
node: nodeCurves.secp256r1,
|
node: nodeCurves.p256,
|
||||||
web: webCurves.secp256r1,
|
web: webCurves.p256,
|
||||||
payloadSize: 32
|
payloadSize: 32
|
||||||
},
|
},
|
||||||
p384: {
|
p384: {
|
||||||
|
@ -72,8 +72,8 @@ const curves = {
|
||||||
keyType: enums.publicKey.ecdsa,
|
keyType: enums.publicKey.ecdsa,
|
||||||
hash: enums.hash.sha384,
|
hash: enums.hash.sha384,
|
||||||
cipher: enums.symmetric.aes192,
|
cipher: enums.symmetric.aes192,
|
||||||
node: nodeCurves.secp384r1,
|
node: nodeCurves.p384,
|
||||||
web: webCurves.secp384r1,
|
web: webCurves.p384,
|
||||||
payloadSize: 48
|
payloadSize: 48
|
||||||
},
|
},
|
||||||
p521: {
|
p521: {
|
||||||
|
@ -81,8 +81,8 @@ const curves = {
|
||||||
keyType: enums.publicKey.ecdsa,
|
keyType: enums.publicKey.ecdsa,
|
||||||
hash: enums.hash.sha512,
|
hash: enums.hash.sha512,
|
||||||
cipher: enums.symmetric.aes256,
|
cipher: enums.symmetric.aes256,
|
||||||
node: nodeCurves.secp521r1,
|
node: nodeCurves.p521,
|
||||||
web: webCurves.secp521r1,
|
web: webCurves.p521,
|
||||||
payloadSize: 66
|
payloadSize: 66
|
||||||
},
|
},
|
||||||
secp256k1: {
|
secp256k1: {
|
||||||
|
@ -99,13 +99,16 @@ const curves = {
|
||||||
},
|
},
|
||||||
curve25519: {
|
curve25519: {
|
||||||
oid: util.bin2str([0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01]),
|
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,
|
hash: enums.hash.sha256,
|
||||||
cipher: enums.symmetric.aes128
|
cipher: enums.symmetric.aes128
|
||||||
},
|
},
|
||||||
brainpoolP256r1: { // TODO 1.3.36.3.3.2.8.1.1.7
|
brainpoolP256r1: { // TODO 1.3.36.3.3.2.8.1.1.7
|
||||||
oid: util.bin2str([0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07])
|
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
|
brainpoolP512r1: { // TODO 1.3.36.3.3.2.8.1.1.13
|
||||||
oid: util.bin2str([0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D])
|
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);
|
this.curve = new EdDSA(name);
|
||||||
break;
|
break;
|
||||||
case enums.publicKey.ecdsa:
|
case enums.publicKey.ecdsa:
|
||||||
case enums.publicKey.ecdh:
|
|
||||||
this.curve = new EC(name);
|
this.curve = new EC(name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown elliptic key type;');
|
throw new Error('Unknown elliptic key type;');
|
||||||
}
|
}
|
||||||
|
this.name = name;
|
||||||
this.oid = curves[name].oid;
|
this.oid = curves[name].oid;
|
||||||
this.hash = params.hash;
|
this.hash = params.hash;
|
||||||
this.cipher = params.cipher;
|
this.cipher = params.cipher;
|
||||||
|
@ -145,14 +148,14 @@ Curve.prototype.keyFromPublic = function (pub) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Curve.prototype.genKeyPair = async function () {
|
Curve.prototype.genKeyPair = async function () {
|
||||||
var r, keyPair;
|
var keyPair;
|
||||||
if (webCrypto && config.use_native && this.web) {
|
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) {
|
} else if (nodeCrypto && config.use_native && this.node) {
|
||||||
keyPair = await nodeGenKeyPair(this.name);
|
keyPair = await nodeGenKeyPair(this.name);
|
||||||
} else {
|
} else {
|
||||||
var compact = this.curve.curve.type === 'edwards' || this.curve.curve.type === 'mont';
|
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) {
|
if (this.keyType === enums.publicKey.eddsa) {
|
||||||
keyPair = { secret: r.getSecret() };
|
keyPair = { secret: r.getSecret() };
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,17 +165,18 @@ Curve.prototype.genKeyPair = async function () {
|
||||||
return new KeyPair(this.curve, keyPair);
|
return new KeyPair(this.curve, keyPair);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function get(oid_or_name) {
|
function get(oid_or_name) {
|
||||||
var name;
|
var name;
|
||||||
if (enums.curve[oid_or_name]) {
|
if (OID.prototype.isPrototypeOf(oid_or_name) &&
|
||||||
name = enums.write(enums.curve, 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]);
|
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');
|
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 = {
|
module.exports = {
|
||||||
Curve: Curve,
|
Curve: Curve,
|
||||||
|
curves: curves,
|
||||||
|
webCurves: webCurves,
|
||||||
|
nodeCurves: nodeCurves,
|
||||||
|
getPreferredHashAlgorithm: getPreferredHashAlgorithm,
|
||||||
generate: generate,
|
generate: generate,
|
||||||
get: get
|
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(
|
var webCryptoKey = await webCrypto.generateKey(
|
||||||
{
|
{ name: "ECDSA", namedCurve: webCurves[name] }, true, ["sign", "verify"]
|
||||||
name: algorithm === "ECDH" ? "ECDH" : "ECDSA",
|
|
||||||
namedCurve: webCurves[name]
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
algorithm === "ECDH" ? ["deriveKey", "deriveBits"] : ["sign", "verify"]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var privateKey = await webCrypto.exportKey("jwk", webCryptoKey.privateKey);
|
var privateKey = await webCrypto.exportKey("jwk", webCryptoKey.privateKey);
|
||||||
|
@ -218,15 +226,15 @@ async function webGenKeyPair(name, algorithm) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pub: {
|
pub: {
|
||||||
x: base64.decode(publicKey.x, 'base64url'),
|
x: base64.decode(publicKey.x, true),
|
||||||
y: base64.decode(publicKey.y, 'base64url')
|
y: base64.decode(publicKey.y, true)
|
||||||
},
|
},
|
||||||
priv: base64.decode(privateKey.d, 'base64url')
|
priv: base64.decode(privateKey.d, true)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function nodeGenKeyPair(name) {
|
async function nodeGenKeyPair(name) {
|
||||||
var ecdh = nodeCrypto.createECDH(name === "secp256r1" ? "prime256v1" : name);
|
var ecdh = nodeCrypto.createECDH(nodeCurves[name]);
|
||||||
await ecdh.generateKeys();
|
await ecdh.generateKeys();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -25,28 +25,9 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import BN from 'bn.js';
|
import hash from '../../hash';
|
||||||
import ASN1 from 'asn1.js';
|
|
||||||
import jwkToPem from 'jwk-to-pem';
|
|
||||||
|
|
||||||
import curves from './curves.js';
|
import curves from './curves.js';
|
||||||
import BigInteger from '../jsbn.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
|
* 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
|
* @return {{r: BigInteger, s: BigInteger}} Signature of the message
|
||||||
*/
|
*/
|
||||||
async function sign(oid, hash_algo, m, d) {
|
async function sign(oid, hash_algo, m, d) {
|
||||||
var signature;
|
|
||||||
const curve = curves.get(oid);
|
const curve = curves.get(oid);
|
||||||
hash_algo = hash_algo ? hash_algo : curve.hash;
|
|
||||||
const key = curve.keyFromPrivate(d.toByteArray());
|
const key = curve.keyFromPrivate(d.toByteArray());
|
||||||
if (webCrypto && config.use_native && curve.web) {
|
const signature = await key.sign(m, hash_algo);
|
||||||
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);
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
r: new BigInteger(signature.r.toArray()),
|
r: new BigInteger(signature.r.toArray()),
|
||||||
s: new BigInteger(signature.s.toArray())
|
s: new BigInteger(signature.s.toArray())
|
||||||
|
@ -84,168 +57,14 @@ async function sign(oid, hash_algo, m, d) {
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
async function verify(oid, hash_algo, signature, m, Q) {
|
async function verify(oid, hash_algo, signature, m, Q) {
|
||||||
var result;
|
|
||||||
const curve = curves.get(oid);
|
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());
|
const key = curve.keyFromPublic(Q.toByteArray());
|
||||||
if (webCrypto && config.use_native && curve.web) {
|
return key.verify(
|
||||||
result = await webVerify(curve, hash_algo, signature, m, key.keyPair.getPublic());
|
m, { r: signature.r.toByteArray(), s: signature.s.toByteArray() }, hash_algo
|
||||||
} 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
sign: sign,
|
sign: sign,
|
||||||
verify: verify
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import hash from '../../hash';
|
||||||
import curves from './curves.js';
|
import curves from './curves.js';
|
||||||
import BigInteger from '../jsbn.js';
|
import BigInteger from '../jsbn.js';
|
||||||
|
|
||||||
|
@ -14,11 +15,9 @@ import BigInteger from '../jsbn.js';
|
||||||
* @return {{r: BigInteger, s: BigInteger}} Signature of the message
|
* @return {{r: BigInteger, s: BigInteger}} Signature of the message
|
||||||
*/
|
*/
|
||||||
async function sign(oid, hash_algo, m, d) {
|
async function sign(oid, hash_algo, m, d) {
|
||||||
var signature;
|
|
||||||
const curve = curves.get(oid);
|
const curve = curves.get(oid);
|
||||||
hash_algo = hash_algo ? hash_algo : curve.hash;
|
|
||||||
const key = curve.keyFromSecret(d.toByteArray());
|
const key = curve.keyFromSecret(d.toByteArray());
|
||||||
signature = await key.sign(m, hash_algo);
|
const signature = await key.sign(m, hash_algo);
|
||||||
return {
|
return {
|
||||||
r: new BigInteger(signature.Rencoded()),
|
r: new BigInteger(signature.Rencoded()),
|
||||||
s: new BigInteger(signature.Sencoded())
|
s: new BigInteger(signature.Sencoded())
|
||||||
|
@ -35,12 +34,10 @@ async function sign(oid, hash_algo, m, d) {
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
async function verify(oid, hash_algo, signature, m, Q) {
|
async function verify(oid, hash_algo, signature, m, Q) {
|
||||||
var result;
|
|
||||||
const curve = curves.get(oid);
|
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());
|
const key = curve.keyFromPublic(Q.toByteArray());
|
||||||
return key.verify(
|
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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import {get, generate} from './curves';
|
import {get, generate, getPreferredHashAlgorithm} from './curves';
|
||||||
import ecdsa from './ecdsa';
|
import ecdsa from './ecdsa';
|
||||||
import eddsa from './eddsa';
|
import eddsa from './eddsa';
|
||||||
import ecdh from './ecdh';
|
import ecdh from './ecdh';
|
||||||
|
@ -37,5 +37,6 @@ module.exports = {
|
||||||
eddsa: eddsa,
|
eddsa: eddsa,
|
||||||
ecdh: ecdh,
|
ecdh: ecdh,
|
||||||
get: get,
|
get: get,
|
||||||
generate: generate
|
generate: generate,
|
||||||
|
getPreferredHashAlgorithm: getPreferredHashAlgorithm
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,9 +25,28 @@
|
||||||
|
|
||||||
'use strict';
|
'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 hash from '../../hash';
|
||||||
import util from '../../../util';
|
import util from '../../../util';
|
||||||
import enums from '../../../enums';
|
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) {
|
function KeyPair(curve, options) {
|
||||||
this.curve = curve;
|
this.curve = curve;
|
||||||
|
@ -35,20 +54,32 @@ function KeyPair(curve, options) {
|
||||||
this.keyPair = this.curve.keyPair(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') {
|
if (typeof message === 'string') {
|
||||||
message = util.str2Uint8Array(message);
|
message = util.str2Uint8Array(message);
|
||||||
}
|
}
|
||||||
const digest = (typeof hash_algo === 'undefined') ? message : hash.digest(hash_algo, message);
|
if (webCrypto && config.use_native && this.curve.web) {
|
||||||
return this.keyPair.sign(digest);
|
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') {
|
if (typeof message === 'string') {
|
||||||
message = util.str2Uint8Array(message);
|
message = util.str2Uint8Array(message);
|
||||||
}
|
}
|
||||||
const digest = (typeof hash_algo === 'undefined') ? message : hash.digest(hash_algo, message);
|
if (webCrypto && config.use_native && this.curve.web) {
|
||||||
return this.keyPair.verify(digest, signature);
|
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) {
|
KeyPair.prototype.derive = function (pub) {
|
||||||
|
@ -81,3 +112,131 @@ KeyPair.prototype.isValid = function () {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
KeyPair: KeyPair
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -17,20 +17,21 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; // Standard radix-64
|
||||||
var b64u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
var b64u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; // URL-safe radix-64
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert binary array to radix-64
|
* Convert binary array to radix-64
|
||||||
* @param {Uint8Array} t Uint8Array to convert
|
* @param {Uint8Array} t Uint8Array to convert
|
||||||
|
* @param {bool} u if true, output is URL-safe
|
||||||
* @returns {string} radix-64 version of input string
|
* @returns {string} radix-64 version of input string
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
function s2r(t, o, u) {
|
function s2r(t, u = false) {
|
||||||
// TODO check btoa alternative
|
// TODO check btoa alternative
|
||||||
var b64 = (u === "base64url") ? b64u : b64s;
|
var b64 = u ? b64u : b64s;
|
||||||
var a, c, n;
|
var a, c, n;
|
||||||
var r = o ? o : [],
|
var r = [],
|
||||||
l = 0,
|
l = 0,
|
||||||
s = 0;
|
s = 0;
|
||||||
var tl = t.length;
|
var tl = t.length;
|
||||||
|
@ -67,33 +68,30 @@ function s2r(t, o, u) {
|
||||||
if ((l % 60) === 0 && !u) {
|
if ((l % 60) === 0 && !u) {
|
||||||
r.push("\n");
|
r.push("\n");
|
||||||
}
|
}
|
||||||
if (u !== 'base64url') {
|
if (!u) {
|
||||||
r.push('=');
|
r.push('=');
|
||||||
l += 1;
|
l += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (s === 1 && u !== 'base64url') {
|
if (s === 1 && !u) {
|
||||||
if ((l % 60) === 0 && !u) {
|
if ((l % 60) === 0 && !u) {
|
||||||
r.push("\n");
|
r.push("\n");
|
||||||
}
|
}
|
||||||
r.push('=');
|
r.push('=');
|
||||||
}
|
}
|
||||||
if (o)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return r.join('');
|
return r.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert radix-64 to binary array
|
* Convert radix-64 to binary array
|
||||||
* @param {String} t radix-64 string to convert
|
* @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
|
* @returns {Uint8Array} binary array version of input string
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
function r2s(t, u) {
|
function r2s(t, u) {
|
||||||
// TODO check atob alternative
|
// TODO check atob alternative
|
||||||
var b64 = (u === "base64url") ? b64u : b64s;
|
var b64 = u ? b64u : b64s;
|
||||||
var c, n;
|
var c, n;
|
||||||
var r = [],
|
var r = [],
|
||||||
s = 0,
|
s = 0,
|
||||||
|
|
17
src/enums.js
17
src/enums.js
|
@ -16,25 +16,40 @@ export default {
|
||||||
"secp256r1": "p256",
|
"secp256r1": "p256",
|
||||||
"prime256v1": "p256",
|
"prime256v1": "p256",
|
||||||
"1.2.840.10045.3.1.7": "p256",
|
"1.2.840.10045.3.1.7": "p256",
|
||||||
|
"2a8648ce3d030107": "p256",
|
||||||
|
"2A8648CE3D030107": "p256",
|
||||||
|
|
||||||
"p384": "p384",
|
"p384": "p384",
|
||||||
"P-384": "p384",
|
"P-384": "p384",
|
||||||
"secp384r1": "p384",
|
"secp384r1": "p384",
|
||||||
"1.3.132.0.34": "p384",
|
"1.3.132.0.34": "p384",
|
||||||
|
"2b81040022": "p384",
|
||||||
|
"2B81040022": "p384",
|
||||||
|
|
||||||
"p521": "p521",
|
"p521": "p521",
|
||||||
"P-521": "p521",
|
"P-521": "p521",
|
||||||
"secp521r1": "p521",
|
"secp521r1": "p521",
|
||||||
"1.3.132.0.35": "p521",
|
"1.3.132.0.35": "p521",
|
||||||
|
"2b81040023": "p521",
|
||||||
|
"2B81040023": "p521",
|
||||||
|
|
||||||
"secp256k1": "secp256k1",
|
"secp256k1": "secp256k1",
|
||||||
"1.3.132.0.10": "secp256k1",
|
"1.3.132.0.10": "secp256k1",
|
||||||
|
"2b8104000a": "secp256k1",
|
||||||
|
"2B8104000A": "secp256k1",
|
||||||
|
|
||||||
"ed25519": "ed25519",
|
"ed25519": "ed25519",
|
||||||
|
"Ed25519": "ed25519",
|
||||||
"1.3.6.1.4.1.11591.15.1": "ed25519",
|
"1.3.6.1.4.1.11591.15.1": "ed25519",
|
||||||
|
"2b06010401da470f01": "ed25519",
|
||||||
|
"2B06010401DA470F01": "ed25519",
|
||||||
|
|
||||||
|
"cv25519": "curve25519",
|
||||||
"curve25519": "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
|
/** A string to key specifier type
|
||||||
|
|
|
@ -145,7 +145,7 @@ Packetlist.prototype.filterByTag = function () {
|
||||||
*/
|
*/
|
||||||
Packetlist.prototype.forEach = function (callback) {
|
Packetlist.prototype.forEach = function (callback) {
|
||||||
for (var i = 0; i < this.length; i++) {
|
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;
|
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
|
* Traverses packet tree and returns first matching packet
|
||||||
* @param {module:enums.packet} type The packet type
|
* @param {module:enums.packet} type The packet type
|
||||||
|
|
|
@ -68,6 +68,14 @@ OID.prototype.write = function () {
|
||||||
String.fromCharCode(this.oid.length)+this.oid);
|
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) {
|
OID.fromClone = function (clone) {
|
||||||
var oid = new OID(clone.oid);
|
var oid = new OID(clone.oid);
|
||||||
return oid;
|
return oid;
|
||||||
|
|
|
@ -175,22 +175,22 @@ describe('Elliptic Curve Cryptography', function () {
|
||||||
it('Signature verification', function (done) {
|
it('Signature verification', function (done) {
|
||||||
var curve = elliptic_curves.get('p256');
|
var curve = elliptic_curves.get('p256');
|
||||||
var key = curve.keyFromPublic(signature_data.pub);
|
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();
|
done();
|
||||||
});
|
});
|
||||||
it('Invalid signature', function (done) {
|
it('Invalid signature', function (done) {
|
||||||
var curve = elliptic_curves.get('p256');
|
var curve = elliptic_curves.get('p256');
|
||||||
var key = curve.keyFromPublic(key_data.p256.pub);
|
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();
|
done();
|
||||||
});
|
});
|
||||||
it('Signature generation', function (done) {
|
it('Signature generation', function () {
|
||||||
var curve = elliptic_curves.get('p256');
|
var curve = elliptic_curves.get('p256');
|
||||||
var key = curve.keyFromPrivate(key_data.p256.priv);
|
var key = curve.keyFromPrivate(key_data.p256.priv);
|
||||||
var signature = key.sign(signature_data.message, 8);
|
return key.sign(signature_data.message, 8).then(signature => {
|
||||||
key = curve.keyFromPublic(key_data.p256.pub);
|
key = curve.keyFromPublic(key_data.p256.pub);
|
||||||
expect(key.verify(signature_data.message, signature, 8)).to.be.true;
|
expect(key.verify(signature_data.message, signature, 8)).to.eventually.be.true;
|
||||||
done();
|
});
|
||||||
});
|
});
|
||||||
it('Shared secret generation', function (done) {
|
it('Shared secret generation', function (done) {
|
||||||
var curve = elliptic_curves.get('p256');
|
var curve = elliptic_curves.get('p256');
|
||||||
|
|
|
@ -200,7 +200,7 @@ describe('Elliptic Curve Cryptography', function () {
|
||||||
var romeo = load_priv_key('romeo');
|
var romeo = load_priv_key('romeo');
|
||||||
var juliet = load_pub_key('juliet');
|
var juliet = load_pub_key('juliet');
|
||||||
expect(romeo.decrypt(data['romeo'].pass)).to.be.true;
|
expect(romeo.decrypt(data['romeo'].pass)).to.be.true;
|
||||||
openpgp.encrypt(
|
return openpgp.encrypt(
|
||||||
{publicKeys: [juliet], privateKeys: [romeo], data: data.romeo.message + "\n"}
|
{publicKeys: [juliet], privateKeys: [romeo], data: data.romeo.message + "\n"}
|
||||||
).then(function (encrypted) {
|
).then(function (encrypted) {
|
||||||
var message = openpgp.message.readArmored(encrypted.data);
|
var message = openpgp.message.readArmored(encrypted.data);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user