rsa/algorithms/
pkcs1v15.rs1use alloc::vec::Vec;
10use digest::Digest;
11use pkcs8::AssociatedOid;
12use rand_core::CryptoRngCore;
13use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
14use zeroize::Zeroizing;
15
16use crate::errors::{Error, Result};
17
18#[inline]
21fn non_zero_random_bytes<R: CryptoRngCore + ?Sized>(rng: &mut R, data: &mut [u8]) {
22 rng.fill_bytes(data);
23
24 for el in data {
25 if *el == 0u8 {
26 while *el == 0u8 {
28 rng.fill_bytes(core::slice::from_mut(el));
29 }
30 }
31 }
32}
33
34pub(crate) fn pkcs1v15_encrypt_pad<R>(
37 rng: &mut R,
38 msg: &[u8],
39 k: usize,
40) -> Result<Zeroizing<Vec<u8>>>
41where
42 R: CryptoRngCore + ?Sized,
43{
44 if msg.len() + 11 > k {
45 return Err(Error::MessageTooLong);
46 }
47
48 let mut em = Zeroizing::new(vec![0u8; k]);
50 em[1] = 2;
51 non_zero_random_bytes(rng, &mut em[2..k - msg.len() - 1]);
52 em[k - msg.len() - 1] = 0;
53 em[k - msg.len()..].copy_from_slice(msg);
54 Ok(em)
55}
56
57#[inline]
65pub(crate) fn pkcs1v15_encrypt_unpad(em: Vec<u8>, k: usize) -> Result<Vec<u8>> {
66 let (valid, out, index) = decrypt_inner(em, k)?;
67 if valid == 0 {
68 return Err(Error::Decryption);
69 }
70
71 Ok(out[index as usize..].to_vec())
72}
73
74#[inline]
80fn decrypt_inner(em: Vec<u8>, k: usize) -> Result<(u8, Vec<u8>, u32)> {
81 if k < 11 {
82 return Err(Error::Decryption);
83 }
84
85 let first_byte_is_zero = em[0].ct_eq(&0u8);
86 let second_byte_is_two = em[1].ct_eq(&2u8);
87
88 let mut looking_for_index = 1u8;
93 let mut index = 0u32;
94
95 for (i, el) in em.iter().enumerate().skip(2) {
96 let equals0 = el.ct_eq(&0u8);
97 index.conditional_assign(&(i as u32), Choice::from(looking_for_index) & equals0);
98 looking_for_index.conditional_assign(&0u8, equals0);
99 }
100
101 let valid_ps = Choice::from((((2i32 + 8i32 - index as i32 - 1i32) >> 31) & 1) as u8);
108 let valid =
109 first_byte_is_zero & second_byte_is_two & Choice::from(!looking_for_index & 1) & valid_ps;
110 index = u32::conditional_select(&0, &(index + 1), valid);
111
112 Ok((valid.unwrap_u8(), em, index))
113}
114
115#[inline]
116pub(crate) fn pkcs1v15_sign_pad(prefix: &[u8], hashed: &[u8], k: usize) -> Result<Vec<u8>> {
117 let hash_len = hashed.len();
118 let t_len = prefix.len() + hashed.len();
119 if k < t_len + 11 {
120 return Err(Error::MessageTooLong);
121 }
122
123 let mut em = vec![0xff; k];
125 em[0] = 0;
126 em[1] = 1;
127 em[k - t_len - 1] = 0;
128 em[k - t_len..k - hash_len].copy_from_slice(prefix);
129 em[k - hash_len..k].copy_from_slice(hashed);
130
131 Ok(em)
132}
133
134#[inline]
135pub(crate) fn pkcs1v15_sign_unpad(prefix: &[u8], hashed: &[u8], em: &[u8], k: usize) -> Result<()> {
136 let hash_len = hashed.len();
137 let t_len = prefix.len() + hashed.len();
138 if k < t_len + 11 {
139 return Err(Error::Verification);
140 }
141
142 let mut ok = em[0].ct_eq(&0u8);
144 ok &= em[1].ct_eq(&1u8);
145 ok &= em[k - hash_len..k].ct_eq(hashed);
146 ok &= em[k - t_len..k - hash_len].ct_eq(prefix);
147 ok &= em[k - t_len - 1].ct_eq(&0u8);
148
149 for el in em.iter().skip(2).take(k - t_len - 3) {
150 ok &= el.ct_eq(&0xff)
151 }
152
153 if ok.unwrap_u8() != 1 {
154 return Err(Error::Verification);
155 }
156
157 Ok(())
158}
159
160#[inline]
162pub(crate) fn pkcs1v15_generate_prefix<D>() -> Vec<u8>
163where
164 D: Digest + AssociatedOid,
165{
166 let oid = D::OID.as_bytes();
167 let oid_len = oid.len() as u8;
168 let digest_len = <D as Digest>::output_size() as u8;
169 let mut v = vec![
170 0x30,
171 oid_len + 8 + digest_len,
172 0x30,
173 oid_len + 4,
174 0x6,
175 oid_len,
176 ];
177 v.extend_from_slice(oid);
178 v.extend_from_slice(&[0x05, 0x00, 0x04, digest_len]);
179 v
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
186
187 #[test]
188 fn test_non_zero_bytes() {
189 for _ in 0..10 {
190 let mut rng = ChaCha8Rng::from_seed([42; 32]);
191 let mut b = vec![0u8; 512];
192 non_zero_random_bytes(&mut rng, &mut b);
193 for el in &b {
194 assert_ne!(*el, 0u8);
195 }
196 }
197 }
198
199 #[test]
200 fn test_encrypt_tiny_no_crash() {
201 let mut rng = ChaCha8Rng::from_seed([42; 32]);
202 let k = 8;
203 let message = vec![1u8; 4];
204 let res = pkcs1v15_encrypt_pad(&mut rng, &message, k);
205 assert_eq!(res, Err(Error::MessageTooLong));
206 }
207}