From af31c079ada7bd51eb6fda86368ae0489a4899a6 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Tue, 17 Mar 2020 19:58:15 +0100 Subject: [PATCH] test: add RSA-OAEP-256 test vectors from the jose mailing list --- ...ng_rsa-oaep-256_with_a128cbc-hs256.test.js | 102 ++++++++++++++++++ test/cookbook/recipes/index.js | 3 +- ...n_using_rsa-oaep-256_with_a128cbc-hs256.js | 46 ++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 test/cookbook/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.test.js create mode 100644 test/cookbook/recipes/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.js diff --git a/test/cookbook/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.test.js b/test/cookbook/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.test.js new file mode 100644 index 00000000..87511d9d --- /dev/null +++ b/test/cookbook/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.test.js @@ -0,0 +1,102 @@ +const test = require('ava') + +const { oaepHashSupported } = require('../../lib/help/runtime_support') + +if (!oaepHashSupported) return + +const recipe = require('./recipes').get('ml-oeap-256') +const { enc: verifiers } = require('./verifiers') + +const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') + +const { + input: { plaintext, key: jwk }, + encrypting_content: { protected: prot } +} = recipe + +const key = asKey(jwk) + +const keystoreEmpty = new KeyStore() +const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) +const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) + +test(`${recipe.title} - compact encrypt`, t => { + const res = JWE.encrypt(plaintext, key, prot) + verifiers.compact(t, res, recipe.output.compact) + t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) +}) + +test(`${recipe.title} - flattened encrypt`, t => { + const res = JWE.encrypt.flattened(plaintext, key, prot) + verifiers.flattened(t, res, recipe.output.json_flat) + t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) +}) + +test(`${recipe.title} - general encrypt`, t => { + const res = JWE.encrypt.general(plaintext, key, prot) + verifiers.general(t, res, recipe.output.json) + t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) +}) + +test(`${recipe.title} - compact decrypt`, t => { + t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) +}) + +test(`${recipe.title} - flattened decrypt`, t => { + t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) +}) + +test(`${recipe.title} - general decrypt`, t => { + t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) +}) + +;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { + test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { + t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) + }) + + test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { + t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) + }) + + test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { + t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) + }) +}) + +test(`${recipe.title} - compact decrypt (failing)`, t => { + t.throws(() => { + JWE.decrypt(recipe.output.compact, keystoreMatchNone) + }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED', message: 'decryption operation failed' }) +}) + +test(`${recipe.title} - flattened decrypt (failing)`, t => { + t.throws(() => { + JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) + }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED', message: 'decryption operation failed' }) +}) + +test(`${recipe.title} - general decrypt (failing)`, t => { + t.throws(() => { + JWE.decrypt(recipe.output.json, keystoreMatchNone) + }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED', message: 'decryption operation failed' }) +}) + +test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { + t.throws(() => { + JWE.decrypt(recipe.output.compact, keystoreEmpty) + }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) +}) + +test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { + t.throws(() => { + JWE.decrypt(recipe.output.json_flat, keystoreEmpty) + }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) +}) + +test(`${recipe.title} - general decrypt (using empty keystore)`, t => { + t.throws(() => { + JWE.decrypt(recipe.output.json, keystoreEmpty) + }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) +}) diff --git a/test/cookbook/recipes/index.js b/test/cookbook/recipes/index.js index be5fec50..eb65571c 100644 --- a/test/cookbook/recipes/index.js +++ b/test/cookbook/recipes/index.js @@ -27,5 +27,6 @@ module.exports = new Map([ ['5.13', require('./5_13.encrypting_to_multiple_recipients')], ['4.1 rfc7797', require('./rfc7797.4_1.hmac-sha2_b64_false')], ['4.2 rfc7797', require('./rfc7797.4_2.hmac-sha2_b64_false')], - ['A.4 rfc8037', require('./rfc8037.a4.ed25519')] + ['A.4 rfc8037', require('./rfc8037.a4.ed25519')], + ['ml-oeap-256', require('./ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256')] ]) diff --git a/test/cookbook/recipes/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.js b/test/cookbook/recipes/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.js new file mode 100644 index 00000000..eb25696f --- /dev/null +++ b/test/cookbook/recipes/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.js @@ -0,0 +1,46 @@ +module.exports = { + title: 'Key Encryption using RSA-OAEP with AES_CBC_HMAC_SHA2', + input: { + plaintext: "Well, as of this moment, they're on DOUBLE SECRET PROBATION!", + key: { + e: 'AQAB', + n: '2cQJH1f6yF9DcGa8Cmbnhn4LHLs5L6kNb2rxkrNFZArJLRaKvaC3tMCKZ8ZgIpO9bVMPx5UMjJoaf7p9O5BSApVqA2J10fUbdSIomCcDwvGo0eyhty0DILLWTMXzGEVM3BXzuJQoeDkuUCXXcCwA4Msyyd2OHVu-pB2OrGv6fcjHwjINty3UoKm08lCvAevBKHsuA-FFwQII9bycvRx5wRqFUjdMAyiOmLYBHBaJSi11g3HVexMcb29v14PSlVzdGUMN8oboa-zcIyaPrIiczLqAkSXQNdEFHrjsJHfFeNMfOblLM7icKN_tyWujYeItt4kqUIimPn5dHjwgcQYE7w', + d: 'dyUz3ItVceX1Tv1WqtZMnKA_0jN5gWMcL7ayf5JISAlCssGfnUre2C10TH0UQjbVMIh-nLMnD5KNJw9Qz5MR28oGG932Gq7hm__ZeA34l-OCe4DdpgwhpvVSHOU9MS1RdSUpmPavAcA_X6ikrAHXZSaoHhxzUgrNTpvBYQMfJUv_492fStIseQ9rwAMOpCWOiWMZOQm3KJVTLLunXdKf_UxmzmKXYKYZWke3AWIzUqnOfqIjfDTMunF4UWU0zKlhcsaQNmYMVrJGajD1bJdy_dbUU3LE8sx-bdkUI6oBk-sFtTTVyVdQcetG9kChJ5EnY5R6tt_4_xFG5kxzTo6qaQ', + p: '7yQmgE60SL7QrXpAJhChLgKnXWi6C8tVx1lA8FTpphpLaCtK-HbgBVHCprC2CfaM1mxFJZahxgFjC9ehuV8OzMNyFs8kekS82EsQGksi8HJPxyR1fU6ATa36ogPG0nNaqm3EDmYyjowhntgBz2OkbFAsTMHTdna-pZBRJa9lm5U', + q: '6R4dzo9LwHLO73EMQPQsmwXjVOvAS5W6rgQ-BCtMhec_QosAXIVE3AGyfweqZm6rurXCVFykDLwJ30GepLQ8nTlzeV6clx0x70saGGKKVmCsHuVYWwgIRyJTrt4SX29NQDZ_FE52NlO3OhPkj1ExSk_pGMqGRFd26K8g0jJsXXM', + dp: 'VByn-hs0qB2Ncmb8ZycUOgWu7ljmjz1up1ZKU_3ZzJWVDkej7-6H7vcJ-u1OqgRxFv4v9_-aWPWl68VlWbkIkJbx6vniv6qrrXwBZu4klOPwEYBOXsucrzXRYOjpJp5yNl2zRslFYQQC00bwpAxNCdfNLRZDlXhAqCUxlYqyt10', + dq: 'MJFbuGtWZvQEdRJicS3uFSY25LxxRc4eJJ8xpIC44rT5Ew4Otzf0zrlzzM92Cv1HvhCcOiNK8nRCwkbTnJEIh-EuU70IdttYSfilqSruk2x0r8Msk1qrDtbyBF60CToRKC2ycDKgolTyuaDnX4yU7lyTvdyD-L0YQwYpmmFy_k0', + qi: 'vy7XCwZ3jyMGik81TIZDAOQKC8FVUc0TG5KVYfti4tgwzUqFwtuB8Oc1ctCKRbE7uZUPwZh4OsCTLqIvqBQda_kaxOxo5EF7iXj6yHmZ2s8P_Z_u3JLuh-oAT_6kmbLx6CAO0DbtKtxp24Ivc1hDfqSwWORgN1AOrSRCmE3nwxg', + kty: 'RSA' + }, + alg: 'RSA-OAEP-256', + enc: 'A128CBC-HS256' + }, + encrypting_content: { + protected: { + alg: 'RSA-OAEP-256', + enc: 'A128CBC-HS256' + } + }, + output: { + compact: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.fL5IL5cMCjjU9G9_ZjsD2XO0HIwTOwbVwulcZVw31_rx2qTcHzbYhIvrvbcVLTfJzn8xbQ3UEL442ZgZ1PcFYKENYePXiEyvYxPN8dmvj_OfLSJDEqR6kvwOb6nghGtxfzdB_VRvFt2eehbCA3gWpiOYHHvSTFdBPGx2KZHQisLz3oZR8EWiZ1woEpHy8a7FoQ2zzuDlZEJQOUrh09b_EJxmcE2jL6wmEtgabyxy3VgWg3GqSPUISlJZV9HThuVJezzktJdpntRDnAPUqjc8IwByGpMleIQcPuBUseRRPr_OsroOJ6eTl5DuFCmBOKb-eNNw5v-GEcVYr1w7X9oXoA.0frdIwx8P8UAzh1s9_PgOA.RAzILH0xfs0yxzML1CzzGExCfE2_wzWKs0FVuXfM8R5H68yTqTbqIqRCp2feAH5GSvluzmztk2_CkGNSjAyoaw.4nMUXOgmgWvM-08tIZ-h5w', + json: { + recipients: [ + { + encrypted_key: 'fL5IL5cMCjjU9G9_ZjsD2XO0HIwTOwbVwulcZVw31_rx2qTcHzbYhIvrvbcVLTfJzn8xbQ3UEL442ZgZ1PcFYKENYePXiEyvYxPN8dmvj_OfLSJDEqR6kvwOb6nghGtxfzdB_VRvFt2eehbCA3gWpiOYHHvSTFdBPGx2KZHQisLz3oZR8EWiZ1woEpHy8a7FoQ2zzuDlZEJQOUrh09b_EJxmcE2jL6wmEtgabyxy3VgWg3GqSPUISlJZV9HThuVJezzktJdpntRDnAPUqjc8IwByGpMleIQcPuBUseRRPr_OsroOJ6eTl5DuFCmBOKb-eNNw5v-GEcVYr1w7X9oXoA' + } + ], + protected: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', + iv: '0frdIwx8P8UAzh1s9_PgOA', + ciphertext: 'RAzILH0xfs0yxzML1CzzGExCfE2_wzWKs0FVuXfM8R5H68yTqTbqIqRCp2feAH5GSvluzmztk2_CkGNSjAyoaw', + tag: '4nMUXOgmgWvM-08tIZ-h5w' + }, + json_flat: { + protected: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', + encrypted_key: 'fL5IL5cMCjjU9G9_ZjsD2XO0HIwTOwbVwulcZVw31_rx2qTcHzbYhIvrvbcVLTfJzn8xbQ3UEL442ZgZ1PcFYKENYePXiEyvYxPN8dmvj_OfLSJDEqR6kvwOb6nghGtxfzdB_VRvFt2eehbCA3gWpiOYHHvSTFdBPGx2KZHQisLz3oZR8EWiZ1woEpHy8a7FoQ2zzuDlZEJQOUrh09b_EJxmcE2jL6wmEtgabyxy3VgWg3GqSPUISlJZV9HThuVJezzktJdpntRDnAPUqjc8IwByGpMleIQcPuBUseRRPr_OsroOJ6eTl5DuFCmBOKb-eNNw5v-GEcVYr1w7X9oXoA', + iv: '0frdIwx8P8UAzh1s9_PgOA', + ciphertext: 'RAzILH0xfs0yxzML1CzzGExCfE2_wzWKs0FVuXfM8R5H68yTqTbqIqRCp2feAH5GSvluzmztk2_CkGNSjAyoaw', + tag: '4nMUXOgmgWvM-08tIZ-h5w' + } + } +}