From d5dd247b2cdbc5b47bb6801289bede3ad07df5f3 Mon Sep 17 00:00:00 2001 From: Dan Ristea Date: Thu, 17 Sep 2020 17:33:52 +0100 Subject: [PATCH] Store named session key parameters (#1157) Change session key parameter handling to mirror key parameters. Parameters are stored as an object rather than an array. MPIs are always stored as Uint8Arrays. --- src/crypto/crypto.js | 69 +++++++++---------- .../public_key_encrypted_session_key.js | 20 +++--- 2 files changed, 39 insertions(+), 50 deletions(-) diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js index 2b65b130..5672e8e9 100644 --- a/src/crypto/crypto.js +++ b/src/crypto/crypto.js @@ -25,7 +25,6 @@ * @requires crypto/random * @requires type/ecdh_symkey * @requires type/kdf_params - * @requires type/mpi * @requires type/oid * @requires enums * @requires util @@ -35,23 +34,13 @@ import publicKey from './public_key'; import * as cipher from './cipher'; import { getRandomBytes } from './random'; -import type_ecdh_symkey from '../type/ecdh_symkey'; +import ECDHSymkey from '../type/ecdh_symkey'; import KDFParams from '../type/kdf_params'; -import type_mpi from '../type/mpi'; import enums from '../enums'; import util from '../util'; import OID from '../type/oid'; import { Curve } from './public_key/elliptic/curves'; -export function constructParams(types, data) { - return types.map(function(type, i) { - if (data && data[i]) { - return new type(data[i]); - } - return new type(); - }); -} - /** * Encrypts data using specified algorithm and public key parameters. * See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1} for public key algorithms. @@ -59,29 +48,26 @@ export function constructParams(types, data) { * @param {Object} publicParams Algorithm-specific public key parameters * @param {Uint8Array} data Data to be encrypted * @param {Uint8Array} fingerprint Recipient fingerprint - * @returns {Array} Encrypted session key parameters + * @returns {Object} Encrypted session key parameters * @async */ export async function publicKeyEncrypt(algo, publicParams, data, fingerprint) { - const types = getEncSessionKeyParamTypes(algo); switch (algo) { case enums.publicKey.rsaEncrypt: case enums.publicKey.rsaEncryptSign: { const { n, e } = publicParams; - const res = await publicKey.rsa.encrypt(data, n, e); - return constructParams(types, [res]); + const c = await publicKey.rsa.encrypt(data, n, e); + return { c }; } case enums.publicKey.elgamal: { const { p, g, y } = publicParams; - const res = await publicKey.elgamal.encrypt(data, p, g, y); - return constructParams(types, [res.c1, res.c2]); + return publicKey.elgamal.encrypt(data, p, g, y); } case enums.publicKey.ecdh: { const { oid, Q, kdfParams } = publicParams; const { publicKey: V, wrappedKey: C } = await publicKey.elliptic.ecdh.encrypt( oid, kdfParams, data, Q, fingerprint); - return constructParams(types, [V, C]); + return { V, C: new ECDHSymkey(C) }; } default: return []; @@ -94,24 +80,22 @@ export async function publicKeyEncrypt(algo, publicParams, data, fingerprint) { * @param {module:enums.publicKey} algo Public key algorithm * @param {Object} publicKeyParams Algorithm-specific public key parameters * @param {Object} privateKeyParams Algorithm-specific private key parameters - * @param {Array} data_params Encrypted session key parameters + * @param {Object} sessionKeyParams Encrypted session key parameters * @param {Uint8Array} fingerprint Recipient fingerprint * @returns {Uint8Array} Decrypted data * @async */ -export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams, data_params, fingerprint) { +export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams, sessionKeyParams, fingerprint) { switch (algo) { case enums.publicKey.rsaEncryptSign: case enums.publicKey.rsaEncrypt: { - const c = data_params[0].toUint8Array(); + const { c } = sessionKeyParams; const { n, e } = publicKeyParams; const { d, p, q, u } = privateKeyParams; return publicKey.rsa.decrypt(c, n, e, d, p, q, u); } case enums.publicKey.elgamal: { - const c1 = data_params[0].toUint8Array(); - const c2 = data_params[1].toUint8Array(); + const { c1, c2 } = sessionKeyParams; const p = publicKeyParams.p; const x = privateKeyParams.x; return publicKey.elgamal.decrypt(c1, c2, p, x); @@ -119,10 +103,9 @@ export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams, case enums.publicKey.ecdh: { const { oid, Q, kdfParams } = publicKeyParams; const { d } = privateKeyParams; - const V = data_params[0].toUint8Array(); - const C = data_params[1].data; + const { V, C } = sessionKeyParams; return publicKey.elliptic.ecdh.decrypt( - oid, kdfParams, V, C, Q, d, fingerprint); + oid, kdfParams, V, C.data, Q, d, fingerprint); } default: throw new Error('Invalid public key encryption algorithm.'); @@ -222,27 +205,37 @@ export function parsePrivateKeyParams(algo, bytes, publicParams) { } /** Returns the types comprising the encrypted session key of an algorithm - * @param {module:enums.publicKey} algo The public key algorithm - * @returns {Array} The array of types + * @param {module:enums.publicKey} algo The key algorithm + * @param {Uint8Array} bytes The key material to parse + * @returns {Object} The session key parameters referenced by name */ -export function getEncSessionKeyParamTypes(algo) { +export function parseEncSessionKeyParams(algo, bytes) { + let read = 0; switch (algo) { // Algorithm-Specific Fields for RSA encrypted session keys: // - MPI of RSA encrypted value m**e mod n. case enums.publicKey.rsaEncrypt: - case enums.publicKey.rsaEncryptSign: - return [type_mpi]; + case enums.publicKey.rsaEncryptSign: { + const c = util.readMPI(bytes.subarray(read)); + return { c }; + } // Algorithm-Specific Fields for Elgamal encrypted session keys: // - MPI of Elgamal value g**k mod p // - MPI of Elgamal value m * y**k mod p - case enums.publicKey.elgamal: - return [type_mpi, type_mpi]; + case enums.publicKey.elgamal: { + const c1 = util.readMPI(bytes.subarray(read)); read += c1.length + 2; + const c2 = util.readMPI(bytes.subarray(read)); + return { c1, c2 }; + } // Algorithm-Specific Fields for ECDH encrypted session keys: // - MPI containing the ephemeral key used to establish the shared secret // - ECDH Symmetric Key - case enums.publicKey.ecdh: - return [type_mpi, type_ecdh_symkey]; + case enums.publicKey.ecdh: { + const V = util.readMPI(bytes.subarray(read)); read += V.length + 2; + const C = new ECDHSymkey(); C.read(bytes.subarray(read)); + return { V, C }; + } default: throw new Error('Invalid public key encryption algorithm.'); } diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js index ddc29615..db0ca210 100644 --- a/src/packet/public_key_encrypted_session_key.js +++ b/src/packet/public_key_encrypted_session_key.js @@ -70,15 +70,8 @@ class PublicKeyEncryptedSessionKeyPacket { this.publicKeyId.read(bytes.subarray(1, bytes.length)); this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9]); - let i = 10; - const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm); - const types = crypto.getEncSessionKeyParamTypes(algo); - this.encrypted = crypto.constructParams(types); - - for (let j = 0; j < types.length; j++) { - i += this.encrypted[j].read(bytes.subarray(i, bytes.length)); - } + this.encrypted = crypto.parseEncSessionKeyParams(algo, bytes.subarray(10)); } /** @@ -87,11 +80,14 @@ class PublicKeyEncryptedSessionKeyPacket { * @returns {Uint8Array} The Uint8Array representation */ write() { - const arr = [new Uint8Array([this.version]), this.publicKeyId.write(), new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)])]; + const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm); - for (let i = 0; i < this.encrypted.length; i++) { - arr.push(this.encrypted[i].write()); - } + const arr = [ + new Uint8Array([this.version]), + this.publicKeyId.write(), + new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)]), + crypto.serializeKeyParams(algo, this.encrypted) + ]; return util.concatUint8Array(arr); }