Skip to content

Commit 141f4a7

Browse files
Xynnn007cursoragent
authored andcommitted
kbs: adapt JWE code for aes-gcm 0.11 API changes
Update key/nonce generation, AeadInOut encryption, and RNG imports after aes-gcm 0.11 breaking changes so KBS builds with the upgraded dependency. Signed-off-by: Cursor Agent <cursoragent@cursor.com> Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 193cd93 commit 141f4a7

4 files changed

Lines changed: 40 additions & 36 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kbs/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ aws = ["aws-config", "aws-sdk-secretsmanager"]
5050
actix = "0.13.5"
5151
actix-web = { workspace = true, features = ["openssl"] }
5252
actix-web-httpauth.workspace = true
53-
aes-gcm = { version = "0.11.0", features = ["zeroize"] }
53+
aes-gcm = { version = "0.11.0", features = [
54+
"zeroize",
55+
"arrayvec",
56+
"getrandom",
57+
] }
5458
# Direct deps to activate their `zeroize` feature: `aes-gcm`'s own `zeroize`
5559
# feature does not propagate down to `aes` or `polyval`. Do not remove.
5660
aes = { version = "0.8", features = ["zeroize"] }

kbs/src/attestation/backend.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
use std::sync::{Arc, LazyLock};
66

77
use actix_web::{HttpRequest, HttpResponse};
8-
use aes_gcm::aead::OsRng;
98
use anyhow::{anyhow, bail, Context};
109
use async_trait::async_trait;
1110
use base64::{engine::general_purpose::STANDARD, Engine};
1211
use kbs_types::{Attestation, Challenge, InitData, Request, Tee};
1312
use key_value_storage::{KeyValueStorageType, StorageBackendConfig};
14-
use rsa::rand_core::RngCore;
13+
use rsa::rand_core::{OsRng, RngCore};
1514
use semver::{BuildMetadata, Prerelease, Version, VersionReq};
1615
use serde::Deserialize;
1716
use serde_json::json;

kbs/src/jwe.rs

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
use core::{clone::Clone, convert::TryInto};
66

77
use aes_gcm::{
8-
aead::{generic_array::GenericArray, AeadMutInPlace, OsRng},
8+
aead::{AeadInOut, Generate},
99
Aes256Gcm, KeyInit, Nonce,
1010
};
11-
use aes_kw::{KeyInit as AesKwKeyInit, KwAes256};
11+
use aes_kw::KwAes256;
1212
use anyhow::{anyhow, bail, Context, Result};
1313
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
1414
use kbs_types::{ProtectedHeader, Response, TeePubKey};
15-
use p256::elliptic_curve::sec1::FromEncodedPoint;
16-
use rsa::{rand_core::RngCore, sha2::Sha256, BigUint, Oaep, Pkcs1v15Encrypt, RsaPublicKey};
15+
use p256::elliptic_curve::{generic_array::GenericArray, sec1::FromEncodedPoint};
16+
use rsa::{rand_core::OsRng, sha2::Sha256, BigUint, Oaep, Pkcs1v15Encrypt, RsaPublicKey};
1717
use serde_json::{json, Map};
1818
use tracing::warn;
1919
use zeroize::Zeroizing;
@@ -70,11 +70,11 @@ const AES_GCM_256_ALGORITHM: &str = "A256GCM";
7070
#[deprecated(note = "This algorithm is no longer recommended.")]
7171
fn rsa_1v15(k_mod: String, k_exp: String, mut payload_data: Vec<u8>) -> Result<Response> {
7272
warn!("Get JWE request using deprecated kcs#1 v1.5 encryption, which has potential security issues.");
73-
let aes_sym_key = Zeroizing::new(Aes256Gcm::generate_key(&mut OsRng));
74-
let mut cipher = Aes256Gcm::new(&*aes_sym_key);
75-
let mut iv = [0u8; 12];
76-
OsRng.fill_bytes(&mut iv);
77-
let nonce = Nonce::from_slice(&iv);
73+
let aes_sym_key = Zeroizing::new(<[u8; 32]>::generate());
74+
let cipher = Aes256Gcm::new_from_slice(aes_sym_key.as_slice())
75+
.map_err(|e| anyhow!("invalid AES key length: {e}"))?;
76+
let iv = <[u8; 12]>::generate();
77+
let nonce = Nonce::from(iv);
7878
let protected = ProtectedHeader {
7979
alg: RSA1_5_ALGORITHM.to_string(),
8080
enc: AES_GCM_256_ALGORITHM.to_string(),
@@ -84,7 +84,7 @@ fn rsa_1v15(k_mod: String, k_exp: String, mut payload_data: Vec<u8>) -> Result<R
8484
let aad = protected.generate_aad().context("Generate JWE AAD")?;
8585

8686
let tag = cipher
87-
.encrypt_in_place_detached(nonce, &aad, &mut payload_data)
87+
.encrypt_inout_detached(&nonce, &aad, payload_data.as_mut_slice().into())
8888
.map_err(|e| anyhow!("AES encrypt Resource payload failed: {e}"))?;
8989

9090
let k_mod = URL_SAFE_NO_PAD
@@ -99,7 +99,7 @@ fn rsa_1v15(k_mod: String, k_exp: String, mut payload_data: Vec<u8>) -> Result<R
9999
let rsa_pub_key =
100100
RsaPublicKey::new(n, e).context("Building RSA key from modulus and exponent failed")?;
101101
let encrypted_key = rsa_pub_key
102-
.encrypt(&mut OsRng, Pkcs1v15Encrypt, &aes_sym_key)
102+
.encrypt(&mut OsRng, Pkcs1v15Encrypt, aes_sym_key.as_slice())
103103
.context("RSA encrypt sym key failed")?;
104104

105105
Ok(Response {
@@ -114,11 +114,11 @@ fn rsa_1v15(k_mod: String, k_exp: String, mut payload_data: Vec<u8>) -> Result<R
114114

115115
/// Use RSA-OAEP SHA-256 to encrypt the payload data.
116116
fn rsa_oaep256(k_mod: String, k_exp: String, mut payload_data: Vec<u8>) -> Result<Response> {
117-
let aes_sym_key = Zeroizing::new(Aes256Gcm::generate_key(&mut OsRng));
118-
let mut cipher = Aes256Gcm::new(&*aes_sym_key);
119-
let mut iv = [0u8; 12];
120-
OsRng.fill_bytes(&mut iv);
121-
let nonce = Nonce::from_slice(&iv);
117+
let aes_sym_key = Zeroizing::new(<[u8; 32]>::generate());
118+
let cipher = Aes256Gcm::new_from_slice(aes_sym_key.as_slice())
119+
.map_err(|e| anyhow!("invalid AES key length: {e}"))?;
120+
let iv = <[u8; 12]>::generate();
121+
let nonce = Nonce::from(iv);
122122
let protected = ProtectedHeader {
123123
alg: RSA_OAEP256_ALGORITHM.to_string(),
124124
enc: AES_GCM_256_ALGORITHM.to_string(),
@@ -128,7 +128,7 @@ fn rsa_oaep256(k_mod: String, k_exp: String, mut payload_data: Vec<u8>) -> Resul
128128
let aad = protected.generate_aad().context("Generate JWE AAD")?;
129129

130130
let tag = cipher
131-
.encrypt_in_place_detached(nonce, &aad, &mut payload_data)
131+
.encrypt_inout_detached(&nonce, &aad, payload_data.as_mut_slice().into())
132132
.map_err(|e| anyhow!("AES encrypt Resource payload failed: {e}"))?;
133133

134134
let k_mod = URL_SAFE_NO_PAD
@@ -144,7 +144,7 @@ fn rsa_oaep256(k_mod: String, k_exp: String, mut payload_data: Vec<u8>) -> Resul
144144
RsaPublicKey::new(n, e).context("Building RSA key from modulus and exponent failed")?;
145145
let padding = Oaep::new::<Sha256>();
146146
let encrypted_key = rsa_pub_key
147-
.encrypt(&mut OsRng, padding, &aes_sym_key)
147+
.encrypt(&mut OsRng, padding, aes_sym_key.as_slice())
148148
.context("RSA encrypt sym key failed")?;
149149

150150
Ok(Response {
@@ -160,7 +160,7 @@ fn rsa_oaep256(k_mod: String, k_exp: String, mut payload_data: Vec<u8>) -> Resul
160160
/// Use ECDH-ES-A256KW to encrypt the payload data. The EC curve is P256.
161161
fn ecdh_es_a256kw_p256(x: String, y: String, mut payload_data: Vec<u8>) -> Result<Response> {
162162
// 1. Generate a random CEK
163-
let cek = Zeroizing::new(Aes256Gcm::generate_key(&mut OsRng));
163+
let cek = Zeroizing::new(<[u8; 32]>::generate());
164164

165165
// 2. Wrap the CEK and generate ProtectedHeader
166166
let x: [u8; 32] = URL_SAFE_NO_PAD
@@ -193,7 +193,7 @@ fn ecdh_es_a256kw_p256(x: String, y: String, mut payload_data: Vec<u8>) -> Resul
193193
.map_err(|_| anyhow!("invalid bytes length of AES wrapping key"))?;
194194
let mut encrypted_key = vec![0; 40];
195195
wrapping_cipher
196-
.wrap_key(&cek, &mut encrypted_key)
196+
.wrap_key(cek.as_slice(), &mut encrypted_key)
197197
.map_err(|e| anyhow!("failed to do AES wrapping: {e:?}"))?;
198198

199199
let point = p256::EncodedPoint::from(encrypter_secret.public_key());
@@ -222,15 +222,15 @@ fn ecdh_es_a256kw_p256(x: String, y: String, mut payload_data: Vec<u8>) -> Resul
222222
};
223223

224224
// 3. Encrypt content with CEK
225-
let mut cek_cipher = Aes256Gcm::new(&*cek);
225+
let cek_cipher = Aes256Gcm::new_from_slice(cek.as_slice())
226+
.map_err(|e| anyhow!("invalid AES key length: {e}"))?;
226227

227-
let mut iv = [0u8; 12];
228-
OsRng.fill_bytes(&mut iv);
229-
let nonce = Nonce::from_slice(&iv);
228+
let iv = <[u8; 12]>::generate();
229+
let nonce = Nonce::from(iv);
230230
let aad = protected.generate_aad().context("Generate JWE AAD")?;
231231

232232
let tag = cek_cipher
233-
.encrypt_in_place_detached(nonce, &aad, &mut payload_data)
233+
.encrypt_inout_detached(&nonce, &aad, payload_data.as_mut_slice().into())
234234
.map_err(|e| anyhow!("AES encrypt Resource payload failed: {e}"))?;
235235

236236
Ok(Response {
@@ -246,7 +246,7 @@ fn ecdh_es_a256kw_p256(x: String, y: String, mut payload_data: Vec<u8>) -> Resul
246246
/// Use ECDH-ES-A256KW to encrypt the payload data. The EC curve is P521.
247247
fn ecdh_es_a256kw_p521(x: String, y: String, mut payload_data: Vec<u8>) -> Result<Response> {
248248
// 1. Generate a random CEK
249-
let cek = Zeroizing::new(Aes256Gcm::generate_key(&mut OsRng));
249+
let cek = Zeroizing::new(<[u8; 32]>::generate());
250250

251251
// 2. Wrap the CEK and generate ProtectedHeader
252252
let x: [u8; 66] = URL_SAFE_NO_PAD
@@ -279,7 +279,7 @@ fn ecdh_es_a256kw_p521(x: String, y: String, mut payload_data: Vec<u8>) -> Resul
279279
.map_err(|_| anyhow!("invalid bytes length of AES wrapping key"))?;
280280
let mut encrypted_key = vec![0; 40];
281281
wrapping_cipher
282-
.wrap_key(&cek, &mut encrypted_key)
282+
.wrap_key(cek.as_slice(), &mut encrypted_key)
283283
.map_err(|e| anyhow!("failed to do AES wrapping: {e:?}"))?;
284284

285285
let point = p521::EncodedPoint::from(encrypter_secret.public_key());
@@ -308,15 +308,15 @@ fn ecdh_es_a256kw_p521(x: String, y: String, mut payload_data: Vec<u8>) -> Resul
308308
};
309309

310310
// 3. Encrypt content with CEK
311-
let mut cek_cipher = Aes256Gcm::new(&*cek);
311+
let cek_cipher = Aes256Gcm::new_from_slice(cek.as_slice())
312+
.map_err(|e| anyhow!("invalid AES key length: {e}"))?;
312313

313-
let mut iv = [0u8; 12];
314-
OsRng.fill_bytes(&mut iv);
315-
let nonce = Nonce::from_slice(&iv);
314+
let iv = <[u8; 12]>::generate();
315+
let nonce = Nonce::from(iv);
316316
let aad = protected.generate_aad().context("Generate JWE AAD")?;
317317

318318
let tag = cek_cipher
319-
.encrypt_in_place_detached(nonce, &aad, &mut payload_data)
319+
.encrypt_inout_detached(&nonce, &aad, payload_data.as_mut_slice().into())
320320
.map_err(|e| anyhow!("AES encrypt Resource payload failed: {e}"))?;
321321

322322
Ok(Response {
@@ -349,7 +349,6 @@ pub fn jwe(tee_pub_key: TeePubKey, payload_data: Vec<u8>) -> Result<Response> {
349349
mod tests {
350350
use core::assert_eq;
351351

352-
use aes_gcm::aead::OsRng;
353352
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
354353
use josekit::jwe::{
355354
alg::{ecdh_es::EcdhEsJweAlgorithm::EcdhEsA256kw, rsaes::RsaesJweAlgorithm::RsaOaep256},
@@ -358,6 +357,7 @@ mod tests {
358357
use kbs_types::TeePubKey;
359358
use openssl::rsa::Rsa;
360359
use p256::pkcs8::EncodePrivateKey;
360+
use rsa::rand_core::OsRng;
361361

362362
use crate::jwe::{
363363
AES_GCM_256_ALGORITHM, ECDH_ES_A256KW, P256_CURVE, P521_CURVE, RSA1_5_ALGORITHM,

0 commit comments

Comments
 (0)