darkbio_crypto/rsa/
mod.rs

1// crypto-rs: cryptography primitives and wrappers
2// Copyright 2025 Dark Bio AG. All rights reserved.
3//
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7//! RSA cryptography wrappers and parametrization.
8//!
9//! https://datatracker.ietf.org/doc/html/rfc8017
10
11use crate::pem;
12use base64::Engine;
13use base64::engine::general_purpose::STANDARD as BASE64;
14use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey, Error};
15use rsa::rand_core::OsRng;
16use rsa::sha2::{Digest, Sha256};
17use rsa::signature::hazmat::PrehashVerifier;
18use rsa::signature::{Keypair, SignatureEncoding, Signer, Verifier};
19use rsa::traits::{PrivateKeyParts, PublicKeyParts};
20use rsa::{BigUint, RsaPrivateKey, RsaPublicKey};
21use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
22
23/// Size of the raw secret key in bytes.
24/// Format: p (128 bytes) || q (128 bytes) || d (256 bytes) || e (8 bytes)
25pub const SECRET_KEY_SIZE: usize = 520;
26
27/// Size of the raw public key in bytes.
28/// Format: n (256 bytes) || e (8 bytes)
29pub const PUBLIC_KEY_SIZE: usize = 264;
30
31/// Size of an RSA-2048 signature.
32pub const SIGNATURE_SIZE: usize = 256;
33
34/// Size of an RSA key fingerprint (SHA256 hash).
35pub const FINGERPRINT_SIZE: usize = 32;
36
37/// SecretKey contains a 2048-bit RSA private key usable for signing, with SHA256
38/// as the underlying hash algorithm. Whilst RSA could also be used for encryption,
39/// that is not exposed on the API as it's not required by the project.
40#[derive(Clone)]
41pub struct SecretKey {
42    inner: rsa::pkcs1v15::SigningKey<Sha256>,
43}
44
45impl SecretKey {
46    /// generate creates a new, random private key.
47    pub fn generate() -> SecretKey {
48        let mut rng = OsRng;
49
50        let key = RsaPrivateKey::new(&mut rng, 2048).unwrap();
51        let sig = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
52        Self { inner: sig }
53    }
54
55    /// from_bytes parses a 520-byte array into a private key.
56    ///
57    /// Format: p (128 bytes) || q (128 bytes) || d (256 bytes) || e (8 bytes),
58    /// all in big-endian.
59    pub fn from_bytes(bytes: &[u8; SECRET_KEY_SIZE]) -> Result<Self, rsa::Error> {
60        let p = BigUint::from_bytes_be(&bytes[0..128]);
61        let q = BigUint::from_bytes_be(&bytes[128..256]);
62        let d = BigUint::from_bytes_be(&bytes[256..512]);
63        let e = BigUint::from_bytes_be(&bytes[512..520]);
64
65        let n = &p * &q;
66
67        // The modulus must be exactly 2048 bits
68        if n.bits() != 2048 {
69            return Err(rsa::Error::InvalidModulus);
70        }
71        // Whilst the RSA algorithm permits different exponents, every modern
72        // system only ever uses 65537 and most also enforce this. Might as
73        // well do the same.
74        if e != BigUint::from(65537u32) {
75            return Err(rsa::Error::InvalidExponent);
76        }
77        let key = RsaPrivateKey::from_components(n, e, d, vec![p, q])?;
78        let sig = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
79        Ok(Self { inner: sig })
80    }
81
82    /// from_der parses a DER buffer into a private key.
83    pub fn from_der(der: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
84        let inner = rsa::pkcs1v15::SigningKey::<Sha256>::from_pkcs8_der(der)?;
85
86        // The modulus must be exactly 2048 bits
87        let key: &RsaPrivateKey = inner.as_ref();
88        if key.n().bits() != 2048 {
89            return Err(Error::KeyMalformed.into());
90        }
91        // Whilst the RSA algorithm permits different exponents, every modern
92        // system only ever uses 65537 and most also enforce this. Might as
93        // well do the same.
94        if *key.e() != BigUint::from(65537u32) {
95            return Err(Error::KeyMalformed.into());
96        }
97        // The upstream rsa crate ignores CRT parameters (dP, dQ, qInv) and
98        // recomputes them, accepting malformed values. We don't want to allow
99        // that, so just round trip the format and see if it's matching or not.
100        let recoded = rsa::pkcs1v15::SigningKey::<Sha256>::to_pkcs8_der(&inner)?;
101        if recoded.as_bytes() != der {
102            return Err(Error::KeyMalformed.into());
103        }
104        Ok(Self { inner })
105    }
106
107    /// from_pem parses a PEM string into a private key.
108    pub fn from_pem(pem_str: &str) -> Result<Self, Box<dyn std::error::Error>> {
109        // Crack open the PEM to get to the private key info
110        let (kind, data) = pem::decode(pem_str.as_bytes())?;
111        if kind != "PRIVATE KEY" {
112            return Err(format!("invalid PEM tag {}", kind).into());
113        }
114        // Parse the DER content
115        Self::from_der(&data)
116    }
117
118    /// to_bytes serializes a private key into a 520-byte array.
119    ///
120    /// Format: p (128 bytes) || q (128 bytes) || d (256 bytes) || e (8 bytes),
121    /// all in big-endian.
122    pub fn to_bytes(&self) -> [u8; SECRET_KEY_SIZE] {
123        let key: &RsaPrivateKey = self.inner.as_ref();
124        let primes = key.primes();
125
126        let mut out = [0u8; 520];
127
128        let p_bytes = primes[0].to_bytes_be();
129        out[128 - p_bytes.len()..128].copy_from_slice(&p_bytes);
130
131        let q_bytes = primes[1].to_bytes_be();
132        out[256 - q_bytes.len()..256].copy_from_slice(&q_bytes);
133
134        let d_bytes = key.d().to_bytes_be();
135        out[512 - d_bytes.len()..512].copy_from_slice(&d_bytes);
136
137        let e_bytes = key.e().to_bytes_be();
138        out[520 - e_bytes.len()..520].copy_from_slice(&e_bytes);
139
140        out
141    }
142
143    /// to_der serializes a private key into a DER buffer.
144    pub fn to_der(&self) -> Vec<u8> {
145        rsa::pkcs1v15::SigningKey::<Sha256>::to_pkcs8_der(&self.inner)
146            .unwrap()
147            .as_bytes()
148            .to_vec()
149    }
150
151    /// to_pem serializes a private key into a PEM string.
152    pub fn to_pem(&self) -> String {
153        pem::encode("PRIVATE KEY", &self.to_der())
154    }
155
156    /// public_key retrieves the public counterpart of the secret key.
157    pub fn public_key(&self) -> PublicKey {
158        let key = self.inner.verifying_key();
159        PublicKey { inner: key }
160    }
161
162    /// fingerprint returns a 256bit unique identified for this key. For RSA, that
163    /// is the SHA256 hash of the raw (le modulus || le exponent) public key.
164    pub fn fingerprint(&self) -> Fingerprint {
165        self.public_key().fingerprint()
166    }
167
168    /// sign creates a digital signature of the message.
169    pub fn sign(&self, message: &[u8]) -> Signature {
170        let sig = self.inner.sign(message);
171        Signature(sig.to_bytes().as_ref().try_into().unwrap())
172    }
173}
174
175/// PublicKey contains a 2048-bit RSA public key usable for verification, with
176/// SHA256 as the underlying hash algorithm. Whilst RSA could also be used for
177/// decryption, that is not exposed on the API as it's not required by the
178/// project.
179#[derive(Debug, Clone)]
180pub struct PublicKey {
181    inner: rsa::pkcs1v15::VerifyingKey<Sha256>,
182}
183
184impl PublicKey {
185    /// from_bytes parses a 264-byte array into a public key.
186    ///
187    /// Format: n (256 bytes) || e (8 bytes), all in big-endian.
188    pub fn from_bytes(bytes: &[u8; PUBLIC_KEY_SIZE]) -> Result<Self, rsa::Error> {
189        let n = BigUint::from_bytes_be(&bytes[0..256]);
190        let e = BigUint::from_bytes_be(&bytes[256..264]);
191
192        // The modulus must be exactly 2048 bits
193        if n.bits() != 2048 {
194            return Err(rsa::Error::InvalidModulus);
195        }
196        // Whilst the RSA algorithm permits different exponents, every modern
197        // system only ever uses 65537 and most also enforce this. Might as
198        // well do the same.
199        if e != BigUint::from(65537u32) {
200            return Err(rsa::Error::InvalidExponent);
201        }
202        let key = RsaPublicKey::new(n, e)?;
203        let inner = rsa::pkcs1v15::VerifyingKey::<Sha256>::new(key);
204        Ok(Self { inner })
205    }
206
207    /// from_der parses a DER buffer into a public key.
208    pub fn from_der(der: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
209        let inner = rsa::pkcs1v15::VerifyingKey::<Sha256>::from_public_key_der(der)?;
210
211        // The modulus must be exactly 2048 bits
212        let key: &RsaPublicKey = inner.as_ref();
213        if key.n().bits() != 2048 {
214            return Err(Error::KeyMalformed.into());
215        }
216        // Whilst the RSA algorithm permits different exponents, every modern
217        // system only ever uses 65537 and most also enforce this. Might as
218        // well do the same.
219        if *key.e() != BigUint::from(65537u32) {
220            return Err(Error::KeyMalformed.into());
221        }
222        Ok(Self { inner })
223    }
224
225    /// from_pem parses a PEM string into a public key.
226    pub fn from_pem(pem_str: &str) -> Result<Self, Box<dyn std::error::Error>> {
227        // Crack open the PEM to get to the public key info
228        let (kind, data) = pem::decode(pem_str.as_bytes())?;
229        if kind != "PUBLIC KEY" {
230            return Err(format!("invalid PEM tag {}", kind).into());
231        }
232        // Parse the DER content
233        Self::from_der(&data)
234    }
235
236    /// to_bytes serializes a public key into a 264-byte array.
237    ///
238    /// Format: n (256 bytes) || e (8 bytes), all in big-endian.
239    pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_SIZE] {
240        let key: &RsaPublicKey = self.inner.as_ref();
241
242        let mut out = [0u8; 264];
243
244        let n_bytes = key.n().to_bytes_be();
245        out[256 - n_bytes.len()..256].copy_from_slice(&n_bytes);
246
247        let e_bytes = key.e().to_bytes_be();
248        out[264 - e_bytes.len()..264].copy_from_slice(&e_bytes);
249
250        out
251    }
252
253    /// to_der serializes a public key into a DER buffer.
254    pub fn to_der(&self) -> Vec<u8> {
255        rsa::pkcs1v15::VerifyingKey::<Sha256>::to_public_key_der(&self.inner)
256            .unwrap()
257            .as_bytes()
258            .to_vec()
259    }
260
261    /// to_pem serializes a public key into a PEM string.
262    pub fn to_pem(&self) -> String {
263        pem::encode("PUBLIC KEY", &self.to_der())
264    }
265
266    /// fingerprint returns a 256bit unique identified for this key. For RSA, that
267    /// is the SHA256 hash of the raw (le modulus || le exponent) public key.
268    pub fn fingerprint(&self) -> Fingerprint {
269        let pubkey: RsaPublicKey = self.inner.as_ref().clone();
270
271        let mut mod_le = pubkey.n().to_bytes_le();
272        mod_le.resize(256, 0);
273        let mut exp_le = pubkey.e().to_bytes_le();
274        exp_le.resize(8, 0);
275
276        let mut hasher = Sha256::new();
277        hasher.update(&mod_le);
278        hasher.update(&exp_le);
279        Fingerprint(hasher.finalize().into())
280    }
281
282    /// verify verifies a digital signature.
283    pub fn verify(
284        &self,
285        message: &[u8],
286        signature: &Signature,
287    ) -> Result<(), rsa::signature::Error> {
288        let sig = rsa::pkcs1v15::Signature::try_from(signature.to_bytes().as_slice())?;
289        self.inner.verify(message, &sig)
290    }
291
292    /// verify_hash verifies a digital signature on an already hashed message.
293    pub fn verify_hash(
294        &self,
295        hash: &[u8],
296        signature: &Signature,
297    ) -> Result<(), rsa::signature::Error> {
298        let sig = rsa::pkcs1v15::Signature::try_from(signature.to_bytes().as_slice())?;
299        self.inner.verify_prehash(hash, &sig)
300    }
301}
302
303impl Serialize for PublicKey {
304    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
305        serializer.serialize_str(&BASE64.encode(self.to_bytes()))
306    }
307}
308
309impl<'de> Deserialize<'de> for PublicKey {
310    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
311        let s = String::deserialize(deserializer)?;
312        let bytes = BASE64.decode(&s).map_err(de::Error::custom)?;
313        let arr: [u8; PUBLIC_KEY_SIZE] = bytes
314            .try_into()
315            .map_err(|_| de::Error::custom("invalid public key length"))?;
316        PublicKey::from_bytes(&arr).map_err(de::Error::custom)
317    }
318}
319
320#[cfg(feature = "cbor")]
321impl crate::cbor::Encode for PublicKey {
322    fn encode_cbor(&self) -> Vec<u8> {
323        self.to_bytes().encode_cbor()
324    }
325}
326
327#[cfg(feature = "cbor")]
328impl crate::cbor::Decode for PublicKey {
329    fn decode_cbor(data: &[u8]) -> Result<Self, crate::cbor::Error> {
330        let bytes = <[u8; PUBLIC_KEY_SIZE]>::decode_cbor(data)?;
331        Self::from_bytes(&bytes).map_err(|e| crate::cbor::Error::DecodeFailed(e.to_string()))
332    }
333
334    fn decode_cbor_notrail(
335        decoder: &mut crate::cbor::Decoder<'_>,
336    ) -> Result<Self, crate::cbor::Error> {
337        let bytes = decoder.decode_bytes_fixed::<PUBLIC_KEY_SIZE>()?;
338        Self::from_bytes(&bytes).map_err(|e| crate::cbor::Error::DecodeFailed(e.to_string()))
339    }
340}
341
342/// Signature contains an RSA-2048 signature.
343#[derive(Debug, Clone, PartialEq, Eq)]
344pub struct Signature([u8; SIGNATURE_SIZE]);
345
346impl Signature {
347    /// from_bytes converts a 256-byte array into a signature.
348    pub fn from_bytes(bytes: &[u8; SIGNATURE_SIZE]) -> Self {
349        Self(*bytes)
350    }
351
352    /// to_bytes converts a signature into a 256-byte array.
353    pub fn to_bytes(&self) -> [u8; SIGNATURE_SIZE] {
354        self.0
355    }
356}
357
358impl Serialize for Signature {
359    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
360        serializer.serialize_str(&BASE64.encode(self.to_bytes()))
361    }
362}
363
364impl<'de> Deserialize<'de> for Signature {
365    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
366        let s = String::deserialize(deserializer)?;
367        let bytes = BASE64.decode(&s).map_err(de::Error::custom)?;
368        let arr: [u8; SIGNATURE_SIZE] = bytes
369            .try_into()
370            .map_err(|_| de::Error::custom("invalid signature length"))?;
371        Ok(Signature::from_bytes(&arr))
372    }
373}
374
375#[cfg(feature = "cbor")]
376impl crate::cbor::Encode for Signature {
377    fn encode_cbor(&self) -> Vec<u8> {
378        self.to_bytes().encode_cbor()
379    }
380}
381
382#[cfg(feature = "cbor")]
383impl crate::cbor::Decode for Signature {
384    fn decode_cbor(data: &[u8]) -> Result<Self, crate::cbor::Error> {
385        let bytes = <[u8; SIGNATURE_SIZE]>::decode_cbor(data)?;
386        Ok(Self::from_bytes(&bytes))
387    }
388
389    fn decode_cbor_notrail(
390        decoder: &mut crate::cbor::Decoder<'_>,
391    ) -> Result<Self, crate::cbor::Error> {
392        let bytes = decoder.decode_bytes_fixed::<SIGNATURE_SIZE>()?;
393        Ok(Self::from_bytes(&bytes))
394    }
395}
396
397/// Fingerprint contains an RSA key fingerprint (SHA256 hash).
398#[derive(Debug, Clone, PartialEq, Eq)]
399pub struct Fingerprint([u8; FINGERPRINT_SIZE]);
400
401impl Fingerprint {
402    /// from_bytes converts a 32-byte array into a fingerprint.
403    pub fn from_bytes(bytes: &[u8; FINGERPRINT_SIZE]) -> Self {
404        Self(*bytes)
405    }
406
407    /// to_bytes converts a fingerprint into a 32-byte array.
408    pub fn to_bytes(&self) -> [u8; FINGERPRINT_SIZE] {
409        self.0
410    }
411}
412
413impl Serialize for Fingerprint {
414    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
415        serializer.serialize_str(&BASE64.encode(self.to_bytes()))
416    }
417}
418
419impl<'de> Deserialize<'de> for Fingerprint {
420    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
421        let s = String::deserialize(deserializer)?;
422        let bytes = BASE64.decode(&s).map_err(de::Error::custom)?;
423        let arr: [u8; FINGERPRINT_SIZE] = bytes
424            .try_into()
425            .map_err(|_| de::Error::custom("invalid fingerprint length"))?;
426        Ok(Fingerprint::from_bytes(&arr))
427    }
428}
429
430#[cfg(feature = "cbor")]
431impl crate::cbor::Encode for Fingerprint {
432    fn encode_cbor(&self) -> Vec<u8> {
433        self.to_bytes().encode_cbor()
434    }
435}
436
437#[cfg(feature = "cbor")]
438impl crate::cbor::Decode for Fingerprint {
439    fn decode_cbor(data: &[u8]) -> Result<Self, crate::cbor::Error> {
440        let bytes = <[u8; FINGERPRINT_SIZE]>::decode_cbor(data)?;
441        Ok(Self::from_bytes(&bytes))
442    }
443
444    fn decode_cbor_notrail(
445        decoder: &mut crate::cbor::Decoder<'_>,
446    ) -> Result<Self, crate::cbor::Error> {
447        let bytes = decoder.decode_bytes_fixed::<FINGERPRINT_SIZE>()?;
448        Ok(Self::from_bytes(&bytes))
449    }
450}
451
452#[cfg(test)]
453mod tests {
454    use super::*;
455
456    // Tests that a raw byte encoded RSA private key can be decoded and re-encoded
457    // to the same bytes. The purpose is not to battle-test the implementation,
458    // rather to ensure that the code implements the format other subsystems expect.
459    #[test]
460    fn test_secretkey_bytes_codec() {
461        // Generated with:
462        //   openssl genrsa -out test.key 2048
463        //   openssl rsa -in test.key -text -noout
464        let part_prime1 = "\
465ed9792f021b214b57fc6230d051da0783673475d9b9cf9f9003367b6362a\
46662201852f112cbb6fcadb00b17470e21dfa39ec2eef58ea2ff7e27b9e63b\
46790af84e482b53ea79760196bbd226627038d84eb16e75e2efacb9f432dbf\
468b93ec3f6fea10ec9c9b984e8c7d4e95fa76befc2f46e42c86d8479586b36\
4697cb49499b37bf01d";
470        let part_prime2 = "\
471da885d75be231c04ebf195455fcec9449044b212f2044ddeeb49c0c14898\
47235f8e91e56a6418570a9f50c2734c4fadb7f2eb2c50cff4ab0b34e389568\
47312f9b42632c66a248e09e52af8eb5e1c8cdd21fe65b86242fdf1e838235d\
474a1bf37ced6ae0e117c8dac77c34917a711bc6ecc949d0f000dae8f22dadf\
47546153c64d5ef7521";
476        let part_priv_exp = "\
47702d864d6371a3586977264fa905c01495adbeba2fbab49cc1ea22d6d5c17\
47871b0a31b2a58c546e81990fa861e0954a4d9119d3698f41ca66b37c0b4a8\
479756f4efdd814d36393e3fb8b9662f1dc7725222565c95eb5389e3caa28e5\
480429608b898d677e9feffbb66207d3e881949dc0b53568a0ea9c6ae06bef3\
4816f74422960d8447b194ebff8ab5f08842153661278bbeb115dd131d26746\
4827315402b5d75560d4c20390499887f3d33021f4dda1cb36bfb9b54ed80c5\
4839bd3213f42a4ca7025d59a64e53d559e14ac84f8438b771c1ac94fb90aa4\
4841c7708e073510ad063bada4a261bc0b311a42b8d482d26b39fb82d44f133\
485c9ab9ccdd77b098fc6c0c647ed663781";
486        let part_pub_exp = "0000000000010001";
487
488        let input = [part_prime1, part_prime2, part_priv_exp, part_pub_exp].concat();
489
490        let bytes: [u8; 520] = hex::decode(&input).unwrap().try_into().unwrap();
491        let key = SecretKey::from_bytes(&bytes).unwrap();
492        assert_eq!(hex::encode(key.to_bytes()), input);
493    }
494
495    // Tests that a raw byte encoded RSA public key can be decoded and re-encoded
496    // to the same bytes. The purpose is not to battle-test the implementation,
497    // rather to ensure that the code implements the format other subsystems expect.
498    #[test]
499    fn test_publickey_bytes_codec() {
500        // Generated with:
501        //   openssl genrsa -out test.key 2048
502        //   openssl rsa -in test.key -text -noout
503        let part_mod = "\
504cad1a263e36205031c65b1befe8b1f65ac0af10c72aeb69ad295d1a651a3\
505f1191d4af8afdef14ab2d66d0253ef98228ee9f85fb822f92fccb3f6c23b\
5064745ac743e002fc81c63dc04531fc176f3cdcb5aebaa2797903fd791b9c8\
507474eb7b999295cf64935d9a5a4626849e77c472a6e00b8ff73d0f1a3b7c4\
5084da7e7bae4726b4f2f7f05741d576a13c1bc9077ee14d7e9af5192f8e7dc\
5092ffb212d4ef9c7fff4e87c3debf9a48346ac3618b24d7932d8e7cf6b266c\
510dce0ad59b16fce0a8420aebd332e28294862ef288917eacabf330cb29161\
511f78fcdf089bc2cb4086af8a7980637fb9cf0b4ed86d6a21208ae5a4e49d1\
5127ab6d945b65cef700217ada913ca34bd";
513        let part_pub_exp = "0000000000010001";
514
515        let input = [part_mod, part_pub_exp].concat();
516
517        let bytes: [u8; 264] = hex::decode(&input).unwrap().try_into().unwrap();
518        let key = PublicKey::from_bytes(&bytes).unwrap();
519        assert_eq!(hex::encode(key.to_bytes()), input);
520    }
521
522    // Tests that a PEM encoded RSA private key can be decoded and re-encoded to
523    // the same string. The purpose is not to battle-test the PEM implementation,
524    // rather to ensure that the code implements the PEM format other subsystems
525    // expect.
526    #[test]
527    fn test_secretkey_pem_codec() {
528        // Generated with:
529        //   openssl genrsa -out test.key 2048
530        let input = "\
531-----BEGIN PRIVATE KEY-----
532MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCwLLXTHaYT57yN
533HZT6BTnJIDaJ8GTnu05PnwQQcV7Xgom164T52qaMmvsK/PGlzMzQdo9YjYKsExZE
534EllJe4O1mVA1T/LyKLkPZgKqcp11/9UAkk3pHsPkb0YOb3g1721K6tQ78ufjeIOt
5355WJ+n+HJHOvhvyjmO0aQ51eh0jSyUu6U9fA+qrtPO4D/mUVRDJmCLSyGzIMd4Xan
536zTSWZ8JWLjahIdMPOZYUrGpICOxwt9Jaow37ogAalRVHnTb8PkklOo9pr0a3ZdQQ
537P3yV/A5gmgXXLi2BkQ0b2y8FOuD/JjBXL4Ks9nUVn/nMMaFhDxmL3ZZ9AuvB94AR
538B0MvuZh9AgMBAAECggEABoVaB1dURJhZDBV0OcI5iVWakr63md/F3kdDnlu+koDd
539/V63rG76izDmsQQYP3Zgt0TW1ehDcmP3ziDG2blycF5WKM2tqGcwlfBvypn8WEnH
5405eWEcEul5JFZ09C8b61N8sOALq01PzVOv8dCPu9jKzL19mfPofX4myKt4esKX2gy
541psId9QmgsrRRsCSvQeUxOA3Sqaa0a+atALZByPKZN8XzmZu1Ie5QPQvh/xYDJU1D
542GEiNgwZGy0eXL2Se5OjKAR40f4SzArbs/Jb2gRFHTjpdJ9g33GqoP94jZPcogtm2
543FHgI5vl9jL4uXiSJLkgl4FfFvoIXWuUi1xAC5NDT4QKBgQDnaxGFvt6vW8JKEyEq
5446Nf9K2Y2nQbvEmqnvS/RPwuqKuh66KCNG2rePFzXLHCplbYHt9hhF+Ity9lFzxSK
545ipRC6BD9aqaqF6qhm1nZWnXsPWjWDsFYzQHv8LA4pL8gmxbz+IOs1jbbIQAdq8X5
546uv7C1YSCrPkpm/nTljzwU/d/gwKBgQDC42in2DURf1+cU9Qw+hNDCy0EgkB7STzV
547dCreCAFXhSIzFwq9bjzOeSFtvZlWxKNJKNUiDXgN/grRREG/m1kW7EdHAMiOVVNK
548SbQ/+zHy6SMKNu0ArkokaCAEludVVRjkwh5GsyFvFaBINJBnp/zDYhNkkxStjCRf
549rW0/fmcH/wKBgF/IA9+caWShEOBB3Kd66fKiJNMT2QvYToaQmhr8AiLzUXeVkuX0
550ZB4JU8/HV/YIveeh4xAEp5uW1J29IN5ajxTGIkoQ+1xJIVl0CBMbCtW1cQ+v2byc
551VWHu97DqFyUyq6RcxnshymCV3wtozi8Xg1w2rXq8hv/+y78UXrKFvllrAoGAItrb
552F9GyRAvcxK+1boD7Ou1fwsOs1p/VknNxSz5xRv7Xi/2d/R0fIOpHEUJsjzkh3u6/
553l5SDGTWLJ7wmaidVeqUNZmR8egBGoi2mYB8D4ubRTn1eS9XgCrzYpRl8DCXpCtiw
55444IcA6sBfIhyHyfLLAJ5Z25qr1M2GiqBNG7d7G8CgYBoIYe3OeuqZn2T+eA3rmMv
555djLUQsO3CvmFYBDvNqmiwNx3OOV/YFQVvSAGaEP/5pJGVmAKUDaALgTveToLV6jq
556bS99QZDnrW+xkvJi6N1ZAlQpIOX5Y/Q2qyBa1Hf2Z21mnqZSN3HHC6aQl+83uety
557JJXbL24vf1AajzeJk6CpdQ==
558-----END PRIVATE KEY-----";
559
560        let key = SecretKey::from_pem(input).unwrap();
561        assert_eq!(key.to_pem().trim(), input.trim());
562    }
563
564    // Tests that a PEM encoded RSA public key can be decoded and re-encoded to
565    // the same string. The purpose is not to battle-test the PEM implementation,
566    // rather to ensure that the code implements the PEM format other subsystems
567    // expect.
568    #[test]
569    fn test_publickey_pem_codec() {
570        // Generated with:
571        //   openssl rsa -in test.key -pubout -out test.pub
572        let input = "\
573-----BEGIN PUBLIC KEY-----
574MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsCy10x2mE+e8jR2U+gU5
575ySA2ifBk57tOT58EEHFe14KJteuE+dqmjJr7CvzxpczM0HaPWI2CrBMWRBJZSXuD
576tZlQNU/y8ii5D2YCqnKddf/VAJJN6R7D5G9GDm94Ne9tSurUO/Ln43iDreVifp/h
577yRzr4b8o5jtGkOdXodI0slLulPXwPqq7TzuA/5lFUQyZgi0shsyDHeF2p800lmfC
578Vi42oSHTDzmWFKxqSAjscLfSWqMN+6IAGpUVR502/D5JJTqPaa9Gt2XUED98lfwO
579YJoF1y4tgZENG9svBTrg/yYwVy+CrPZ1FZ/5zDGhYQ8Zi92WfQLrwfeAEQdDL7mY
580fQIDAQAB
581-----END PUBLIC KEY-----";
582
583        let key = PublicKey::from_pem(input).unwrap();
584        assert_eq!(key.to_pem().trim(), input.trim());
585    }
586
587    // Tests that a DER encoded RSA private key can be decoded and re-encoded to
588    // the same string. The purpose is not to battle-test the DER implementation,
589    // rather to ensure that the code implements the DER format other subsystems
590    // expect.
591    #[test]
592    fn test_privatekey_der_codec() {
593        // Generated with:
594        //   openssl rsa -in test.key -outform DER -out test.key.der
595        //   cat test.key.der | xxd -p
596        let input = "\
597308204bc020100300d06092a864886f70d0101010500048204a6308204a2\
5980201000282010100b02cb5d31da613e7bc8d1d94fa0539c9203689f064e7\
599bb4e4f9f0410715ed78289b5eb84f9daa68c9afb0afcf1a5ccccd0768f58\
6008d82ac1316441259497b83b59950354ff2f228b90f6602aa729d75ffd500\
601924de91ec3e46f460e6f7835ef6d4aead43bf2e7e37883ade5627e9fe1c9\
6021cebe1bf28e63b4690e757a1d234b252ee94f5f03eaabb4f3b80ff994551\
6030c99822d2c86cc831de176a7cd349667c2562e36a121d30f399614ac6a48\
60408ec70b7d25aa30dfba2001a9515479d36fc3e49253a8f69af46b765d410\
6053f7c95fc0e609a05d72e2d81910d1bdb2f053ae0ff2630572f82acf67515\
6069ff9cc31a1610f198bdd967d02ebc1f7801107432fb9987d020301000102\
60782010006855a0757544498590c157439c23989559a92beb799dfc5de4743\
6089e5bbe9280ddfd5eb7ac6efa8b30e6b104183f7660b744d6d5e8437263f7\
609ce20c6d9b972705e5628cdada8673095f06fca99fc5849c7e5e584704ba5\
610e49159d3d0bc6fad4df2c3802ead353f354ebfc7423eef632b32f5f667cf\
611a1f5f89b22ade1eb0a5f6832a6c21df509a0b2b451b024af41e531380dd2\
612a9a6b46be6ad00b641c8f29937c5f3999bb521ee503d0be1ff1603254d43\
61318488d830646cb47972f649ee4e8ca011e347f84b302b6ecfc96f6811147\
6144e3a5d27d837dc6aa83fde2364f72882d9b6147808e6f97d8cbe2e5e2489\
6152e4825e057c5be82175ae522d71002e4d0d3e102818100e76b1185bedeaf\
6165bc24a13212ae8d7fd2b66369d06ef126aa7bd2fd13f0baa2ae87ae8a08d\
6171b6ade3c5cd72c70a995b607b7d86117e22dcbd945cf148a8a9442e810fd\
6186aa6aa17aaa19b59d95a75ec3d68d60ec158cd01eff0b038a4bf209b16f3\
619f883acd636db21001dabc5f9bafec2d58482acf9299bf9d3963cf053f77f\
6208302818100c2e368a7d835117f5f9c53d430fa13430b2d0482407b493cd5\
621742ade080157852233170abd6e3cce79216dbd9956c4a34928d5220d780d\
622fe0ad14441bf9b5916ec474700c88e55534a49b43ffb31f2e9230a36ed00\
623ae4a2468200496e7555518e4c21e46b3216f15a048349067a7fcc3621364\
6249314ad8c245fad6d3f7e6707ff0281805fc803df9c6964a110e041dca77a\
625e9f2a224d313d90bd84e86909a1afc0222f351779592e5f4641e0953cfc7\
62657f608bde7a1e31004a79b96d49dbd20de5a8f14c6224a10fb5c49215974\
62708131b0ad5b5710fafd9bc9c5561eef7b0ea172532aba45cc67b21ca6095\
628df0b68ce2f17835c36ad7abc86fffecbbf145eb285be596b02818022dadb\
62917d1b2440bdcc4afb56e80fb3aed5fc2c3acd69fd59273714b3e7146fed7\
6308bfd9dfd1d1f20ea4711426c8f3921deeebf97948319358b27bc266a2755\
6317aa50d66647c7a0046a22da6601f03e2e6d14e7d5e4bd5e00abcd8a5197c\
6320c25e90ad8b0e3821c03ab017c88721f27cb2c0279676e6aaf53361a2a81\
633346eddec6f028180682187b739ebaa667d93f9e037ae632f7632d442c3b7\
6340af9856010ef36a9a2c0dc7738e57f605415bd20066843ffe6924656600a\
6355036802e04ef793a0b57a8ea6d2f7d4190e7ad6fb192f262e8dd59025429\
63620e5f963f436ab205ad477f6676d669ea6523771c70ba69097ef37b9eb72\
6372495db2f6e2f7f501a8f378993a0a975";
638
639        let der = hex::decode(&input).unwrap();
640        let key = SecretKey::from_der(&der).unwrap();
641        assert_eq!(hex::encode(key.to_der()), input);
642    }
643
644    // Tests that a DER encoded RSA public key can be decoded and re-encoded to
645    // the same string. The purpose is not to battle-test the DER implementation,
646    // rather to ensure that the code implements the DER format other subsystems
647    // expect.
648    #[test]
649    fn test_publickey_der_codec() {
650        // Generated with:
651        //   openssl rsa -in test.key -pubout -outform DER -out test.pub.der
652        //   cat test.pub.der | xxd -p
653        let input = "\
65430820122300d06092a864886f70d01010105000382010f003082010a0282\
655010100b02cb5d31da613e7bc8d1d94fa0539c9203689f064e7bb4e4f9f04\
65610715ed78289b5eb84f9daa68c9afb0afcf1a5ccccd0768f588d82ac1316\
657441259497b83b59950354ff2f228b90f6602aa729d75ffd500924de91ec3\
658e46f460e6f7835ef6d4aead43bf2e7e37883ade5627e9fe1c91cebe1bf28\
659e63b4690e757a1d234b252ee94f5f03eaabb4f3b80ff9945510c99822d2c\
66086cc831de176a7cd349667c2562e36a121d30f399614ac6a4808ec70b7d2\
6615aa30dfba2001a9515479d36fc3e49253a8f69af46b765d4103f7c95fc0e\
662609a05d72e2d81910d1bdb2f053ae0ff2630572f82acf675159ff9cc31a1\
663610f198bdd967d02ebc1f7801107432fb9987d0203010001";
664
665        let der = hex::decode(&input).unwrap();
666        let key = PublicKey::from_der(&der).unwrap();
667        assert_eq!(hex::encode(key.to_der()), input);
668    }
669
670    // Tests that the implemented fingerprint algorithm produces the expected
671    // checksum. The purpose is not to battle-test the implementation, rather
672    // to ensure that the code implements the format other subsystems expect.
673    #[test]
674    fn test_fingerprint() {
675        // Generated with:
676        //   from Cryptodome.PublicKey import RSA
677        //   import hashlib
678        //
679        //   with open('key.pem') as f:
680        //       key = RSA.importKey(f.read())
681        //   mod_le = key.n.to_bytes(256, 'little')
682        //   exp_le = key.e.to_bytes(8, 'little')
683        //
684        //   print(hashlib.sha256(mod_le + exp_le).hexdigest())
685        let input = "1e2eaa59f13165ce5c3b4e028fd259767c2ee8d43d5d5ba7debf9d31834b46db";
686
687        let key = PublicKey::from_pem(
688            "-----BEGIN PUBLIC KEY-----
689MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsCy10x2mE+e8jR2U+gU5
690ySA2ifBk57tOT58EEHFe14KJteuE+dqmjJr7CvzxpczM0HaPWI2CrBMWRBJZSXuD
691tZlQNU/y8ii5D2YCqnKddf/VAJJN6R7D5G9GDm94Ne9tSurUO/Ln43iDreVifp/h
692yRzr4b8o5jtGkOdXodI0slLulPXwPqq7TzuA/5lFUQyZgi0shsyDHeF2p800lmfC
693Vi42oSHTDzmWFKxqSAjscLfSWqMN+6IAGpUVR502/D5JJTqPaa9Gt2XUED98lfwO
694YJoF1y4tgZENG9svBTrg/yYwVy+CrPZ1FZ/5zDGhYQ8Zi92WfQLrwfeAEQdDL7mY
695fQIDAQAB
696-----END PUBLIC KEY-----",
697        )
698        .unwrap();
699        assert_eq!(hex::encode(key.fingerprint().to_bytes()), input);
700    }
701
702    // Tests signing and verifying messages. Note, this test is not meant to test
703    // cryptography, it is mostly an API sanity check to verify that everything
704    // seems to work.
705    //
706    // TODO(karalabe): Get some live test vectors for a bit more sanity
707    #[test]
708    fn test_sign_verify() {
709        // Create the keys for Alice
710        let secret = SecretKey::generate();
711        let public = secret.public_key();
712
713        // Run a bunch of different authentication/encryption combinations
714        struct TestCase<'a> {
715            message: &'a [u8],
716        }
717        let tests = [TestCase {
718            message: b"message to authenticate",
719        }];
720
721        for tt in &tests {
722            // Sign the message using the test case data
723            let signature = secret.sign(tt.message);
724
725            // Verify the signature message
726            public
727                .verify(tt.message, &signature)
728                .unwrap_or_else(|e| panic!("failed to verify message: {}", e));
729        }
730    }
731}