diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2021-08-25 01:29:02 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-24 21:59:02 +0200 |
commit | 85a56e7144cb2e213eb670f754027d19e31c315a (patch) | |
tree | bc9757ef1340a14cd0efce3856bda3ef5ba9f2fa /ext/crypto/00_crypto.js | |
parent | 4853be20f2d649842ebc97124d8479c7aad7cc9b (diff) |
feat(ext/crypto): implement encrypt, decrypt & generateKey for RSA-OAEP (#11654)
Diffstat (limited to 'ext/crypto/00_crypto.js')
-rw-r--r-- | ext/crypto/00_crypto.js | 236 |
1 files changed, 235 insertions, 1 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 115271dab..fd7431b7c 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -56,6 +56,7 @@ RsaPssParams: {}, EcdsaParams: { hash: "HashAlgorithmIdentifier" }, HmacImportParams: { hash: "HashAlgorithmIdentifier" }, + RsaOaepParams: { label: "BufferSource" }, }; const supportedAlgorithms = { @@ -68,6 +69,7 @@ "generateKey": { "RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams", "RSA-PSS": "RsaHashedKeyGenParams", + "RSA-OAEP": "RsaHashedKeyGenParams", "ECDSA": "EcKeyGenParams", "HMAC": "HmacKeyGenParams", }, @@ -85,6 +87,12 @@ "importKey": { "HMAC": "HmacImportParams", }, + "encrypt": { + "RSA-OAEP": "RsaOaepParams", + }, + "decrypt": { + "RSA-OAEP": "RsaOaepParams", + }, }; // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm @@ -306,6 +314,173 @@ * @param {BufferSource} data * @returns {Promise<any>} */ + async encrypt(algorithm, key, data) { + webidl.assertBranded(this, SubtleCrypto); + const prefix = "Failed to execute 'encrypt' on 'SubtleCrypto'"; + webidl.requiredArguments(arguments.length, 3, { prefix }); + algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { + prefix, + context: "Argument 1", + }); + key = webidl.converters.CryptoKey(key, { + prefix, + context: "Argument 2", + }); + data = webidl.converters.BufferSource(data, { + prefix, + context: "Argument 3", + }); + + // 2. + if (ArrayBufferIsView(data)) { + data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + } else { + data = new Uint8Array(data); + } + data = TypedArrayPrototypeSlice(data); + + // 3. + const normalizedAlgorithm = normalizeAlgorithm(algorithm, "encrypt"); + + const handle = key[_handle]; + const keyData = WeakMapPrototypeGet(KEY_STORE, handle); + + switch (normalizedAlgorithm.name) { + case "RSA-OAEP": { + // 1. + if (key[_type] !== "public") { + throw new DOMException( + "Key type not supported", + "InvalidAccessError", + ); + } + + // 2. + if (normalizedAlgorithm.label) { + if (ArrayBufferIsView(normalizedAlgorithm.label)) { + normalizedAlgorithm.label = new Uint8Array( + normalizedAlgorithm.label.buffer, + normalizedAlgorithm.label.byteOffset, + normalizedAlgorithm.label.byteLength, + ); + } else { + normalizedAlgorithm.label = new Uint8Array( + normalizedAlgorithm.label, + ); + } + normalizedAlgorithm.label = TypedArrayPrototypeSlice( + normalizedAlgorithm.label, + ); + } else { + normalizedAlgorithm.label = new Uint8Array(); + } + + // 3-5. + const hashAlgorithm = key[_algorithm].hash.name; + const cipherText = await core.opAsync("op_crypto_encrypt_key", { + key: keyData, + algorithm: "RSA-OAEP", + hash: hashAlgorithm, + }, data); + + // 6. + return cipherText.buffer; + } + default: + throw new DOMException("Not implemented", "NotSupportedError"); + } + } + + /** + * @param {string} algorithm + * @param {CryptoKey} key + * @param {BufferSource} data + * @returns {Promise<any>} + */ + async decrypt(algorithm, key, data) { + webidl.assertBranded(this, SubtleCrypto); + const prefix = "Failed to execute 'decrypt' on 'SubtleCrypto'"; + webidl.requiredArguments(arguments.length, 3, { prefix }); + algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { + prefix, + context: "Argument 1", + }); + key = webidl.converters.CryptoKey(key, { + prefix, + context: "Argument 2", + }); + data = webidl.converters.BufferSource(data, { + prefix, + context: "Argument 3", + }); + + // 2. + if (ArrayBufferIsView(data)) { + data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + } else { + data = new Uint8Array(data); + } + data = TypedArrayPrototypeSlice(data); + + // 3. + const normalizedAlgorithm = normalizeAlgorithm(algorithm, "decrypt"); + + const handle = key[_handle]; + const keyData = WeakMapPrototypeGet(KEY_STORE, handle); + + switch (normalizedAlgorithm.name) { + case "RSA-OAEP": { + // 1. + if (key[_type] !== "private") { + throw new DOMException( + "Key type not supported", + "InvalidAccessError", + ); + } + + // 2. + if (normalizedAlgorithm.label) { + if (ArrayBufferIsView(normalizedAlgorithm.label)) { + normalizedAlgorithm.label = new Uint8Array( + normalizedAlgorithm.label.buffer, + normalizedAlgorithm.label.byteOffset, + normalizedAlgorithm.label.byteLength, + ); + } else { + normalizedAlgorithm.label = new Uint8Array( + normalizedAlgorithm.label, + ); + } + normalizedAlgorithm.label = TypedArrayPrototypeSlice( + normalizedAlgorithm.label, + ); + } else { + normalizedAlgorithm.label = new Uint8Array(); + } + + // 3-5. + const hashAlgorithm = key[_algorithm].hash.name; + const plainText = await core.opAsync("op_crypto_decrypt_key", { + key: keyData, + algorithm: "RSA-OAEP", + hash: hashAlgorithm, + label: normalizedAlgorithm.label, + }, data); + + // 6. + return plainText.buffer; + } + default: + throw new DOMException("Not implemented", "NotSupportedError"); + } + } + + /** + * @param {string} algorithm + * @param {CryptoKey} key + * @param {BufferSource} data + * @returns {Promise<any>} + */ async sign(algorithm, key, data) { webidl.assertBranded(this, SubtleCrypto); const prefix = "Failed to execute 'sign' on 'SubtleCrypto'"; @@ -833,7 +1008,66 @@ // 19-22. return { publicKey, privateKey }; } - // TODO(lucacasonato): RSA-OAEP + case "RSA-OAEP": { + if ( + ArrayPrototypeFind( + usages, + (u) => + !ArrayPrototypeIncludes([ + "encrypt", + "decrypt", + "wrapKey", + "unwrapKey", + ], u), + ) !== undefined + ) { + throw new DOMException("Invalid key usages", "SyntaxError"); + } + + // 2. + const keyData = await core.opAsync( + "op_crypto_generate_key", + { + name: normalizedAlgorithm.name, + modulusLength: normalizedAlgorithm.modulusLength, + publicExponent: normalizedAlgorithm.publicExponent, + }, + ); + const handle = {}; + WeakMapPrototypeSet(KEY_STORE, handle, { + type: "pkcs8", + data: keyData, + }); + + // 4-8. + const algorithm = { + name: normalizedAlgorithm.name, + modulusLength: normalizedAlgorithm.modulusLength, + publicExponent: normalizedAlgorithm.publicExponent, + hash: normalizedAlgorithm.hash, + }; + + // 9-13. + const publicKey = constructKey( + "public", + true, + usageIntersection(usages, ["encrypt", "wrapKey"]), + algorithm, + handle, + ); + + // 14-18. + const privateKey = constructKey( + "private", + extractable, + usageIntersection(usages, ["decrypt", "unwrapKey"]), + algorithm, + handle, + ); + + // 19-22. + return { publicKey, privateKey }; + } case "ECDSA": { // 1. if ( |