deno.land / x / deno@v1.28.2 / ext / crypto / encrypt.rs
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309use crate::shared::*;
use aes::cipher::block_padding::Pkcs7;use aes::cipher::BlockEncryptMut;use aes::cipher::KeyIvInit;use aes::cipher::StreamCipher;use aes_gcm::aead::generic_array::typenum::U12;use aes_gcm::aead::generic_array::typenum::U16;use aes_gcm::aead::generic_array::ArrayLength;use aes_gcm::aes::Aes128;use aes_gcm::aes::Aes192;use aes_gcm::aes::Aes256;use aes_gcm::AeadInPlace;use aes_gcm::KeyInit;use aes_gcm::Nonce;use ctr::Ctr128BE;use ctr::Ctr32BE;use ctr::Ctr64BE;use deno_core::error::type_error;use deno_core::error::AnyError;use deno_core::op;use deno_core::ZeroCopyBuf;use rand::rngs::OsRng;use rsa::pkcs1::DecodeRsaPublicKey;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, }, #[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, }, #[serde(rename = "AES-CTR", rename_all = "camelCase")] AesCtr { #[serde(with = "serde_bytes")] counter: Vec<u8>, ctr_length: usize, key_length: usize, },}
#[op]pub async fn op_crypto_encrypt( 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) } EncryptAlgorithm::AesGcm { iv, additional_data, length, tag_length, } => encrypt_aes_gcm(key, length, tag_length, iv, additional_data, &data), EncryptAlgorithm::AesCtr { counter, ctr_length, key_length, } => encrypt_aes_ctr(key, key_length, &counter, ctr_length, &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>, AnyError> { 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>, AnyError> { 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 Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
let cipher = Aes128CbcEnc::new_from_slices(key, &iv) .map_err(|_| operation_error("invalid key or iv".to_string()))?; cipher.encrypt_padded_vec_mut::<Pkcs7>(data) } 192 => { // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 type Aes192CbcEnc = cbc::Encryptor<aes::Aes192>;
let cipher = Aes192CbcEnc::new_from_slices(key, &iv) .map_err(|_| operation_error("invalid key or iv".to_string()))?; cipher.encrypt_padded_vec_mut::<Pkcs7>(data) } 256 => { // Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315 type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
let cipher = Aes256CbcEnc::new_from_slices(key, &iv) .map_err(|_| operation_error("invalid key or iv".to_string()))?; cipher.encrypt_padded_vec_mut::<Pkcs7>(data) } _ => return Err(type_error("invalid length")), }; Ok(ciphertext)}
fn encrypt_aes_gcm_general<N: ArrayLength<u8>>( key: &[u8], iv: Vec<u8>, length: usize, ciphertext: &mut [u8], additional_data: Vec<u8>,) -> Result<aes_gcm::Tag, AnyError> { let nonce = Nonce::<N>::from_slice(&iv); let tag = match length { 128 => { let cipher = aes_gcm::AesGcm::<Aes128, N>::new_from_slice(key) .map_err(|_| operation_error("Encryption failed"))?; cipher .encrypt_in_place_detached(nonce, &additional_data, ciphertext) .map_err(|_| operation_error("Encryption failed"))? } 192 => { let cipher = aes_gcm::AesGcm::<Aes192, N>::new_from_slice(key) .map_err(|_| operation_error("Encryption failed"))?; cipher .encrypt_in_place_detached(nonce, &additional_data, ciphertext) .map_err(|_| operation_error("Encryption failed"))? } 256 => { let cipher = aes_gcm::AesGcm::<Aes256, N>::new_from_slice(key) .map_err(|_| operation_error("Encryption failed"))?; cipher .encrypt_in_place_detached(nonce, &additional_data, ciphertext) .map_err(|_| operation_error("Encryption failed"))? } _ => return Err(type_error("invalid length")), };
Ok(tag)}
fn encrypt_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();
let mut ciphertext = data.to_vec(); // Fixed 96-bit OR 128-bit nonce let tag = match iv.len() { 12 => encrypt_aes_gcm_general::<U12>( key, iv, length, &mut ciphertext, additional_data, )?, 16 => encrypt_aes_gcm_general::<U16>( key, iv, length, &mut ciphertext, additional_data, )?, _ => return Err(type_error("iv length not equal to 12 or 16")), };
// Truncated tag to the specified tag length. // `tag` is fixed to be 16 bytes long and (tag_length / 8) is always <= 16 let tag = &tag[..(tag_length / 8)];
// C | T ciphertext.extend_from_slice(tag);
Ok(ciphertext)}
fn encrypt_aes_ctr_gen<B>( key: &[u8], counter: &[u8], data: &[u8],) -> Result<Vec<u8>, AnyError>where B: KeyIvInit + StreamCipher,{ let mut cipher = B::new(key.into(), counter.into());
let mut ciphertext = data.to_vec(); cipher .try_apply_keystream(&mut ciphertext) .map_err(|_| operation_error("tried to encrypt too much data"))?;
Ok(ciphertext)}
fn encrypt_aes_ctr( key: RawKeyData, key_length: usize, counter: &[u8], ctr_length: usize, data: &[u8],) -> Result<Vec<u8>, AnyError> { let key = key.as_secret_key()?;
match ctr_length { 32 => match key_length { 128 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes128>>(key, counter, data), 192 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes192>>(key, counter, data), 256 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes256>>(key, counter, data), _ => Err(type_error("invalid length")), }, 64 => match key_length { 128 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes128>>(key, counter, data), 192 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes192>>(key, counter, data), 256 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes256>>(key, counter, data), _ => Err(type_error("invalid length")), }, 128 => match key_length { 128 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes128>>(key, counter, data), 192 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes192>>(key, counter, data), 256 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes256>>(key, counter, data), _ => Err(type_error("invalid length")), }, _ => Err(type_error( "invalid counter length. Currently supported 32/64/128 bits", )), }}
Version Info