diff options
Diffstat (limited to 'ext/crypto')
-rw-r--r-- | ext/crypto/00_crypto.js | 71 | ||||
-rw-r--r-- | ext/crypto/01_webidl.js | 12 | ||||
-rw-r--r-- | ext/crypto/Cargo.toml | 2 | ||||
-rw-r--r-- | ext/crypto/lib.deno_crypto.d.ts | 8 | ||||
-rw-r--r-- | ext/crypto/lib.rs | 90 |
5 files changed, 181 insertions, 2 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 4b4770e13..85849153d 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -117,9 +117,11 @@ }, "encrypt": { "RSA-OAEP": "RsaOaepParams", + "AES-CBC": "AesCbcParams", }, "decrypt": { "RSA-OAEP": "RsaOaepParams", + "AES-CBC": "AesCbcParams", }, "wrapKey": { // TODO(@littledivy): Enable this once implemented. @@ -440,6 +442,41 @@ // 6. return cipherText.buffer; } + case "AES-CBC": { + if (ArrayBufferIsView(normalizedAlgorithm.iv)) { + normalizedAlgorithm.iv = new Uint8Array( + normalizedAlgorithm.iv.buffer, + normalizedAlgorithm.iv.byteOffset, + normalizedAlgorithm.iv.byteLength, + ); + } else { + normalizedAlgorithm.iv = new Uint8Array( + normalizedAlgorithm.iv, + ); + } + normalizedAlgorithm.iv = TypedArrayPrototypeSlice( + normalizedAlgorithm.iv, + ); + + // 1. + if (normalizedAlgorithm.iv.byteLength !== 16) { + throw new DOMException( + "Initialization vector must be 16 bytes", + "OperationError", + ); + } + + // 2. + const cipherText = await core.opAsync("op_crypto_encrypt_key", { + key: keyData, + algorithm: "AES-CBC", + length: key[_algorithm].length, + iv: normalizedAlgorithm.iv, + }, data); + + // 4. + return cipherText.buffer; + } default: throw new DOMException("Not implemented", "NotSupportedError"); } @@ -524,6 +561,40 @@ // 6. return plainText.buffer; } + case "AES-CBC": { + if (ArrayBufferIsView(normalizedAlgorithm.iv)) { + normalizedAlgorithm.iv = new Uint8Array( + normalizedAlgorithm.iv.buffer, + normalizedAlgorithm.iv.byteOffset, + normalizedAlgorithm.iv.byteLength, + ); + } else { + normalizedAlgorithm.iv = new Uint8Array( + normalizedAlgorithm.iv, + ); + } + normalizedAlgorithm.iv = TypedArrayPrototypeSlice( + normalizedAlgorithm.iv, + ); + + // 1. + if (normalizedAlgorithm.iv.byteLength !== 16) { + throw new DOMException( + "Counter must be 16 bytes", + "OperationError", + ); + } + + const plainText = await core.opAsync("op_crypto_decrypt_key", { + key: keyData, + algorithm: "AES-CBC", + iv: normalizedAlgorithm.iv, + length: key[_algorithm].length, + }, data); + + // 6. + return plainText.buffer; + } default: throw new DOMException("Not implemented", "NotSupportedError"); } diff --git a/ext/crypto/01_webidl.js b/ext/crypto/01_webidl.js index 90bee464c..c14e4ff22 100644 --- a/ext/crypto/01_webidl.js +++ b/ext/crypto/01_webidl.js @@ -367,6 +367,18 @@ webidl.converters.Pbkdf2Params = webidl .createDictionaryConverter("Pbkdf2Params", dictPbkdf2Params); + const dictAesCbcParams = [ + ...dictAlgorithm, + { + key: "iv", + converter: webidl.converters["BufferSource"], + required: true, + }, + ]; + + webidl.converters.AesCbcParams = webidl + .createDictionaryConverter("AesCbcParams", dictAesCbcParams); + webidl.converters.CryptoKey = webidl.createInterfaceConverter( "CryptoKey", CryptoKey, diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index 060845b70..16839d8d1 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -14,6 +14,8 @@ description = "Web Cryptography API implementation for Deno" path = "lib.rs" [dependencies] +aes = "0.7.5" +block-modes = "0.8.1" deno_core = { version = "0.102.0", path = "../../core" } deno_web = { version = "0.51.0", path = "../web" } lazy_static = "1.4.0" diff --git a/ext/crypto/lib.deno_crypto.d.ts b/ext/crypto/lib.deno_crypto.d.ts index e5592d5bf..4ed7c51f8 100644 --- a/ext/crypto/lib.deno_crypto.d.ts +++ b/ext/crypto/lib.deno_crypto.d.ts @@ -56,6 +56,10 @@ interface JsonWebKey { y?: string; } +interface AesCbcParams extends Algorithm { + iv: BufferSource; +} + interface HmacKeyGenParams extends Algorithm { hash: HashAlgorithmIdentifier; length?: number; @@ -213,12 +217,12 @@ interface SubtleCrypto { data: BufferSource, ): Promise<ArrayBuffer>; encrypt( - algorithm: AlgorithmIdentifier | RsaOaepParams, + algorithm: AlgorithmIdentifier | RsaOaepParams | AesCbcParams, key: CryptoKey, data: BufferSource, ): Promise<ArrayBuffer>; decrypt( - algorithm: AlgorithmIdentifier | RsaOaepParams, + algorithm: AlgorithmIdentifier | RsaOaepParams | AesCbcParams, key: CryptoKey, data: BufferSource, ): Promise<ArrayBuffer>; diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 6376aedbb..6b67185dd 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -19,6 +19,7 @@ use std::convert::TryInto; use std::num::NonZeroU32; use std::rc::Rc; +use block_modes::BlockMode; use lazy_static::lazy_static; use num_traits::cast::FromPrimitive; use rand::rngs::OsRng; @@ -892,8 +893,12 @@ pub async fn op_crypto_derive_bits( pub struct EncryptArg { key: KeyData, algorithm: Algorithm, + // RSA-OAEP hash: Option<CryptoHash>, label: Option<ZeroCopyBuf>, + // AES-CBC + iv: Option<ZeroCopyBuf>, + length: Option<usize>, } pub async fn op_crypto_encrypt_key( @@ -945,6 +950,46 @@ pub async fn op_crypto_encrypt_key( .into(), ) } + Algorithm::AesCbc => { + let key = &*args.key.data; + let length = args + .length + .ok_or_else(|| type_error("Missing argument length".to_string()))?; + let iv = args + .iv + .ok_or_else(|| type_error("Missing argument iv".to_string()))?; + + // 2-3. + let ciphertext = match length { + 128 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes128Cbc = + block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>; + + let cipher = Aes128Cbc::new_from_slices(key, &iv)?; + cipher.encrypt_vec(data) + } + 192 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes192Cbc = + block_modes::Cbc<aes::Aes192, block_modes::block_padding::Pkcs7>; + + let cipher = Aes192Cbc::new_from_slices(key, &iv)?; + cipher.encrypt_vec(data) + } + 256 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes256Cbc = + block_modes::Cbc<aes::Aes256, block_modes::block_padding::Pkcs7>; + + let cipher = Aes256Cbc::new_from_slices(key, &iv)?; + cipher.encrypt_vec(data) + } + _ => unreachable!(), + }; + + Ok(ciphertext.into()) + } _ => Err(type_error("Unsupported algorithm".to_string())), } } @@ -1451,8 +1496,12 @@ pub async fn op_crypto_import_key( pub struct DecryptArg { key: KeyData, algorithm: Algorithm, + // RSA-OAEP hash: Option<CryptoHash>, label: Option<ZeroCopyBuf>, + // AES-CBC + iv: Option<ZeroCopyBuf>, + length: Option<usize>, } pub async fn op_crypto_decrypt_key( @@ -1503,6 +1552,47 @@ pub async fn op_crypto_decrypt_key( .into(), ) } + Algorithm::AesCbc => { + let key = &*args.key.data; + let length = args + .length + .ok_or_else(|| type_error("Missing argument length".to_string()))?; + let iv = args + .iv + .ok_or_else(|| type_error("Missing argument iv".to_string()))?; + + // 2. + let plaintext = match length { + 128 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes128Cbc = + block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>; + let cipher = Aes128Cbc::new_from_slices(key, &iv)?; + + cipher.decrypt_vec(data)? + } + 192 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes192Cbc = + block_modes::Cbc<aes::Aes192, block_modes::block_padding::Pkcs7>; + let cipher = Aes192Cbc::new_from_slices(key, &iv)?; + + cipher.decrypt_vec(data)? + } + 256 => { + // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 + type Aes256Cbc = + block_modes::Cbc<aes::Aes256, block_modes::block_padding::Pkcs7>; + let cipher = Aes256Cbc::new_from_slices(key, &iv)?; + + cipher.decrypt_vec(data)? + } + _ => unreachable!(), + }; + + // 6. + Ok(plaintext.into()) + } _ => Err(type_error("Unsupported algorithm".to_string())), } } |