summaryrefslogtreecommitdiff
path: root/ext/crypto/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ext/crypto/lib.rs')
-rw-r--r--ext/crypto/lib.rs75
1 files changed, 75 insertions, 0 deletions
diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs
index 8cbd399ee..0331d0dc3 100644
--- a/ext/crypto/lib.rs
+++ b/ext/crypto/lib.rs
@@ -1,5 +1,9 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+use aes_kw::KekAes128;
+use aes_kw::KekAes192;
+use aes_kw::KekAes256;
+
use deno_core::error::custom_error;
use deno_core::error::not_supported;
use deno_core::error::type_error;
@@ -11,6 +15,7 @@ use deno_core::Extension;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use serde::Deserialize;
+use shared::operation_error;
use std::cell::RefCell;
use std::num::NonZeroU32;
@@ -47,6 +52,7 @@ use sha2::Digest;
use sha2::Sha256;
use sha2::Sha384;
use sha2::Sha512;
+use std::convert::TryFrom;
use std::path::PathBuf;
pub use rand; // Re-export rand
@@ -68,6 +74,7 @@ use crate::key::Algorithm;
use crate::key::CryptoHash;
use crate::key::CryptoNamedCurve;
use crate::key::HkdfOutput;
+use crate::shared::RawKeyData;
use crate::shared::ID_MFG1;
use crate::shared::ID_P_SPECIFIED;
use crate::shared::ID_SHA1_OID;
@@ -95,6 +102,8 @@ pub fn init(maybe_seed: Option<u64>) -> Extension {
("op_crypto_decrypt", op_async(op_crypto_decrypt)),
("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)),
+ ("op_crypto_wrap_key", op_sync(op_crypto_wrap_key)),
+ ("op_crypto_unwrap_key", op_sync(op_crypto_unwrap_key)),
])
.state(move |state| {
if let Some(seed) = maybe_seed {
@@ -815,6 +824,72 @@ pub async fn op_crypto_subtle_digest(
Ok(output)
}
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct WrapUnwrapKeyArg {
+ key: RawKeyData,
+ algorithm: Algorithm,
+}
+
+pub fn op_crypto_wrap_key(
+ _state: &mut OpState,
+ args: WrapUnwrapKeyArg,
+ data: ZeroCopyBuf,
+) -> Result<ZeroCopyBuf, AnyError> {
+ let algorithm = args.algorithm;
+
+ match algorithm {
+ Algorithm::AesKw => {
+ let key = args.key.as_secret_key()?;
+
+ if data.len() % 8 != 0 {
+ return Err(type_error("Data must be multiple of 8 bytes"));
+ }
+
+ let wrapped_key = match key.len() {
+ 16 => KekAes128::new(key.into()).wrap_vec(&data),
+ 24 => KekAes192::new(key.into()).wrap_vec(&data),
+ 32 => KekAes256::new(key.into()).wrap_vec(&data),
+ _ => return Err(type_error("Invalid key length")),
+ }
+ .map_err(|_| operation_error("encryption error"))?;
+
+ Ok(wrapped_key.into())
+ }
+ _ => Err(type_error("Unsupported algorithm")),
+ }
+}
+
+pub fn op_crypto_unwrap_key(
+ _state: &mut OpState,
+ args: WrapUnwrapKeyArg,
+ data: ZeroCopyBuf,
+) -> Result<ZeroCopyBuf, AnyError> {
+ let algorithm = args.algorithm;
+ match algorithm {
+ Algorithm::AesKw => {
+ let key = args.key.as_secret_key()?;
+
+ if data.len() % 8 != 0 {
+ return Err(type_error("Data must be multiple of 8 bytes"));
+ }
+
+ let unwrapped_key = match key.len() {
+ 16 => KekAes128::new(key.into()).unwrap_vec(&data),
+ 24 => KekAes192::new(key.into()).unwrap_vec(&data),
+ 32 => KekAes256::new(key.into()).unwrap_vec(&data),
+ _ => return Err(type_error("Invalid key length")),
+ }
+ .map_err(|_| {
+ operation_error("decryption error - integrity check failed")
+ })?;
+
+ Ok(unwrapped_key.into())
+ }
+ _ => Err(type_error("Unsupported algorithm")),
+ }
+}
+
pub fn get_declaration() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_crypto.d.ts")
}