From 06952b4e30c13e3f9d75cdffa8b88a44a5bb4fdf Mon Sep 17 00:00:00 2001 From: Aron Wussler Date: Fri, 18 Jan 2019 16:06:57 +0100 Subject: [PATCH 1/9] Make ephemeral secret available from ECDH module --- src/crypto/public_key/elliptic/ecdh.js | 70 +++++++++++++++++++------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index c5421189..3347d313 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -58,6 +58,30 @@ async function kdf(hash_algo, X, length, param) { return digest.subarray(0, length); } +/** + * Generate ECDHE ephemeral key and secret from public key + * + * @param {module:type/oid} oid Elliptic curve object identifier + * @param {module:enums.symmetric} cipher_algo Symmetric cipher to use + * @param {module:enums.hash} hash_algo Hash algorithm to use + * @param {Uint8Array} Q Recipient public key + * @param {String} fingerprint Recipient fingerprint + * @returns {Promise<{V: BN, C: Uint8Array}>} Returns public part of ephemeral key and generated ephemeral secret + * @async + */ +async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint) { + const curve = new Curve(oid); + const param = buildEcdhParam(enums.publicKey.ecdh, oid, cipher_algo, hash_algo, fingerprint); + cipher_algo = enums.read(enums.symmetric, cipher_algo); + const v = await curve.genKeyPair(); + Q = curve.keyFromPublic(Q); + const S = v.derive(Q); + const Z = await kdf(hash_algo, S, cipher[cipher_algo].keySize, param); + return { + V: new BN(v.getPublic()), + Z: Z + }; +} /** * Encrypt and wrap a session key @@ -68,22 +92,38 @@ async function kdf(hash_algo, X, length, param) { * @param {module:type/mpi} m Value derived from session key (RFC 6637) * @param {Uint8Array} Q Recipient public key * @param {String} fingerprint Recipient fingerprint - * @returns {Promise<{V: BN, C: BN}>} Returns ephemeral key and encoded session key + * @returns {Promise<{V: BN, C: BN}>} Returns public part of ephemeral key and encoded session key * @async */ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { + const key = await genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint); + const C = aes_kw.wrap(key.Z, m.toString()); + return { + V: key.V, + C: C + }; +} + +/** + * Generate ECDHE secret from private key and public part of ephemeral key + * + * @param {module:type/oid} oid Elliptic curve object identifier + * @param {module:enums.symmetric} cipher_algo Symmetric cipher to use + * @param {module:enums.hash} hash_algo Hash algorithm to use + * @param {BN} V Public part of ephemeral key + * @param {Uint8Array} d Recipient private key + * @param {String} fingerprint Recipient fingerprint + * @returns {Promise} Generated ephemeral secret + * @async + */ +async function genPrivateEphemeralKey(oid, cipher_algo, hash_algo, V, d, fingerprint) { const curve = new Curve(oid); const param = buildEcdhParam(enums.publicKey.ecdh, oid, cipher_algo, hash_algo, fingerprint); cipher_algo = enums.read(enums.symmetric, cipher_algo); - const v = await curve.genKeyPair(); - Q = curve.keyFromPublic(Q); - const S = v.derive(Q); - const Z = await kdf(hash_algo, S, cipher[cipher_algo].keySize, param); - const C = aes_kw.wrap(Z, m.toString()); - return { - V: new BN(v.getPublic()), - C: C - }; + V = curve.keyFromPublic(V); + d = curve.keyFromPrivate(d); + const S = d.derive(V); + return kdf(hash_algo, S, cipher[cipher_algo].keySize, param); } /** @@ -100,14 +140,8 @@ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { * @async */ async function decrypt(oid, cipher_algo, hash_algo, V, C, d, fingerprint) { - const curve = new Curve(oid); - const param = buildEcdhParam(enums.publicKey.ecdh, oid, cipher_algo, hash_algo, fingerprint); - cipher_algo = enums.read(enums.symmetric, cipher_algo); - V = curve.keyFromPublic(V); - d = curve.keyFromPrivate(d); - const S = d.derive(V); - const Z = await kdf(hash_algo, S, cipher[cipher_algo].keySize, param); + const Z = await genPrivateEphemeralKey(oid, cipher_algo, hash_algo, V, d, fingerprint); return new BN(aes_kw.unwrap(Z, C)); } -export default { encrypt, decrypt }; +export default { encrypt, decrypt, genPublicEphemeralKey, genPrivateEphemeralKey }; From f77ebc76054395375119877576e944270b447f17 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Fri, 18 Jan 2019 16:40:13 +0100 Subject: [PATCH 2/9] Update src/crypto/public_key/elliptic/ecdh.js Co-Authored-By: wussler --- src/crypto/public_key/elliptic/ecdh.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index 3347d313..80a51a10 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -66,7 +66,7 @@ async function kdf(hash_algo, X, length, param) { * @param {module:enums.hash} hash_algo Hash algorithm to use * @param {Uint8Array} Q Recipient public key * @param {String} fingerprint Recipient fingerprint - * @returns {Promise<{V: BN, C: Uint8Array}>} Returns public part of ephemeral key and generated ephemeral secret + * @returns {Promise<{V: BN, Z: Uint8Array}>} Returns public part of ephemeral key and generated ephemeral secret * @async */ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint) { From 680aa03bcde7e5150104dc01a0ba8fa909f2ad2a Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Fri, 18 Jan 2019 16:40:22 +0100 Subject: [PATCH 3/9] Update src/crypto/public_key/elliptic/ecdh.js Co-Authored-By: wussler --- src/crypto/public_key/elliptic/ecdh.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index 80a51a10..66ee9598 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -96,7 +96,7 @@ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint * @async */ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { - const key = await genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint); + const { V, Z } = await genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint); const C = aes_kw.wrap(key.Z, m.toString()); return { V: key.V, From 31f72fb64d19a0df41e641312fbea8c062c822ef Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Fri, 18 Jan 2019 16:40:31 +0100 Subject: [PATCH 4/9] Update src/crypto/public_key/elliptic/ecdh.js Co-Authored-By: wussler --- src/crypto/public_key/elliptic/ecdh.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index 66ee9598..d44f1232 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -98,7 +98,7 @@ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { const { V, Z } = await genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint); const C = aes_kw.wrap(key.Z, m.toString()); - return { + return { V, C }; V: key.V, C: C }; From 4c809a484602265587c800f1142b97f37944af51 Mon Sep 17 00:00:00 2001 From: Aron Wussler Date: Mon, 21 Jan 2019 14:57:02 +0100 Subject: [PATCH 5/9] Fix to returns --- src/crypto/public_key/elliptic/ecdh.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index d44f1232..027cb630 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -76,10 +76,9 @@ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint const v = await curve.genKeyPair(); Q = curve.keyFromPublic(Q); const S = v.derive(Q); - const Z = await kdf(hash_algo, S, cipher[cipher_algo].keySize, param); return { V: new BN(v.getPublic()), - Z: Z + Z: await kdf(hash_algo, S, cipher[cipher_algo].keySize, param) }; } @@ -97,11 +96,8 @@ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint */ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { const { V, Z } = await genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint); - const C = aes_kw.wrap(key.Z, m.toString()); + const C = aes_kw.wrap(Z, m.toString()); return { V, C }; - V: key.V, - C: C - }; } /** From 1face482ba6268e3be8ea6ee448f3a9201097155 Mon Sep 17 00:00:00 2001 From: Aron Wussler Date: Mon, 21 Jan 2019 15:35:45 +0100 Subject: [PATCH 6/9] Naming --- src/crypto/public_key/elliptic/ecdh.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index 027cb630..aff0a232 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -76,10 +76,9 @@ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint const v = await curve.genKeyPair(); Q = curve.keyFromPublic(Q); const S = v.derive(Q); - return { - V: new BN(v.getPublic()), - Z: await kdf(hash_algo, S, cipher[cipher_algo].keySize, param) - }; + const V = new BN(v.getPublic()); + const Z = await kdf(hash_algo, S, cipher[cipher_algo].keySize, param); + return { V, Z }; } /** From 6d9160dd876a72df627ab27f8b4dc53f794ef185 Mon Sep 17 00:00:00 2001 From: wussler Date: Tue, 22 Jan 2019 16:22:05 +0100 Subject: [PATCH 7/9] Fix mistake in documentation --- src/crypto/public_key/elliptic/ecdh.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index aff0a232..343ca5ff 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -105,7 +105,7 @@ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { * @param {module:type/oid} oid Elliptic curve object identifier * @param {module:enums.symmetric} cipher_algo Symmetric cipher to use * @param {module:enums.hash} hash_algo Hash algorithm to use - * @param {BN} V Public part of ephemeral key + * @param {Uint8Array} V Public part of ephemeral key * @param {Uint8Array} d Recipient private key * @param {String} fingerprint Recipient fingerprint * @returns {Promise} Generated ephemeral secret @@ -127,7 +127,7 @@ async function genPrivateEphemeralKey(oid, cipher_algo, hash_algo, V, d, fingerp * @param {module:type/oid} oid Elliptic curve object identifier * @param {module:enums.symmetric} cipher_algo Symmetric cipher to use * @param {module:enums.hash} hash_algo Hash algorithm to use - * @param {BN} V Public part of ephemeral key + * @param {Uint8Array} V Public part of ephemeral key * @param {Uint8Array} C Encrypted and wrapped value derived from session key * @param {Uint8Array} d Recipient private key * @param {String} fingerprint Recipient fingerprint From 2975e49dd0be89bd7a18560f5baf3a303cc820b7 Mon Sep 17 00:00:00 2001 From: wussler Date: Tue, 22 Jan 2019 16:24:55 +0100 Subject: [PATCH 8/9] genPublicEphemeralKey to return Uint8Array --- src/crypto/public_key/elliptic/ecdh.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index 343ca5ff..6e01c943 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -61,12 +61,12 @@ async function kdf(hash_algo, X, length, param) { /** * Generate ECDHE ephemeral key and secret from public key * - * @param {module:type/oid} oid Elliptic curve object identifier - * @param {module:enums.symmetric} cipher_algo Symmetric cipher to use - * @param {module:enums.hash} hash_algo Hash algorithm to use - * @param {Uint8Array} Q Recipient public key - * @param {String} fingerprint Recipient fingerprint - * @returns {Promise<{V: BN, Z: Uint8Array}>} Returns public part of ephemeral key and generated ephemeral secret + * @param {module:type/oid} oid Elliptic curve object identifier + * @param {module:enums.symmetric} cipher_algo Symmetric cipher to use + * @param {module:enums.hash} hash_algo Hash algorithm to use + * @param {Uint8Array} Q Recipient public key + * @param {String} fingerprint Recipient fingerprint + * @returns {Promise<{V: Uint8Array, Z: Uint8Array}>} Returns public part of ephemeral key and generated ephemeral secret * @async */ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint) { @@ -76,7 +76,7 @@ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint const v = await curve.genKeyPair(); Q = curve.keyFromPublic(Q); const S = v.derive(Q); - const V = new BN(v.getPublic()); + const V = new Uint8Array(v.getPublic()); const Z = await kdf(hash_algo, S, cipher[cipher_algo].keySize, param); return { V, Z }; } @@ -95,8 +95,10 @@ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint */ async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { const { V, Z } = await genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint); - const C = aes_kw.wrap(Z, m.toString()); - return { V, C }; + return { + V: BN(V), + C: aes_kw.wrap(Z, m.toString()) + }; } /** From 6b19af0a63e41eae0d6642b9e1b4ee86648201d1 Mon Sep 17 00:00:00 2001 From: wussler Date: Tue, 22 Jan 2019 16:50:06 +0100 Subject: [PATCH 9/9] new BN, fix doc --- src/crypto/public_key/elliptic/ecdh.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js index 6e01c943..430a9cdd 100644 --- a/src/crypto/public_key/elliptic/ecdh.js +++ b/src/crypto/public_key/elliptic/ecdh.js @@ -96,7 +96,7 @@ async function genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) { const { V, Z } = await genPublicEphemeralKey(oid, cipher_algo, hash_algo, Q, fingerprint); return { - V: BN(V), + V: new BN(V), C: aes_kw.wrap(Z, m.toString()) }; } @@ -133,7 +133,7 @@ async function genPrivateEphemeralKey(oid, cipher_algo, hash_algo, V, d, fingerp * @param {Uint8Array} C Encrypted and wrapped value derived from session key * @param {Uint8Array} d Recipient private key * @param {String} fingerprint Recipient fingerprint - * @returns {Promise} Value derived from session + * @returns {Promise} Value derived from session * @async */ async function decrypt(oid, cipher_algo, hash_algo, V, C, d, fingerprint) {