/** * @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} msg_MPIs Algorithm-specific signature parameters * @param {Array} 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} 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.'); } } };