0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

refactor(ext/crypto): cleanup decrypt code (#13120)

This commit is contained in:
Divy Srivastava 2021-12-20 20:37:36 +05:30 committed by GitHub
parent 17d81ad2ef
commit 04fe513003
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 160 additions and 125 deletions

View file

@ -572,7 +572,7 @@
// 3-5.
const hashAlgorithm = key[_algorithm].hash.name;
const plainText = await core.opAsync("op_crypto_decrypt_key", {
const plainText = await core.opAsync("op_crypto_decrypt", {
key: keyData,
algorithm: "RSA-OAEP",
hash: hashAlgorithm,
@ -593,7 +593,7 @@
);
}
const plainText = await core.opAsync("op_crypto_decrypt_key", {
const plainText = await core.opAsync("op_crypto_decrypt", {
key: keyData,
algorithm: "AES-CBC",
iv: normalizedAlgorithm.iv,

155
ext/crypto/decrypt.rs Normal file
View file

@ -0,0 +1,155 @@
use std::cell::RefCell;
use std::rc::Rc;
use crate::shared::*;
use block_modes::BlockMode;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use rsa::pkcs1::FromRsaPrivateKey;
use rsa::PaddingScheme;
use serde::Deserialize;
use sha1::Digest;
use sha1::Sha1;
use sha2::Sha256;
use sha2::Sha384;
use sha2::Sha512;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DecryptOptions {
key: RawKeyData,
#[serde(flatten)]
algorithm: DecryptAlgorithm,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase", tag = "algorithm")]
pub enum DecryptAlgorithm {
#[serde(rename = "RSA-OAEP")]
RsaOaep {
hash: ShaHash,
#[serde(with = "serde_bytes")]
label: Vec<u8>,
},
#[serde(rename = "AES-CBC", rename_all = "camelCase")]
AesCbc {
#[serde(with = "serde_bytes")]
iv: Vec<u8>,
length: usize,
},
}
pub async fn op_crypto_decrypt(
_state: Rc<RefCell<OpState>>,
opts: DecryptOptions,
data: ZeroCopyBuf,
) -> Result<ZeroCopyBuf, AnyError> {
let key = opts.key;
let fun = move || match opts.algorithm {
DecryptAlgorithm::RsaOaep { hash, label } => {
decrypt_rsa_oaep(key, hash, label, &data)
}
DecryptAlgorithm::AesCbc { iv, length } => {
decrypt_aes_cbc(key, length, iv, &data)
}
};
let buf = tokio::task::spawn_blocking(fun).await.unwrap()?;
Ok(buf.into())
}
fn decrypt_rsa_oaep(
key: RawKeyData,
hash: ShaHash,
label: Vec<u8>,
data: &[u8],
) -> Result<Vec<u8>, deno_core::anyhow::Error> {
let key = key.as_rsa_private_key()?;
let private_key = rsa::RsaPrivateKey::from_pkcs1_der(key)?;
let label = Some(String::from_utf8_lossy(&label).to_string());
let padding = match hash {
ShaHash::Sha1 => PaddingScheme::OAEP {
digest: Box::new(Sha1::new()),
mgf_digest: Box::new(Sha1::new()),
label,
},
ShaHash::Sha256 => PaddingScheme::OAEP {
digest: Box::new(Sha256::new()),
mgf_digest: Box::new(Sha256::new()),
label,
},
ShaHash::Sha384 => PaddingScheme::OAEP {
digest: Box::new(Sha384::new()),
mgf_digest: Box::new(Sha384::new()),
label,
},
ShaHash::Sha512 => PaddingScheme::OAEP {
digest: Box::new(Sha512::new()),
mgf_digest: Box::new(Sha512::new()),
label,
},
};
private_key
.decrypt(padding, data)
.map_err(|e| custom_error("DOMExceptionOperationError", e.to_string()))
}
fn decrypt_aes_cbc(
key: RawKeyData,
length: usize,
iv: Vec<u8>,
data: &[u8],
) -> Result<Vec<u8>, deno_core::anyhow::Error> {
let key = key.as_secret_key()?;
// 2.
let plaintext = match length {
128 => {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes128Cbc =
block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>;
let cipher = Aes128Cbc::new_from_slices(key, &iv)?;
cipher.decrypt_vec(data).map_err(|_| {
custom_error(
"DOMExceptionOperationError",
"Decryption failed".to_string(),
)
})?
}
192 => {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes192Cbc =
block_modes::Cbc<aes::Aes192, block_modes::block_padding::Pkcs7>;
let cipher = Aes192Cbc::new_from_slices(key, &iv)?;
cipher.decrypt_vec(data).map_err(|_| {
custom_error(
"DOMExceptionOperationError",
"Decryption failed".to_string(),
)
})?
}
256 => {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes256Cbc =
block_modes::Cbc<aes::Aes256, block_modes::block_padding::Pkcs7>;
let cipher = Aes256Cbc::new_from_slices(key, &iv)?;
cipher.decrypt_vec(data).map_err(|_| {
custom_error(
"DOMExceptionOperationError",
"Decryption failed".to_string(),
)
})?
}
_ => unreachable!(),
};
// 6.
Ok(plaintext)
}

View file

@ -16,7 +16,6 @@ use std::cell::RefCell;
use std::num::NonZeroU32;
use std::rc::Rc;
use block_modes::BlockMode;
use p256::elliptic_curve::sec1::FromEncodedPoint;
use p256::pkcs8::FromPrivateKey;
use rand::rngs::OsRng;
@ -52,6 +51,7 @@ use std::path::PathBuf;
pub use rand; // Re-export rand
mod decrypt;
mod encrypt;
mod export_key;
mod generate_key;
@ -59,6 +59,7 @@ mod import_key;
mod key;
mod shared;
pub use crate::decrypt::op_crypto_decrypt;
pub use crate::encrypt::op_crypto_encrypt;
pub use crate::export_key::op_crypto_export_key;
pub use crate::generate_key::op_crypto_generate_key;
@ -91,7 +92,7 @@ pub fn init(maybe_seed: Option<u64>) -> Extension {
("op_crypto_import_key", op_sync(op_crypto_import_key)),
("op_crypto_export_key", op_sync(op_crypto_export_key)),
("op_crypto_encrypt", op_async(op_crypto_encrypt)),
("op_crypto_decrypt_key", op_async(op_crypto_decrypt_key)),
("op_crypto_decrypt", op_async(op_crypto_decrypt)),
("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)),
])
@ -779,127 +780,6 @@ impl<'a> TryFrom<rsa::pkcs8::der::asn1::Any<'a>>
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DecryptArg {
key: KeyData,
algorithm: Algorithm,
// RSA-OAEP
hash: Option<CryptoHash>,
label: Option<ZeroCopyBuf>,
// AES-CBC
iv: Option<ZeroCopyBuf>,
length: Option<usize>,
}
pub async fn op_crypto_decrypt_key(
_state: Rc<RefCell<OpState>>,
args: DecryptArg,
zero_copy: ZeroCopyBuf,
) -> Result<ZeroCopyBuf, AnyError> {
let data = &*zero_copy;
let algorithm = args.algorithm;
match algorithm {
Algorithm::RsaOaep => {
let private_key: RsaPrivateKey =
RsaPrivateKey::from_pkcs1_der(&*args.key.data)?;
let label = args.label.map(|l| String::from_utf8_lossy(&*l).to_string());
let padding = match args
.hash
.ok_or_else(|| type_error("Missing argument hash".to_string()))?
{
CryptoHash::Sha1 => PaddingScheme::OAEP {
digest: Box::new(Sha1::new()),
mgf_digest: Box::new(Sha1::new()),
label,
},
CryptoHash::Sha256 => PaddingScheme::OAEP {
digest: Box::new(Sha256::new()),
mgf_digest: Box::new(Sha256::new()),
label,
},
CryptoHash::Sha384 => PaddingScheme::OAEP {
digest: Box::new(Sha384::new()),
mgf_digest: Box::new(Sha384::new()),
label,
},
CryptoHash::Sha512 => PaddingScheme::OAEP {
digest: Box::new(Sha512::new()),
mgf_digest: Box::new(Sha512::new()),
label,
},
};
Ok(
private_key
.decrypt(padding, data)
.map_err(|e| {
custom_error("DOMExceptionOperationError", e.to_string())
})?
.into(),
)
}
Algorithm::AesCbc => {
let key = &*args.key.data;
let length = args
.length
.ok_or_else(|| type_error("Missing argument length".to_string()))?;
let iv = args
.iv
.ok_or_else(|| type_error("Missing argument iv".to_string()))?;
// 2.
let plaintext = match length {
128 => {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes128Cbc =
block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>;
let cipher = Aes128Cbc::new_from_slices(key, &iv)?;
cipher.decrypt_vec(data).map_err(|_| {
custom_error(
"DOMExceptionOperationError",
"Decryption failed".to_string(),
)
})?
}
192 => {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes192Cbc =
block_modes::Cbc<aes::Aes192, block_modes::block_padding::Pkcs7>;
let cipher = Aes192Cbc::new_from_slices(key, &iv)?;
cipher.decrypt_vec(data).map_err(|_| {
custom_error(
"DOMExceptionOperationError",
"Decryption failed".to_string(),
)
})?
}
256 => {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes256Cbc =
block_modes::Cbc<aes::Aes256, block_modes::block_padding::Pkcs7>;
let cipher = Aes256Cbc::new_from_slices(key, &iv)?;
cipher.decrypt_vec(data).map_err(|_| {
custom_error(
"DOMExceptionOperationError",
"Decryption failed".to_string(),
)
})?
}
_ => unreachable!(),
};
// 6.
Ok(plaintext.into())
}
_ => Err(type_error("Unsupported algorithm".to_string())),
}
}
pub fn op_crypto_random_uuid(
state: &mut OpState,
_: (),