Store named signature parameters (#1158)
Also, remove the now-unnecessary MPI type.
This commit is contained in:
parent
d5dd247b2c
commit
331a0c27a9
|
@ -29,8 +29,8 @@ import util from '../util';
|
||||||
/**
|
/**
|
||||||
* AES key wrap
|
* AES key wrap
|
||||||
* @function
|
* @function
|
||||||
* @param {String} key
|
* @param {Uint8Array} key
|
||||||
* @param {String} data
|
* @param {Uint8Array} data
|
||||||
* @returns {Uint8Array}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
export function wrap(key, data) {
|
export function wrap(key, data) {
|
||||||
|
|
|
@ -247,7 +247,7 @@ export function parseEncSessionKeyParams(algo, bytes) {
|
||||||
* @param {Object} params The key parameters indexed by name
|
* @param {Object} params The key parameters indexed by name
|
||||||
* @returns {Uint8Array} The array containing the MPIs
|
* @returns {Uint8Array} The array containing the MPIs
|
||||||
*/
|
*/
|
||||||
export function serializeKeyParams(algo, params) {
|
export function serializeParams(algo, params) {
|
||||||
const orderedParams = Object.keys(params).map(name => {
|
const orderedParams = Object.keys(params).map(name => {
|
||||||
const param = params[name];
|
const param = params[name];
|
||||||
return util.isUint8Array(param) ? util.uint8ArrayToMpi(param) : param.write();
|
return util.isUint8Array(param) ? util.uint8ArrayToMpi(param) : param.write();
|
||||||
|
|
|
@ -38,7 +38,6 @@ import hash from '../../hash';
|
||||||
import enums from '../../../enums';
|
import enums from '../../../enums';
|
||||||
import util from '../../../util';
|
import util from '../../../util';
|
||||||
import * as pkcs5 from '../../pkcs5';
|
import * as pkcs5 from '../../pkcs5';
|
||||||
import MPI from '../../../type/mpi';
|
|
||||||
import { keyFromPublic, keyFromPrivate, getIndutnyCurve } from './indutnyKey';
|
import { keyFromPublic, keyFromPrivate, getIndutnyCurve } from './indutnyKey';
|
||||||
|
|
||||||
const webCrypto = util.getWebCrypto();
|
const webCrypto = util.getWebCrypto();
|
||||||
|
@ -135,14 +134,14 @@ async function genPublicEphemeralKey(curve, Q) {
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function encrypt(oid, kdfParams, data, Q, fingerprint) {
|
export async function encrypt(oid, kdfParams, data, Q, fingerprint) {
|
||||||
const m = new MPI(pkcs5.encode(data));
|
const m = pkcs5.encode(data);
|
||||||
|
|
||||||
const curve = new Curve(oid);
|
const curve = new Curve(oid);
|
||||||
const { publicKey, sharedKey } = await genPublicEphemeralKey(curve, Q);
|
const { publicKey, sharedKey } = await genPublicEphemeralKey(curve, Q);
|
||||||
const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint);
|
const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint);
|
||||||
const cipher_algo = enums.read(enums.symmetric, kdfParams.cipher);
|
const cipher_algo = enums.read(enums.symmetric, kdfParams.cipher);
|
||||||
const Z = await kdf(kdfParams.hash, sharedKey, cipher[cipher_algo].keySize, param);
|
const Z = await kdf(kdfParams.hash, sharedKey, cipher[cipher_algo].keySize, param);
|
||||||
const wrappedKey = aes_kw.wrap(Z, m.toString());
|
const wrappedKey = aes_kw.wrap(Z, m);
|
||||||
return { publicKey, wrappedKey };
|
return { publicKey, wrappedKey };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,8 @@ nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest());
|
||||||
* @param {Uint8Array} publicKey Public key
|
* @param {Uint8Array} publicKey Public key
|
||||||
* @param {Uint8Array} privateKey Private key used to sign the message
|
* @param {Uint8Array} privateKey Private key used to sign the message
|
||||||
* @param {Uint8Array} hashed The hashed message
|
* @param {Uint8Array} hashed The hashed message
|
||||||
* @returns {{R: Uint8Array,
|
* @returns {{r: Uint8Array,
|
||||||
* S: Uint8Array}} Signature of the message
|
* s: Uint8Array}} Signature of the message
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function sign(oid, hash_algo, message, publicKey, privateKey, hashed) {
|
export async function sign(oid, hash_algo, message, publicKey, privateKey, hashed) {
|
||||||
|
@ -47,8 +47,8 @@ export async function sign(oid, hash_algo, message, publicKey, privateKey, hashe
|
||||||
const signature = nacl.sign.detached(hashed, secretKey);
|
const signature = nacl.sign.detached(hashed, secretKey);
|
||||||
// EdDSA signature params are returned in little-endian format
|
// EdDSA signature params are returned in little-endian format
|
||||||
return {
|
return {
|
||||||
R: signature.subarray(0, 32),
|
r: signature.subarray(0, 32),
|
||||||
S: signature.subarray(32)
|
s: signature.subarray(32)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,16 +56,16 @@ export async function sign(oid, hash_algo, message, publicKey, privateKey, hashe
|
||||||
* Verifies if a signature is valid for a message
|
* Verifies if a signature is valid for a message
|
||||||
* @param {module:type/oid} oid Elliptic curve object identifier
|
* @param {module:type/oid} oid Elliptic curve object identifier
|
||||||
* @param {module:enums.hash} hash_algo Hash algorithm used in the signature
|
* @param {module:enums.hash} hash_algo Hash algorithm used in the signature
|
||||||
* @param {{R: Uint8Array,
|
* @param {{r: Uint8Array,
|
||||||
S: Uint8Array}} signature Signature to verify the message
|
s: Uint8Array}} signature Signature to verify the message
|
||||||
* @param {Uint8Array} m Message to verify
|
* @param {Uint8Array} m Message to verify
|
||||||
* @param {Uint8Array} publicKey Public key used to verify the message
|
* @param {Uint8Array} publicKey Public key used to verify the message
|
||||||
* @param {Uint8Array} hashed The hashed message
|
* @param {Uint8Array} hashed The hashed message
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function verify(oid, hash_algo, { R, S }, m, publicKey, hashed) {
|
export async function verify(oid, hash_algo, { r, s }, m, publicKey, hashed) {
|
||||||
const signature = util.concatUint8Array([R, S]);
|
const signature = util.concatUint8Array([r, s]);
|
||||||
return nacl.sign.detached.verify(hashed, signature, publicKey.subarray(1));
|
return nacl.sign.detached.verify(hashed, signature, publicKey.subarray(1));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,48 +10,87 @@ import publicKey from './public_key';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse signature in binary form to get the parameters.
|
||||||
|
* See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1}
|
||||||
|
* See {@link https://tools.ietf.org/html/rfc4880#section-5.2.2|RFC 4880 5.2.2.}
|
||||||
|
* @param {module:enums.publicKey} algo Public key algorithm
|
||||||
|
* @param {Uint8Array} signature Data for which the signature was created
|
||||||
|
* @returns {Object} True if signature is valid
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
export function parseSignatureParams(algo, signature) {
|
||||||
|
let read = 0;
|
||||||
|
switch (algo) {
|
||||||
|
// Algorithm-Specific Fields for RSA signatures:
|
||||||
|
// - MPI of RSA signature value m**d mod n.
|
||||||
|
case enums.publicKey.rsaEncryptSign:
|
||||||
|
case enums.publicKey.rsaEncrypt:
|
||||||
|
case enums.publicKey.rsaSign: {
|
||||||
|
const s = util.readMPI(signature.subarray(read));
|
||||||
|
return { s };
|
||||||
|
}
|
||||||
|
// Algorithm-Specific Fields for DSA or ECDSA signatures:
|
||||||
|
// - MPI of DSA or ECDSA value r.
|
||||||
|
// - MPI of DSA or ECDSA value s.
|
||||||
|
case enums.publicKey.dsa:
|
||||||
|
case enums.publicKey.ecdsa:
|
||||||
|
{
|
||||||
|
const r = util.readMPI(signature.subarray(read)); read += r.length + 2;
|
||||||
|
const s = util.readMPI(signature.subarray(read));
|
||||||
|
return { r, s };
|
||||||
|
}
|
||||||
|
// Algorithm-Specific Fields for EdDSA signatures:
|
||||||
|
// - MPI of an EC point r.
|
||||||
|
// - EdDSA value s, in MPI, in the little endian representation.
|
||||||
|
// EdDSA signature parameters are encoded in little-endian format
|
||||||
|
// https://tools.ietf.org/html/rfc8032#section-5.1.2
|
||||||
|
case enums.publicKey.eddsa: {
|
||||||
|
const r = util.padToLength(util.readMPI(signature.subarray(read)), 32, 'le'); read += r.length + 2;
|
||||||
|
const s = util.padToLength(util.readMPI(signature.subarray(read)), 32, 'le');
|
||||||
|
return { r, s };
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid signature algorithm.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies the signature provided for data using specified algorithms and public key parameters.
|
* Verifies the signature provided for data using specified algorithms and public key parameters.
|
||||||
* See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1}
|
* See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1}
|
||||||
* and {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4}
|
* and {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4}
|
||||||
* for public key and hash algorithms.
|
* for public key and hash algorithms.
|
||||||
* @param {module:enums.publicKey} algo Public key algorithm
|
* @param {module:enums.publicKey} algo Public key algorithm
|
||||||
* @param {module:enums.hash} hash_algo Hash algorithm
|
* @param {module:enums.hash} hashAlgo Hash algorithm
|
||||||
* @param {Array<module:type/mpi>} msg_MPIs Algorithm-specific signature parameters
|
* @param {Object} signature Named algorithm-specific signature parameters
|
||||||
* @param {Object} publicParams Algorithm-specific public key parameters
|
* @param {Object} publicParams Algorithm-specific public key parameters
|
||||||
* @param {Uint8Array} data Data for which the signature was created
|
* @param {Uint8Array} data Data for which the signature was created
|
||||||
* @param {Uint8Array} hashed The hashed data
|
* @param {Uint8Array} hashed The hashed data
|
||||||
* @returns {Boolean} True if signature is valid
|
* @returns {Boolean} True if signature is valid
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function verify(algo, hash_algo, msg_MPIs, publicParams, data, hashed) {
|
export async function verify(algo, hashAlgo, signature, publicParams, data, hashed) {
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case enums.publicKey.rsaEncryptSign:
|
case enums.publicKey.rsaEncryptSign:
|
||||||
case enums.publicKey.rsaEncrypt:
|
case enums.publicKey.rsaEncrypt:
|
||||||
case enums.publicKey.rsaSign: {
|
case enums.publicKey.rsaSign: {
|
||||||
const { n, e } = publicParams;
|
const { n, e } = publicParams;
|
||||||
const m = msg_MPIs[0].toUint8Array('be', n.length);
|
const { s } = signature;
|
||||||
return publicKey.rsa.verify(hash_algo, data, m, n, e, hashed);
|
return publicKey.rsa.verify(hashAlgo, data, s, n, e, hashed);
|
||||||
}
|
}
|
||||||
case enums.publicKey.dsa: {
|
case enums.publicKey.dsa: {
|
||||||
const r = await msg_MPIs[0].toUint8Array();
|
|
||||||
const s = await msg_MPIs[1].toUint8Array();
|
|
||||||
const { g, p, q, y } = publicParams;
|
const { g, p, q, y } = publicParams;
|
||||||
return publicKey.dsa.verify(hash_algo, r, s, hashed, g, p, q, y);
|
const { r, s } = signature;
|
||||||
|
return publicKey.dsa.verify(hashAlgo, r, s, hashed, g, p, q, y);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ecdsa: {
|
case enums.publicKey.ecdsa: {
|
||||||
const { oid, Q } = publicParams;
|
const { oid, Q } = publicParams;
|
||||||
const signature = { r: msg_MPIs[0].toUint8Array(), s: msg_MPIs[1].toUint8Array() };
|
return publicKey.elliptic.ecdsa.verify(oid, hashAlgo, signature, data, Q, hashed);
|
||||||
return publicKey.elliptic.ecdsa.verify(oid, hash_algo, signature, data, Q, hashed);
|
|
||||||
}
|
}
|
||||||
case enums.publicKey.eddsa: {
|
case enums.publicKey.eddsa: {
|
||||||
const { oid, Q } = publicParams;
|
const { oid, Q } = publicParams;
|
||||||
// EdDSA signature params are expected in little-endian format
|
return publicKey.elliptic.eddsa.verify(oid, hashAlgo, signature, data, Q, hashed);
|
||||||
const signature = {
|
|
||||||
R: msg_MPIs[0].toUint8Array('le', 32),
|
|
||||||
S: msg_MPIs[1].toUint8Array('le', 32)
|
|
||||||
};
|
|
||||||
return publicKey.elliptic.eddsa.verify(oid, hash_algo, signature, data, Q, hashed);
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error('Invalid signature algorithm.');
|
throw new Error('Invalid signature algorithm.');
|
||||||
|
@ -64,15 +103,15 @@ export async function verify(algo, hash_algo, msg_MPIs, publicParams, data, hash
|
||||||
* and {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4}
|
* and {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4}
|
||||||
* for public key and hash algorithms.
|
* for public key and hash algorithms.
|
||||||
* @param {module:enums.publicKey} algo Public key algorithm
|
* @param {module:enums.publicKey} algo Public key algorithm
|
||||||
* @param {module:enums.hash} hash_algo Hash algorithm
|
* @param {module:enums.hash} hashAlgo Hash algorithm
|
||||||
* @param {Object} publicKeyParams Algorithm-specific public and private key parameters
|
* @param {Object} publicKeyParams Algorithm-specific public and private key parameters
|
||||||
* @param {Object} privateKeyParams Algorithm-specific public and private key parameters
|
* @param {Object} privateKeyParams Algorithm-specific public and private key parameters
|
||||||
* @param {Uint8Array} data Data to be signed
|
* @param {Uint8Array} data Data to be signed
|
||||||
* @param {Uint8Array} hashed The hashed data
|
* @param {Uint8Array} hashed The hashed data
|
||||||
* @returns {Uint8Array} Signature
|
* @returns {Object} Signature Object containing named signature parameters
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
export async function sign(algo, hash_algo, publicKeyParams, privateKeyParams, data, hashed) {
|
export async function sign(algo, hashAlgo, publicKeyParams, privateKeyParams, data, hashed) {
|
||||||
if (!publicKeyParams || !privateKeyParams) {
|
if (!publicKeyParams || !privateKeyParams) {
|
||||||
throw new Error('Missing key parameters');
|
throw new Error('Missing key parameters');
|
||||||
}
|
}
|
||||||
|
@ -82,17 +121,13 @@ export async function sign(algo, hash_algo, publicKeyParams, privateKeyParams, d
|
||||||
case enums.publicKey.rsaSign: {
|
case enums.publicKey.rsaSign: {
|
||||||
const { n, e } = publicKeyParams;
|
const { n, e } = publicKeyParams;
|
||||||
const { d, p, q, u } = privateKeyParams;
|
const { d, p, q, u } = privateKeyParams;
|
||||||
const signature = await publicKey.rsa.sign(hash_algo, data, n, e, d, p, q, u, hashed);
|
const s = await publicKey.rsa.sign(hashAlgo, data, n, e, d, p, q, u, hashed);
|
||||||
return util.uint8ArrayToMpi(signature);
|
return { s };
|
||||||
}
|
}
|
||||||
case enums.publicKey.dsa: {
|
case enums.publicKey.dsa: {
|
||||||
const { g, p, q } = publicKeyParams;
|
const { g, p, q } = publicKeyParams;
|
||||||
const { x } = privateKeyParams;
|
const { x } = privateKeyParams;
|
||||||
const signature = await publicKey.dsa.sign(hash_algo, hashed, g, p, q, x);
|
return publicKey.dsa.sign(hashAlgo, hashed, g, p, q, x);
|
||||||
return util.concatUint8Array([
|
|
||||||
util.uint8ArrayToMpi(signature.r),
|
|
||||||
util.uint8ArrayToMpi(signature.s)
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
case enums.publicKey.elgamal: {
|
case enums.publicKey.elgamal: {
|
||||||
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
|
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
|
||||||
|
@ -100,20 +135,12 @@ export async function sign(algo, hash_algo, publicKeyParams, privateKeyParams, d
|
||||||
case enums.publicKey.ecdsa: {
|
case enums.publicKey.ecdsa: {
|
||||||
const { oid, Q } = publicKeyParams;
|
const { oid, Q } = publicKeyParams;
|
||||||
const { d } = privateKeyParams;
|
const { d } = privateKeyParams;
|
||||||
const signature = await publicKey.elliptic.ecdsa.sign(oid, hash_algo, data, Q, d, hashed);
|
return publicKey.elliptic.ecdsa.sign(oid, hashAlgo, data, Q, d, hashed);
|
||||||
return util.concatUint8Array([
|
|
||||||
util.uint8ArrayToMpi(signature.r),
|
|
||||||
util.uint8ArrayToMpi(signature.s)
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
case enums.publicKey.eddsa: {
|
case enums.publicKey.eddsa: {
|
||||||
const { oid, Q } = publicKeyParams;
|
const { oid, Q } = publicKeyParams;
|
||||||
const { seed } = privateKeyParams;
|
const { seed } = privateKeyParams;
|
||||||
const signature = await publicKey.elliptic.eddsa.sign(oid, hash_algo, data, Q, seed, hashed);
|
return publicKey.elliptic.eddsa.sign(oid, hashAlgo, data, Q, seed, hashed);
|
||||||
return util.concatUint8Array([
|
|
||||||
util.uint8ArrayToMpi(signature.R),
|
|
||||||
util.uint8ArrayToMpi(signature.S)
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error('Invalid signature algorithm.');
|
throw new Error('Invalid signature algorithm.');
|
||||||
|
|
|
@ -52,12 +52,6 @@ export { default as util } from './util';
|
||||||
*/
|
*/
|
||||||
export * from './packet';
|
export * from './packet';
|
||||||
|
|
||||||
/**
|
|
||||||
* @see module:type/mpi
|
|
||||||
* @name module:openpgp.MPI
|
|
||||||
*/
|
|
||||||
export { default as MPI } from './type/mpi';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see module:type/s2k
|
* @see module:type/s2k
|
||||||
* @name module:openpgp.S2K
|
* @name module:openpgp.S2K
|
||||||
|
|
|
@ -238,7 +238,7 @@ export async function mergeSignatures(source, dest, attr, checkFn) {
|
||||||
await Promise.all(source.map(async function(sourceSig) {
|
await Promise.all(source.map(async function(sourceSig) {
|
||||||
if (!sourceSig.isExpired() && (!checkFn || await checkFn(sourceSig)) &&
|
if (!sourceSig.isExpired() && (!checkFn || await checkFn(sourceSig)) &&
|
||||||
!dest[attr].some(function(destSig) {
|
!dest[attr].some(function(destSig) {
|
||||||
return util.equalsUint8Array(destSig.signature, sourceSig.signature);
|
return util.equalsUint8Array(destSig.write_params(), sourceSig.write_params());
|
||||||
})) {
|
})) {
|
||||||
dest[attr].push(sourceSig);
|
dest[attr].push(sourceSig);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires type/keyid
|
* @requires type/keyid
|
||||||
* @requires type/mpi
|
|
||||||
* @requires config
|
* @requires config
|
||||||
* @requires crypto
|
* @requires crypto
|
||||||
* @requires enums
|
* @requires enums
|
||||||
|
@ -142,7 +141,7 @@ class PublicKeyPacket {
|
||||||
const algo = enums.write(enums.publicKey, this.algorithm);
|
const algo = enums.write(enums.publicKey, this.algorithm);
|
||||||
arr.push(new Uint8Array([algo]));
|
arr.push(new Uint8Array([algo]));
|
||||||
|
|
||||||
const params = crypto.serializeKeyParams(algo, this.publicParams);
|
const params = crypto.serializeParams(algo, this.publicParams);
|
||||||
if (this.version === 5) {
|
if (this.version === 5) {
|
||||||
// A four-octet scalar octet count for the following key material
|
// A four-octet scalar octet count for the following key material
|
||||||
arr.push(util.writeNumber(params.length, 4));
|
arr.push(util.writeNumber(params.length, 4));
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires type/keyid
|
* @requires type/keyid
|
||||||
* @requires type/mpi
|
|
||||||
* @requires crypto
|
* @requires crypto
|
||||||
* @requires enums
|
* @requires enums
|
||||||
* @requires util
|
* @requires util
|
||||||
|
@ -56,8 +55,8 @@ class PublicKeyEncryptedSessionKeyPacket {
|
||||||
this.sessionKey = null;
|
this.sessionKey = null;
|
||||||
this.sessionKeyAlgorithm = null;
|
this.sessionKeyAlgorithm = null;
|
||||||
|
|
||||||
/** @type {Array<module:type/mpi>} */
|
/** @type {Object} */
|
||||||
this.encrypted = [];
|
this.encrypted = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,7 +85,7 @@ class PublicKeyEncryptedSessionKeyPacket {
|
||||||
new Uint8Array([this.version]),
|
new Uint8Array([this.version]),
|
||||||
this.publicKeyId.write(),
|
this.publicKeyId.write(),
|
||||||
new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)]),
|
new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)]),
|
||||||
crypto.serializeKeyParams(algo, this.encrypted)
|
crypto.serializeParams(algo, this.encrypted)
|
||||||
];
|
];
|
||||||
|
|
||||||
return util.concatUint8Array(arr);
|
return util.concatUint8Array(arr);
|
||||||
|
|
|
@ -211,7 +211,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||||
if (!this.isDummy()) {
|
if (!this.isDummy()) {
|
||||||
if (!this.s2k_usage) {
|
if (!this.s2k_usage) {
|
||||||
const algo = enums.write(enums.publicKey, this.algorithm);
|
const algo = enums.write(enums.publicKey, this.algorithm);
|
||||||
const cleartextParams = crypto.serializeKeyParams(algo, this.privateParams);
|
const cleartextParams = crypto.serializeParams(algo, this.privateParams);
|
||||||
this.keyMaterial = util.concatUint8Array([
|
this.keyMaterial = util.concatUint8Array([
|
||||||
cleartextParams,
|
cleartextParams,
|
||||||
util.writeChecksum(cleartextParams)
|
util.writeChecksum(cleartextParams)
|
||||||
|
@ -294,7 +294,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||||
this.s2k = new type_s2k();
|
this.s2k = new type_s2k();
|
||||||
this.s2k.salt = await crypto.random.getRandomBytes(8);
|
this.s2k.salt = await crypto.random.getRandomBytes(8);
|
||||||
const algo = enums.write(enums.publicKey, this.algorithm);
|
const algo = enums.write(enums.publicKey, this.algorithm);
|
||||||
const cleartext = crypto.serializeKeyParams(algo, this.privateParams);
|
const cleartext = crypto.serializeParams(algo, this.privateParams);
|
||||||
this.symmetric = 'aes256';
|
this.symmetric = 'aes256';
|
||||||
const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric);
|
const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric);
|
||||||
const blockLen = crypto.cipher[this.symmetric].blockSize;
|
const blockLen = crypto.cipher[this.symmetric].blockSize;
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
* @requires web-stream-tools
|
* @requires web-stream-tools
|
||||||
* @requires packet/packet
|
* @requires packet/packet
|
||||||
* @requires type/keyid
|
* @requires type/keyid
|
||||||
* @requires type/mpi
|
|
||||||
* @requires crypto
|
* @requires crypto
|
||||||
* @requires enums
|
* @requires enums
|
||||||
* @requires util
|
* @requires util
|
||||||
|
@ -28,7 +27,6 @@
|
||||||
import stream from 'web-stream-tools';
|
import stream from 'web-stream-tools';
|
||||||
import { readSimpleLength, writeSimpleLength } from './packet';
|
import { readSimpleLength, writeSimpleLength } from './packet';
|
||||||
import type_keyid from '../type/keyid.js';
|
import type_keyid from '../type/keyid.js';
|
||||||
import type_mpi from '../type/mpi.js';
|
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import enums from '../enums';
|
import enums from '../enums';
|
||||||
import util from '../util';
|
import util from '../util';
|
||||||
|
@ -133,7 +131,19 @@ class SignaturePacket {
|
||||||
this.signedHashValue = bytes.subarray(i, i + 2);
|
this.signedHashValue = bytes.subarray(i, i + 2);
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
||||||
this.signature = bytes.subarray(i, bytes.length);
|
this.params = crypto.signature.parseSignatureParams(this.publicKeyAlgorithm, bytes.subarray(i, bytes.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Uint8Array | ReadableStream<Uint8Array>}
|
||||||
|
*/
|
||||||
|
write_params() {
|
||||||
|
if (this.params instanceof Promise) {
|
||||||
|
return stream.fromAsync(
|
||||||
|
async () => crypto.serializeParams(this.publicKeyAlgorithm, await this.params)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return crypto.serializeParams(this.publicKeyAlgorithm, this.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
write() {
|
write() {
|
||||||
|
@ -141,7 +151,7 @@ class SignaturePacket {
|
||||||
arr.push(this.signatureData);
|
arr.push(this.signatureData);
|
||||||
arr.push(this.write_unhashed_sub_packets());
|
arr.push(this.write_unhashed_sub_packets());
|
||||||
arr.push(this.signedHashValue);
|
arr.push(this.signedHashValue);
|
||||||
arr.push(stream.clone(this.signature));
|
arr.push(this.write_params());
|
||||||
return util.concat(arr);
|
return util.concat(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,9 +191,9 @@ class SignaturePacket {
|
||||||
publicKeyAlgorithm, hashAlgorithm, key.publicParams, key.privateParams, toHash, await stream.readToEnd(hash)
|
publicKeyAlgorithm, hashAlgorithm, key.publicParams, key.privateParams, toHash, await stream.readToEnd(hash)
|
||||||
);
|
);
|
||||||
if (streaming) {
|
if (streaming) {
|
||||||
this.signature = stream.fromAsync(signed);
|
this.params = signed();
|
||||||
} else {
|
} else {
|
||||||
this.signature = await signed();
|
this.params = await signed();
|
||||||
|
|
||||||
// Store the fact that this signature is valid, e.g. for when we call `await
|
// Store the fact that this signature is valid, e.g. for when we call `await
|
||||||
// getLatestValidSignature(this.revocationSignatures, key, data)` later.
|
// getLatestValidSignature(this.revocationSignatures, key, data)` later.
|
||||||
|
@ -661,6 +671,7 @@ class SignaturePacket {
|
||||||
* @param {module:enums.signature} signatureType expected signature type
|
* @param {module:enums.signature} signatureType expected signature type
|
||||||
* @param {String|Object} data data which on the signature applies
|
* @param {String|Object} data data which on the signature applies
|
||||||
* @param {Boolean} detached (optional) whether to verify a detached signature
|
* @param {Boolean} detached (optional) whether to verify a detached signature
|
||||||
|
* @param {Boolean} streaming (optional) whether to process data as a stream
|
||||||
* @returns {Promise<Boolean>} True if message is verified, else false.
|
* @returns {Promise<Boolean>} True if message is verified, else false.
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
|
@ -687,33 +698,10 @@ class SignaturePacket {
|
||||||
throw new Error('Message digest did not match');
|
throw new Error('Message digest did not match');
|
||||||
}
|
}
|
||||||
|
|
||||||
let mpicount = 0;
|
this.params = await this.params;
|
||||||
// Algorithm-Specific Fields for RSA signatures:
|
|
||||||
// - multiprecision number (MPI) of RSA signature value m**d mod n.
|
|
||||||
if (publicKeyAlgorithm > 0 && publicKeyAlgorithm < 4) {
|
|
||||||
mpicount = 1;
|
|
||||||
|
|
||||||
// Algorithm-Specific Fields for DSA, ECDSA, and EdDSA signatures:
|
|
||||||
// - MPI of DSA value r.
|
|
||||||
// - MPI of DSA value s.
|
|
||||||
} else if (publicKeyAlgorithm === enums.publicKey.dsa ||
|
|
||||||
publicKeyAlgorithm === enums.publicKey.ecdsa ||
|
|
||||||
publicKeyAlgorithm === enums.publicKey.eddsa) {
|
|
||||||
mpicount = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// EdDSA signature parameters are encoded in little-endian format
|
|
||||||
// https://tools.ietf.org/html/rfc8032#section-5.1.2
|
|
||||||
const endian = publicKeyAlgorithm === enums.publicKey.eddsa ? 'le' : 'be';
|
|
||||||
const mpi = [];
|
|
||||||
let i = 0;
|
|
||||||
this.signature = await stream.readToEnd(this.signature);
|
|
||||||
for (let j = 0; j < mpicount; j++) {
|
|
||||||
mpi[j] = new type_mpi();
|
|
||||||
i += mpi[j].read(this.signature.subarray(i, this.signature.length), endian);
|
|
||||||
}
|
|
||||||
const verified = await crypto.signature.verify(
|
const verified = await crypto.signature.verify(
|
||||||
publicKeyAlgorithm, hashAlgorithm, mpi, key.publicParams,
|
publicKeyAlgorithm, hashAlgorithm, this.params, key.publicParams,
|
||||||
toHash, hash
|
toHash, hash
|
||||||
);
|
);
|
||||||
if (!verified) {
|
if (!verified) {
|
||||||
|
|
137
src/type/mpi.js
137
src/type/mpi.js
|
@ -1,137 +0,0 @@
|
||||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
|
||||||
// Copyright (C) 2011 Recurity Labs GmbH
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 3.0 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
// Hint: We hold our MPIs as an array of octets in big endian format preceding a two
|
|
||||||
// octet scalar: MPI: [a,b,c,d,e,f]
|
|
||||||
// - MPI size: (a << 8) | b
|
|
||||||
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of type MPI ({@link https://tools.ietf.org/html/rfc4880#section-3.2|RFC4880 3.2})
|
|
||||||
* Multiprecision integers (also called MPIs) are unsigned integers used
|
|
||||||
* to hold large integers such as the ones used in cryptographic
|
|
||||||
* calculations.
|
|
||||||
* An MPI consists of two pieces: a two-octet scalar that is the length
|
|
||||||
* of the MPI in bits followed by a string of octets that contain the
|
|
||||||
* actual integer.
|
|
||||||
* @requires util
|
|
||||||
* @module type/mpi
|
|
||||||
*/
|
|
||||||
import util from '../util';
|
|
||||||
|
|
||||||
class MPI {
|
|
||||||
constructor(data) {
|
|
||||||
/** An implementation dependent integer */
|
|
||||||
if (data instanceof MPI) {
|
|
||||||
this.data = data.data;
|
|
||||||
} else if (util.isBigInteger(data)) {
|
|
||||||
this.fromBigInteger(data);
|
|
||||||
} else if (util.isBN(data)) {
|
|
||||||
this.fromBN(data);
|
|
||||||
} else if (util.isUint8Array(data)) {
|
|
||||||
this.fromUint8Array(data);
|
|
||||||
} else if (util.isString(data)) {
|
|
||||||
this.fromString(data);
|
|
||||||
} else {
|
|
||||||
this.data = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parsing function for a MPI ({@link https://tools.ietf.org/html/rfc4880#section-3.2|RFC 4880 3.2}).
|
|
||||||
* @param {Uint8Array|string} bytes Payload of MPI data
|
|
||||||
* @param {'be'|'le'} endian Endianness of the data; 'be' for big-endian or 'le' for little-endian
|
|
||||||
* @returns {Integer} Length of data read
|
|
||||||
*/
|
|
||||||
read(bytes, endian = 'be') {
|
|
||||||
if (util.isString(bytes)) {
|
|
||||||
bytes = util.strToUint8Array(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
const bits = (bytes[0] << 8) | bytes[1];
|
|
||||||
const bytelen = (bits + 7) >>> 3;
|
|
||||||
const payload = bytes.subarray(2, 2 + bytelen);
|
|
||||||
|
|
||||||
this.fromUint8Array(payload, endian);
|
|
||||||
|
|
||||||
return 2 + bytelen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the mpi object to a bytes as specified in
|
|
||||||
* {@link https://tools.ietf.org/html/rfc4880#section-3.2|RFC4880 3.2}
|
|
||||||
* @param {String} endian Endianness of the payload; 'be' for big-endian or 'le' for little-endian
|
|
||||||
* @param {Integer} length Length of the data part of the MPI
|
|
||||||
* @returns {Uint8Aray} mpi Byte representation
|
|
||||||
*/
|
|
||||||
write(endian, length) {
|
|
||||||
return util.uint8ArrayToMpi(this.toUint8Array(endian, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
bitLength() {
|
|
||||||
return (this.data.length - 1) * 8 + util.nbits(this.data[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
byteLength() {
|
|
||||||
return this.data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
toUint8Array(endian, length) {
|
|
||||||
endian = endian || 'be';
|
|
||||||
length = length || this.data.length;
|
|
||||||
|
|
||||||
const payload = new Uint8Array(length);
|
|
||||||
const start = endian === 'le' ? 0 : length - this.data.length;
|
|
||||||
payload.set(this.data, start);
|
|
||||||
if (endian === 'le') {
|
|
||||||
payload.reverse();
|
|
||||||
}
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
fromUint8Array(bytes, endian = 'be') {
|
|
||||||
this.data = new Uint8Array(bytes.length);
|
|
||||||
this.data.set(bytes);
|
|
||||||
|
|
||||||
if (endian === 'le') {
|
|
||||||
this.data.reverse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toString() {
|
|
||||||
return util.uint8ArrayToStr(this.toUint8Array());
|
|
||||||
}
|
|
||||||
|
|
||||||
fromString(str, endian = 'be') {
|
|
||||||
this.fromUint8Array(util.strToUint8Array(str), endian);
|
|
||||||
}
|
|
||||||
|
|
||||||
async toBigInteger() {
|
|
||||||
const BigInteger = await util.getBigInteger();
|
|
||||||
return new BigInteger(this.toUint8Array());
|
|
||||||
}
|
|
||||||
|
|
||||||
fromBigInteger(n) {
|
|
||||||
this.data = n.toUint8Array();
|
|
||||||
}
|
|
||||||
|
|
||||||
fromBN(bn) {
|
|
||||||
this.data = bn.toArrayLike(Uint8Array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MPI;
|
|
|
@ -194,9 +194,6 @@ export default {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a Uint8Array to an MPI-formatted Uint8Array.
|
* Convert a Uint8Array to an MPI-formatted Uint8Array.
|
||||||
* Note: the output is **not** an MPI object.
|
|
||||||
* @see {@link module:type/mpi/MPI.fromUint8Array}
|
|
||||||
* @see {@link module:type/mpi/MPI.toUint8Array}
|
|
||||||
* @param {Uint8Array} bin An array of 8-bit integers to convert
|
* @param {Uint8Array} bin An array of 8-bit integers to convert
|
||||||
* @returns {Uint8Array} MPI-formatted Uint8Array
|
* @returns {Uint8Array} MPI-formatted Uint8Array
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -211,37 +211,26 @@ module.exports = () => describe('API functional testing', function() {
|
||||||
|
|
||||||
describe('Sign and verify', function () {
|
describe('Sign and verify', function () {
|
||||||
it('RSA', async function () {
|
it('RSA', async function () {
|
||||||
return crypto.signature.sign(
|
const RSAsignedData = await crypto.signature.sign(
|
||||||
1, 2, RSAPublicParams, RSAPrivateParams, data, await crypto.hash.digest(2, data)
|
openpgp.enums.publicKey.rsaEncryptSign, openpgp.enums.hash.sha1, RSAPublicParams, RSAPrivateParams, data, await crypto.hash.digest(2, data)
|
||||||
).then(async RSAsignedData => {
|
);
|
||||||
const RSAsignedDataMPI = new openpgp.MPI();
|
const success = await crypto.signature.verify(
|
||||||
RSAsignedDataMPI.read(RSAsignedData);
|
openpgp.enums.publicKey.rsaEncryptSign, openpgp.enums.hash.sha1, RSAsignedData, RSAPublicParams, data, await crypto.hash.digest(2, data)
|
||||||
return crypto.signature.verify(
|
);
|
||||||
1, 2, [RSAsignedDataMPI], RSAPublicParams, data, await crypto.hash.digest(2, data)
|
|
||||||
).then(success => {
|
|
||||||
return expect(success).to.be.true;
|
return expect(success).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('DSA', async function () {
|
it('DSA', async function () {
|
||||||
return crypto.signature.sign(
|
const DSAsignedData = await crypto.signature.sign(
|
||||||
17, 2, DSAPublicParams, DSAPrivateParams, data, await crypto.hash.digest(2, data)
|
openpgp.enums.publicKey.dsa, openpgp.enums.hash.sha1, DSAPublicParams, DSAPrivateParams, data, await crypto.hash.digest(2, data)
|
||||||
).then(async DSAsignedData => {
|
);
|
||||||
DSAsignedData = util.uint8ArrayToStr(DSAsignedData);
|
const success = await crypto.signature.verify(
|
||||||
const DSAmsgMPIs = [];
|
openpgp.enums.publicKey.dsa, openpgp.enums.hash.sha1, DSAsignedData, DSAPublicParams, data, await crypto.hash.digest(2, data)
|
||||||
DSAmsgMPIs[0] = new openpgp.MPI();
|
);
|
||||||
DSAmsgMPIs[1] = new openpgp.MPI();
|
|
||||||
DSAmsgMPIs[0].read(DSAsignedData.substring(0,34));
|
|
||||||
DSAmsgMPIs[1].read(DSAsignedData.substring(34,68));
|
|
||||||
return crypto.signature.verify(
|
|
||||||
17, 2, DSAmsgMPIs, DSAPublicParams, data, await crypto.hash.digest(2, data)
|
|
||||||
).then(success => {
|
|
||||||
return expect(success).to.be.true;
|
return expect(success).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Encrypt and decrypt', function () {
|
describe('Encrypt and decrypt', function () {
|
||||||
let symmAlgos = Object.keys(openpgp.enums.symmetric);
|
let symmAlgos = Object.keys(openpgp.enums.symmetric);
|
||||||
|
|
|
@ -39,8 +39,7 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
|
||||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||||
const message = await openpgp.crypto.generateSessionKey('aes256');
|
const message = await openpgp.crypto.generateSessionKey('aes256');
|
||||||
const encrypted = await openpgp.crypto.publicKey.rsa.encrypt(message, n, e);
|
const encrypted = await openpgp.crypto.publicKey.rsa.encrypt(message, n, e);
|
||||||
const result = new openpgp.MPI(encrypted);
|
const decrypted = await openpgp.crypto.publicKey.rsa.decrypt(encrypted, n, e, d, p, q, u);
|
||||||
const decrypted = await openpgp.crypto.publicKey.rsa.decrypt(result.toUint8Array(), n, e, d, p, q, u);
|
|
||||||
expect(decrypted).to.deep.equal(message);
|
expect(decrypted).to.deep.equal(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -155,14 +155,4 @@ module.exports = () => describe('BigInteger interface', function() {
|
||||||
const expected = nBN.testn(5) ? 1 : 0;
|
const expected = nBN.testn(5) ? 1 : 0;
|
||||||
expect(n.getBit(i) === expected).to.be.true;
|
expect(n.getBit(i) === expected).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('MPI and BigInteger conversions', function() {
|
|
||||||
it('MPI to/from BigInteger is correct', async function() {
|
|
||||||
const input = '417653931840771530406225971293556769925351769207235721650257629558293828796031115397206059067934284452829611906818956352854418342467914729341523414945427019410284762464062112274326172407819051167058569790660930309496043254270888417520676082271432948852231332576271876251597199882908964994070268531832274431027';
|
|
||||||
const n = new BigInteger(input);
|
|
||||||
const mpi = new openpgp.MPI(n);
|
|
||||||
|
|
||||||
expect((await mpi.toBigInteger()).equal(n)).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1611,16 +1611,12 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
|
||||||
|
|
||||||
const opt = { rsaBits: 512, userIds: { name:'test', email:'a@b.com' }, passphrase: null };
|
const opt = { rsaBits: 512, userIds: { name:'test', email:'a@b.com' }, passphrase: null };
|
||||||
if (openpgp.util.getWebCryptoAll()) { opt.rsaBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
|
if (openpgp.util.getWebCryptoAll()) { opt.rsaBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
|
||||||
return openpgp.generateKey(opt).then(function(gen) {
|
const { key: generatedKey } = await openpgp.generateKey(opt);
|
||||||
const generatedKey = gen.key;
|
const detachedSig = await msg.signDetached([generatedKey, privKey2]);
|
||||||
return msg.signDetached([generatedKey, privKey2]).then(detachedSig => {
|
const result = await msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]);
|
||||||
return msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]).then(async result => {
|
|
||||||
expect(await result[0].verified).to.be.true;
|
expect(await result[0].verified).to.be.true;
|
||||||
expect(await result[1].verified).to.be.true;
|
expect(await result[1].verified).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Sign message with key without password', function() {
|
it('Sign message with key without password', function() {
|
||||||
const opt = { userIds: { name:'test', email:'a@b.com' }, passphrase: null };
|
const opt = { userIds: { name:'test', email:'a@b.com' }, passphrase: null };
|
||||||
|
|
|
@ -216,8 +216,8 @@ module.exports = () => (openpgp.config.ci ? describe.skip : describe)('X25519 Cr
|
||||||
const util = openpgp.util;
|
const util = openpgp.util;
|
||||||
function testVector(vector) {
|
function testVector(vector) {
|
||||||
const curve = new elliptic.Curve('ed25519');
|
const curve = new elliptic.Curve('ed25519');
|
||||||
const { publicKey } = openpgp.crypto.publicKey.nacl.sign.keyPair.fromSeed(openpgp.util.hexToUint8Array(vector.SECRET_KEY));
|
const { publicKey } = openpgp.crypto.publicKey.nacl.sign.keyPair.fromSeed(util.hexToUint8Array(vector.SECRET_KEY));
|
||||||
expect(publicKey).to.deep.equal(openpgp.util.hexToUint8Array(vector.PUBLIC_KEY));
|
expect(publicKey).to.deep.equal(util.hexToUint8Array(vector.PUBLIC_KEY));
|
||||||
const data = util.strToUint8Array(vector.MESSAGE);
|
const data = util.strToUint8Array(vector.MESSAGE);
|
||||||
const privateParams = {
|
const privateParams = {
|
||||||
seed: util.hexToUint8Array(vector.SECRET_KEY)
|
seed: util.hexToUint8Array(vector.SECRET_KEY)
|
||||||
|
@ -226,17 +226,14 @@ module.exports = () => (openpgp.config.ci ? describe.skip : describe)('X25519 Cr
|
||||||
oid: new openpgp.OID(curve.oid),
|
oid: new openpgp.OID(curve.oid),
|
||||||
Q: util.hexToUint8Array('40' + vector.PUBLIC_KEY)
|
Q: util.hexToUint8Array('40' + vector.PUBLIC_KEY)
|
||||||
};
|
};
|
||||||
const msg_MPIs = [
|
const R = util.hexToUint8Array(vector.SIGNATURE.R);
|
||||||
new openpgp.MPI(util.uint8ArrayToStr(util.hexToUint8Array(vector.SIGNATURE.R).reverse())),
|
const S = util.hexToUint8Array(vector.SIGNATURE.S);
|
||||||
new openpgp.MPI(util.uint8ArrayToStr(util.hexToUint8Array(vector.SIGNATURE.S).reverse()))
|
|
||||||
];
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
signature.sign(22, undefined, publicParams, privateParams, undefined, data).then(signed => {
|
signature.sign(22, undefined, publicParams, privateParams, undefined, data).then(({ r, s }) => {
|
||||||
const len = (((signed[0] << 8) | signed[1]) + 7) / 8;
|
expect(R).to.deep.eq(r);
|
||||||
expect(util.hexToUint8Array(vector.SIGNATURE.R)).to.deep.eq(signed.slice(2, 2 + len));
|
expect(S).to.deep.eq(s);
|
||||||
expect(util.hexToUint8Array(vector.SIGNATURE.S)).to.deep.eq(signed.slice(4 + len));
|
|
||||||
}),
|
}),
|
||||||
signature.verify(22, undefined, msg_MPIs, publicParams, undefined, data).then(result => {
|
signature.verify(22, undefined, { r: R, s: S }, publicParams, undefined, data).then(result => {
|
||||||
expect(result).to.be.true;
|
expect(result).to.be.true;
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user