From 82b38a2cf17cde7aedc182339a8fbb3f108886ea Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Fri, 15 Nov 2024 00:24:36 +0800 Subject: [PATCH] feat: v1.0.1, update datakey --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/cli.rs | 6 +++--- src/jose.rs | 13 +++++++++++-- src/serve_datakey.rs | 24 ++++++++++++------------ src/serve_encrypt_decrypt.rs | 20 ++++++++++++++++---- 6 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e85f4a0..1c97791 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -874,7 +874,7 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "local-mini-kms" -version = "1.0.0" +version = "1.0.1" dependencies = [ "aes-gcm-stream", "aes-kw", diff --git a/Cargo.toml b/Cargo.toml index 8998eee..d5d9b15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "local-mini-kms" -version = "1.0.0" +version = "1.0.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/cli.rs b/src/cli.rs index 53f850a..71e5355 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -164,7 +164,7 @@ async fn do_write(_arg_matches: &ArgMatches<'_>, sub_arg_matches: &ArgMatches<'_ return simple_error!("Require one of value, value-hex, value-base64"); }; let data = do_inner_request(sub_arg_matches, "write", &body).await?; - success!("Value: {}", serde_json::to_string_pretty(&data)?); + println!("{}", serde_json::to_string_pretty(&data)?); Ok(Some(0)) } @@ -183,7 +183,7 @@ async fn do_encrypt(_arg_matches: &ArgMatches<'_>, sub_arg_matches: &ArgMatches< return simple_error!("Require one of value, value-hex, value-base64"); }; let data = do_inner_request(sub_arg_matches, "encrypt", &body).await?; - success!("Value: {}", serde_json::to_string_pretty(&data)?); + println!("{}", serde_json::to_string_pretty(&data)?); Ok(Some(0)) } @@ -193,7 +193,7 @@ async fn do_decrypt(_arg_matches: &ArgMatches<'_>, sub_arg_matches: &ArgMatches< let body = json!({ "encrypted_value": value }); let data = do_inner_request(sub_arg_matches, "decrypt", &body).await?; - success!("Value: {}", serde_json::to_string_pretty(&data)?); + println!("{}", serde_json::to_string_pretty(&data)?); Ok(Some(0)) } diff --git a/src/jose.rs b/src/jose.rs index 39c479e..dd255b9 100644 --- a/src/jose.rs +++ b/src/jose.rs @@ -23,7 +23,10 @@ pub struct JweHeader { pub enc: String, pub alg: String, pub vendor: String, + #[serde(skip_serializing_if = "Option::is_none")] pub version: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub data_type: Option, } pub fn generate_rsa_key(bits: u32) -> XResult { @@ -56,6 +59,7 @@ pub fn serialize_jwe_rsa(payload: &[u8], rsa_public_key: &RsaPublicKey) -> XResu alg: JWE_ALG_RSA_OAEP.to_string(), vendor: "local-mini-kms".to_string(), version: None, + data_type: None, }; serialize_jwe_fn(&header, payload, |data_key| -> XResult> { let mut r = thread_rng(); @@ -73,15 +77,20 @@ pub fn deserialize_jwe_rsa(jwe: &str, rsa: &RsaPrivateKey) -> XResult<(Vec, } pub fn serialize_jwe_aes(payload: &[u8], key: &[u8]) -> XResult { - serialize_jwe_aes_32(payload, to_bytes32(key)?) + serialize_jwe_aes_32(None, payload, to_bytes32(key)?) } -pub fn serialize_jwe_aes_32(payload: &[u8], key: [u8; 32]) -> XResult { +pub fn serialize_jwe_aes_with_data_type(data_type: &str, payload: &[u8], key: &[u8]) -> XResult { + serialize_jwe_aes_32(Some(data_type.to_string()), payload, to_bytes32(key)?) +} + +pub fn serialize_jwe_aes_32(data_type: Option, payload: &[u8], key: [u8; 32]) -> XResult { let header = JweHeader { enc: JWE_ENC_A256GCM.to_string(), alg: JWE_ALG_A256KW.to_string(), vendor: "local-mini-kms".to_string(), version: Some(get_master_key_checksum(&key)), + data_type, }; serialize_jwe_fn(&header, payload, |data_key| -> XResult> { let kek = Kek::from(key); diff --git a/src/serve_datakey.rs b/src/serve_datakey.rs index 8664ca1..56c24d3 100644 --- a/src/serve_datakey.rs +++ b/src/serve_datakey.rs @@ -19,6 +19,7 @@ use serde_json::{Map, Value}; struct DataKeyRequest { key_type: String, key_spec: String, + key_name: Option, return_plaintext: Option, } @@ -38,9 +39,9 @@ async fn inner_generate(req: Request) -> XResult<(StatusCode, Value)> { let ret_key_plaintext = request.return_plaintext.unwrap_or(false); let response_result = match (request.key_type.as_str(), request.key_spec.as_str()) { - ("aes", "128") => generate_aes("datakey.aes_128:", key, 16, ret_key_plaintext), - ("aes", "192") => generate_aes("datakey.aes_192:", key, 24, ret_key_plaintext), - ("aes", "256") => generate_aes("datakey.aes_256:", key, 32, ret_key_plaintext), + ("aes", "128") => generate_aes("datakey:aes-128", key, 16, ret_key_plaintext), + ("aes", "192") => generate_aes("datakey:aes-192", key, 24, ret_key_plaintext), + ("aes", "256") => generate_aes("datakey:aes-256", key, 32, ret_key_plaintext), // TODO rsa 2048, rsa 3072, rsa 4096 // TODO ec p256, p384, p521, ed25519, cv25519 _ => return serve_common::error("invalid key_type or key_spec"), @@ -56,22 +57,21 @@ async fn inner_generate(req: Request) -> XResult<(StatusCode, Value)> { map.insert("key_plaintext".to_string(), Value::String(STANDARD.encode(&key_plaintext))); } map.insert("key_ciphertext".to_string(), Value::String(key_ciphertext)); + + if let Some(_key_name) = &request.key_name { + // TODO write datakey to db + // TODO let data_key_name = format!("datakey:{}", key_name); + } + Ok((StatusCode::OK, Value::Object(map))) } } } -fn generate_aes(prefix: &str, key: SecBytes, len: i32, ret_key_plaintext: bool) -> XResult<(Option>, String)> { +fn generate_aes(data_key_type: &str, key: SecBytes, len: i32, ret_key_plaintext: bool) -> XResult<(Option>, String)> { let bytes: [u8; 32] = random(); let value = &bytes[0..len as usize]; let key_plaintext = iff!(ret_key_plaintext, Some(value.to_vec()), None); - let key_ciphertext = jose::serialize_jwe_aes(&join_prefix_value(prefix, value), &key.read())?; + let key_ciphertext = jose::serialize_jwe_aes_with_data_type(data_key_type, value, &key.read())?; Ok((key_plaintext, key_ciphertext)) } - -fn join_prefix_value(prefix: &str, value: &[u8]) -> Vec { - let mut ret = Vec::with_capacity(prefix.len() + value.len()); - ret.extend_from_slice(prefix.as_bytes()); - ret.extend_from_slice(value); - ret -} \ No newline at end of file diff --git a/src/serve_encrypt_decrypt.rs b/src/serve_encrypt_decrypt.rs index a2e6a5c..b6d9b83 100644 --- a/src/serve_encrypt_decrypt.rs +++ b/src/serve_encrypt_decrypt.rs @@ -1,8 +1,8 @@ -use hyper::{Body, Request, Response, StatusCode}; use hyper::body::Buf; +use hyper::{Body, Request, Response, StatusCode}; use rust_util::{debugging, XResult}; use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; +use serde_json::{json, Map, Value}; use crate::do_response; use crate::jose; @@ -29,8 +29,20 @@ async fn inner_decrypt(req: Request) -> XResult<(StatusCode, Value)> { let decrypted_value = jose::deserialize_jwe_aes(&data.encrypted_value, &key.read()); drop(key); - decrypted_value.map(|v| { - let map = byte_to_multi_view_map(&v.0, true); + decrypted_value.map(|(data, header)| { + let mut map = byte_to_multi_view_map(&data, true); + let mut header_map = Map::new(); + header_map.insert("enc".to_string(), Value::String(header.enc.clone())); + header_map.insert("alg".to_string(), Value::String(header.alg.clone())); + if let Some(version) = &header.version { + header_map.insert("version".to_string(), Value::String(version.to_string())); + } + if let Some(data_type) = &header.data_type { + header_map.insert("data_type".to_string(), Value::String(data_type.to_string())); + } + if !header_map.is_empty() { + map.insert("header".to_string(), Value::Object(header_map)); + } (StatusCode::OK, Value::Object(map)) }) }