1use super::der;
10use byteorder::{BigEndian, ByteOrder};
11use num_bigint::BigUint;
12use sha1::{Digest, Sha1};
13
14pub trait Padding {
16 fn pub_pad(&mut self, input: impl AsRef<[u8]>, k: usize) -> Vec<u8>;
18}
19
20pub trait Rng {
22 type Error: std::error::Error;
23
24 fn fill(&mut self, dest: &mut [u8]) -> Result<(), Self::Error>;
26}
27
28pub struct GetRandom;
30
31impl Rng for GetRandom {
32 type Error = getrandom::Error;
33
34 fn fill(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
35 getrandom::fill(dest)
36 }
37}
38
39#[derive(Debug)]
41pub struct Pkcs1Padding<T> {
42 rng: T,
43}
44
45impl<T> Pkcs1Padding<T> {
46 pub fn new(rng: T) -> Self {
47 Self { rng }
48 }
49}
50
51impl<T: Rng> Padding for Pkcs1Padding<T> {
52 fn pub_pad(&mut self, input: impl AsRef<[u8]>, k: usize) -> Vec<u8> {
53 let input = input.as_ref();
54 let input_len = input.len();
55 assert!(
56 input_len < k - 11,
57 "The length of the data D shall not be more than k-11 octets"
58 );
59
60 let mut output = vec![0u8; k];
61
62 output[0] = 0x00;
63 output[1] = 0x02;
64 let ps_len = k - 3 - input_len;
65
66 for i in 0..ps_len {
67 while output[i + 2] == 0 {
68 self.rng
69 .fill(&mut output[i + 2..=i + 2])
70 .expect("rng ran out of entropy while padding");
71 }
72 }
73
74 output[2 + ps_len] = 0x00;
75 output[2 + ps_len + 1..].copy_from_slice(input);
76 output
77 }
78}
79
80#[derive(Debug)]
82pub struct Pkcs1OaepPadding<T> {
83 rng: T,
84}
85
86impl<T> Pkcs1OaepPadding<T> {
87 const HASH_LEN: usize = 20;
89
90 pub fn new(rng: T) -> Self {
91 Self { rng }
92 }
93
94 fn mgf1(seed: &[u8], len: usize) -> Vec<u8> {
98 if len as u64 > 2u64.pow(32) * Self::HASH_LEN as u64 {
99 panic!("mask too long");
100 }
101
102 let output = (0..len.div_ceil(Self::HASH_LEN))
103 .map(|c| {
104 let cs = &mut [0u8; 4];
105 BigEndian::write_u32(cs, c as u32);
106 Sha1::digest([seed, cs].concat()).to_vec()
107 })
108 .collect::<Vec<Vec<u8>>>()
109 .concat();
110
111 output[..len].into()
112 }
113}
114
115impl<T: Rng> Padding for Pkcs1OaepPadding<T> {
116 fn pub_pad(&mut self, input: impl AsRef<[u8]>, k: usize) -> Vec<u8> {
118 let input = input.as_ref();
119 if input.len() > k - 2 * Self::HASH_LEN - 1 {
122 panic!("message too long");
123 }
124 let mut ps = vec![0; k - input.len() - 2 * Self::HASH_LEN - 2];
127 ps.push(0x01);
128 let p_hash = Sha1::digest([]).to_vec();
130 let db = [&*p_hash, &*ps, input].concat();
133 let mut seed = vec![0; Self::HASH_LEN];
135 self.rng.fill(&mut seed[..]).expect("rng out of entropy");
136 let db_mask = Self::mgf1(&seed, k - Self::HASH_LEN);
138 let masked_db: Vec<_> = db.into_iter().zip(db_mask).map(|(a, b)| a ^ b).collect();
140 let seed_mask = Self::mgf1(&masked_db, Self::HASH_LEN);
142 let masked_seed: Vec<_> = seed
144 .into_iter()
145 .zip(seed_mask)
146 .map(|(a, b)| a ^ b)
147 .collect();
148 [&*masked_seed, &*masked_db].concat()
150 }
151}
152
153#[derive(Debug)]
154pub struct PublicKey {
155 modulus: BigUint,
156 exponent: BigUint,
157}
158
159impl PublicKey {
160 pub fn new(modulus: BigUint, exponent: BigUint) -> PublicKey {
162 PublicKey { modulus, exponent }
163 }
164
165 pub fn from_pem(pem_data: impl AsRef<[u8]>) -> PublicKey {
171 let (der, file_type) = der::pem_to_der(pem_data);
172 let (modulus, exponent) = der::parse_pub_key(&der, file_type);
173 PublicKey::new(modulus, exponent)
174 }
175
176 pub fn num_octets(&self) -> usize {
178 (self.modulus.bits() as usize + 6) >> 3
179 }
180
181 pub fn modulus(&self) -> &BigUint {
183 &self.modulus
184 }
185
186 pub fn exponent(&self) -> &BigUint {
188 &self.exponent
189 }
190
191 pub fn encrypt_block(&self, block: impl AsRef<[u8]>, mut pad: impl Padding) -> Vec<u8> {
197 let enc_block = pad.pub_pad(block, self.num_octets());
198 let enc_int = BigUint::from_bytes_be(&enc_block);
199 let rsa = enc_int.modpow(self.exponent(), self.modulus());
200 let mut rsa_bytes = rsa.to_bytes_be();
201 while rsa_bytes.len() < self.num_octets() {
203 rsa_bytes.insert(0, 0);
204 }
205 rsa_bytes
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use std::io::Read;
212
213 use super::*;
214
215 const SEED: &[u8; 64] = b"\x03\x2e\x45\x32\x6f\xa8\x59\xa7\x2e\xc2\x35\xac\xff\x92\x9b\x15\xd1\
216 \x37\x2e\x30\xb2\x07\x25\x5f\x06\x11\xb8\xf7\x85\xd7\x64\x37\x41\x52\xe0\xac\x00\x9e\x50\x9e\
217 \x7b\xa3\x0c\xd2\xf1\x77\x8e\x11\x3b\x64\xe1\x35\xcf\x4e\x22\x92\xc7\x5e\xfe\x52\x88\xed\xfd\
218 \xa4";
219 const MASK: &[u8; 128] =
220 b"\x5f\x8d\xe1\x05\xb5\xe9\x6b\x2e\x49\x0d\xde\xcb\xd1\x47\xdd\x1d\xef\
221 \x7e\x3b\x8e\x0e\x6a\x26\xeb\x7b\x95\x6c\xcb\x8b\x3b\xdc\x1c\xa9\x75\xbc\x57\xc3\x98\x9e\x8f\
222 \xba\xd3\x1a\x22\x46\x55\xd8\x00\xc4\x69\x54\x84\x0f\xf3\x20\x52\xcd\xf0\xd6\x40\x56\x2b\xdf\
223 \xad\xfa\x26\x3c\xfc\xcf\x3c\x52\xb2\x9f\x2a\xf4\xa1\x86\x99\x59\xbc\x77\xf8\x54\xcf\x15\xbd\
224 \x7a\x25\x19\x29\x85\xa8\x42\xdb\xff\x8e\x13\xef\xee\x5b\x7e\x7e\x55\xbb\xe4\xd3\x89\x64\x7c\
225 \x68\x6a\x9a\x9a\xb3\xfb\x88\x9b\x2d\x77\x67\xd3\x83\x7e\xea\x4e\x0a\x2f\x04";
226
227 struct Seed<'a>(&'a [u8]);
228
229 impl<'a> Rng for Seed<'a> {
230 type Error = std::io::Error;
231
232 fn fill(&mut self, dest: &mut [u8]) -> Result<(), std::io::Error> {
233 self.0.read_exact(dest)
234 }
235 }
236
237 #[test]
238 fn mgf1() {
239 let mask = Pkcs1OaepPadding::<()>::mgf1(&SEED[..], 128);
240 assert_eq!(mask, &MASK[..]);
241 }
242
243 #[test]
244 fn rsa_pkcs() {
245 let modulus: &[u8] = &[
246 0xa8, 0xb3, 0xb2, 0x84, 0xaf, 0x8e, 0xb5, 0x0b, 0x38, 0x70, 0x34, 0xa8, 0x60, 0xf1,
247 0x46, 0xc4, 0x91, 0x9f, 0x31, 0x87, 0x63, 0xcd, 0x6c, 0x55, 0x98, 0xc8, 0xae, 0x48,
248 0x11, 0xa1, 0xe0, 0xab, 0xc4, 0xc7, 0xe0, 0xb0, 0x82, 0xd6, 0x93, 0xa5, 0xe7, 0xfc,
249 0xed, 0x67, 0x5c, 0xf4, 0x66, 0x85, 0x12, 0x77, 0x2c, 0x0c, 0xbc, 0x64, 0xa7, 0x42,
250 0xc6, 0xc6, 0x30, 0xf5, 0x33, 0xc8, 0xcc, 0x72, 0xf6, 0x2a, 0xe8, 0x33, 0xc4, 0x0b,
251 0xf2, 0x58, 0x42, 0xe9, 0x84, 0xbb, 0x78, 0xbd, 0xbf, 0x97, 0xc0, 0x10, 0x7d, 0x55,
252 0xbd, 0xb6, 0x62, 0xf5, 0xc4, 0xe0, 0xfa, 0xb9, 0x84, 0x5c, 0xb5, 0x14, 0x8e, 0xf7,
253 0x39, 0x2d, 0xd3, 0xaa, 0xff, 0x93, 0xae, 0x1e, 0x6b, 0x66, 0x7b, 0xb3, 0xd4, 0x24,
254 0x76, 0x16, 0xd4, 0xf5, 0xba, 0x10, 0xd4, 0xcf, 0xd2, 0x26, 0xde, 0x88, 0xd3, 0x9f,
255 0x16, 0xfb,
256 ];
257 let exponent: &[u8] = &[0x01, 0x00, 0x01];
258
259 let msg1: &[u8] = &[
260 0x66, 0x28, 0x19, 0x4e, 0x12, 0x07, 0x3d, 0xb0, 0x3b, 0xa9, 0x4c, 0xda, 0x9e, 0xf9,
261 0x53, 0x23, 0x97, 0xd5, 0x0d, 0xba, 0x79, 0xb9, 0x87, 0x00, 0x4a, 0xfe, 0xfe, 0x34,
262 ];
263 let seed1: &[u8] = &[
264 0x01, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xae, 0x00,
265 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00,
266 0xf8, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x00,
267 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00,
268 0xb9, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6b, 0x00,
269 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
270 0xfc, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xf4, 0x00,
271 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,
272 0x5b, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x55, 0x00,
273 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00,
274 0x93, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x04, 0x00,
275 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
276 0xeb, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x5e, 0x00,
277 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00,
278 0xb4, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x88, 0x00,
279 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00,
280 0x4d, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xf5, 0x00,
281 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00,
282 0x38, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xce, 0x00,
283 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
284 0x4b, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x96, 0x00,
285 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
286 0xd6, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x97, 0x00,
287 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
288 0x9b, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x83, 0x00,
289 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
290 0x84, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xab, 0x00,
291 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00,
292 ];
293 let cipher_text1 = vec![
294 0x50, 0xb4, 0xc1, 0x41, 0x36, 0xbd, 0x19, 0x8c, 0x2f, 0x3c, 0x3e, 0xd2, 0x43, 0xfc,
295 0xe0, 0x36, 0xe1, 0x68, 0xd5, 0x65, 0x17, 0x98, 0x4a, 0x26, 0x3c, 0xd6, 0x64, 0x92,
296 0xb8, 0x08, 0x04, 0xf1, 0x69, 0xd2, 0x10, 0xf2, 0xb9, 0xbd, 0xfb, 0x48, 0xb1, 0x2f,
297 0x9e, 0xa0, 0x50, 0x09, 0xc7, 0x7d, 0xa2, 0x57, 0xcc, 0x60, 0x0c, 0xce, 0xfe, 0x3a,
298 0x62, 0x83, 0x78, 0x9d, 0x8e, 0xa0, 0xe6, 0x07, 0xac, 0x58, 0xe2, 0x69, 0x0e, 0xc4,
299 0xeb, 0xc1, 0x01, 0x46, 0xe8, 0xcb, 0xaa, 0x5e, 0xd4, 0xd5, 0xcc, 0xe6, 0xfe, 0x7b,
300 0x0f, 0xf9, 0xef, 0xc1, 0xea, 0xbb, 0x56, 0x4d, 0xbf, 0x49, 0x82, 0x85, 0xf4, 0x49,
301 0xee, 0x61, 0xdd, 0x7b, 0x42, 0xee, 0x5b, 0x58, 0x92, 0xcb, 0x90, 0x60, 0x1f, 0x30,
302 0xcd, 0xa0, 0x7b, 0xf2, 0x64, 0x89, 0x31, 0x0b, 0xcd, 0x23, 0xb5, 0x28, 0xce, 0xab,
303 0x3c, 0x31,
304 ];
305
306 let public_key = PublicKey::new(
307 BigUint::from_bytes_be(modulus),
308 BigUint::from_bytes_be(exponent),
309 );
310
311 let rng = Seed(seed1);
312 let pad = Pkcs1Padding::new(rng);
313
314 let cipher_text = public_key.encrypt_block(msg1, pad);
315 assert_eq!(cipher_text, cipher_text1);
316 }
317
318 #[test]
319 fn rsa_oaep() {
320 let modulus: &[u8] = &[
321 0xbb, 0xf8, 0x2f, 0x09, 0x06, 0x82, 0xce, 0x9c, 0x23, 0x38, 0xac, 0x2b, 0x9d, 0xa8,
322 0x71, 0xf7, 0x36, 0x8d, 0x07, 0xee, 0xd4, 0x10, 0x43, 0xa4, 0x40, 0xd6, 0xb6, 0xf0,
323 0x74, 0x54, 0xf5, 0x1f, 0xb8, 0xdf, 0xba, 0xaf, 0x03, 0x5c, 0x02, 0xab, 0x61, 0xea,
324 0x48, 0xce, 0xeb, 0x6f, 0xcd, 0x48, 0x76, 0xed, 0x52, 0x0d, 0x60, 0xe1, 0xec, 0x46,
325 0x19, 0x71, 0x9d, 0x8a, 0x5b, 0x8b, 0x80, 0x7f, 0xaf, 0xb8, 0xe0, 0xa3, 0xdf, 0xc7,
326 0x37, 0x72, 0x3e, 0xe6, 0xb4, 0xb7, 0xd9, 0x3a, 0x25, 0x84, 0xee, 0x6a, 0x64, 0x9d,
327 0x06, 0x09, 0x53, 0x74, 0x88, 0x34, 0xb2, 0x45, 0x45, 0x98, 0x39, 0x4e, 0xe0, 0xaa,
328 0xb1, 0x2d, 0x7b, 0x61, 0xa5, 0x1f, 0x52, 0x7a, 0x9a, 0x41, 0xf6, 0xc1, 0x68, 0x7f,
329 0xe2, 0x53, 0x72, 0x98, 0xca, 0x2a, 0x8f, 0x59, 0x46, 0xf8, 0xe5, 0xfd, 0x09, 0x1d,
330 0xbd, 0xcb,
331 ];
332 let exponent: &[u8] = &[0x11];
333 let msg: &[u8] = &[
334 0xd4, 0x36, 0xe9, 0x95, 0x69, 0xfd, 0x32, 0xa7, 0xc8, 0xa0, 0x5b, 0xbc, 0x90, 0xd3,
335 0x2c, 0x49,
336 ];
337 let seed: &[u8] = &[
338 0xaa, 0xfd, 0x12, 0xf6, 0x59, 0xca, 0xe6, 0x34, 0x89, 0xb4, 0x79, 0xe5, 0x07, 0x6d,
339 0xde, 0xc2, 0xf0, 0x6c, 0xb5, 0x8f,
340 ];
341 let correct_cipher_text = vec![
342 0x12, 0x53, 0xe0, 0x4d, 0xc0, 0xa5, 0x39, 0x7b, 0xb4, 0x4a, 0x7a, 0xb8, 0x7e, 0x9b,
343 0xf2, 0xa0, 0x39, 0xa3, 0x3d, 0x1e, 0x99, 0x6f, 0xc8, 0x2a, 0x94, 0xcc, 0xd3, 0x00,
344 0x74, 0xc9, 0x5d, 0xf7, 0x63, 0x72, 0x20, 0x17, 0x06, 0x9e, 0x52, 0x68, 0xda, 0x5d,
345 0x1c, 0x0b, 0x4f, 0x87, 0x2c, 0xf6, 0x53, 0xc1, 0x1d, 0xf8, 0x23, 0x14, 0xa6, 0x79,
346 0x68, 0xdf, 0xea, 0xe2, 0x8d, 0xef, 0x04, 0xbb, 0x6d, 0x84, 0xb1, 0xc3, 0x1d, 0x65,
347 0x4a, 0x19, 0x70, 0xe5, 0x78, 0x3b, 0xd6, 0xeb, 0x96, 0xa0, 0x24, 0xc2, 0xca, 0x2f,
348 0x4a, 0x90, 0xfe, 0x9f, 0x2e, 0xf5, 0xc9, 0xc1, 0x40, 0xe5, 0xbb, 0x48, 0xda, 0x95,
349 0x36, 0xad, 0x87, 0x00, 0xc8, 0x4f, 0xc9, 0x13, 0x0a, 0xde, 0xa7, 0x4e, 0x55, 0x8d,
350 0x51, 0xa7, 0x4d, 0xdf, 0x85, 0xd8, 0xb5, 0x0d, 0xe9, 0x68, 0x38, 0xd6, 0x06, 0x3e,
351 0x09, 0x55,
352 ];
353
354 let public_key = PublicKey::new(
355 BigUint::from_bytes_be(modulus),
356 BigUint::from_bytes_be(exponent),
357 );
358
359 let rng = Seed(seed);
360 let pad = Pkcs1OaepPadding::new(rng);
361
362 let cipher_text = public_key.encrypt_block(msg, pad);
363 assert_eq!(cipher_text, correct_cipher_text);
364 }
365}