summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/crypto/00_crypto.js53
-rw-r--r--ext/crypto/01_webidl.js12
-rw-r--r--ext/crypto/Cargo.toml2
-rw-r--r--ext/crypto/lib.deno_crypto.d.ts10
-rw-r--r--ext/crypto/lib.rs39
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,