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.
This commit is contained in:
Dan Ristea 2020-09-17 17:33:52 +01:00 committed by Daniel Huigens
parent 400ae63c5e
commit d5dd247b2c
2 changed files with 39 additions and 50 deletions

View File

@ -25,7 +25,6 @@
* @requires crypto/random * @requires crypto/random
* @requires type/ecdh_symkey * @requires type/ecdh_symkey
* @requires type/kdf_params * @requires type/kdf_params
* @requires type/mpi
* @requires type/oid * @requires type/oid
* @requires enums * @requires enums
* @requires util * @requires util
@ -35,23 +34,13 @@
import publicKey from './public_key'; import publicKey from './public_key';
import * as cipher from './cipher'; import * as cipher from './cipher';
import { getRandomBytes } from './random'; 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 KDFParams from '../type/kdf_params';
import type_mpi from '../type/mpi';
import enums from '../enums'; import enums from '../enums';
import util from '../util'; import util from '../util';
import OID from '../type/oid'; import OID from '../type/oid';
import { Curve } from './public_key/elliptic/curves'; 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. * 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. * 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 {Object} publicParams Algorithm-specific public key parameters
* @param {Uint8Array} data Data to be encrypted * @param {Uint8Array} data Data to be encrypted
* @param {Uint8Array} fingerprint Recipient fingerprint * @param {Uint8Array} fingerprint Recipient fingerprint
* @returns {Array<module:type/mpi| * @returns {Object} Encrypted session key parameters
* module:type/ecdh_symkey>} Encrypted session key parameters
* @async * @async
*/ */
export async function publicKeyEncrypt(algo, publicParams, data, fingerprint) { export async function publicKeyEncrypt(algo, publicParams, data, fingerprint) {
const types = getEncSessionKeyParamTypes(algo);
switch (algo) { switch (algo) {
case enums.publicKey.rsaEncrypt: case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign: { case enums.publicKey.rsaEncryptSign: {
const { n, e } = publicParams; const { n, e } = publicParams;
const res = await publicKey.rsa.encrypt(data, n, e); const c = await publicKey.rsa.encrypt(data, n, e);
return constructParams(types, [res]); return { c };
} }
case enums.publicKey.elgamal: { case enums.publicKey.elgamal: {
const { p, g, y } = publicParams; const { p, g, y } = publicParams;
const res = await publicKey.elgamal.encrypt(data, p, g, y); return publicKey.elgamal.encrypt(data, p, g, y);
return constructParams(types, [res.c1, res.c2]);
} }
case enums.publicKey.ecdh: { case enums.publicKey.ecdh: {
const { oid, Q, kdfParams } = publicParams; const { oid, Q, kdfParams } = publicParams;
const { publicKey: V, wrappedKey: C } = await publicKey.elliptic.ecdh.encrypt( const { publicKey: V, wrappedKey: C } = await publicKey.elliptic.ecdh.encrypt(
oid, kdfParams, data, Q, fingerprint); oid, kdfParams, data, Q, fingerprint);
return constructParams(types, [V, C]); return { V, C: new ECDHSymkey(C) };
} }
default: default:
return []; return [];
@ -94,24 +80,22 @@ export async function publicKeyEncrypt(algo, publicParams, data, fingerprint) {
* @param {module:enums.publicKey} algo Public key algorithm * @param {module:enums.publicKey} algo Public key algorithm
* @param {Object} publicKeyParams Algorithm-specific public key parameters * @param {Object} publicKeyParams Algorithm-specific public key parameters
* @param {Object} privateKeyParams Algorithm-specific private key parameters * @param {Object} privateKeyParams Algorithm-specific private key parameters
* @param {Array<module:type/mpi| * @param {Object} sessionKeyParams Encrypted session key parameters
module:type/ecdh_symkey>} data_params Encrypted session key parameters
* @param {Uint8Array} fingerprint Recipient fingerprint * @param {Uint8Array} fingerprint Recipient fingerprint
* @returns {Uint8Array} Decrypted data * @returns {Uint8Array} Decrypted data
* @async * @async
*/ */
export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams, data_params, fingerprint) { export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams, sessionKeyParams, fingerprint) {
switch (algo) { switch (algo) {
case enums.publicKey.rsaEncryptSign: case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaEncrypt: { case enums.publicKey.rsaEncrypt: {
const c = data_params[0].toUint8Array(); const { c } = sessionKeyParams;
const { n, e } = publicKeyParams; const { n, e } = publicKeyParams;
const { d, p, q, u } = privateKeyParams; const { d, p, q, u } = privateKeyParams;
return publicKey.rsa.decrypt(c, n, e, d, p, q, u); return publicKey.rsa.decrypt(c, n, e, d, p, q, u);
} }
case enums.publicKey.elgamal: { case enums.publicKey.elgamal: {
const c1 = data_params[0].toUint8Array(); const { c1, c2 } = sessionKeyParams;
const c2 = data_params[1].toUint8Array();
const p = publicKeyParams.p; const p = publicKeyParams.p;
const x = privateKeyParams.x; const x = privateKeyParams.x;
return publicKey.elgamal.decrypt(c1, c2, p, x); return publicKey.elgamal.decrypt(c1, c2, p, x);
@ -119,10 +103,9 @@ export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams,
case enums.publicKey.ecdh: { case enums.publicKey.ecdh: {
const { oid, Q, kdfParams } = publicKeyParams; const { oid, Q, kdfParams } = publicKeyParams;
const { d } = privateKeyParams; const { d } = privateKeyParams;
const V = data_params[0].toUint8Array(); const { V, C } = sessionKeyParams;
const C = data_params[1].data;
return publicKey.elliptic.ecdh.decrypt( return publicKey.elliptic.ecdh.decrypt(
oid, kdfParams, V, C, Q, d, fingerprint); oid, kdfParams, V, C.data, Q, d, fingerprint);
} }
default: default:
throw new Error('Invalid public key encryption algorithm.'); 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 /** Returns the types comprising the encrypted session key of an algorithm
* @param {module:enums.publicKey} algo The public key algorithm * @param {module:enums.publicKey} algo The key algorithm
* @returns {Array<Object>} The array of types * @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) { switch (algo) {
// Algorithm-Specific Fields for RSA encrypted session keys: // Algorithm-Specific Fields for RSA encrypted session keys:
// - MPI of RSA encrypted value m**e mod n. // - MPI of RSA encrypted value m**e mod n.
case enums.publicKey.rsaEncrypt: case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign: case enums.publicKey.rsaEncryptSign: {
return [type_mpi]; const c = util.readMPI(bytes.subarray(read));
return { c };
}
// Algorithm-Specific Fields for Elgamal encrypted session keys: // Algorithm-Specific Fields for Elgamal encrypted session keys:
// - MPI of Elgamal value g**k mod p // - MPI of Elgamal value g**k mod p
// - MPI of Elgamal value m * y**k mod p // - MPI of Elgamal value m * y**k mod p
case enums.publicKey.elgamal: case enums.publicKey.elgamal: {
return [type_mpi, type_mpi]; 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: // Algorithm-Specific Fields for ECDH encrypted session keys:
// - MPI containing the ephemeral key used to establish the shared secret // - MPI containing the ephemeral key used to establish the shared secret
// - ECDH Symmetric Key // - ECDH Symmetric Key
case enums.publicKey.ecdh: case enums.publicKey.ecdh: {
return [type_mpi, type_ecdh_symkey]; const V = util.readMPI(bytes.subarray(read)); read += V.length + 2;
const C = new ECDHSymkey(); C.read(bytes.subarray(read));
return { V, C };
}
default: default:
throw new Error('Invalid public key encryption algorithm.'); throw new Error('Invalid public key encryption algorithm.');
} }

View File

@ -70,15 +70,8 @@ class PublicKeyEncryptedSessionKeyPacket {
this.publicKeyId.read(bytes.subarray(1, bytes.length)); this.publicKeyId.read(bytes.subarray(1, bytes.length));
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9]); this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9]);
let i = 10;
const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm); const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm);
const types = crypto.getEncSessionKeyParamTypes(algo); this.encrypted = crypto.parseEncSessionKeyParams(algo, bytes.subarray(10));
this.encrypted = crypto.constructParams(types);
for (let j = 0; j < types.length; j++) {
i += this.encrypted[j].read(bytes.subarray(i, bytes.length));
}
} }
/** /**
@ -87,11 +80,14 @@ class PublicKeyEncryptedSessionKeyPacket {
* @returns {Uint8Array} The Uint8Array representation * @returns {Uint8Array} The Uint8Array representation
*/ */
write() { 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++) { const arr = [
arr.push(this.encrypted[i].write()); new Uint8Array([this.version]),
} this.publicKeyId.write(),
new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)]),
crypto.serializeKeyParams(algo, this.encrypted)
];
return util.concatUint8Array(arr); return util.concatUint8Array(arr);
} }