rsa/algorithms/
pkcs1v15.rs1use alloc::vec::Vec;
10use const_oid::AssociatedOid;
11use crypto_bigint::{Choice, CtAssign, CtEq, CtSelect};
12use digest::Digest;
13use rand_core::TryCryptoRng;
14use zeroize::Zeroizing;
15
16use crate::errors::{Error, Result};
17
18#[inline]
21fn non_zero_random_bytes<R: TryCryptoRng + ?Sized>(
22 rng: &mut R,
23 data: &mut [u8],
24) -> core::result::Result<(), R::Error> {
25 rng.try_fill_bytes(data)?;
26
27 for el in data {
28 if *el == 0u8 {
29 while *el == 0u8 {
31 rng.try_fill_bytes(core::slice::from_mut(el))?;
32 }
33 }
34 }
35
36 Ok(())
37}
38
39pub(crate) fn pkcs1v15_encrypt_pad<R>(
42 rng: &mut R,
43 msg: &[u8],
44 k: usize,
45) -> Result<Zeroizing<Vec<u8>>>
46where
47 R: TryCryptoRng + ?Sized,
48{
49 if msg.len() + 11 > k {
50 return Err(Error::MessageTooLong);
51 }
52
53 let mut em = Zeroizing::new(vec![0u8; k]);
55 em[1] = 2;
56 non_zero_random_bytes(rng, &mut em[2..k - msg.len() - 1]).map_err(|_: R::Error| Error::Rng)?;
57 em[k - msg.len() - 1] = 0;
58 em[k - msg.len()..].copy_from_slice(msg);
59 Ok(em)
60}
61
62#[inline]
70pub(crate) fn pkcs1v15_encrypt_unpad(em: Vec<u8>, k: usize) -> Result<Vec<u8>> {
71 let (valid, out, index) = decrypt_inner(em, k)?;
72 if valid == 0 {
73 return Err(Error::Decryption);
74 }
75
76 Ok(out[index as usize..].to_vec())
77}
78
79#[inline]
85fn decrypt_inner(em: Vec<u8>, k: usize) -> Result<(u8, Vec<u8>, u32)> {
86 if k < 11 {
87 return Err(Error::Decryption);
88 }
89
90 let first_byte_is_zero = em[0].ct_eq(&0u8);
91 let second_byte_is_two = em[1].ct_eq(&2u8);
92
93 let mut looking_for_index = Choice::TRUE;
98 let mut index = 0u32;
99
100 for (i, el) in em.iter().enumerate().skip(2) {
101 let equals0 = el.ct_eq(&0u8);
102 index.ct_assign(&(i as u32), looking_for_index & equals0);
103 looking_for_index &= !equals0;
104 }
105
106 let valid_ps = Choice::from_u8_lsb((((2i32 + 8i32 - index as i32 - 1i32) >> 31) & 1) as u8);
113 let valid = first_byte_is_zero & second_byte_is_two & !looking_for_index & valid_ps;
114 index = u32::ct_select(&0, &(index + 1), valid);
115
116 Ok((valid.to_u8(), em, index))
117}
118
119#[inline]
120pub(crate) fn pkcs1v15_sign_pad(prefix: &[u8], hashed: &[u8], k: usize) -> Result<Vec<u8>> {
121 let hash_len = hashed.len();
122 let t_len = prefix.len() + hashed.len();
123 if k < t_len + 11 {
124 return Err(Error::MessageTooLong);
125 }
126
127 let mut em = vec![0xff; k];
129 em[0] = 0;
130 em[1] = 1;
131 em[k - t_len - 1] = 0;
132 em[k - t_len..k - hash_len].copy_from_slice(prefix);
133 em[k - hash_len..k].copy_from_slice(hashed);
134
135 Ok(em)
136}
137
138#[inline]
139pub(crate) fn pkcs1v15_sign_unpad(prefix: &[u8], hashed: &[u8], em: &[u8], k: usize) -> Result<()> {
140 let hash_len = hashed.len();
141 let t_len = prefix.len() + hashed.len();
142 if k < t_len + 11 {
143 return Err(Error::Verification);
144 }
145
146 let mut ok = em[0].ct_eq(&0u8);
148 ok &= em[1].ct_eq(&1u8);
149 ok &= em[k - hash_len..k].ct_eq(hashed);
150 ok &= em[k - t_len..k - hash_len].ct_eq(prefix);
151 ok &= em[k - t_len - 1].ct_eq(&0u8);
152
153 for el in em.iter().skip(2).take(k - t_len - 3) {
154 ok &= el.ct_eq(&0xff)
155 }
156
157 if !ok.to_bool() {
159 return Err(Error::Verification);
160 }
161
162 Ok(())
163}
164
165#[inline]
167pub(crate) fn pkcs1v15_generate_prefix<D>() -> Vec<u8>
168where
169 D: Digest + AssociatedOid,
170{
171 let oid = D::OID.as_bytes();
172 let oid_len = oid.len() as u8;
173 let digest_len = <D as Digest>::output_size() as u8;
174 let mut v = vec![
175 0x30,
176 oid_len + 8 + digest_len,
177 0x30,
178 oid_len + 4,
179 0x6,
180 oid_len,
181 ];
182 v.extend_from_slice(oid);
183 v.extend_from_slice(&[0x05, 0x00, 0x04, digest_len]);
184 v
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use rand::rngs::ChaCha8Rng;
191 use rand_core::SeedableRng;
192
193 #[test]
194 fn test_non_zero_bytes() {
195 for _ in 0..10 {
196 let mut rng = ChaCha8Rng::from_seed([42; 32]);
197 let mut b = vec![0u8; 512];
198 non_zero_random_bytes(&mut rng, &mut b).unwrap();
199 for el in &b {
200 assert_ne!(*el, 0u8);
201 }
202 }
203 }
204
205 #[test]
206 fn test_encrypt_tiny_no_crash() {
207 let mut rng = ChaCha8Rng::from_seed([42; 32]);
208 let k = 8;
209 let message = vec![1u8; 4];
210 let res = pkcs1v15_encrypt_pad(&mut rng, &message, k);
211 assert_eq!(res, Err(Error::MessageTooLong));
212 }
213}