summaryrefslogtreecommitdiff
path: root/ext/crypto/encrypt.rs
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2021-12-15 22:18:26 +0100
committerGitHub <noreply@github.com>2021-12-15 22:18:26 +0100
commitf0e1a6b84c282a37a5cfd278fc145ba645ee9073 (patch)
tree4231858e8745e34bda932829911e0c71433f132a /ext/crypto/encrypt.rs
parent5a3ded66113e7a2cacae3ffb8123038450c701e8 (diff)
refactor(ext/crypto): clean up encrypt rust code (#13094)
Diffstat (limited to 'ext/crypto/encrypt.rs')
-rw-r--r--ext/crypto/encrypt.rs138
1 files changed, 138 insertions, 0 deletions
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)
+}