summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock102
-rw-r--r--cli/tests/unit/webcrypto_test.ts25
-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
7 files changed, 240 insertions, 3 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7bbe0d637..4f6b82d02 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -482,6 +482,17 @@ dependencies = [
"generic-array",
"rand_core 0.6.3",
"subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "crypto-mac"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
+dependencies = [
+ "generic-array",
+ "subtle",
]
[[package]]
@@ -727,6 +738,8 @@ dependencies = [
"deno_web",
"lazy_static",
"num-traits",
+ "p256",
+ "p384",
"rand 0.8.4",
"ring",
"rsa",
@@ -1117,12 +1130,40 @@ dependencies = [
]
[[package]]
+name = "ecdsa"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
+dependencies = [
+ "der",
+ "elliptic-curve",
+ "hmac",
+ "signature",
+]
+
+[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
+name = "elliptic-curve"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b"
+dependencies = [
+ "crypto-bigint",
+ "ff",
+ "generic-array",
+ "group",
+ "pkcs8",
+ "rand_core 0.6.3",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
name = "encoding_rs"
version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1229,6 +1270,16 @@ dependencies = [
]
[[package]]
+name = "ff"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
+dependencies = [
+ "rand_core 0.6.3",
+ "subtle",
+]
+
+[[package]]
name = "filetime"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1545,6 +1596,17 @@ dependencies = [
]
[[package]]
+name = "group"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
+dependencies = [
+ "ff",
+ "rand_core 0.6.3",
+ "subtle",
+]
+
+[[package]]
name = "h2"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1609,6 +1671,16 @@ dependencies = [
]
[[package]]
+name = "hmac"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
+dependencies = [
+ "crypto-mac",
+ "digest",
+]
+
+[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2337,6 +2409,26 @@ dependencies = [
]
[[package]]
+name = "p256"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186"
+dependencies = [
+ "ecdsa",
+ "elliptic-curve",
+ "sha2",
+]
+
+[[package]]
+name = "p384"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f23bc88c404ccc881c8a1ad62ba5cd7d336a64ecbf46de4874f2ad955f67b157"
+dependencies = [
+ "elliptic-curve",
+]
+
+[[package]]
name = "parking_lot"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3222,6 +3314,16 @@ dependencies = [
]
[[package]]
+name = "signature"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335"
+dependencies = [
+ "digest",
+ "rand_core 0.6.3",
+]
+
+[[package]]
name = "siphasher"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts
index b38a9934f..80275b002 100644
--- a/cli/tests/unit/webcrypto_test.ts
+++ b/cli/tests/unit/webcrypto_test.ts
@@ -513,6 +513,31 @@ unitTest(async function testHkdfDeriveBits() {
assertEquals(result.byteLength, 128 / 8);
});
+// TODO(@littledivy): Enable WPT when we have importKey support
+unitTest(async function testECDH() {
+ const namedCurve = "P-256";
+ const keyPair = await crypto.subtle.generateKey(
+ {
+ name: "ECDH",
+ namedCurve,
+ },
+ true,
+ ["deriveBits"],
+ );
+
+ const derivedKey = await crypto.subtle.deriveBits(
+ {
+ name: "ECDH",
+ public: keyPair.publicKey,
+ },
+ keyPair.privateKey,
+ 256,
+ );
+
+ assert(derivedKey instanceof ArrayBuffer);
+ assertEquals(derivedKey.byteLength, 256 / 8);
+});
+
unitTest(async function testWrapKey() {
// Test wrapKey
const key = await crypto.subtle.generateKey(
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,