1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-23 15:49:44 -05:00

refactor(ext/crypto): symmetric jwk decode in rust (#13047)

This commit is contained in:
Luca Casonato 2021-12-10 22:23:19 +01:00 committed by GitHub
parent 2bdb528eb8
commit cbfc8dd59d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 54 additions and 23 deletions

1
Cargo.lock generated
View file

@ -767,6 +767,7 @@ name = "deno_crypto"
version = "0.42.0"
dependencies = [
"aes",
"base64 0.13.0",
"block-modes",
"deno_core",
"deno_web",

View file

@ -12,7 +12,7 @@
const core = window.Deno.core;
const webidl = window.__bootstrap.webidl;
const { DOMException } = window.__bootstrap.domException;
const { atob, btoa } = window.__bootstrap.base64;
const { btoa } = window.__bootstrap.base64;
const {
ArrayPrototypeFind,
@ -23,7 +23,6 @@
BigInt64Array,
StringPrototypeToUpperCase,
StringPrototypeReplace,
StringPrototypeCharCodeAt,
StringFromCharCode,
Symbol,
SymbolFor,
@ -169,23 +168,6 @@
},
};
// Decodes the unpadded base64 to the octet sequence containing key value `k` defined in RFC7518 Section 6.4
function decodeSymmetricKey(key) {
// Decode from base64url without `=` padding.
const base64 = StringPrototypeReplace(
StringPrototypeReplace(key, /\-/g, "+"),
/\_/g,
"/",
);
const decodedKey = atob(base64);
const keyLength = decodedKey.length;
const keyBytes = new Uint8Array(keyLength);
for (let i = 0; i < keyLength; i++) {
keyBytes[i] = StringPrototypeCharCodeAt(decodedKey, i);
}
return keyBytes;
}
function unpaddedBase64(bytes) {
let binaryString = "";
for (let i = 0; i < bytes.length; i++) {
@ -1901,7 +1883,12 @@
}
// 4.
data = decodeSymmetricKey(jwk.k);
const { rawData } = core.opSync(
"op_crypto_import_key",
{ algorithm: "AES" },
{ jwkSecret: jwk },
);
data = rawData.data;
// 5.
switch (data.byteLength * 8) {
@ -2038,6 +2025,7 @@
case "jwk": {
// TODO(@littledivy): Why does the spec validate JWK twice?
const jwk = keyData;
// 2.
if (jwk.kty !== "oct") {
throw new DOMException(
@ -2055,7 +2043,12 @@
}
// 4.
data = decodeSymmetricKey(jwk.k);
const { rawData } = core.opSync(
"op_crypto_import_key",
{ algorithm: "HMAC" },
{ jwkSecret: jwk },
);
data = rawData.data;
// 5.
hash = normalizedAlgorithm.hash;

View file

@ -15,6 +15,7 @@ path = "lib.rs"
[dependencies]
aes = "0.7.5"
base64 = "0.13.0"
block-modes = "0.8.1"
deno_core = { version = "0.110.0", path = "../../core" }
deno_web = { version = "0.59.0", path = "../web" }

View file

@ -11,12 +11,12 @@ use crate::OaepPrivateKeyParameters;
use crate::PssPrivateKeyParameters;
#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
#[serde(rename_all = "camelCase")]
pub enum KeyData {
Spki(ZeroCopyBuf),
Pkcs8(ZeroCopyBuf),
Raw(ZeroCopyBuf),
Jwk { k: String },
JwkSecret { k: String },
}
#[derive(Deserialize)]
@ -32,6 +32,10 @@ pub enum ImportKeyOptions {
Ecdsa { named_curve: EcNamedCurve },
#[serde(rename = "ECDH", rename_all = "camelCase")]
Ecdh { named_curve: EcNamedCurve },
#[serde(rename = "AES", rename_all = "camelCase")]
Aes {},
#[serde(rename = "HMAC", rename_all = "camelCase")]
Hmac {},
}
#[derive(Serialize)]
@ -45,6 +49,10 @@ pub enum ImportKeyResult {
},
#[serde(rename_all = "camelCase")]
Ec { raw_data: RawKeyData },
#[serde(rename_all = "camelCase")]
Aes { raw_data: RawKeyData },
#[serde(rename_all = "camelCase")]
Hmac { raw_data: RawKeyData },
}
pub fn op_crypto_import_key(
@ -62,6 +70,8 @@ pub fn op_crypto_import_key(
| ImportKeyOptions::Ecdh { named_curve } => {
import_key_ec(key_data, named_curve)
}
ImportKeyOptions::Aes {} => import_key_aes(key_data),
ImportKeyOptions::Hmac {} => import_key_hmac(key_data),
}
}
@ -576,3 +586,29 @@ fn import_key_ec(
_ => return Err(unsupported_format()),
})
}
fn import_key_aes(key_data: KeyData) -> Result<ImportKeyResult, AnyError> {
Ok(match key_data {
KeyData::JwkSecret { k } => {
let data = base64::decode_config(k, base64::URL_SAFE)
.map_err(|_| data_error("invalid key data"))?;
ImportKeyResult::Hmac {
raw_data: RawKeyData::Secret(data.into()),
}
}
_ => return Err(unsupported_format()),
})
}
fn import_key_hmac(key_data: KeyData) -> Result<ImportKeyResult, AnyError> {
Ok(match key_data {
KeyData::JwkSecret { k } => {
let data = base64::decode_config(k, base64::URL_SAFE)
.map_err(|_| data_error("invalid key data"))?;
ImportKeyResult::Hmac {
raw_data: RawKeyData::Secret(data.into()),
}
}
_ => return Err(unsupported_format()),
})
}