Skip to content

Commit 8e8bd6a

Browse files
authoredFeb 13, 2025··
oaep: support non-string labels (#467)
This rework oaep to support non-string labels. One use-case is encryption of secrets in TPM. https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=297 > # Section B.4 RSAES_OAEP > > For RSA keys protecting a secret value (such as, an encryption key or a session secret), the L parameter > is a byte stream, the last byte of which must be zero, indicating the intended use of the encrypted value.
1 parent f7d1214 commit 8e8bd6a

File tree

4 files changed

+40
-64
lines changed

4 files changed

+40
-64
lines changed
 

‎src/algorithms/oaep.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
22
//!
3-
use alloc::string::String;
3+
use alloc::boxed::Box;
44
use alloc::vec::Vec;
55

66
use digest::{Digest, DynDigest, FixedOutputReset};
@@ -62,7 +62,7 @@ pub(crate) fn oaep_encrypt<R: CryptoRngCore + ?Sized>(
6262
msg: &[u8],
6363
digest: &mut dyn DynDigest,
6464
mgf_digest: &mut dyn DynDigest,
65-
label: Option<String>,
65+
label: Option<Box<[u8]>>,
6666
k: usize,
6767
) -> Result<Zeroizing<Vec<u8>>> {
6868
let h_size = digest.output_size();
@@ -72,7 +72,7 @@ pub(crate) fn oaep_encrypt<R: CryptoRngCore + ?Sized>(
7272
return Err(Error::LabelTooLong);
7373
}
7474

75-
digest.update(label.as_bytes());
75+
digest.update(&label);
7676
let p_hash = digest.finalize_reset();
7777

7878
encrypt_internal(rng, msg, &p_hash, h_size, k, |seed, db| {
@@ -96,7 +96,7 @@ pub(crate) fn oaep_encrypt_digest<
9696
>(
9797
rng: &mut R,
9898
msg: &[u8],
99-
label: Option<String>,
99+
label: Option<Box<[u8]>>,
100100
k: usize,
101101
) -> Result<Zeroizing<Vec<u8>>> {
102102
let h_size = <D as Digest>::output_size();
@@ -106,7 +106,7 @@ pub(crate) fn oaep_encrypt_digest<
106106
return Err(Error::LabelTooLong);
107107
}
108108

109-
let p_hash = D::digest(label.as_bytes());
109+
let p_hash = D::digest(&label);
110110

111111
encrypt_internal(rng, msg, &p_hash, h_size, k, |seed, db| {
112112
let mut mgf_digest = MGD::new();
@@ -130,7 +130,7 @@ pub(crate) fn oaep_decrypt(
130130
em: &mut [u8],
131131
digest: &mut dyn DynDigest,
132132
mgf_digest: &mut dyn DynDigest,
133-
label: Option<String>,
133+
label: Option<Box<[u8]>>,
134134
k: usize,
135135
) -> Result<Vec<u8>> {
136136
let h_size = digest.output_size();
@@ -140,7 +140,7 @@ pub(crate) fn oaep_decrypt(
140140
return Err(Error::Decryption);
141141
}
142142

143-
digest.update(label.as_bytes());
143+
digest.update(&label);
144144

145145
let expected_p_hash = digest.finalize_reset();
146146

@@ -170,7 +170,7 @@ pub(crate) fn oaep_decrypt(
170170
#[inline]
171171
pub(crate) fn oaep_decrypt_digest<D: Digest, MGD: Digest + FixedOutputReset>(
172172
em: &mut [u8],
173-
label: Option<String>,
173+
label: Option<Box<[u8]>>,
174174
k: usize,
175175
) -> Result<Vec<u8>> {
176176
let h_size = <D as Digest>::output_size();
@@ -180,7 +180,7 @@ pub(crate) fn oaep_decrypt_digest<D: Digest, MGD: Digest + FixedOutputReset>(
180180
return Err(Error::LabelTooLong);
181181
}
182182

183-
let expected_p_hash = D::digest(label.as_bytes());
183+
let expected_p_hash = D::digest(&label);
184184

185185
let res = decrypt_inner(em, h_size, &expected_p_hash, k, |seed, db| {
186186
let mut mgf_digest = MGD::new();

‎src/oaep.rs

+20-28
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ mod encrypting_key;
1010
pub use self::{decrypting_key::DecryptingKey, encrypting_key::EncryptingKey};
1111

1212
use alloc::boxed::Box;
13-
use alloc::string::{String, ToString};
1413
use alloc::vec::Vec;
1514
use core::fmt;
1615
use crypto_bigint::BoxedUint;
@@ -44,7 +43,7 @@ pub struct Oaep {
4443
pub mgf_digest: Box<dyn DynDigest + Send + Sync>,
4544

4645
/// Optional label.
47-
pub label: Option<String>,
46+
pub label: Option<Box<[u8]>>,
4847
}
4948

5049
impl Oaep {
@@ -77,13 +76,13 @@ impl Oaep {
7776
}
7877

7978
/// Create a new OAEP `PaddingScheme` with an associated `label`, using `T` as the hash function for both the label and for MGF1.
80-
pub fn new_with_label<T: 'static + Digest + DynDigest + Send + Sync, S: AsRef<str>>(
79+
pub fn new_with_label<T: 'static + Digest + DynDigest + Send + Sync, S: Into<Box<[u8]>>>(
8180
label: S,
8281
) -> Self {
8382
Self {
8483
digest: Box::new(T::new()),
8584
mgf_digest: Box::new(T::new()),
86-
label: Some(label.as_ref().to_string()),
85+
label: Some(label.into()),
8786
}
8887
}
8988

@@ -123,14 +122,14 @@ impl Oaep {
123122
pub fn new_with_mgf_hash_and_label<
124123
T: 'static + Digest + DynDigest + Send + Sync,
125124
U: 'static + Digest + DynDigest + Send + Sync,
126-
S: AsRef<str>,
125+
S: Into<Box<[u8]>>,
127126
>(
128127
label: S,
129128
) -> Self {
130129
Self {
131130
digest: Box::new(T::new()),
132131
mgf_digest: Box::new(U::new()),
133-
label: Some(label.as_ref().to_string()),
132+
label: Some(label.into()),
134133
}
135134
}
136135
}
@@ -193,7 +192,7 @@ fn encrypt<R: CryptoRngCore + ?Sized>(
193192
msg: &[u8],
194193
digest: &mut dyn DynDigest,
195194
mgf_digest: &mut dyn DynDigest,
196-
label: Option<String>,
195+
label: Option<Box<[u8]>>,
197196
) -> Result<Vec<u8>> {
198197
key::check_public(pub_key)?;
199198

@@ -214,7 +213,7 @@ fn encrypt_digest<R: CryptoRngCore + ?Sized, D: Digest, MGD: Digest + FixedOutpu
214213
rng: &mut R,
215214
pub_key: &RsaPublicKey,
216215
msg: &[u8],
217-
label: Option<String>,
216+
label: Option<Box<[u8]>>,
218217
) -> Result<Vec<u8>> {
219218
key::check_public(pub_key)?;
220219

@@ -243,7 +242,7 @@ fn decrypt<R: CryptoRngCore + ?Sized>(
243242
ciphertext: &[u8],
244243
digest: &mut dyn DynDigest,
245244
mgf_digest: &mut dyn DynDigest,
246-
label: Option<String>,
245+
label: Option<Box<[u8]>>,
247246
) -> Result<Vec<u8>> {
248247
if ciphertext.len() != priv_key.size() {
249248
return Err(Error::Decryption);
@@ -274,7 +273,7 @@ fn decrypt_digest<R: CryptoRngCore + ?Sized, D: Digest, MGD: Digest + FixedOutpu
274273
rng: Option<&mut R>,
275274
priv_key: &RsaPrivateKey,
276275
ciphertext: &[u8],
277-
label: Option<String>,
276+
label: Option<Box<[u8]>>,
278277
) -> Result<Vec<u8>> {
279278
key::check_public(priv_key)?;
280279

@@ -296,7 +295,6 @@ mod tests {
296295
use crate::traits::PublicKeyParts;
297296
use crate::traits::{Decryptor, RandomizedDecryptor, RandomizedEncryptor};
298297

299-
use alloc::string::String;
300298
use crypto_bigint::{BoxedUint, Odd};
301299
use digest::{Digest, DynDigest, FixedOutputReset};
302300
use rand_chacha::{
@@ -369,18 +367,12 @@ mod tests {
369367
do_test_oaep_with_different_hashes::<Sha3_512, Sha1>(&priv_key);
370368
}
371369

372-
fn get_label(rng: &mut ChaCha8Rng) -> Option<String> {
373-
const GEN_ASCII_STR_CHARSET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
374-
abcdefghijklmnopqrstuvwxyz\
375-
0123456789=+";
376-
370+
fn get_label(rng: &mut ChaCha8Rng) -> Option<Box<[u8]>> {
377371
let mut buf = [0u8; 32];
378372
rng.fill_bytes(&mut buf);
379-
if buf[0] < (1 << 7) {
380-
for v in buf.iter_mut() {
381-
*v = GEN_ASCII_STR_CHARSET[(*v >> 2) as usize];
382-
}
383-
Some(core::str::from_utf8(&buf).unwrap().to_string())
373+
374+
if rng.next_u32() % 2 == 0 {
375+
Some(buf.into())
384376
} else {
385377
None
386378
}
@@ -405,7 +397,7 @@ mod tests {
405397
let pub_key: RsaPublicKey = prk.into();
406398

407399
let ciphertext = if let Some(ref label) = label {
408-
let padding = Oaep::new_with_label::<D, _>(label);
400+
let padding = Oaep::new_with_label::<D, _>(label.clone());
409401
pub_key.encrypt(&mut rng, padding, &input).unwrap()
410402
} else {
411403
let padding = Oaep::new::<D>();
@@ -415,8 +407,8 @@ mod tests {
415407
assert_ne!(input, ciphertext);
416408
let blind: bool = rng.next_u32() < (1 << 31);
417409

418-
let padding = if let Some(ref label) = label {
419-
Oaep::new_with_label::<D, _>(label)
410+
let padding = if let Some(label) = label {
411+
Oaep::new_with_label::<D, Box<[u8]>>(label)
420412
} else {
421413
Oaep::new::<D>()
422414
};
@@ -453,7 +445,7 @@ mod tests {
453445
let pub_key: RsaPublicKey = prk.into();
454446

455447
let ciphertext = if let Some(ref label) = label {
456-
let padding = Oaep::new_with_mgf_hash_and_label::<D, U, _>(label);
448+
let padding = Oaep::new_with_mgf_hash_and_label::<D, U, _>(label.clone());
457449
pub_key.encrypt(&mut rng, padding, &input).unwrap()
458450
} else {
459451
let padding = Oaep::new_with_mgf_hash::<D, U>();
@@ -463,7 +455,7 @@ mod tests {
463455
assert_ne!(input, ciphertext);
464456
let blind: bool = rng.next_u32() < (1 << 31);
465457

466-
let padding = if let Some(ref label) = label {
458+
let padding = if let Some(label) = label {
467459
Oaep::new_with_mgf_hash_and_label::<D, U, _>(label)
468460
} else {
469461
Oaep::new_with_mgf_hash::<D, U>()
@@ -491,7 +483,7 @@ mod tests {
491483
priv_key
492484
.decrypt_blinded(
493485
&mut rng,
494-
Oaep::new_with_label::<Sha1, _>("label"),
486+
Oaep::new_with_label::<Sha1, _>("label".as_bytes()),
495487
&ciphertext,
496488
)
497489
.is_err(),
@@ -579,7 +571,7 @@ mod tests {
579571
let priv_key = get_private_key();
580572
let pub_key: RsaPublicKey = (&priv_key).into();
581573
let encrypting_key = EncryptingKey::<Sha1>::new(pub_key);
582-
let decrypting_key = DecryptingKey::<Sha1>::new_with_label(priv_key, "label");
574+
let decrypting_key = DecryptingKey::<Sha1>::new_with_label(priv_key, "label".as_bytes());
583575
let ciphertext = encrypting_key
584576
.encrypt_with_rng(&mut rng, "a_plain_text".as_bytes())
585577
.unwrap();

‎src/oaep/decrypting_key.rs

+6-19
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ use crate::{
44
traits::{Decryptor, RandomizedDecryptor},
55
Result, RsaPrivateKey,
66
};
7-
use alloc::{
8-
string::{String, ToString},
9-
vec::Vec,
10-
};
7+
use alloc::{boxed::Box, vec::Vec};
118
use core::marker::PhantomData;
129
use digest::{Digest, FixedOutputReset};
1310
use rand_core::CryptoRngCore;
@@ -26,7 +23,7 @@ where
2623
MGD: Digest + FixedOutputReset,
2724
{
2825
inner: RsaPrivateKey,
29-
label: Option<String>,
26+
label: Option<Box<[u8]>>,
3027
phantom: PhantomData<D>,
3128
mg_phantom: PhantomData<MGD>,
3229
}
@@ -47,10 +44,10 @@ where
4744
}
4845

4946
/// Create a new verifying key from an RSA public key using provided label
50-
pub fn new_with_label<S: AsRef<str>>(key: RsaPrivateKey, label: S) -> Self {
47+
pub fn new_with_label<S: Into<Box<[u8]>>>(key: RsaPrivateKey, label: S) -> Self {
5148
Self {
5249
inner: key,
53-
label: Some(label.as_ref().to_string()),
50+
label: Some(label.into()),
5451
phantom: Default::default(),
5552
mg_phantom: Default::default(),
5653
}
@@ -63,12 +60,7 @@ where
6360
MGD: Digest + FixedOutputReset,
6461
{
6562
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
66-
decrypt_digest::<DummyRng, D, MGD>(
67-
None,
68-
&self.inner,
69-
ciphertext,
70-
self.label.as_ref().cloned(),
71-
)
63+
decrypt_digest::<DummyRng, D, MGD>(None, &self.inner, ciphertext, self.label.clone())
7264
}
7365
}
7466

@@ -82,12 +74,7 @@ where
8274
rng: &mut R,
8375
ciphertext: &[u8],
8476
) -> Result<Vec<u8>> {
85-
decrypt_digest::<_, D, MGD>(
86-
Some(rng),
87-
&self.inner,
88-
ciphertext,
89-
self.label.as_ref().cloned(),
90-
)
77+
decrypt_digest::<_, D, MGD>(Some(rng), &self.inner, ciphertext, self.label.clone())
9178
}
9279
}
9380

‎src/oaep/encrypting_key.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use super::encrypt_digest;
22
use crate::{traits::RandomizedEncryptor, Result, RsaPublicKey};
3-
use alloc::{
4-
string::{String, ToString},
5-
vec::Vec,
6-
};
3+
use alloc::{boxed::Box, vec::Vec};
74
use core::marker::PhantomData;
85
use digest::{Digest, FixedOutputReset};
96
use rand_core::CryptoRngCore;
@@ -21,7 +18,7 @@ where
2118
MGD: Digest + FixedOutputReset,
2219
{
2320
inner: RsaPublicKey,
24-
label: Option<String>,
21+
label: Option<Box<[u8]>>,
2522
phantom: PhantomData<D>,
2623
mg_phantom: PhantomData<MGD>,
2724
}
@@ -42,10 +39,10 @@ where
4239
}
4340

4441
/// Create a new verifying key from an RSA public key using provided label
45-
pub fn new_with_label<S: AsRef<str>>(key: RsaPublicKey, label: S) -> Self {
42+
pub fn new_with_label<S: Into<Box<[u8]>>>(key: RsaPublicKey, label: S) -> Self {
4643
Self {
4744
inner: key,
48-
label: Some(label.as_ref().to_string()),
45+
label: Some(label.into()),
4946
phantom: Default::default(),
5047
mg_phantom: Default::default(),
5148
}
@@ -62,7 +59,7 @@ where
6259
rng: &mut R,
6360
msg: &[u8],
6461
) -> Result<Vec<u8>> {
65-
encrypt_digest::<_, D, MGD>(rng, &self.inner, msg, self.label.as_ref().cloned())
62+
encrypt_digest::<_, D, MGD>(rng, &self.inner, msg, self.label.clone())
6663
}
6764
}
6865

0 commit comments

Comments
 (0)
Please sign in to comment.