diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/crypto/00_crypto.js | 53 | ||||
-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 | 10 | ||||
-rw-r--r-- | ext/crypto/lib.rs | 39 |
5 files changed, 113 insertions, 3 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index f0ba0b4bf..4b4770e13 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -113,6 +113,7 @@ "deriveBits": { "HKDF": "HkdfParams", "PBKDF2": "Pbkdf2Params", + "ECDH": "EcdhKeyDeriveParams", }, "encrypt": { "RSA-OAEP": "RsaOaepParams", @@ -2138,6 +2139,58 @@ return buf.buffer; } + case "ECDH": { + // 1. + if (baseKey[_type] !== "private") { + throw new DOMException("Invalid key type", "InvalidAccessError"); + } + // 2. + const publicKey = normalizedAlgorithm.public; + // 3. + if (publicKey[_type] !== "public") { + throw new DOMException("Invalid key type", "InvalidAccessError"); + } + // 4. + if (publicKey[_algorithm].name !== baseKey[_algorithm].name) { + throw new DOMException( + "Algorithm mismatch", + "InvalidAccessError", + ); + } + // 5. + if ( + publicKey[_algorithm].namedCurve !== baseKey[_algorithm].namedCurve + ) { + throw new DOMException( + "namedCurve mismatch", + "InvalidAccessError", + ); + } + // 6. + if ( + ArrayPrototypeIncludes( + supportedNamedCurves, + publicKey[_algorithm].namedCurve, + ) + ) { + const baseKeyhandle = baseKey[_handle]; + const baseKeyData = WeakMapPrototypeGet(KEY_STORE, baseKeyhandle); + const publicKeyhandle = baseKey[_handle]; + const publicKeyData = WeakMapPrototypeGet(KEY_STORE, publicKeyhandle); + + const buf = await core.opAsync("op_crypto_derive_bits", { + key: baseKeyData, + publicKey: publicKeyData, + algorithm: "ECDH", + namedCurve: publicKey[_algorithm].namedCurve, + length, + }); + + return buf.buffer; + } else { + throw new DOMException("Not implemented", "NotSupportedError"); + } + } case "HKDF": { // 1. if (length === null || length === 0 || length % 8 !== 0) { diff --git a/ext/crypto/01_webidl.js b/ext/crypto/01_webidl.js index 8d9e061c6..90bee464c 100644 --- a/ext/crypto/01_webidl.js +++ b/ext/crypto/01_webidl.js @@ -385,4 +385,16 @@ webidl.converters.CryptoKeyPair = webidl .createDictionaryConverter("CryptoKeyPair", dictCryptoKeyPair); + + const dictEcdhKeyDeriveParams = [ + ...dictAlgorithm, + { + key: "public", + converter: webidl.converters.CryptoKey, + required: true, + }, + ]; + + webidl.converters.EcdhKeyDeriveParams = webidl + .createDictionaryConverter("EcdhKeyDeriveParams", dictEcdhKeyDeriveParams); })(this); diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index d04f8dc33..060845b70 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -18,6 +18,8 @@ deno_core = { version = "0.102.0", path = "../../core" } deno_web = { version = "0.51.0", path = "../web" } lazy_static = "1.4.0" num-traits = "0.2.14" +p256 = { version = "0.9.0", features = ["ecdh"] } +p384 = "0.8.0" rand = "0.8.4" ring = { version = "0.16.20", features = ["std"] } rsa = { version = "0.5.0", default-features = false, features = ["std"] } diff --git a/ext/crypto/lib.deno_crypto.d.ts b/ext/crypto/lib.deno_crypto.d.ts index 673e8f9cb..e5592d5bf 100644 --- a/ext/crypto/lib.deno_crypto.d.ts +++ b/ext/crypto/lib.deno_crypto.d.ts @@ -125,6 +125,10 @@ interface Pbkdf2Params extends Algorithm { salt: BufferSource; } +interface EcdhKeyDeriveParams extends Algorithm { + public: CryptoKey; +} + interface AesKeyGenParams extends Algorithm { length: number; } @@ -219,7 +223,11 @@ interface SubtleCrypto { data: BufferSource, ): Promise<ArrayBuffer>; deriveBits( - algorithm: AlgorithmIdentifier | HkdfParams | Pbkdf2Params, + algorithm: + | AlgorithmIdentifier + | HkdfParams + | Pbkdf2Params + | EcdhKeyDeriveParams, baseKey: CryptoKey, length: number, ): Promise<ArrayBuffer>; diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 948ef53a1..6376aedbb 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -43,6 +43,7 @@ use rsa::pkcs1::der::Encodable; use rsa::pkcs1::FromRsaPrivateKey; use rsa::pkcs1::ToRsaPrivateKey; use rsa::pkcs8::der::asn1; +use rsa::pkcs8::FromPrivateKey; use rsa::BigUint; use rsa::PublicKey; use rsa::RsaPrivateKey; @@ -792,18 +793,23 @@ pub struct DeriveKeyArg { hash: Option<CryptoHash>, length: usize, iterations: Option<u32>, + // ECDH + public_key: Option<KeyData>, + named_curve: Option<CryptoNamedCurve>, + // HKDF info: Option<ZeroCopyBuf>, } pub async fn op_crypto_derive_bits( _state: Rc<RefCell<OpState>>, args: DeriveKeyArg, - zero_copy: ZeroCopyBuf, + zero_copy: Option<ZeroCopyBuf>, ) -> Result<ZeroCopyBuf, AnyError> { - let salt = &*zero_copy; let algorithm = args.algorithm; match algorithm { Algorithm::Pbkdf2 => { + let zero_copy = zero_copy.ok_or_else(not_supported)?; + let salt = &*zero_copy; // The caller must validate these cases. assert!(args.length > 0); assert!(args.length % 8 == 0); @@ -823,7 +829,36 @@ pub async fn op_crypto_derive_bits( pbkdf2::derive(algorithm, iterations, salt, &secret, &mut out); Ok(out.into()) } + Algorithm::Ecdh => { + let named_curve = args + .named_curve + .ok_or_else(|| type_error("Missing argument namedCurve".to_string()))?; + + let public_key = args + .public_key + .ok_or_else(|| type_error("Missing argument publicKey".to_string()))?; + + match named_curve { + CryptoNamedCurve::P256 => { + let secret_key = p256::SecretKey::from_pkcs8_der(&args.key.data)?; + let public_key = + p256::SecretKey::from_pkcs8_der(&public_key.data)?.public_key(); + + let shared_secret = p256::elliptic_curve::ecdh::diffie_hellman( + secret_key.to_secret_scalar(), + public_key.as_affine(), + ); + + Ok(shared_secret.as_bytes().to_vec().into()) + } + // TODO(@littledivy): support for P384 + // https://github.com/RustCrypto/elliptic-curves/issues/240 + _ => Err(type_error("Unsupported namedCurve".to_string())), + } + } Algorithm::Hkdf => { + let zero_copy = zero_copy.ok_or_else(not_supported)?; + let salt = &*zero_copy; let algorithm = match args.hash.ok_or_else(not_supported)? { CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY, CryptoHash::Sha256 => hkdf::HKDF_SHA256, |