summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/crypto/00_crypto.js4
-rw-r--r--ext/crypto/encrypt.rs138
-rw-r--r--ext/crypto/lib.rs110
-rw-r--r--ext/crypto/shared.rs7
4 files changed, 150 insertions, 109 deletions
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js
index 3e0af0b3c..c8c7d9810 100644
--- a/ext/crypto/00_crypto.js
+++ b/ext/crypto/00_crypto.js
@@ -3136,7 +3136,7 @@
// 3-5.
const hashAlgorithm = key[_algorithm].hash.name;
- const cipherText = await core.opAsync("op_crypto_encrypt_key", {
+ const cipherText = await core.opAsync("op_crypto_encrypt", {
key: keyData,
algorithm: "RSA-OAEP",
hash: hashAlgorithm,
@@ -3158,7 +3158,7 @@
}
// 2.
- const cipherText = await core.opAsync("op_crypto_encrypt_key", {
+ const cipherText = await core.opAsync("op_crypto_encrypt", {
key: keyData,
algorithm: "AES-CBC",
length: key[_algorithm].length,
diff --git a/ext/crypto/encrypt.rs b/ext/crypto/encrypt.rs
new file mode 100644
index 000000000..87e3fd2e0
--- /dev/null
+++ b/ext/crypto/encrypt.rs
@@ -0,0 +1,138 @@
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use crate::shared::*;
+use block_modes::BlockMode;
+use deno_core::error::type_error;
+use deno_core::error::AnyError;
+use deno_core::OpState;
+use deno_core::ZeroCopyBuf;
+use rand::rngs::OsRng;
+use rsa::pkcs1::FromRsaPublicKey;
+use rsa::PaddingScheme;
+use rsa::PublicKey;
+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 EncryptOptions {
+ key: RawKeyData,
+ #[serde(flatten)]
+ algorithm: EncryptAlgorithm,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase", tag = "algorithm")]
+pub enum EncryptAlgorithm {
+ #[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_encrypt(
+ _state: Rc<RefCell<OpState>>,
+ opts: EncryptOptions,
+ data: ZeroCopyBuf,
+) -> Result<ZeroCopyBuf, AnyError> {
+ let key = opts.key;
+ let fun = move || match opts.algorithm {
+ EncryptAlgorithm::RsaOaep { hash, label } => {
+ encrypt_rsa_oaep(key, hash, label, &data)
+ }
+ EncryptAlgorithm::AesCbc { iv, length } => {
+ encrypt_aes_cbc(key, length, iv, &data)
+ }
+ };
+ let buf = tokio::task::spawn_blocking(fun).await.unwrap()?;
+ Ok(buf.into())
+}
+
+fn encrypt_rsa_oaep(
+ key: RawKeyData,
+ hash: ShaHash,
+ label: Vec<u8>,
+ data: &[u8],
+) -> Result<Vec<u8>, deno_core::anyhow::Error> {
+ let label = String::from_utf8_lossy(&label).to_string();
+
+ let public_key = key.as_rsa_public_key()?;
+ let public_key = rsa::RsaPublicKey::from_pkcs1_der(&public_key)
+ .map_err(|_| operation_error("failed to decode public key"))?;
+ let mut rng = OsRng;
+ let padding = match hash {
+ ShaHash::Sha1 => PaddingScheme::OAEP {
+ digest: Box::new(Sha1::new()),
+ mgf_digest: Box::new(Sha1::new()),
+ label: Some(label),
+ },
+ ShaHash::Sha256 => PaddingScheme::OAEP {
+ digest: Box::new(Sha256::new()),
+ mgf_digest: Box::new(Sha256::new()),
+ label: Some(label),
+ },
+ ShaHash::Sha384 => PaddingScheme::OAEP {
+ digest: Box::new(Sha384::new()),
+ mgf_digest: Box::new(Sha384::new()),
+ label: Some(label),
+ },
+ ShaHash::Sha512 => PaddingScheme::OAEP {
+ digest: Box::new(Sha512::new()),
+ mgf_digest: Box::new(Sha512::new()),
+ label: Some(label),
+ },
+ };
+ let encrypted = public_key
+ .encrypt(&mut rng, padding, data)
+ .map_err(|_| operation_error("Encryption failed"))?;
+ Ok(encrypted)
+}
+
+fn encrypt_aes_cbc(
+ key: RawKeyData,
+ length: usize,
+ iv: Vec<u8>,
+ data: &[u8],
+) -> Result<Vec<u8>, deno_core::anyhow::Error> {
+ let key = key.as_secret_key()?;
+ let ciphertext = 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.encrypt_vec(data)
+ }
+ 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.encrypt_vec(data)
+ }
+ 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.encrypt_vec(data)
+ }
+ _ => return Err(type_error("invalid length")),
+ };
+ Ok(ciphertext)
+}
diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs
index a15f2d986..bb7ad5f32 100644
--- a/ext/crypto/lib.rs
+++ b/ext/crypto/lib.rs
@@ -54,12 +54,14 @@ use std::path::PathBuf;
pub use rand; // Re-export rand
+mod encrypt;
mod export_key;
mod generate_key;
mod import_key;
mod key;
mod shared;
+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;
pub use crate::import_key::op_crypto_import_key;
@@ -67,7 +69,6 @@ use crate::key::Algorithm;
use crate::key::CryptoHash;
use crate::key::CryptoNamedCurve;
use crate::key::HkdfOutput;
-
use crate::shared::ID_MFG1;
use crate::shared::ID_P_SPECIFIED;
use crate::shared::ID_SHA1_OID;
@@ -96,7 +97,7 @@ pub fn init(maybe_seed: Option<u64>) -> Extension {
("op_crypto_derive_bits", op_async(op_crypto_derive_bits)),
("op_crypto_import_key", op_sync(op_crypto_import_key)),
("op_crypto_export_key", op_sync(op_crypto_export_key)),
- ("op_crypto_encrypt_key", op_async(op_crypto_encrypt_key)),
+ ("op_crypto_encrypt", op_async(op_crypto_encrypt)),
("op_crypto_decrypt_key", op_async(op_crypto_decrypt_key)),
("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)),
@@ -561,19 +562,6 @@ pub async fn op_crypto_derive_bits(
}
}
-#[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct EncryptArg {
- key: KeyData,
- algorithm: Algorithm,
- // RSA-OAEP
- hash: Option<CryptoHash>,
- label: Option<ZeroCopyBuf>,
- // AES-CBC
- iv: Option<ZeroCopyBuf>,
- length: Option<usize>,
-}
-
fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, AnyError> {
let public_key = match key_data.r#type {
KeyType::Private => {
@@ -585,98 +573,6 @@ fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, AnyError> {
Ok(public_key)
}
-pub async fn op_crypto_encrypt_key(
- _state: Rc<RefCell<OpState>>,
- args: EncryptArg,
- zero_copy: ZeroCopyBuf,
-) -> Result<ZeroCopyBuf, AnyError> {
- let data = &*zero_copy;
- let algorithm = args.algorithm;
-
- match algorithm {
- Algorithm::RsaOaep => {
- let public_key = read_rsa_public_key(args.key)?;
- let label = args.label.map(|l| String::from_utf8_lossy(&*l).to_string());
- let mut rng = OsRng;
- 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(
- public_key
- .encrypt(&mut rng, 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-3.
- let ciphertext = 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.encrypt_vec(data)
- }
- 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.encrypt_vec(data)
- }
- 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.encrypt_vec(data)
- }
- _ => unreachable!(),
- };
-
- Ok(ciphertext.into())
- }
- _ => Err(type_error("Unsupported algorithm".to_string())),
- }
-}
-
// The parameters field associated with OID id-RSASSA-PSS
// Defined in RFC 3447, section A.2.3
//
diff --git a/ext/crypto/shared.rs b/ext/crypto/shared.rs
index 0b70db24e..1a0703b26 100644
--- a/ext/crypto/shared.rs
+++ b/ext/crypto/shared.rs
@@ -90,6 +90,13 @@ impl RawKeyData {
_ => Err(type_error("expected private key")),
}
}
+
+ pub fn as_secret_key(&self) -> Result<&[u8], AnyError> {
+ match self {
+ RawKeyData::Secret(data) => Ok(data),
+ _ => Err(type_error("expected secret key")),
+ }
+ }
}
pub fn data_error(msg: impl Into<Cow<'static, str>>) -> AnyError {