Skip to main content

mysql_common/crypto/
rsa.rs

1// Copyright (c) 2021 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use super::der;
10use byteorder::{BigEndian, ByteOrder};
11use num_bigint::BigUint;
12use sha1::{Digest, Sha1};
13
14/// Padding operation trait.
15pub trait Padding {
16    /// Padding operation for `input` bytes, where `k` is the length of modulus in octets.
17    fn pub_pad(&mut self, input: impl AsRef<[u8]>, k: usize) -> Vec<u8>;
18}
19
20/// Represents a source of random bytes.
21pub trait Rng {
22    type Error: std::error::Error;
23
24    /// Implementor must fill all the bytes in the `dest`.
25    fn fill(&mut self, dest: &mut [u8]) -> Result<(), Self::Error>;
26}
27
28/// Randomness source based on the [`getrandom::fill`].
29pub 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/// Padding, as described in PKCS #1: RSA Encryption Version 1.5 (rfc2313).
40#[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/// Padding, as described in PKCS #1: RSA Cryptography Specifications Version 2.0 (rfc2437).
81#[derive(Debug)]
82pub struct Pkcs1OaepPadding<T> {
83    rng: T,
84}
85
86impl<T> Pkcs1OaepPadding<T> {
87    /// Length of a SHA-1 hash digest.
88    const HASH_LEN: usize = 20;
89
90    pub fn new(rng: T) -> Self {
91        Self { rng }
92    }
93
94    /// Mask Generation Function as defined in rfc2437.
95    ///
96    /// It will use SHA-1 as a hash function.
97    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    /// Will pad input according to PKCS #1 v2 with encoding parameters equal to `[]`.
117    fn pub_pad(&mut self, input: impl AsRef<[u8]>, k: usize) -> Vec<u8> {
118        let input = input.as_ref();
119        // 1. Skip because encoding parameters == []
120        // 2. If ||M|| > emLen-2hLen-1 then output "message too long" and stop.
121        if input.len() > k - 2 * Self::HASH_LEN - 1 {
122            panic!("message too long");
123        }
124        // 3. Generate an octet string PS consisting of emLen-||M||-2hLen-1 zero
125        //    octets. The length of PS may be 0.
126        let mut ps = vec![0; k - input.len() - 2 * Self::HASH_LEN - 2];
127        ps.push(0x01);
128        // 4. Let pHash = Hash(P), an octet string of length hLen.
129        let p_hash = Sha1::digest([]).to_vec();
130        // 5. Concatenate pHash, PS, the message M, and other padding to form a
131        //    data block DB as: DB = pHash || PS || 01 || M
132        let db = [&*p_hash, &*ps, input].concat();
133        // 6. Generate a random octet string seed of length hLen.
134        let mut seed = vec![0; Self::HASH_LEN];
135        self.rng.fill(&mut seed[..]).expect("rng out of entropy");
136        // 7. Let dbMask = MGF(seed, emLen-hLen).
137        let db_mask = Self::mgf1(&seed, k - Self::HASH_LEN);
138        // 8. Let maskedDB = DB \xor dbMask.
139        let masked_db: Vec<_> = db.into_iter().zip(db_mask).map(|(a, b)| a ^ b).collect();
140        // 9. Let seedMask = MGF(maskedDB, hLen).
141        let seed_mask = Self::mgf1(&masked_db, Self::HASH_LEN);
142        // 10. Let maskedSeed = seed \xor seedMask.
143        let masked_seed: Vec<_> = seed
144            .into_iter()
145            .zip(seed_mask)
146            .map(|(a, b)| a ^ b)
147            .collect();
148        // 11. Let EM = maskedSeed || maskedDB.
149        [&*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    /// Basic constructor.
161    pub fn new(modulus: BigUint, exponent: BigUint) -> PublicKey {
162        PublicKey { modulus, exponent }
163    }
164
165    /// Will parse public key from pem representation.
166    ///
167    /// # Panic
168    ///
169    /// Will panic in case of bad pem data.
170    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    /// Returns number of octets in the modulus.
177    pub fn num_octets(&self) -> usize {
178        (self.modulus.bits() as usize + 6) >> 3
179    }
180
181    /// Returns modulus of the public key.
182    pub fn modulus(&self) -> &BigUint {
183        &self.modulus
184    }
185
186    /// Returns exponent of the public key.
187    pub fn exponent(&self) -> &BigUint {
188        &self.exponent
189    }
190
191    /// Will encrypt block with public key.
192    ///
193    /// # Panic
194    ///
195    /// Will panic if block is too long for key or padding.
196    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        // is this needed?
202        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}