From 2a9d6dfaac2a6aa13e44cda340f45a4b7ddfccae Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Wed, 13 Nov 2024 00:15:30 +0800 Subject: [PATCH] feat: jose --- __crypto/jose-test/Cargo.lock | 444 +++++++++++++++++++++++++++++++++ __crypto/jose-test/Cargo.toml | 4 + __crypto/jose-test/src/jose.rs | 153 ++++++++++++ __crypto/jose-test/src/main.rs | 44 ++-- 4 files changed, 616 insertions(+), 29 deletions(-) create mode 100644 __crypto/jose-test/src/jose.rs diff --git a/__crypto/jose-test/Cargo.lock b/__crypto/jose-test/Cargo.lock index 3ba9ba0..547eab8 100644 --- a/__crypto/jose-test/Cargo.lock +++ b/__crypto/jose-test/Cargo.lock @@ -2,6 +2,54 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "aes-gcm-stream" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "163d1209787b2226543db17d317f5e9f5f54fd0d0f20834318f92013ebd78f37" +dependencies = [ + "aes", + "cipher", + "ghash", + "zeroize", +] + +[[package]] +name = "aes-kw" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69fa2b352dcefb5f7f3a5fb840e02665d311d878955380515e4fd50095dd3d8c" +dependencies = [ + "aes", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -17,6 +65,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + [[package]] name = "autocfg" version = "1.4.0" @@ -57,6 +111,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "block-buffer" version = "0.10.4" @@ -105,6 +165,16 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -117,6 +187,24 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -156,6 +244,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -167,6 +264,27 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "elliptic-curve" version = "0.13.8" @@ -201,6 +319,31 @@ dependencies = [ "subtle", ] +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "generic-array" version = "0.14.7" @@ -223,6 +366,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "group" version = "0.13.0" @@ -273,6 +426,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "itoa" version = "1.0.11" @@ -325,16 +487,37 @@ dependencies = [ name = "jose-test" version = "0.1.0" dependencies = [ + "aes-gcm-stream", + "aes-kw", "base64", "biscuit", "jose-jwe", "jose-jwk", + "josekit", "rand", "rsa", + "rust_util", "serde", "serde_json", ] +[[package]] +name = "josekit" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a603084e34e151e215d232e401df0d9299bdced264b8054e4888ea614e59bb06" +dependencies = [ + "anyhow", + "base64", + "flate2", + "openssl", + "regex", + "serde", + "serde_json", + "thiserror", + "time", +] + [[package]] name = "js-sys" version = "0.3.72" @@ -365,6 +548,16 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", +] + [[package]] name = "log" version = "0.4.22" @@ -377,6 +570,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -404,6 +606,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -440,6 +648,50 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "p256" version = "0.13.2" @@ -490,6 +742,30 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -556,6 +832,46 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "ring" version = "0.17.8" @@ -591,6 +907,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rust_util" +version = "0.6.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bca5d3493eb29d08dc76ee784a78723fe366fec5dfe67ab37da9d50fb868f7c" +dependencies = [ + "lazy_static", + "libc", + "term", + "term_size", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + [[package]] name = "ryu" version = "1.0.18" @@ -698,6 +1032,66 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "term_size" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "typenum" version = "1.17.0" @@ -710,12 +1104,28 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -783,6 +1193,28 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.52.0" @@ -893,4 +1325,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "serde", + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] diff --git a/__crypto/jose-test/Cargo.toml b/__crypto/jose-test/Cargo.toml index e41d9ef..d2effe4 100644 --- a/__crypto/jose-test/Cargo.toml +++ b/__crypto/jose-test/Cargo.toml @@ -4,11 +4,15 @@ version = "0.1.0" edition = "2021" [dependencies] +aes-gcm-stream = "0.2.3" +aes-kw = { version = "0.2.1", features = ["alloc"] } base64 = "0.22.1" biscuit = "0.7.0" jose-jwe = "0.0.0" jose-jwk = { version = "0.1.2", features = ["rsa"] } +josekit = "0.10.0" rand = { version = "0.8.5", features = [] } rsa = "0.9.6" +rust_util = "0.6.47" serde = "1.0.214" serde_json = "1.0.132" diff --git a/__crypto/jose-test/src/jose.rs b/__crypto/jose-test/src/jose.rs new file mode 100644 index 0000000..907afaf --- /dev/null +++ b/__crypto/jose-test/src/jose.rs @@ -0,0 +1,153 @@ +use aes_gcm_stream::Aes256GcmStreamEncryptor; +use aes_kw::Kek; +use base64::engine::general_purpose::URL_SAFE_NO_PAD; +use base64::Engine; +use josekit::jwe; +use josekit::jwe::alg::aeskw::AeskwJweAlgorithm; +use josekit::jwe::alg::rsaes::RsaesJweAlgorithm; +use josekit::jwe::JweHeader; +use josekit::jwk::alg::rsa::RsaKeyPair; +use josekit::jwk::Jwk; +use rand::random; +use rand::rngs::OsRng; +use rsa::RsaPrivateKey; +use rust_util::XResult; +use serde::Serialize; +use serde_json::Value; + +const LOCAL_KMS_PREFIX: &str = "LKMS:"; + + +// JWE format: +// BASE64URL(UTF8(JWE Protected Header)) || '.' || +// BASE64URL(JWE Encrypted Key) || '.' || BASE64URL(JWE Initialization Vector) +// || '.' || BASE64URL(JWE Ciphertext) || '.' || BASE64URL(JWE Authentication Tag). +// +// RSA JWE Header: +// {"enc":"A256GCM","vendor":"local-mini-kms","alg":"RSA-OAEP"} +// eyJlbmMiOiJBMjU2R0NNIiwidmVuZG9yIjoibG9jYWwtbWluaS1rbXMiLCJhbGciOiJSU0EtT0FFUCJ9.VQ_R +// yGjXqQlUIbRIMgaYRSaX5FMRBzZ6ApfdZ2yAwiG70hjNfR3ss7x4PYqMm6QtITm1O4_fp7I3bY8iUz5Njyth_ +// Min7Xm2-WsQ6gq9yN58btkUBFm60c7SC5XLaqE1pEtBAz7786bJk6M4NeOtDAOFAmIb2j1EwnS5vweBtmNv7N +// UFIgvx806T3WkCFDOkMSJ10_6LSa0z-lIac-s68svsU5WW8CXVKxHAbxaHyX_otu2HxXzDZlF5Goamh5ZJtr0 +// 0yW_bzDCx3hZ2nMK3Ve7IJ2ZLAMmvhj9LKWkPtoqH0dGHaPHWff5P3rZ4vtKywt_h5b6SYII_mEoJcpByMyGw +// TXCtZymDt82Tyv_FesW2721JgyGxnukuOxQRTw4MfGYIO5bldL3uGGI_H4HXlXhM_kp3wuPAZ0vH4Jj2KD6MV +// DDTJQaEBQIEF07i7WiNynr57kbahYwextRXYP7LgoUHfFwA5GGGpN-UkuWLlKkYLTmXGrPYnL6Cf9D3euP7nF +// ml2oA2hjig-UuYf9A_QSEqNsMxYDuG-rggn3H_iXNl4ooYcxSVOXhTKfoV578MkNwG75BdHN5FeRYIKq0HCTM +// lGqqBWmDibPtMd7Uq1JrDd8774lnA8JcZcCMSia4m6WJSbG0kOuJ4NJPOUrYtNEJXgWKU3FQzDB-apLMQdac. +// WYJgsdZRLk310KWd.P333-S2VYg.PCfruTdk8vh3a8wcjJCe-g +// +// RSA-OAEP RSA using Optimal Asymmetric Encryption Padding (OAEP), as defined in RFC 3447 [RFC3447] +// A256GCM Advanced Encryption Standard (AES) using 256 bit keys in Galois/Counter Mode, as defined in [FIPS‑197] and [NIST‑800‑38D] +// +// AES JWE Header: +// {"enc":"A256GCM","vendor":"local-mini-kms","version":"5b90f66a1c6a918d","alg":"A256KW"} +// eyJlbmMiOiJBMjU2R0NNIiwidmVuZG9yIjoibG9jYWwtbWluaS1rbXMiLCJ2ZXJzaW9uIjoiNWI5MGY2NmExYz +// ZhOTE4ZCIsImFsZyI6IkEyNTZLVyJ9.K2_P-b_Gq9wbrssbcS5AmiUwcnNTnnZSe7rBI1SixVrC7TfFK0fruw. +// ez3OKjOHAIIYnfM0.wSO3aXo.-vGJwk8JQKhi3voIlAA9gQ +// +// A256GCM Advanced Encryption Standard (AES) using 256 bit keys in Galois/Counter Mode, as defined in [FIPS‑197] and [NIST‑800‑38D] +// 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 { + let mut rng = OsRng::default(); + Ok(RsaPrivateKey::new(&mut rng, bits as usize)?) +} + +pub fn generate_rsa_key(bits: u32) -> XResult { + 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 { + 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(jwe: &str, jwk: &Jwk) -> XResult<(Vec, 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 +// Ciphertext: RxMPrw +// Authentication Tag: 5VC8Y_qSPdSubbGNGyfn6A +// +// JWE Header: {"alg":"A256KW","enc":"A256GCM"} +// Encrypted key (CEK): 66xZoxFI18zfvLMO6WU1zzqqX1tT8xu_qZzMQyPcfVuajPNkOJUXQA +// IV: X5ZL8yaOektXmfny +// Ciphertext: brz-Lg +// Authentication Tag: xG-EvM-9hrw0XRiuRW7HrA +// +// https://security.stackexchange.com/questions/80966/what-is-the-point-of-aes-key-wrap-with-json-web-encryption + +#[derive(Serialize)] +struct JweHeader2 { + pub enc: String, + pub alg: String, + pub vendor: String, +} + +pub fn serialize_jwe_aes_2(payload: &[u8], key: [u8; 32]) -> XResult { + let header = JweHeader2 { + enc: "A256GCM".to_string(), + alg: "A256KW".to_string(), + vendor: "local-mini-kms".to_string(), + }; + 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(); + let mut encryptor = Aes256GcmStreamEncryptor::new(data_key, &nonce); + encryptor.init_adata(header_b64.as_bytes()); + let mut e = encryptor.update(payload); + 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 mut jwe = String::new(); + jwe.push_str(&header_b64); + jwe.push_str("."); + jwe.push_str(&URL_SAFE_NO_PAD.encode(&wrap_key)); + jwe.push_str("."); + jwe.push_str(&URL_SAFE_NO_PAD.encode(&nonce)); + jwe.push_str("."); + jwe.push_str(&URL_SAFE_NO_PAD.encode(&e)); + jwe.push_str("."); + jwe.push_str(&URL_SAFE_NO_PAD.encode(&t)); + + Ok(jwe) +} + +pub fn serialize_jwe_aes(payload: &[u8], key: &[u8]) -> XResult { + 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(jwe: &str, key: &[u8]) -> XResult<(Vec, JweHeader)> { + let decrypter = AeskwJweAlgorithm::A256kw.decrypter_from_bytes(key)?; + Ok(jwe::deserialize_compact(&get_jwe(jwe), &decrypter)?) +} + +fn get_jwe(jwe: &str) -> String { + if jwe.starts_with(LOCAL_KMS_PREFIX) { + jwe.chars().skip(LOCAL_KMS_PREFIX.len()).collect() + } else { + jwe.to_string() + } +} \ No newline at end of file diff --git a/__crypto/jose-test/src/main.rs b/__crypto/jose-test/src/main.rs index 7aa9e8d..d283015 100644 --- a/__crypto/jose-test/src/main.rs +++ b/__crypto/jose-test/src/main.rs @@ -1,41 +1,27 @@ +mod jose; + use base64::Engine; use jose_jwk::jose_b64::serde::Bytes; use jose_jwk::Rsa; +use rand::random; use rand::rngs::ThreadRng; use rsa::Pkcs1v15Encrypt; use serde_json::Value; +use crate::jose::{deserialize_jwe_aes, serialize_jwe_aes_2}; fn main() { - // JWE format: - // BASE64URL(UTF8(JWE Protected Header)) || '.' || - // BASE64URL(JWE Encrypted Key) || '.' || BASE64URL(JWE Initialization Vector) - // || '.' || BASE64URL(JWE Ciphertext) || '.' || BASE64URL(JWE Authentication Tag). - // - // RSA JWE Header: - // {"enc":"A256GCM","vendor":"local-mini-kms","alg":"RSA-OAEP"} - // eyJlbmMiOiJBMjU2R0NNIiwidmVuZG9yIjoibG9jYWwtbWluaS1rbXMiLCJhbGciOiJSU0EtT0FFUCJ9.VQ_R - // yGjXqQlUIbRIMgaYRSaX5FMRBzZ6ApfdZ2yAwiG70hjNfR3ss7x4PYqMm6QtITm1O4_fp7I3bY8iUz5Njyth_ - // Min7Xm2-WsQ6gq9yN58btkUBFm60c7SC5XLaqE1pEtBAz7786bJk6M4NeOtDAOFAmIb2j1EwnS5vweBtmNv7N - // UFIgvx806T3WkCFDOkMSJ10_6LSa0z-lIac-s68svsU5WW8CXVKxHAbxaHyX_otu2HxXzDZlF5Goamh5ZJtr0 - // 0yW_bzDCx3hZ2nMK3Ve7IJ2ZLAMmvhj9LKWkPtoqH0dGHaPHWff5P3rZ4vtKywt_h5b6SYII_mEoJcpByMyGw - // TXCtZymDt82Tyv_FesW2721JgyGxnukuOxQRTw4MfGYIO5bldL3uGGI_H4HXlXhM_kp3wuPAZ0vH4Jj2KD6MV - // DDTJQaEBQIEF07i7WiNynr57kbahYwextRXYP7LgoUHfFwA5GGGpN-UkuWLlKkYLTmXGrPYnL6Cf9D3euP7nF - // ml2oA2hjig-UuYf9A_QSEqNsMxYDuG-rggn3H_iXNl4ooYcxSVOXhTKfoV578MkNwG75BdHN5FeRYIKq0HCTM - // lGqqBWmDibPtMd7Uq1JrDd8774lnA8JcZcCMSia4m6WJSbG0kOuJ4NJPOUrYtNEJXgWKU3FQzDB-apLMQdac. - // WYJgsdZRLk310KWd.P333-S2VYg.PCfruTdk8vh3a8wcjJCe-g - // - // RSA-OAEP RSA using Optimal Asymmetric Encryption Padding (OAEP), as defined in RFC 3447 [RFC3447] - // A256GCM Advanced Encryption Standard (AES) using 256 bit keys in Galois/Counter Mode, as defined in [FIPS‑197] and [NIST‑800‑38D] - // - // AES JWE Header: - // {"enc":"A256GCM","vendor":"local-mini-kms","version":"5b90f66a1c6a918d","alg":"A256KW"} - // eyJlbmMiOiJBMjU2R0NNIiwidmVuZG9yIjoibG9jYWwtbWluaS1rbXMiLCJ2ZXJzaW9uIjoiNWI5MGY2NmExYz - // ZhOTE4ZCIsImFsZyI6IkEyNTZLVyJ9.K2_P-b_Gq9wbrssbcS5AmiUwcnNTnnZSe7rBI1SixVrC7TfFK0fruw. - // ez3OKjOHAIIYnfM0.wSO3aXo.-vGJwk8JQKhi3voIlAA9gQ - // - // A256GCM Advanced Encryption Standard (AES) using 256 bit keys in Galois/Counter Mode, as defined in [FIPS‑197] and [NIST‑800‑38D] - // A256KW Advanced Encryption Standard (AES) Key Wrap Algorithm using 256 bit keys, as defined in RFC 3394 [RFC3394] + let key: [u8; 32] = random(); + let payload = b"hello world"; + let e = serialize_jwe_aes_2(payload, key).unwrap(); + println!("{}", e); + + let (d, h) = deserialize_jwe_aes(&e, &key).unwrap(); + println!("{:?}", d); + println!("{:?}", h); +} + +fn main2() { let rsa_jwk = r##"{ "kty":"RSA", "e":"AQAB",