diff --git a/src/crypto/aes_kw.js b/src/crypto/aes_kw.js index 669858b0..14d5839c 100644 --- a/src/crypto/aes_kw.js +++ b/src/crypto/aes_kw.js @@ -29,8 +29,8 @@ import util from '../util'; /** * AES key wrap * @function - * @param {String} key - * @param {String} data + * @param {Uint8Array} key + * @param {Uint8Array} data * @returns {Uint8Array} */ export function wrap(key, data) { diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js index 5672e8e9..e1558b3d 100644 --- a/src/crypto/crypto.js +++ b/src/crypto/crypto.js @@ -247,7 +247,7 @@ export function parseEncSessionKeyParams(algo, bytes) { * @param {Object} params The key parameters indexed by name * @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 param = params[name]; return util.isUint8Array(param) ? util.uint8ArrayToMpi(param) : param.write(); diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index 53a4852d..9e1a90af 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -38,7 +38,6 @@ import hash from '../../hash'; import enums from '../../../enums'; import util from '../../../util'; import * as pkcs5 from '../../pkcs5'; -import MPI from '../../../type/mpi'; import { keyFromPublic, keyFromPrivate, getIndutnyCurve } from './indutnyKey'; const webCrypto = util.getWebCrypto(); @@ -135,14 +134,14 @@ async function genPublicEphemeralKey(curve, Q) { * @async */ 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 { publicKey, sharedKey } = await genPublicEphemeralKey(curve, Q); const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint); const cipher_algo = enums.read(enums.symmetric, kdfParams.cipher); 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 }; } diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js index 9c2e99a4..f3845228 100644 --- a/src/crypto/public_key/elliptic/eddsa.js +++ b/src/crypto/public_key/elliptic/eddsa.js @@ -38,8 +38,8 @@ nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest()); * @param {Uint8Array} publicKey Public key * @param {Uint8Array} privateKey Private key used to sign the message * @param {Uint8Array} hashed The hashed message - * @returns {{R: Uint8Array, - * S: Uint8Array}} Signature of the message + * @returns {{r: Uint8Array, + * s: Uint8Array}} Signature of the message * @async */ 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); // EdDSA signature params are returned in little-endian format return { - R: signature.subarray(0, 32), - S: signature.subarray(32) + r: signature.subarray(0, 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 * @param {module:type/oid} oid Elliptic curve object identifier * @param {module:enums.hash} hash_algo Hash algorithm used in the signature - * @param {{R: Uint8Array, - S: Uint8Array}} signature Signature to verify the message + * @param {{r: Uint8Array, + s: Uint8Array}} signature Signature to verify the message * @param {Uint8Array} m Message to verify * @param {Uint8Array} publicKey Public key used to verify the message * @param {Uint8Array} hashed The hashed message * @returns {Boolean} * @async */ -export async function verify(oid, hash_algo, { R, S }, m, publicKey, hashed) { - const signature = util.concatUint8Array([R, S]); +export async function verify(oid, hash_algo, { r, s }, m, publicKey, hashed) { + const signature = util.concatUint8Array([r, s]); return nacl.sign.detached.verify(hashed, signature, publicKey.subarray(1)); } /** diff --git a/src/crypto/signature.js b/src/crypto/signature.js index 2adda547..fc42f2ba 100644 --- a/src/crypto/signature.js +++ b/src/crypto/signature.js @@ -10,48 +10,87 @@ import publicKey from './public_key'; import enums from '../enums'; 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. * 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 {Object} publicParams Algorithm-specific public key parameters - * @param {Uint8Array} data Data for which the signature was created - * @param {Uint8Array} hashed The hashed data - * @returns {Boolean} True if signature is valid + * @param {module:enums.publicKey} algo Public key algorithm + * @param {module:enums.hash} hashAlgo Hash algorithm + * @param {Object} signature Named algorithm-specific signature parameters + * @param {Object} publicParams Algorithm-specific public key parameters + * @param {Uint8Array} data Data for which the signature was created + * @param {Uint8Array} hashed The hashed data + * @returns {Boolean} True if signature is valid * @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) { case enums.publicKey.rsaEncryptSign: case enums.publicKey.rsaEncrypt: case enums.publicKey.rsaSign: { const { n, e } = publicParams; - const m = msg_MPIs[0].toUint8Array('be', n.length); - return publicKey.rsa.verify(hash_algo, data, m, n, e, hashed); + const { s } = signature; + return publicKey.rsa.verify(hashAlgo, data, s, n, e, hashed); } case enums.publicKey.dsa: { - const r = await msg_MPIs[0].toUint8Array(); - const s = await msg_MPIs[1].toUint8Array(); 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: { const { oid, Q } = publicParams; - const signature = { r: msg_MPIs[0].toUint8Array(), s: msg_MPIs[1].toUint8Array() }; - return publicKey.elliptic.ecdsa.verify(oid, hash_algo, signature, data, Q, hashed); + return publicKey.elliptic.ecdsa.verify(oid, hashAlgo, signature, data, Q, hashed); } case enums.publicKey.eddsa: { const { oid, Q } = publicParams; - // EdDSA signature params are expected in little-endian format - 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); + return publicKey.elliptic.eddsa.verify(oid, hashAlgo, signature, data, Q, hashed); } default: 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} * for public key and hash algorithms. * @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} privateKeyParams Algorithm-specific public and private key parameters * @param {Uint8Array} data Data to be signed * @param {Uint8Array} hashed The hashed data - * @returns {Uint8Array} Signature + * @returns {Object} Signature Object containing named signature parameters * @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) { throw new Error('Missing key parameters'); } @@ -82,17 +121,13 @@ export async function sign(algo, hash_algo, publicKeyParams, privateKeyParams, d case enums.publicKey.rsaSign: { const { n, e } = publicKeyParams; const { d, p, q, u } = privateKeyParams; - const signature = await publicKey.rsa.sign(hash_algo, data, n, e, d, p, q, u, hashed); - return util.uint8ArrayToMpi(signature); + const s = await publicKey.rsa.sign(hashAlgo, data, n, e, d, p, q, u, hashed); + return { s }; } case enums.publicKey.dsa: { const { g, p, q } = publicKeyParams; const { x } = privateKeyParams; - const signature = await publicKey.dsa.sign(hash_algo, hashed, g, p, q, x); - return util.concatUint8Array([ - util.uint8ArrayToMpi(signature.r), - util.uint8ArrayToMpi(signature.s) - ]); + return publicKey.dsa.sign(hashAlgo, hashed, g, p, q, x); } case enums.publicKey.elgamal: { 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: { const { oid, Q } = publicKeyParams; const { d } = privateKeyParams; - const signature = await publicKey.elliptic.ecdsa.sign(oid, hash_algo, data, Q, d, hashed); - return util.concatUint8Array([ - util.uint8ArrayToMpi(signature.r), - util.uint8ArrayToMpi(signature.s) - ]); + return publicKey.elliptic.ecdsa.sign(oid, hashAlgo, data, Q, d, hashed); } case enums.publicKey.eddsa: { const { oid, Q } = publicKeyParams; const { seed } = privateKeyParams; - const signature = await publicKey.elliptic.eddsa.sign(oid, hash_algo, data, Q, seed, hashed); - return util.concatUint8Array([ - util.uint8ArrayToMpi(signature.R), - util.uint8ArrayToMpi(signature.S) - ]); + return publicKey.elliptic.eddsa.sign(oid, hashAlgo, data, Q, seed, hashed); } default: throw new Error('Invalid signature algorithm.'); diff --git a/src/index.js b/src/index.js index b1efb6a8..6d512fd3 100644 --- a/src/index.js +++ b/src/index.js @@ -52,12 +52,6 @@ export { default as util } from './util'; */ export * from './packet'; -/** - * @see module:type/mpi - * @name module:openpgp.MPI - */ -export { default as MPI } from './type/mpi'; - /** * @see module:type/s2k * @name module:openpgp.S2K diff --git a/src/key/helper.js b/src/key/helper.js index 6fa49059..9a7eb485 100644 --- a/src/key/helper.js +++ b/src/key/helper.js @@ -238,7 +238,7 @@ export async function mergeSignatures(source, dest, attr, checkFn) { await Promise.all(source.map(async function(sourceSig) { if (!sourceSig.isExpired() && (!checkFn || await checkFn(sourceSig)) && !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); } diff --git a/src/packet/public_key.js b/src/packet/public_key.js index 8d6542ca..b2ac9728 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -19,7 +19,6 @@ /** * @requires type/keyid - * @requires type/mpi * @requires config * @requires crypto * @requires enums @@ -142,7 +141,7 @@ class PublicKeyPacket { const algo = enums.write(enums.publicKey, this.algorithm); arr.push(new Uint8Array([algo])); - const params = crypto.serializeKeyParams(algo, this.publicParams); + const params = crypto.serializeParams(algo, this.publicParams); if (this.version === 5) { // A four-octet scalar octet count for the following key material arr.push(util.writeNumber(params.length, 4)); diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js index db0ca210..f414007a 100644 --- a/src/packet/public_key_encrypted_session_key.js +++ b/src/packet/public_key_encrypted_session_key.js @@ -17,7 +17,6 @@ /** * @requires type/keyid - * @requires type/mpi * @requires crypto * @requires enums * @requires util @@ -56,8 +55,8 @@ class PublicKeyEncryptedSessionKeyPacket { this.sessionKey = null; this.sessionKeyAlgorithm = null; - /** @type {Array} */ - this.encrypted = []; + /** @type {Object} */ + this.encrypted = {}; } /** @@ -86,7 +85,7 @@ class PublicKeyEncryptedSessionKeyPacket { new Uint8Array([this.version]), this.publicKeyId.write(), new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)]), - crypto.serializeKeyParams(algo, this.encrypted) + crypto.serializeParams(algo, this.encrypted) ]; return util.concatUint8Array(arr); diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 8ccd3dbe..f8f92f84 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -211,7 +211,7 @@ class SecretKeyPacket extends PublicKeyPacket { if (!this.isDummy()) { if (!this.s2k_usage) { 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([ cleartextParams, util.writeChecksum(cleartextParams) @@ -294,7 +294,7 @@ class SecretKeyPacket extends PublicKeyPacket { this.s2k = new type_s2k(); this.s2k.salt = await crypto.random.getRandomBytes(8); 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'; const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric); const blockLen = crypto.cipher[this.symmetric].blockSize; diff --git a/src/packet/signature.js b/src/packet/signature.js index 275e7c7e..ffd7da0c 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -19,7 +19,6 @@ * @requires web-stream-tools * @requires packet/packet * @requires type/keyid - * @requires type/mpi * @requires crypto * @requires enums * @requires util @@ -28,7 +27,6 @@ import stream from 'web-stream-tools'; import { readSimpleLength, writeSimpleLength } from './packet'; import type_keyid from '../type/keyid.js'; -import type_mpi from '../type/mpi.js'; import crypto from '../crypto'; import enums from '../enums'; import util from '../util'; @@ -133,7 +131,19 @@ class SignaturePacket { this.signedHashValue = bytes.subarray(i, 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} + */ + 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() { @@ -141,7 +151,7 @@ class SignaturePacket { arr.push(this.signatureData); arr.push(this.write_unhashed_sub_packets()); arr.push(this.signedHashValue); - arr.push(stream.clone(this.signature)); + arr.push(this.write_params()); return util.concat(arr); } @@ -181,9 +191,9 @@ class SignaturePacket { publicKeyAlgorithm, hashAlgorithm, key.publicParams, key.privateParams, toHash, await stream.readToEnd(hash) ); if (streaming) { - this.signature = stream.fromAsync(signed); + this.params = signed(); } else { - this.signature = await signed(); + this.params = await signed(); // Store the fact that this signature is valid, e.g. for when we call `await // getLatestValidSignature(this.revocationSignatures, key, data)` later. @@ -661,6 +671,7 @@ class SignaturePacket { * @param {module:enums.signature} signatureType expected signature type * @param {String|Object} data data which on the signature applies * @param {Boolean} detached (optional) whether to verify a detached signature + * @param {Boolean} streaming (optional) whether to process data as a stream * @returns {Promise} True if message is verified, else false. * @async */ @@ -687,33 +698,10 @@ class SignaturePacket { throw new Error('Message digest did not match'); } - let mpicount = 0; - // Algorithm-Specific Fields for RSA signatures: - // - multiprecision number (MPI) of RSA signature value m**d mod n. - if (publicKeyAlgorithm > 0 && publicKeyAlgorithm < 4) { - mpicount = 1; + this.params = await this.params; - // 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( - publicKeyAlgorithm, hashAlgorithm, mpi, key.publicParams, + publicKeyAlgorithm, hashAlgorithm, this.params, key.publicParams, toHash, hash ); if (!verified) { diff --git a/src/type/mpi.js b/src/type/mpi.js deleted file mode 100644 index 6b5df1ef..00000000 --- a/src/type/mpi.js +++ /dev/null @@ -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; diff --git a/src/util.js b/src/util.js index 431d4245..fe9991fd 100644 --- a/src/util.js +++ b/src/util.js @@ -194,9 +194,6 @@ export default { /** * 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 * @returns {Uint8Array} MPI-formatted Uint8Array */ diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js index 63171ba1..c8f2c313 100644 --- a/test/crypto/crypto.js +++ b/test/crypto/crypto.js @@ -211,35 +211,24 @@ module.exports = () => describe('API functional testing', function() { describe('Sign and verify', function () { it('RSA', async function () { - return crypto.signature.sign( - 1, 2, RSAPublicParams, RSAPrivateParams, data, await crypto.hash.digest(2, data) - ).then(async RSAsignedData => { - const RSAsignedDataMPI = new openpgp.MPI(); - RSAsignedDataMPI.read(RSAsignedData); - return crypto.signature.verify( - 1, 2, [RSAsignedDataMPI], RSAPublicParams, data, await crypto.hash.digest(2, data) - ).then(success => { - return expect(success).to.be.true; - }); - }); + const RSAsignedData = await crypto.signature.sign( + openpgp.enums.publicKey.rsaEncryptSign, openpgp.enums.hash.sha1, RSAPublicParams, RSAPrivateParams, data, await crypto.hash.digest(2, data) + ); + const success = await crypto.signature.verify( + openpgp.enums.publicKey.rsaEncryptSign, openpgp.enums.hash.sha1, RSAsignedData, RSAPublicParams, data, await crypto.hash.digest(2, data) + ); + return expect(success).to.be.true; }); it('DSA', async function () { - return crypto.signature.sign( - 17, 2, DSAPublicParams, DSAPrivateParams, data, await crypto.hash.digest(2, data) - ).then(async DSAsignedData => { - DSAsignedData = util.uint8ArrayToStr(DSAsignedData); - const DSAmsgMPIs = []; - 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; - }); - }); + const DSAsignedData = await crypto.signature.sign( + openpgp.enums.publicKey.dsa, openpgp.enums.hash.sha1, DSAPublicParams, DSAPrivateParams, data, await crypto.hash.digest(2, data) + ); + const success = await crypto.signature.verify( + openpgp.enums.publicKey.dsa, openpgp.enums.hash.sha1, DSAsignedData, DSAPublicParams, data, await crypto.hash.digest(2, data) + ); + + return expect(success).to.be.true; }); }); diff --git a/test/crypto/rsa.js b/test/crypto/rsa.js index 3719f702..67558f2a 100644 --- a/test/crypto/rsa.js +++ b/test/crypto/rsa.js @@ -39,8 +39,7 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra const { n, e, d, p, q, u } = { ...publicParams, ...privateParams }; const message = await openpgp.crypto.generateSessionKey('aes256'); 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(result.toUint8Array(), n, e, d, p, q, u); + const decrypted = await openpgp.crypto.publicKey.rsa.decrypt(encrypted, n, e, d, p, q, u); expect(decrypted).to.deep.equal(message); }); diff --git a/test/general/biginteger.js b/test/general/biginteger.js index 29171198..befa6347 100644 --- a/test/general/biginteger.js +++ b/test/general/biginteger.js @@ -155,14 +155,4 @@ module.exports = () => describe('BigInteger interface', function() { const expected = nBN.testn(5) ? 1 : 0; 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; - }); - }); }); diff --git a/test/general/signature.js b/test/general/signature.js index b007a3c2..010ad1a2 100644 --- a/test/general/signature.js +++ b/test/general/signature.js @@ -656,7 +656,7 @@ WPVMYDzj6X7I1A+nWeNiPlp2PoUUUvdCLisY1aU1wyTJa7wBsLARsrhXk5/R1pQt Blk+CJ7ytHy6En8542bB/yC+Z9/zWbVuhg== =jmT1 -----END PGP PUBLIC KEY BLOCK-----`; - + const msg_sig_expired = ['-----BEGIN PGP MESSAGE-----', 'Comment: GPGTools - https://gpgtools.org', @@ -1609,21 +1609,17 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA const privKey2 = await openpgp.readArmoredKey(priv_key_arm2); await privKey2.decrypt('hello world'); - 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 - return openpgp.generateKey(opt).then(function(gen) { - const generatedKey = gen.key; - return msg.signDetached([generatedKey, privKey2]).then(detachedSig => { - return msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]).then(async result => { - expect(await result[0].verified).to.be.true; - expect(await result[1].verified).to.be.true; - }); - }); - }); + const { key: generatedKey } = await openpgp.generateKey(opt); + const detachedSig = await msg.signDetached([generatedKey, privKey2]); + const result = await msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]); + expect(await result[0].verified).to.be.true; + expect(await result[1].verified).to.be.true; }); 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 }; return openpgp.generateKey(opt).then(function(gen) { const key = gen.key; let message = openpgp.Message.fromText('hello world'); diff --git a/test/general/streaming.js b/test/general/streaming.js index abbb06dc..4814d2fe 100644 --- a/test/general/streaming.js +++ b/test/general/streaming.js @@ -971,4 +971,4 @@ module.exports = () => describe('Streaming', function() { expect(await openpgp.stream.readToEnd(decrypted.data)).to.deep.equal(plaintext); }); } -}); \ No newline at end of file +}); diff --git a/test/general/x25519.js b/test/general/x25519.js index 6a092009..2c1016e7 100644 --- a/test/general/x25519.js +++ b/test/general/x25519.js @@ -216,8 +216,8 @@ module.exports = () => (openpgp.config.ci ? describe.skip : describe)('X25519 Cr const util = openpgp.util; function testVector(vector) { const curve = new elliptic.Curve('ed25519'); - const { publicKey } = openpgp.crypto.publicKey.nacl.sign.keyPair.fromSeed(openpgp.util.hexToUint8Array(vector.SECRET_KEY)); - expect(publicKey).to.deep.equal(openpgp.util.hexToUint8Array(vector.PUBLIC_KEY)); + const { publicKey } = openpgp.crypto.publicKey.nacl.sign.keyPair.fromSeed(util.hexToUint8Array(vector.SECRET_KEY)); + expect(publicKey).to.deep.equal(util.hexToUint8Array(vector.PUBLIC_KEY)); const data = util.strToUint8Array(vector.MESSAGE); const privateParams = { 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), Q: util.hexToUint8Array('40' + vector.PUBLIC_KEY) }; - const msg_MPIs = [ - new openpgp.MPI(util.uint8ArrayToStr(util.hexToUint8Array(vector.SIGNATURE.R).reverse())), - new openpgp.MPI(util.uint8ArrayToStr(util.hexToUint8Array(vector.SIGNATURE.S).reverse())) - ]; + const R = util.hexToUint8Array(vector.SIGNATURE.R); + const S = util.hexToUint8Array(vector.SIGNATURE.S); return Promise.all([ - signature.sign(22, undefined, publicParams, privateParams, undefined, data).then(signed => { - const len = (((signed[0] << 8) | signed[1]) + 7) / 8; - expect(util.hexToUint8Array(vector.SIGNATURE.R)).to.deep.eq(signed.slice(2, 2 + len)); - expect(util.hexToUint8Array(vector.SIGNATURE.S)).to.deep.eq(signed.slice(4 + len)); + signature.sign(22, undefined, publicParams, privateParams, undefined, data).then(({ r, s }) => { + expect(R).to.deep.eq(r); + expect(S).to.deep.eq(s); }), - 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; }) ]);