// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::op; use deno_core::OpState; use deno_core::ResourceId; use deno_core::StringOrBuffer; use deno_core::ZeroCopyBuf; use std::rc::Rc; use rsa::padding::PaddingScheme; use rsa::pkcs8::DecodePrivateKey; use rsa::pkcs8::DecodePublicKey; use rsa::PublicKey; use rsa::RsaPrivateKey; use rsa::RsaPublicKey; mod cipher; mod digest; #[op(fast)] pub fn op_node_create_hash(state: &mut OpState, algorithm: &str) -> u32 { state .resource_table .add(match digest::Context::new(algorithm) { Ok(context) => context, Err(_) => return 0, }) } #[op(fast)] pub fn op_node_hash_update(state: &mut OpState, rid: u32, data: &[u8]) -> bool { let context = match state.resource_table.get::(rid) { Ok(context) => context, _ => return false, }; context.update(data); true } #[op(fast)] pub fn op_node_hash_update_str( state: &mut OpState, rid: u32, data: &str, ) -> bool { let context = match state.resource_table.get::(rid) { Ok(context) => context, _ => return false, }; context.update(data.as_bytes()); true } #[op] pub fn op_node_hash_digest( state: &mut OpState, rid: ResourceId, ) -> Result { let context = state.resource_table.take::(rid)?; let context = Rc::try_unwrap(context) .map_err(|_| type_error("Hash context is already in use"))?; Ok(context.digest()?.into()) } #[op] pub fn op_node_hash_digest_hex( state: &mut OpState, rid: ResourceId, ) -> Result { let context = state.resource_table.take::(rid)?; let context = Rc::try_unwrap(context) .map_err(|_| type_error("Hash context is already in use"))?; let digest = context.digest()?; Ok(hex::encode(digest)) } #[op] pub fn op_node_hash_clone( state: &mut OpState, rid: ResourceId, ) -> Result { let context = state.resource_table.get::(rid)?; Ok(state.resource_table.add(context.as_ref().clone())) } #[op] pub fn op_node_private_encrypt( key: StringOrBuffer, msg: StringOrBuffer, padding: u32, ) -> Result { let key = RsaPrivateKey::from_pkcs8_pem((&key).try_into()?)?; let mut rng = rand::thread_rng(); match padding { 1 => Ok( key .encrypt(&mut rng, PaddingScheme::new_pkcs1v15_encrypt(), &msg)? .into(), ), 4 => Ok( key .encrypt(&mut rng, PaddingScheme::new_oaep::(), &msg)? .into(), ), _ => Err(type_error("Unknown padding")), } } #[op] pub fn op_node_private_decrypt( key: StringOrBuffer, msg: StringOrBuffer, padding: u32, ) -> Result { let key = RsaPrivateKey::from_pkcs8_pem((&key).try_into()?)?; match padding { 1 => Ok( key .decrypt(PaddingScheme::new_pkcs1v15_encrypt(), &msg)? .into(), ), 4 => Ok( key .decrypt(PaddingScheme::new_oaep::(), &msg)? .into(), ), _ => Err(type_error("Unknown padding")), } } #[op] pub fn op_node_public_encrypt( key: StringOrBuffer, msg: StringOrBuffer, padding: u32, ) -> Result { let key = RsaPublicKey::from_public_key_pem((&key).try_into()?)?; let mut rng = rand::thread_rng(); match padding { 1 => Ok( key .encrypt(&mut rng, PaddingScheme::new_pkcs1v15_encrypt(), &msg)? .into(), ), 4 => Ok( key .encrypt(&mut rng, PaddingScheme::new_oaep::(), &msg)? .into(), ), _ => Err(type_error("Unknown padding")), } } #[op(fast)] pub fn op_node_create_cipheriv( state: &mut OpState, algorithm: &str, key: &[u8], iv: &[u8], ) -> u32 { state.resource_table.add( match cipher::CipherContext::new(algorithm, key, iv) { Ok(context) => context, Err(_) => return 0, }, ) } #[op(fast)] pub fn op_node_cipheriv_encrypt( state: &mut OpState, rid: u32, input: &[u8], output: &mut [u8], ) -> bool { let context = match state.resource_table.get::(rid) { Ok(context) => context, Err(_) => return false, }; context.encrypt(input, output); true } #[op] pub fn op_node_cipheriv_final( state: &mut OpState, rid: u32, input: &[u8], output: &mut [u8], ) -> Result<(), AnyError> { let context = state.resource_table.take::(rid)?; let context = Rc::try_unwrap(context) .map_err(|_| type_error("Cipher context is already in use"))?; context.r#final(input, output) }