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 rand::Rng;
13use sha1::{Digest, Sha1};
14
15/// Padding operation trait.
16pub trait Padding {
17    /// Padding operation for `input` bytes, where `k` is the length of modulus in octets.
18    fn pub_pad(&mut self, input: impl AsRef<[u8]>, k: usize) -> Vec<u8>;
19}
20
21/// Padding, as described in PKCS #1: RSA Encryption Version 1.5 (rfc2313).
22#[derive(Debug)]
23pub struct Pkcs1Padding<T> {
24    rng: T,
25}
26
27impl<T> Pkcs1Padding<T> {
28    pub fn new(rng: T) -> Self {
29        Self { rng }
30    }
31}
32
33impl<T: Rng> Padding for Pkcs1Padding<T> {
34    fn pub_pad(&mut self, input: impl AsRef<[u8]>, k: usize) -> Vec<u8> {
35        let input = input.as_ref();
36        let input_len = input.len();
37        assert!(
38            input_len < k - 11,
39            "The length of the data D shall not be more than k-11 octets"
40        );
41
42        let mut output = vec![0u8; k];
43
44        output[0] = 0x00;
45        output[1] = 0x02;
46        let ps_len = k - 3 - input_len;
47
48        for i in 0..ps_len {
49            let x = loop {
50                match self.rng.gen::<u8>() {
51                    0x00 => continue,
52                    x => break x,
53                }
54            };
55            output[i + 2] = x;
56        }
57
58        output[2 + ps_len] = 0x00;
59        output[2 + ps_len + 1..].copy_from_slice(input);
60        output
61    }
62}
63
64/// Padding, as described in PKCS #1: RSA Cryptography Specifications Version 2.0 (rfc2437).
65#[derive(Debug)]
66pub struct Pkcs1OaepPadding<T> {
67    rng: T,
68}
69
70impl<T> Pkcs1OaepPadding<T> {
71    /// Length of a SHA-1 hash digest.
72    const HASH_LEN: usize = 20;
73
74    pub fn new(rng: T) -> Self {
75        Self { rng }
76    }
77
78    /// Mask Generation Function as defined in rfc2437.
79    ///
80    /// It will use SHA-1 as a hash function.
81    fn mgf1(seed: &[u8], len: usize) -> Vec<u8> {
82        if len as u64 > 2u64.pow(32) * Self::HASH_LEN as u64 {
83            panic!("mask too long");
84        }
85
86        fn ceil_div(dividend: usize, divisor: usize) -> usize {
87            let mut quotient = dividend / divisor;
88            if dividend % divisor > 0 {
89                quotient += 1;
90            }
91            quotient
92        }
93
94        let output = (0..ceil_div(len, Self::HASH_LEN))
95            .map(|c| {
96                let cs = &mut [0u8; 4];
97                BigEndian::write_u32(cs, c as u32);
98                Sha1::digest([seed, cs].concat()).to_vec()
99            })
100            .collect::<Vec<Vec<u8>>>()
101            .concat();
102
103        output[..len].into()
104    }
105}
106
107impl<T: Rng> Padding for Pkcs1OaepPadding<T> {
108    /// Will pad input according to PKCS #1 v2 with encoding parameters equal to `[]`.
109    fn pub_pad(&mut self, input: impl AsRef<[u8]>, k: usize) -> Vec<u8> {
110        let input = input.as_ref();
111        // 1. Skip because encoding parameters == []
112        // 2. If ||M|| > emLen-2hLen-1 then output "message too long" and stop.
113        if input.len() > k - 2 * Self::HASH_LEN - 1 {
114            panic!("message too long");
115        }
116        // 3. Generate an octet string PS consisting of emLen-||M||-2hLen-1 zero
117        //    octets. The length of PS may be 0.
118        let mut ps = vec![0; k - input.len() - 2 * Self::HASH_LEN - 2];
119        ps.push(0x01);
120        // 4. Let pHash = Hash(P), an octet string of length hLen.
121        let p_hash = Sha1::digest([]).to_vec();
122        // 5. Concatenate pHash, PS, the message M, and other padding to form a
123        //    data block DB as: DB = pHash || PS || 01 || M
124        let db = [&*p_hash, &*ps, input].concat();
125        // 6. Generate a random octet string seed of length hLen.
126        let seed: Vec<_> = (0..Self::HASH_LEN).map(|_| self.rng.gen()).collect();
127        // 7. Let dbMask = MGF(seed, emLen-hLen).
128        let db_mask = Self::mgf1(&seed, k - Self::HASH_LEN);
129        // 8. Let maskedDB = DB \xor dbMask.
130        let masked_db: Vec<_> = db.into_iter().zip(db_mask).map(|(a, b)| a ^ b).collect();
131        // 9. Let seedMask = MGF(maskedDB, hLen).
132        let seed_mask = Self::mgf1(&masked_db, Self::HASH_LEN);
133        // 10. Let maskedSeed = seed \xor seedMask.
134        let masked_seed: Vec<_> = seed
135            .into_iter()
136            .zip(seed_mask)
137            .map(|(a, b)| a ^ b)
138            .collect();
139        // 11. Let EM = maskedSeed || maskedDB.
140        [&*masked_seed, &*masked_db].concat()
141    }
142}
143
144#[derive(Debug)]
145pub struct PublicKey {
146    modulus: BigUint,
147    exponent: BigUint,
148}
149
150impl PublicKey {
151    /// Basic constructor.
152    pub fn new(modulus: BigUint, exponent: BigUint) -> PublicKey {
153        PublicKey { modulus, exponent }
154    }
155
156    /// Will parse public key from pem representation.
157    ///
158    /// # Panic
159    ///
160    /// Will panic in case of bad pem data.
161    pub fn from_pem(pem_data: impl AsRef<[u8]>) -> PublicKey {
162        let (der, file_type) = der::pem_to_der(pem_data);
163        let (modulus, exponent) = der::parse_pub_key(&der, file_type);
164        PublicKey::new(modulus, exponent)
165    }
166
167    /// Returns number of octets in the modulus.
168    pub fn num_octets(&self) -> usize {
169        (self.modulus.bits() as usize + 6) >> 3
170    }
171
172    /// Returns modulus of the public key.
173    pub fn modulus(&self) -> &BigUint {
174        &self.modulus
175    }
176
177    /// Returns exponent of the public key.
178    pub fn exponent(&self) -> &BigUint {
179        &self.exponent
180    }
181
182    /// Will encrypt block with public key.
183    ///
184    /// # Panic
185    ///
186    /// Will panic if block is too long for key or padding.
187    pub fn encrypt_block(&self, block: impl AsRef<[u8]>, mut pad: impl Padding) -> Vec<u8> {
188        let enc_block = pad.pub_pad(block, self.num_octets());
189        let enc_int = BigUint::from_bytes_be(&enc_block);
190        let rsa = enc_int.modpow(self.exponent(), self.modulus());
191        let mut rsa_bytes = rsa.to_bytes_be();
192        // is this needed?
193        while rsa_bytes.len() < self.num_octets() {
194            rsa_bytes.insert(0, 0);
195        }
196        rsa_bytes
197    }
198}
199
200#[cfg(test)]
201mod tests {
202    use std::io::Read;
203
204    use super::*;
205    use rand::RngCore;
206
207    const SEED: &[u8; 64] = b"\x03\x2e\x45\x32\x6f\xa8\x59\xa7\x2e\xc2\x35\xac\xff\x92\x9b\x15\xd1\
208    \x37\x2e\x30\xb2\x07\x25\x5f\x06\x11\xb8\xf7\x85\xd7\x64\x37\x41\x52\xe0\xac\x00\x9e\x50\x9e\
209    \x7b\xa3\x0c\xd2\xf1\x77\x8e\x11\x3b\x64\xe1\x35\xcf\x4e\x22\x92\xc7\x5e\xfe\x52\x88\xed\xfd\
210    \xa4";
211    const MASK: &[u8; 128] =
212        b"\x5f\x8d\xe1\x05\xb5\xe9\x6b\x2e\x49\x0d\xde\xcb\xd1\x47\xdd\x1d\xef\
213    \x7e\x3b\x8e\x0e\x6a\x26\xeb\x7b\x95\x6c\xcb\x8b\x3b\xdc\x1c\xa9\x75\xbc\x57\xc3\x98\x9e\x8f\
214    \xba\xd3\x1a\x22\x46\x55\xd8\x00\xc4\x69\x54\x84\x0f\xf3\x20\x52\xcd\xf0\xd6\x40\x56\x2b\xdf\
215    \xad\xfa\x26\x3c\xfc\xcf\x3c\x52\xb2\x9f\x2a\xf4\xa1\x86\x99\x59\xbc\x77\xf8\x54\xcf\x15\xbd\
216    \x7a\x25\x19\x29\x85\xa8\x42\xdb\xff\x8e\x13\xef\xee\x5b\x7e\x7e\x55\xbb\xe4\xd3\x89\x64\x7c\
217    \x68\x6a\x9a\x9a\xb3\xfb\x88\x9b\x2d\x77\x67\xd3\x83\x7e\xea\x4e\x0a\x2f\x04";
218
219    /// Replacement for the deprecated `rand::ReadRng`.
220    struct Seed<'a>(&'a [u8]);
221
222    impl<'a> RngCore for Seed<'a> {
223        fn next_u32(&mut self) -> u32 {
224            let mut buf = [0; 4];
225            self.fill_bytes(&mut buf);
226            u32::from_le_bytes(buf)
227        }
228
229        fn next_u64(&mut self) -> u64 {
230            let mut buf = [0; 8];
231            self.fill_bytes(&mut buf);
232            u64::from_le_bytes(buf)
233        }
234
235        fn fill_bytes(&mut self, dest: &mut [u8]) {
236            self.try_fill_bytes(dest).unwrap_or_else(|err| {
237                panic!(
238                    "reading random bytes from Read implementation failed; error: {}",
239                    err
240                )
241            });
242        }
243
244        fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
245            if dest.is_empty() {
246                return Ok(());
247            }
248            self.0.read_exact(dest).map_err(|e| rand::Error::new(e))
249        }
250    }
251
252    #[test]
253    fn mgf1() {
254        let mask = Pkcs1OaepPadding::<()>::mgf1(&SEED[..], 128);
255        assert_eq!(mask, &MASK[..]);
256    }
257
258    #[test]
259    fn rsa_pkcs() {
260        let modulus = vec![
261            0xa8, 0xb3, 0xb2, 0x84, 0xaf, 0x8e, 0xb5, 0x0b, 0x38, 0x70, 0x34, 0xa8, 0x60, 0xf1,
262            0x46, 0xc4, 0x91, 0x9f, 0x31, 0x87, 0x63, 0xcd, 0x6c, 0x55, 0x98, 0xc8, 0xae, 0x48,
263            0x11, 0xa1, 0xe0, 0xab, 0xc4, 0xc7, 0xe0, 0xb0, 0x82, 0xd6, 0x93, 0xa5, 0xe7, 0xfc,
264            0xed, 0x67, 0x5c, 0xf4, 0x66, 0x85, 0x12, 0x77, 0x2c, 0x0c, 0xbc, 0x64, 0xa7, 0x42,
265            0xc6, 0xc6, 0x30, 0xf5, 0x33, 0xc8, 0xcc, 0x72, 0xf6, 0x2a, 0xe8, 0x33, 0xc4, 0x0b,
266            0xf2, 0x58, 0x42, 0xe9, 0x84, 0xbb, 0x78, 0xbd, 0xbf, 0x97, 0xc0, 0x10, 0x7d, 0x55,
267            0xbd, 0xb6, 0x62, 0xf5, 0xc4, 0xe0, 0xfa, 0xb9, 0x84, 0x5c, 0xb5, 0x14, 0x8e, 0xf7,
268            0x39, 0x2d, 0xd3, 0xaa, 0xff, 0x93, 0xae, 0x1e, 0x6b, 0x66, 0x7b, 0xb3, 0xd4, 0x24,
269            0x76, 0x16, 0xd4, 0xf5, 0xba, 0x10, 0xd4, 0xcf, 0xd2, 0x26, 0xde, 0x88, 0xd3, 0x9f,
270            0x16, 0xfb,
271        ];
272        let exponent = vec![0x01, 0x00, 0x01];
273
274        let msg1 = vec![
275            0x66, 0x28, 0x19, 0x4e, 0x12, 0x07, 0x3d, 0xb0, 0x3b, 0xa9, 0x4c, 0xda, 0x9e, 0xf9,
276            0x53, 0x23, 0x97, 0xd5, 0x0d, 0xba, 0x79, 0xb9, 0x87, 0x00, 0x4a, 0xfe, 0xfe, 0x34,
277        ];
278        let seed1 = vec![
279            0x01, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xae, 0x00,
280            0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00,
281            0xf8, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x00,
282            0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00,
283            0xb9, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6b, 0x00,
284            0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
285            0xfc, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xf4, 0x00,
286            0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,
287            0x5b, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x55, 0x00,
288            0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00,
289            0x93, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x04, 0x00,
290            0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
291            0xeb, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x5e, 0x00,
292            0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00,
293            0xb4, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x88, 0x00,
294            0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00,
295            0x4d, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xf5, 0x00,
296            0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00,
297            0x38, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xce, 0x00,
298            0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
299            0x4b, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x96, 0x00,
300            0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
301            0xd6, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x97, 0x00,
302            0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
303            0x9b, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x83, 0x00,
304            0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
305            0x84, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xab, 0x00,
306            0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00,
307        ];
308        let cipher_text1 = vec![
309            0x50, 0xb4, 0xc1, 0x41, 0x36, 0xbd, 0x19, 0x8c, 0x2f, 0x3c, 0x3e, 0xd2, 0x43, 0xfc,
310            0xe0, 0x36, 0xe1, 0x68, 0xd5, 0x65, 0x17, 0x98, 0x4a, 0x26, 0x3c, 0xd6, 0x64, 0x92,
311            0xb8, 0x08, 0x04, 0xf1, 0x69, 0xd2, 0x10, 0xf2, 0xb9, 0xbd, 0xfb, 0x48, 0xb1, 0x2f,
312            0x9e, 0xa0, 0x50, 0x09, 0xc7, 0x7d, 0xa2, 0x57, 0xcc, 0x60, 0x0c, 0xce, 0xfe, 0x3a,
313            0x62, 0x83, 0x78, 0x9d, 0x8e, 0xa0, 0xe6, 0x07, 0xac, 0x58, 0xe2, 0x69, 0x0e, 0xc4,
314            0xeb, 0xc1, 0x01, 0x46, 0xe8, 0xcb, 0xaa, 0x5e, 0xd4, 0xd5, 0xcc, 0xe6, 0xfe, 0x7b,
315            0x0f, 0xf9, 0xef, 0xc1, 0xea, 0xbb, 0x56, 0x4d, 0xbf, 0x49, 0x82, 0x85, 0xf4, 0x49,
316            0xee, 0x61, 0xdd, 0x7b, 0x42, 0xee, 0x5b, 0x58, 0x92, 0xcb, 0x90, 0x60, 0x1f, 0x30,
317            0xcd, 0xa0, 0x7b, 0xf2, 0x64, 0x89, 0x31, 0x0b, 0xcd, 0x23, 0xb5, 0x28, 0xce, 0xab,
318            0x3c, 0x31,
319        ];
320
321        let public_key = PublicKey::new(
322            BigUint::from_bytes_be(&modulus),
323            BigUint::from_bytes_be(&exponent),
324        );
325
326        let rng = Seed(&*seed1);
327        let pad = Pkcs1Padding::new(rng);
328
329        let cipher_text = public_key.encrypt_block(msg1, pad);
330        assert_eq!(cipher_text, cipher_text1);
331    }
332
333    #[test]
334    fn rsa_oaep() {
335        let modulus = vec![
336            0xbb, 0xf8, 0x2f, 0x09, 0x06, 0x82, 0xce, 0x9c, 0x23, 0x38, 0xac, 0x2b, 0x9d, 0xa8,
337            0x71, 0xf7, 0x36, 0x8d, 0x07, 0xee, 0xd4, 0x10, 0x43, 0xa4, 0x40, 0xd6, 0xb6, 0xf0,
338            0x74, 0x54, 0xf5, 0x1f, 0xb8, 0xdf, 0xba, 0xaf, 0x03, 0x5c, 0x02, 0xab, 0x61, 0xea,
339            0x48, 0xce, 0xeb, 0x6f, 0xcd, 0x48, 0x76, 0xed, 0x52, 0x0d, 0x60, 0xe1, 0xec, 0x46,
340            0x19, 0x71, 0x9d, 0x8a, 0x5b, 0x8b, 0x80, 0x7f, 0xaf, 0xb8, 0xe0, 0xa3, 0xdf, 0xc7,
341            0x37, 0x72, 0x3e, 0xe6, 0xb4, 0xb7, 0xd9, 0x3a, 0x25, 0x84, 0xee, 0x6a, 0x64, 0x9d,
342            0x06, 0x09, 0x53, 0x74, 0x88, 0x34, 0xb2, 0x45, 0x45, 0x98, 0x39, 0x4e, 0xe0, 0xaa,
343            0xb1, 0x2d, 0x7b, 0x61, 0xa5, 0x1f, 0x52, 0x7a, 0x9a, 0x41, 0xf6, 0xc1, 0x68, 0x7f,
344            0xe2, 0x53, 0x72, 0x98, 0xca, 0x2a, 0x8f, 0x59, 0x46, 0xf8, 0xe5, 0xfd, 0x09, 0x1d,
345            0xbd, 0xcb,
346        ];
347        let exponent = vec![0x11];
348        let msg = vec![
349            0xd4, 0x36, 0xe9, 0x95, 0x69, 0xfd, 0x32, 0xa7, 0xc8, 0xa0, 0x5b, 0xbc, 0x90, 0xd3,
350            0x2c, 0x49,
351        ];
352        let seed: Vec<u8> = vec![
353            0xaa, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xf6, 0x00,
354            0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00,
355            0x34, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x79, 0x00,
356            0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00,
357            0xde, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x6c, 0x00,
358            0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00,
359        ];
360        let correct_cipher_text = vec![
361            0x12, 0x53, 0xe0, 0x4d, 0xc0, 0xa5, 0x39, 0x7b, 0xb4, 0x4a, 0x7a, 0xb8, 0x7e, 0x9b,
362            0xf2, 0xa0, 0x39, 0xa3, 0x3d, 0x1e, 0x99, 0x6f, 0xc8, 0x2a, 0x94, 0xcc, 0xd3, 0x00,
363            0x74, 0xc9, 0x5d, 0xf7, 0x63, 0x72, 0x20, 0x17, 0x06, 0x9e, 0x52, 0x68, 0xda, 0x5d,
364            0x1c, 0x0b, 0x4f, 0x87, 0x2c, 0xf6, 0x53, 0xc1, 0x1d, 0xf8, 0x23, 0x14, 0xa6, 0x79,
365            0x68, 0xdf, 0xea, 0xe2, 0x8d, 0xef, 0x04, 0xbb, 0x6d, 0x84, 0xb1, 0xc3, 0x1d, 0x65,
366            0x4a, 0x19, 0x70, 0xe5, 0x78, 0x3b, 0xd6, 0xeb, 0x96, 0xa0, 0x24, 0xc2, 0xca, 0x2f,
367            0x4a, 0x90, 0xfe, 0x9f, 0x2e, 0xf5, 0xc9, 0xc1, 0x40, 0xe5, 0xbb, 0x48, 0xda, 0x95,
368            0x36, 0xad, 0x87, 0x00, 0xc8, 0x4f, 0xc9, 0x13, 0x0a, 0xde, 0xa7, 0x4e, 0x55, 0x8d,
369            0x51, 0xa7, 0x4d, 0xdf, 0x85, 0xd8, 0xb5, 0x0d, 0xe9, 0x68, 0x38, 0xd6, 0x06, 0x3e,
370            0x09, 0x55,
371        ];
372
373        let public_key = PublicKey::new(
374            BigUint::from_bytes_be(&modulus),
375            BigUint::from_bytes_be(&exponent),
376        );
377
378        let rng = Seed(&*seed);
379        let pad = Pkcs1OaepPadding::new(rng);
380
381        let cipher_text = public_key.encrypt_block(msg, pad);
382        assert_eq!(cipher_text, correct_cipher_text);
383    }
384}