fork-openpgpjs/src/crypto/signature.js
2018-02-22 00:37:42 -08:00

128 lines
5.2 KiB
JavaScript

/**
* @requires bn.js
* @requires crypto/public_key
* @requires crypto/pkcs1
* @requires enums
* @requires util
* @module crypto/signature
*/
import BN from 'bn.js';
import publicKey from './public_key';
import pkcs1 from './pkcs1';
import enums from '../enums';
import util from '../util';
export default {
/**
* 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}
* and {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4}
* for public key and hash algorithms.
* @param {module:enums.publicKey} algo Public key algorithm
* @param {module:enums.hash} hash_algo Hash algorithm
* @param {Array<module:type/mpi>} msg_MPIs Algorithm-specific signature parameters
* @param {Array<module:type/mpi>} pub_MPIs Algorithm-specific public key parameters
* @param {Uint8Array} data Data for which the signature was created
* @return {Boolean} True if signature is valid
*/
verify: async function(algo, hash_algo, msg_MPIs, pub_MPIs, data) {
switch (algo) {
case enums.publicKey.rsa_encrypt_sign:
case enums.publicKey.rsa_encrypt:
case enums.publicKey.rsa_sign: {
const m = msg_MPIs[0].toBN();
const n = pub_MPIs[0].toBN();
const e = pub_MPIs[1].toBN();
const EM = publicKey.rsa.verify(m, n, e);
const EM2 = pkcs1.emsa.encode(hash_algo, util.Uint8Array2str(data), n.byteLength());
return util.hexidump(EM) === EM2;
}
case enums.publicKey.dsa: {
const r = msg_MPIs[0].toBN();
const s = msg_MPIs[1].toBN();
const p = pub_MPIs[0].toBN();
const q = pub_MPIs[1].toBN();
const g = pub_MPIs[2].toBN();
const y = pub_MPIs[3].toBN();
return publicKey.dsa.verify(hash_algo, r, s, data, p, q, g, y);
}
case enums.publicKey.ecdsa: {
const oid = pub_MPIs[0];
const signature = { r: msg_MPIs[0].toUint8Array(), s: msg_MPIs[1].toUint8Array() };
const Q = pub_MPIs[1].toUint8Array();
return publicKey.elliptic.ecdsa.verify(oid, hash_algo, signature, data, Q);
}
case enums.publicKey.eddsa: {
const oid = pub_MPIs[0];
const signature = { R: msg_MPIs[0].toBN(), S: msg_MPIs[1].toBN() };
const Q = pub_MPIs[1].toBN();
return publicKey.elliptic.eddsa.verify(oid, hash_algo, signature, data, Q);
}
default:
throw new Error('Invalid signature algorithm.');
}
},
/**
* Creates a signature on data using specified algorithms and private key parameters.
* 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}
* for public key and hash algorithms.
* @param {module:enums.publicKey} algo Public key algorithm
* @param {module:enums.hash} hash_algo Hash algorithm
* @param {Array<module:type/mpi>} key_params Algorithm-specific public and private key parameters
* @param {Uint8Array} data Data to be signed
* @return {Uint8Array} Signature
*/
sign: async function(algo, hash_algo, key_params, data) {
switch (algo) {
case enums.publicKey.rsa_encrypt_sign:
case enums.publicKey.rsa_encrypt:
case enums.publicKey.rsa_sign: {
const n = key_params[0].toBN();
const e = key_params[1].toBN();
const d = key_params[2].toBN();
data = util.Uint8Array2str(data);
const m = new BN(pkcs1.emsa.encode(hash_algo, data, n.byteLength()), 16);
const signature = publicKey.rsa.sign(m, n, e, d);
return util.Uint8Array2MPI(signature);
}
case enums.publicKey.dsa: {
const p = key_params[0].toBN();
const q = key_params[1].toBN();
const g = key_params[2].toBN();
const x = key_params[4].toBN();
const signature = publicKey.dsa.sign(hash_algo, data, g, p, q, x);
return util.concatUint8Array([
util.Uint8Array2MPI(signature.r.toArrayLike(Uint8Array)),
util.Uint8Array2MPI(signature.s.toArrayLike(Uint8Array))
]);
}
case enums.publicKey.elgamal: {
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
}
case enums.publicKey.ecdsa: {
const oid = key_params[0];
const d = key_params[2].toUint8Array();
const signature = await publicKey.elliptic.ecdsa.sign(oid, hash_algo, data, d);
return util.concatUint8Array([
util.Uint8Array2MPI(signature.r.toArrayLike(Uint8Array)),
util.Uint8Array2MPI(signature.s.toArrayLike(Uint8Array))
]);
}
case enums.publicKey.eddsa: {
const oid = key_params[0];
const d = key_params[2].toBN();
const signature = await publicKey.elliptic.eddsa.sign(oid, hash_algo, data, d);
return util.concatUint8Array([
util.Uint8Array2MPI(Uint8Array.from(signature.R)),
util.Uint8Array2MPI(Uint8Array.from(signature.S))
]);
}
default:
throw new Error('Invalid signature algorithm.');
}
}
};