feat: update jose-test

This commit is contained in:
2024-11-13 23:54:06 +08:00
parent 1b59475ab9
commit cc4c793835
2 changed files with 113 additions and 95 deletions

View File

@@ -9,9 +9,9 @@ use josekit::jwe::JweHeader;
use josekit::jwk::alg::rsa::RsaKeyPair;
use josekit::jwk::Jwk;
use rand::random;
use rand::rngs::OsRng;
use rsa::{Oaep, RsaPrivateKey};
use rust_util::XResult;
use rand::rngs::{OsRng, ThreadRng};
use rsa::{Oaep, RsaPrivateKey, RsaPublicKey};
use rust_util::{opt_result, simple_error, XResult};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sha1::Sha1;
@@ -48,59 +48,6 @@ const LOCAL_KMS_PREFIX: &str = "LKMS:";
// A256GCM Advanced Encryption Standard (AES) using 256 bit keys in Galois/Counter Mode, as defined in [FIPS197] and [NIST80038D]
// A256KW Advanced Encryption Standard (AES) Key Wrap Algorithm using 256 bit keys, as defined in RFC 3394 [RFC3394]
pub fn generate_rsa_key_2(bits: u32) -> XResult<RsaPrivateKey> {
let mut rng = OsRng::default();
Ok(RsaPrivateKey::new(&mut rng, bits as usize)?)
}
pub fn generate_rsa_key(bits: u32) -> XResult<RsaKeyPair> {
Ok(RsaKeyPair::generate(bits)?)
}
pub fn serialize_jwe_rsa_2(payload: &[u8], jwk: &Jwk) {
// TODO ...
}
pub fn serialize_jwe_rsa(payload: &[u8], jwk: &Jwk) -> XResult<String> {
let mut header = JweHeader::new();
header.set_content_encryption("A256GCM");
header.set_claim("vendor", Some(Value::String("local-mini-kms".to_string())))?;
let encrypter = RsaesJweAlgorithm::RsaOaep.encrypter_from_jwk(jwk)?;
Ok(format!("{}{}", LOCAL_KMS_PREFIX, jwe::serialize_compact(payload, &header, &encrypter)?))
}
pub fn deserialize_jwe_rsa_2(jwe: &str, rsa: &RsaPrivateKey) -> XResult<(Vec<u8>, JweHeader2)> {
let jwe_parts = jwe.split(".").collect::<Vec<&str>>();
if jwe_parts.len() != 5 {
panic!("Invalid jwe");
}
let header_bytes = URL_SAFE_NO_PAD.decode(jwe_parts[0].as_bytes()).unwrap();
let header: JweHeader2 = serde_json::from_slice(&header_bytes).unwrap();
println!("{:?}", jwe_parts);
println!("{:?}", header);
let key_wrap = URL_SAFE_NO_PAD.decode(jwe_parts[1].as_bytes()).unwrap();
let nonce = URL_SAFE_NO_PAD.decode(jwe_parts[2].as_bytes()).unwrap();
let ciphertext = URL_SAFE_NO_PAD.decode(jwe_parts[3].as_bytes()).unwrap();
let tag = URL_SAFE_NO_PAD.decode(jwe_parts[4].as_bytes()).unwrap();
let data_key = rsa.decrypt(Oaep::new::<Sha1>(), &key_wrap).unwrap();
let data_key_b32 = bytes_to_32(&data_key);
let mut decryptor = Aes256GcmStreamDecryptor::new(data_key_b32, &nonce);
decryptor.init_adata(jwe_parts[0].as_bytes());
let mut p1 = decryptor.update(&ciphertext);
let p2 = decryptor.update(&tag);
let pf = decryptor.finalize().unwrap();
p1.extend_from_slice(&p2);
p1.extend_from_slice(&pf);
Ok((p1, header))
}
pub fn deserialize_jwe_rsa(jwe: &str, jwk: &Jwk) -> XResult<(Vec<u8>, JweHeader)> {
let decrypter = RsaesJweAlgorithm::RsaOaep.decrypter_from_jwk(jwk)?;
Ok(jwe::deserialize_compact(&get_jwe(jwe), &decrypter)?)
}
// JWE Header: {"alg":"dir","enc":"A256GCM"}
// Encrypted key (CEK): (blank)
// IV: Vlf_WdLm-spHbfJe
@@ -115,6 +62,46 @@ pub fn deserialize_jwe_rsa(jwe: &str, jwk: &Jwk) -> XResult<(Vec<u8>, JweHeader)
//
// https://security.stackexchange.com/questions/80966/what-is-the-point-of-aes-key-wrap-with-json-web-encryption
pub fn generate_rsa_key_2(bits: u32) -> XResult<RsaPrivateKey> {
let mut rng = OsRng::default();
Ok(RsaPrivateKey::new(&mut rng, bits as usize)?)
}
pub fn generate_rsa_key(bits: u32) -> XResult<RsaKeyPair> {
Ok(RsaKeyPair::generate(bits)?)
}
pub fn serialize_jwe_rsa_2(payload: &[u8], rsa_public_key: &RsaPublicKey) -> XResult<String> {
let header = JweHeader2 {
enc: "A256GCM".to_string(),
alg: "RSA-OAEP".to_string(),
vendor: "local-mini-kms".to_string(),
};
serialize_jwe_fn(&header, payload, |data_key| -> XResult<Vec<u8>> {
let mut r = ThreadRng::default();
Ok(opt_result!(rsa_public_key.encrypt(&mut r, Oaep::new::<Sha1>(), data_key), "Wrap key failed: {}"))
})
}
pub fn serialize_jwe_rsa(payload: &[u8], jwk: &Jwk) -> XResult<String> {
let mut header = JweHeader::new();
header.set_content_encryption("A256GCM");
header.set_claim("vendor", Some(Value::String("local-mini-kms".to_string())))?;
let encrypter = RsaesJweAlgorithm::RsaOaep.encrypter_from_jwk(jwk)?;
Ok(format!("{}{}", LOCAL_KMS_PREFIX, jwe::serialize_compact(payload, &header, &encrypter)?))
}
pub fn deserialize_jwe_rsa_2(jwe: &str, rsa: &RsaPrivateKey) -> XResult<(Vec<u8>, JweHeader2)> {
deserialize_jwe_fn(jwe, |key_wrap| -> XResult<(Vec<u8>)> {
Ok(opt_result!(rsa.decrypt(Oaep::new::<Sha1>(), &key_wrap), "Unwrap key failed: {}"))
})
}
pub fn deserialize_jwe_rsa(jwe: &str, jwk: &Jwk) -> XResult<(Vec<u8>, JweHeader)> {
let decrypter = RsaesJweAlgorithm::RsaOaep.decrypter_from_jwk(jwk)?;
Ok(jwe::deserialize_compact(&get_jwe(jwe), &decrypter)?)
}
#[derive(Debug, Serialize, Deserialize)]
pub struct JweHeader2 {
pub enc: String,
@@ -128,9 +115,39 @@ pub fn serialize_jwe_aes_2(payload: &[u8], key: [u8; 32]) -> XResult<String> {
alg: "A256KW".to_string(),
vendor: "local-mini-kms".to_string(),
};
serialize_jwe_fn(&header, payload, |data_key| -> XResult<Vec<u8>> {
let kek = Kek::from(key);
Ok(opt_result!(kek.wrap_vec(&data_key[..]), "Wrap key failed: {}"))
})
}
pub fn serialize_jwe_aes(payload: &[u8], key: &[u8]) -> XResult<String> {
let mut header = JweHeader::new();
header.set_content_encryption("A256GCM");
header.set_claim("vendor", Some(Value::String("local-mini-kms".to_string())))?;
// header.set_claim("version", Some(Value::String(get_master_key_checksum(key))))?;
let encrypter = AeskwJweAlgorithm::A256kw.encrypter_from_bytes(key)?;
Ok(format!("{}{}", LOCAL_KMS_PREFIX, jwe::serialize_compact(payload, &header, &encrypter)?))
}
pub fn deserialize_jwe_aes_2(jwe: &str, key: [u8; 32]) -> XResult<(Vec<u8>, JweHeader2)> {
deserialize_jwe_fn(jwe, |key_wrap| -> XResult<(Vec<u8>)> {
let kek = Kek::from(key);
Ok(opt_result!(kek.unwrap_vec(&key_wrap), "Unwrap key failed: {}"))
})
}
pub fn deserialize_jwe_aes(jwe: &str, key: &[u8]) -> XResult<(Vec<u8>, JweHeader)> {
let decrypter = AeskwJweAlgorithm::A256kw.decrypter_from_bytes(key)?;
Ok(jwe::deserialize_compact(&get_jwe(jwe), &decrypter)?)
}
fn serialize_jwe_fn<F>(header: &JweHeader2, payload: &[u8], key_wrap_fn: F) -> XResult<String>
where
F: Fn(&[u8]) -> XResult<Vec<u8>>,
{
let header_str = serde_json::to_string(&header).unwrap();
let header_b64 = URL_SAFE_NO_PAD.encode(header_str.as_bytes());
// let key: [u8; 32] = key.into();
let data_key: [u8; 32] = random();
let nonce: [u8; 12] = random();
@@ -140,8 +157,7 @@ pub fn serialize_jwe_aes_2(payload: &[u8], key: [u8; 32]) -> XResult<String> {
let (f, t) = encryptor.finalize();
e.extend_from_slice(&f);
let kek = Kek::from(key);
let wrap_key = kek.wrap_vec(&data_key[..]).unwrap();
let wrap_key = key_wrap_fn(&data_key)?;
let mut jwe = String::new();
jwe.push_str(&header_b64);
@@ -157,59 +173,52 @@ pub fn serialize_jwe_aes_2(payload: &[u8], key: [u8; 32]) -> XResult<String> {
Ok(jwe)
}
pub fn serialize_jwe_aes(payload: &[u8], key: &[u8]) -> XResult<String> {
let mut header = JweHeader::new();
header.set_content_encryption("A256GCM");
header.set_claim("vendor", Some(Value::String("local-mini-kms".to_string())))?;
// header.set_claim("version", Some(Value::String(get_master_key_checksum(key))))?;
let encrypter = AeskwJweAlgorithm::A256kw.encrypter_from_bytes(key)?;
Ok(format!("{}{}", LOCAL_KMS_PREFIX, jwe::serialize_compact(payload, &header, &encrypter)?))
}
pub fn deserialize_jwe_aes_2(jwe: &str, key: [u8; 32]) -> XResult<(Vec<u8>, JweHeader2)> {
fn deserialize_jwe_fn<F>(jwe: &str, key_unwrap_fn: F) -> XResult<(Vec<u8>, JweHeader2)>
where
F: Fn(&[u8]) -> XResult<Vec<u8>>,
{
let jwe_parts = jwe.split(".").collect::<Vec<&str>>();
if jwe_parts.len() != 5 {
panic!("Invalid jwe");
return simple_error!("Invalid JWE: {}", jwe);
}
let header_bytes = URL_SAFE_NO_PAD.decode(jwe_parts[0].as_bytes()).unwrap();
let header: JweHeader2 = serde_json::from_slice(&header_bytes).unwrap();
println!("{:?}", jwe_parts);
println!("{:?}", header);
let key_wrap = URL_SAFE_NO_PAD.decode(jwe_parts[1].as_bytes()).unwrap();
let nonce = URL_SAFE_NO_PAD.decode(jwe_parts[2].as_bytes()).unwrap();
let ciphertext = URL_SAFE_NO_PAD.decode(jwe_parts[3].as_bytes()).unwrap();
let tag = URL_SAFE_NO_PAD.decode(jwe_parts[4].as_bytes()).unwrap();
let header_bytes = opt_result!(decode_url_safe_no_pad(jwe_parts[0]), "Invalid JWE header: {}, JWE: {}", jwe);
let header: JweHeader2 = opt_result!(serde_json::from_slice(&header_bytes), "Invalid JWE header: {}, JWE: {}", jwe);
let cek = opt_result!(decode_url_safe_no_pad(jwe_parts[1]), "Invalid JWE CEK: {}, JWE: {}", jwe);
let iv = opt_result!(decode_url_safe_no_pad(jwe_parts[2]), "Invalid JWE IV: {}, JWE: {}", jwe);
let ciphertext = opt_result!(decode_url_safe_no_pad(jwe_parts[3]), "Invalid JWE ciphertext: {}, JWE: {}", jwe);
let tag = opt_result!(decode_url_safe_no_pad(jwe_parts[4]), "Invalid JWE tag: {}, JWE: {}", jwe);
let kek = Kek::from(key);
let data_key = kek.unwrap_vec(&key_wrap).unwrap();
let data_key_b32 = bytes_to_32(&data_key);
let data_key = key_unwrap_fn(&cek)?;
let data_key_b32 = opt_result!(to_bytes32(&data_key), "Invalid JWE CEK: {}, JWE: {}", jwe);
let mut decryptor = Aes256GcmStreamDecryptor::new(data_key_b32, &nonce);
let mut decryptor = Aes256GcmStreamDecryptor::new(data_key_b32, &iv);
decryptor.init_adata(jwe_parts[0].as_bytes());
let mut p1 = decryptor.update(&ciphertext);
let p2 = decryptor.update(&tag);
let pf = decryptor.finalize().unwrap();
p1.extend_from_slice(&p2);
p1.extend_from_slice(&pf);
Ok((p1, header))
let mut plaintext = decryptor.update(&ciphertext);
let plaintext_2 = decryptor.update(&tag);
let plaintext_final = opt_result!(decryptor.finalize(), "Invalid JWE: {}, JWE: {}", jwe);
plaintext.extend_from_slice(&plaintext_2);
plaintext.extend_from_slice(&plaintext_final);
Ok((plaintext, header))
}
pub fn deserialize_jwe_aes(jwe: &str, key: &[u8]) -> XResult<(Vec<u8>, JweHeader)> {
let decrypter = AeskwJweAlgorithm::A256kw.decrypter_from_bytes(key)?;
Ok(jwe::deserialize_compact(&get_jwe(jwe), &decrypter)?)
#[inline]
fn decode_url_safe_no_pad(s: &str) -> XResult<Vec<u8>> {
Ok(URL_SAFE_NO_PAD.decode(s.as_bytes())?)
}
fn bytes_to_32(bytes: &[u8]) -> [u8; 32] {
#[inline]
fn to_bytes32(bytes: &[u8]) -> XResult<[u8; 32]> {
if bytes.len() != 32 {
panic!("Invalid bytes");
return simple_error!("Not valid 32 bytes");
}
let mut ret = [0; 32];
for i in 0..32 {
ret[i] = bytes[i];
}
ret
Ok(ret)
}
#[inline]
fn get_jwe(jwe: &str) -> String {
if jwe.starts_with(LOCAL_KMS_PREFIX) {
jwe.chars().skip(LOCAL_KMS_PREFIX.len()).collect()

View File

@@ -1,6 +1,6 @@
mod jose;
use crate::jose::{deserialize_jwe_aes, deserialize_jwe_aes_2, deserialize_jwe_rsa_2, serialize_jwe_aes_2, serialize_jwe_rsa};
use crate::jose::{deserialize_jwe_aes, deserialize_jwe_aes_2, deserialize_jwe_rsa_2, serialize_jwe_aes_2, serialize_jwe_rsa, serialize_jwe_rsa_2};
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use jose_jwk::{Jwk, Key, Rsa};
@@ -48,6 +48,15 @@ fn main() {
println!("DD: {}", String::from_utf8_lossy(&dd));
println!("HH: {:?}", hh);
println!("-------------------------------------------------------------------------------------");
let rsa_jwe2 = serialize_jwe_rsa_2(b"hello world 003", rsa_public_key).unwrap();
println!(">>> {}", rsa_jwe2);
// let rsa_jwe2 = rsa_jwe2.chars().skip(5).collect::<String>();
let (ddd, hhh) = deserialize_jwe_rsa_2(&rsa_jwe2, &rsa_key).unwrap();
println!("DDD: {}", String::from_utf8_lossy(&ddd));
println!("HHH: {:?}", hhh);
println!("-------------------------------------------------------------------------------------");
main2();
}