diff options
Diffstat (limited to 'extensions/crypto/lib.rs')
-rw-r--r-- | extensions/crypto/lib.rs | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/extensions/crypto/lib.rs b/extensions/crypto/lib.rs index 66e576c6a..d390afdab 100644 --- a/extensions/crypto/lib.rs +++ b/extensions/crypto/lib.rs @@ -34,7 +34,9 @@ use ring::signature::EcdsaSigningAlgorithm; use rsa::padding::PaddingScheme; use rsa::BigUint; use rsa::PrivateKeyEncoding; +use rsa::PublicKey; use rsa::RSAPrivateKey; +use rsa::RSAPublicKey; use sha1::Sha1; use sha2::Digest; use sha2::Sha256; @@ -70,6 +72,7 @@ pub fn init(maybe_seed: Option<u64>) -> Extension { ), ("op_crypto_generate_key", op_async(op_crypto_generate_key)), ("op_crypto_sign_key", op_async(op_crypto_sign_key)), + ("op_crypto_verify_key", op_async(op_crypto_verify_key)), ("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)), ("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)), ]) @@ -378,6 +381,136 @@ pub async fn op_crypto_sign_key( Ok(signature.into()) } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VerifyArg { + key: KeyData, + algorithm: Algorithm, + salt_length: Option<u32>, + hash: Option<CryptoHash>, + signature: ZeroCopyBuf, +} + +pub async fn op_crypto_verify_key( + _state: Rc<RefCell<OpState>>, + args: VerifyArg, + zero_copy: Option<ZeroCopyBuf>, +) -> Result<bool, AnyError> { + let zero_copy = zero_copy.ok_or_else(null_opbuf)?; + let data = &*zero_copy; + let algorithm = args.algorithm; + + let verification = match algorithm { + Algorithm::RsassaPkcs1v15 => { + let public_key: RSAPublicKey = + RSAPrivateKey::from_pkcs8(&*args.key.data)?.to_public_key(); + let (padding, hashed) = match args + .hash + .ok_or_else(|| type_error("Missing argument hash".to_string()))? + { + CryptoHash::Sha1 => { + let mut hasher = Sha1::new(); + hasher.update(&data); + ( + PaddingScheme::PKCS1v15Sign { + hash: Some(rsa::hash::Hash::SHA1), + }, + hasher.finalize()[..].to_vec(), + ) + } + CryptoHash::Sha256 => { + let mut hasher = Sha256::new(); + hasher.update(&data); + ( + PaddingScheme::PKCS1v15Sign { + hash: Some(rsa::hash::Hash::SHA2_256), + }, + hasher.finalize()[..].to_vec(), + ) + } + CryptoHash::Sha384 => { + let mut hasher = Sha384::new(); + hasher.update(&data); + ( + PaddingScheme::PKCS1v15Sign { + hash: Some(rsa::hash::Hash::SHA2_384), + }, + hasher.finalize()[..].to_vec(), + ) + } + CryptoHash::Sha512 => { + let mut hasher = Sha512::new(); + hasher.update(&data); + ( + PaddingScheme::PKCS1v15Sign { + hash: Some(rsa::hash::Hash::SHA2_512), + }, + hasher.finalize()[..].to_vec(), + ) + } + }; + + public_key + .verify(padding, &hashed, &*args.signature) + .is_ok() + } + Algorithm::RsaPss => { + let salt_len = args + .salt_length + .ok_or_else(|| type_error("Missing argument saltLength".to_string()))? + as usize; + let public_key: RSAPublicKey = + RSAPrivateKey::from_pkcs8(&*args.key.data)?.to_public_key(); + + let rng = OsRng; + let (padding, hashed) = match args + .hash + .ok_or_else(|| type_error("Missing argument hash".to_string()))? + { + CryptoHash::Sha1 => { + let mut hasher = Sha1::new(); + hasher.update(&data); + ( + PaddingScheme::new_pss_with_salt::<Sha1, _>(rng, salt_len), + hasher.finalize()[..].to_vec(), + ) + } + CryptoHash::Sha256 => { + let mut hasher = Sha256::new(); + hasher.update(&data); + ( + PaddingScheme::new_pss_with_salt::<Sha256, _>(rng, salt_len), + hasher.finalize()[..].to_vec(), + ) + } + CryptoHash::Sha384 => { + let mut hasher = Sha384::new(); + hasher.update(&data); + ( + PaddingScheme::new_pss_with_salt::<Sha384, _>(rng, salt_len), + hasher.finalize()[..].to_vec(), + ) + } + CryptoHash::Sha512 => { + let mut hasher = Sha512::new(); + hasher.update(&data); + ( + PaddingScheme::new_pss_with_salt::<Sha512, _>(rng, salt_len), + hasher.finalize()[..].to_vec(), + ) + } + }; + + public_key + .verify(padding, &hashed, &*args.signature) + .is_ok() + } + _ => return Err(type_error("Unsupported algorithm".to_string())), + }; + + Ok(verification) +} + pub fn op_crypto_random_uuid( state: &mut OpState, _: (), |