mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
feat(ext/crypto): implement AES-GCM decryption (#13319)
This commit is contained in:
parent
eda6e58520
commit
919ded1a0b
5 changed files with 173 additions and 122 deletions
|
@ -1444,6 +1444,15 @@ Deno.test(async function testAesGcmEncrypt() {
|
|||
// deno-fmt-ignore
|
||||
new Uint8Array([50,223,112,178,166,156,255,110,125,138,95,141,82,47,14,164,134,247,22]),
|
||||
);
|
||||
|
||||
const plainText = await crypto.subtle.decrypt(
|
||||
{ name: "AES-GCM", iv, additionalData: new Uint8Array() },
|
||||
key,
|
||||
cipherText,
|
||||
);
|
||||
assert(plainText instanceof ArrayBuffer);
|
||||
assertEquals(plainText.byteLength, 3);
|
||||
assertEquals(new Uint8Array(plainText), data);
|
||||
});
|
||||
|
||||
async function roundTripSecretJwk(
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
"decrypt": {
|
||||
"RSA-OAEP": "RsaOaepParams",
|
||||
"AES-CBC": "AesCbcParams",
|
||||
"AES-GCM": "AesGcmParams",
|
||||
"AES-CTR": "AesCtrParams",
|
||||
},
|
||||
"get key length": {
|
||||
|
@ -631,6 +632,66 @@
|
|||
// 4.
|
||||
return cipherText.buffer;
|
||||
}
|
||||
case "AES-GCM": {
|
||||
normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
|
||||
|
||||
// 1.
|
||||
if (normalizedAlgorithm.tagLength === undefined) {
|
||||
normalizedAlgorithm.tagLength = 128;
|
||||
} else if (
|
||||
!ArrayPrototypeIncludes(
|
||||
[32, 64, 96, 104, 112, 120, 128],
|
||||
normalizedAlgorithm.tagLength,
|
||||
)
|
||||
) {
|
||||
throw new DOMException(
|
||||
"Invalid tag length",
|
||||
"OperationError",
|
||||
);
|
||||
}
|
||||
|
||||
// 2.
|
||||
if (data.byteLength < normalizedAlgorithm.tagLength / 8) {
|
||||
throw new DOMException(
|
||||
"Tag length overflows ciphertext",
|
||||
"OperationError",
|
||||
);
|
||||
}
|
||||
|
||||
// 3. We only support 96-bit nonce for now.
|
||||
if (normalizedAlgorithm.iv.byteLength !== 12) {
|
||||
throw new DOMException(
|
||||
"Initialization vector length not supported",
|
||||
"NotSupportedError",
|
||||
);
|
||||
}
|
||||
|
||||
// 4.
|
||||
if (normalizedAlgorithm.additionalData !== undefined) {
|
||||
if (normalizedAlgorithm.additionalData.byteLength > (2 ** 64) - 1) {
|
||||
throw new DOMException(
|
||||
"Additional data too large",
|
||||
"OperationError",
|
||||
);
|
||||
}
|
||||
normalizedAlgorithm.additionalData = copyBuffer(
|
||||
normalizedAlgorithm.additionalData,
|
||||
);
|
||||
}
|
||||
|
||||
// 5-8.
|
||||
const plaintext = await core.opAsync("op_crypto_decrypt", {
|
||||
key: keyData,
|
||||
algorithm: "AES-GCM",
|
||||
length: key[_algorithm].length,
|
||||
iv: normalizedAlgorithm.iv,
|
||||
additionalData: normalizedAlgorithm.additionalData,
|
||||
tagLength: normalizedAlgorithm.tagLength,
|
||||
}, data);
|
||||
|
||||
// 9.
|
||||
return plaintext.buffer;
|
||||
}
|
||||
default:
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
|
|
|
@ -2,8 +2,16 @@ use std::cell::RefCell;
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::shared::*;
|
||||
use aes::cipher::generic_array::GenericArray;
|
||||
use aes::Aes192;
|
||||
use aes::BlockEncrypt;
|
||||
use aes::NewBlockCipher;
|
||||
use aes_gcm::AeadCore;
|
||||
use aes_gcm::AeadInPlace;
|
||||
use aes_gcm::Aes128Gcm;
|
||||
use aes_gcm::Aes256Gcm;
|
||||
use aes_gcm::NewAead;
|
||||
use aes_gcm::Nonce;
|
||||
use block_modes::BlockMode;
|
||||
use ctr::cipher::NewCipher;
|
||||
use ctr::cipher::StreamCipher;
|
||||
|
@ -17,6 +25,7 @@ use deno_core::error::type_error;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::OpState;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use elliptic_curve::consts::U12;
|
||||
use rsa::pkcs1::FromRsaPrivateKey;
|
||||
use rsa::PaddingScheme;
|
||||
use serde::Deserialize;
|
||||
|
@ -56,8 +65,19 @@ pub enum DecryptAlgorithm {
|
|||
ctr_length: usize,
|
||||
key_length: usize,
|
||||
},
|
||||
#[serde(rename = "AES-GCM", rename_all = "camelCase")]
|
||||
AesGcm {
|
||||
#[serde(with = "serde_bytes")]
|
||||
iv: Vec<u8>,
|
||||
#[serde(with = "serde_bytes")]
|
||||
additional_data: Option<Vec<u8>>,
|
||||
length: usize,
|
||||
tag_length: usize,
|
||||
},
|
||||
}
|
||||
|
||||
type Aes192Gcm = aes_gcm::AesGcm<Aes192, U12>;
|
||||
|
||||
pub async fn op_crypto_decrypt(
|
||||
_state: Rc<RefCell<OpState>>,
|
||||
opts: DecryptOptions,
|
||||
|
@ -76,6 +96,12 @@ pub async fn op_crypto_decrypt(
|
|||
ctr_length,
|
||||
key_length,
|
||||
} => decrypt_aes_ctr(key, key_length, &counter, ctr_length, &data),
|
||||
DecryptAlgorithm::AesGcm {
|
||||
iv,
|
||||
additional_data,
|
||||
length,
|
||||
tag_length,
|
||||
} => decrypt_aes_gcm(key, length, tag_length, iv, additional_data, &data),
|
||||
};
|
||||
let buf = tokio::task::spawn_blocking(fun).await.unwrap()?;
|
||||
Ok(buf.into())
|
||||
|
@ -195,6 +221,30 @@ where
|
|||
Ok(plaintext)
|
||||
}
|
||||
|
||||
fn decrypt_aes_gcm_gen<B>(
|
||||
key: &[u8],
|
||||
tag: &GenericArray<u8, <B as AeadCore>::TagSize>,
|
||||
nonce: &GenericArray<u8, <B as AeadCore>::NonceSize>,
|
||||
additional_data: Vec<u8>,
|
||||
plaintext: &mut [u8],
|
||||
) -> Result<(), AnyError>
|
||||
where
|
||||
B: AeadInPlace + NewAead,
|
||||
{
|
||||
let cipher =
|
||||
B::new_from_slice(key).map_err(|_| operation_error("Decryption failed"))?;
|
||||
cipher
|
||||
.decrypt_in_place_detached(
|
||||
nonce,
|
||||
additional_data.as_slice(),
|
||||
plaintext,
|
||||
tag,
|
||||
)
|
||||
.map_err(|_| operation_error("Decryption failed"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt_aes_ctr(
|
||||
key: RawKeyData,
|
||||
key_length: usize,
|
||||
|
@ -228,3 +278,53 @@ fn decrypt_aes_ctr(
|
|||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt_aes_gcm(
|
||||
key: RawKeyData,
|
||||
length: usize,
|
||||
tag_length: usize,
|
||||
iv: Vec<u8>,
|
||||
additional_data: Option<Vec<u8>>,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, AnyError> {
|
||||
let key = key.as_secret_key()?;
|
||||
let additional_data = additional_data.unwrap_or_default();
|
||||
|
||||
// Fixed 96-bit nonce
|
||||
if iv.len() != 12 {
|
||||
return Err(type_error("iv length not equal to 12"));
|
||||
}
|
||||
|
||||
let nonce = Nonce::from_slice(&iv);
|
||||
|
||||
let sep = data.len() - (tag_length / 8);
|
||||
let tag = &data[sep..];
|
||||
// The actual ciphertext, called plaintext because it is reused in place.
|
||||
let mut plaintext = data[..sep].to_vec();
|
||||
match length {
|
||||
128 => decrypt_aes_gcm_gen::<Aes128Gcm>(
|
||||
key,
|
||||
tag.into(),
|
||||
nonce,
|
||||
additional_data,
|
||||
&mut plaintext,
|
||||
)?,
|
||||
192 => decrypt_aes_gcm_gen::<Aes192Gcm>(
|
||||
key,
|
||||
tag.into(),
|
||||
nonce,
|
||||
additional_data,
|
||||
&mut plaintext,
|
||||
)?,
|
||||
256 => decrypt_aes_gcm_gen::<Aes256Gcm>(
|
||||
key,
|
||||
tag.into(),
|
||||
nonce,
|
||||
additional_data,
|
||||
&mut plaintext,
|
||||
)?,
|
||||
_ => return Err(type_error("invalid length")),
|
||||
};
|
||||
|
||||
Ok(plaintext)
|
||||
}
|
||||
|
|
1
ext/crypto/lib.deno_crypto.d.ts
vendored
1
ext/crypto/lib.deno_crypto.d.ts
vendored
|
@ -264,6 +264,7 @@ interface SubtleCrypto {
|
|||
| AlgorithmIdentifier
|
||||
| RsaOaepParams
|
||||
| AesCbcParams
|
||||
| AesGcmParams
|
||||
| AesCtrParams,
|
||||
key: CryptoKey,
|
||||
data: BufferSource,
|
||||
|
|
|
@ -212,48 +212,6 @@
|
|||
"AES-GCM 256-bit key, no additional data, 120-bit tag decryption with altered ciphertext",
|
||||
"AES-GCM 256-bit key, 128-bit tag decryption with altered ciphertext",
|
||||
"AES-GCM 256-bit key, no additional data, 128-bit tag decryption with altered ciphertext",
|
||||
"AES-GCM 128-bit key, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, illegal tag length 24-bits",
|
||||
"AES-GCM 128-bit key, illegal tag length 48-bits",
|
||||
"AES-GCM 128-bit key, illegal tag length 72-bits",
|
||||
|
@ -271,25 +229,7 @@
|
|||
"AES-GCM 256-bit key, illegal tag length 72-bits",
|
||||
"AES-GCM 256-bit key, illegal tag length 95-bits",
|
||||
"AES-GCM 256-bit key, illegal tag length 129-bits",
|
||||
"AES-GCM 256-bit key, illegal tag length 256-bits",
|
||||
"AES-GCM 128-bit key, illegal tag length 24-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 48-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 72-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 95-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 129-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 256-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 24-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 48-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 72-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 95-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 129-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 256-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 24-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 48-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 72-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 95-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 129-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 256-bits decryption"
|
||||
"AES-GCM 256-bit key, illegal tag length 256-bits"
|
||||
],
|
||||
"aes_gcm.https.any.worker.html": [
|
||||
"AES-GCM 128-bit key, 32-bit tag",
|
||||
|
@ -460,48 +400,6 @@
|
|||
"AES-GCM 256-bit key, no additional data, 120-bit tag decryption with altered ciphertext",
|
||||
"AES-GCM 256-bit key, 128-bit tag decryption with altered ciphertext",
|
||||
"AES-GCM 256-bit key, no additional data, 128-bit tag decryption with altered ciphertext",
|
||||
"AES-GCM 128-bit key, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, no additional data, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 192-bit key, no additional data, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 32-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 64-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 96-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 104-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 112-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 120-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 256-bit key, no additional data, 128-bit tag without decrypt usage",
|
||||
"AES-GCM 128-bit key, illegal tag length 24-bits",
|
||||
"AES-GCM 128-bit key, illegal tag length 48-bits",
|
||||
"AES-GCM 128-bit key, illegal tag length 72-bits",
|
||||
|
@ -519,25 +417,7 @@
|
|||
"AES-GCM 256-bit key, illegal tag length 72-bits",
|
||||
"AES-GCM 256-bit key, illegal tag length 95-bits",
|
||||
"AES-GCM 256-bit key, illegal tag length 129-bits",
|
||||
"AES-GCM 256-bit key, illegal tag length 256-bits",
|
||||
"AES-GCM 128-bit key, illegal tag length 24-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 48-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 72-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 95-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 129-bits decryption",
|
||||
"AES-GCM 128-bit key, illegal tag length 256-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 24-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 48-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 72-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 95-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 129-bits decryption",
|
||||
"AES-GCM 192-bit key, illegal tag length 256-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 24-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 48-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 72-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 95-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 129-bits decryption",
|
||||
"AES-GCM 256-bit key, illegal tag length 256-bits decryption"
|
||||
"AES-GCM 256-bit key, illegal tag length 256-bits"
|
||||
],
|
||||
"rsa_oaep.https.any.html": true,
|
||||
"rsa_oaep.https.any.worker.html": true
|
||||
|
|
Loading…
Reference in a new issue