//! ```ignore //! // Private-key information shall have ASN.1 type PrivateKeyInfo //! PrivateKeyInfo ::= SEQUENCE { //! version Version, //! privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, //! privateKey PrivateKey, //! attributes [0] IMPLICIT Attributes OPTIONAL //! } //! //! // version is the syntax version number, for compatibility with future revisions of the spec. //! // It shall be 0 for this version. //! Version ::= INTEGER //! //! // privateKeyAlgorithm identifies the private-key algorithm. One example of a private-key //! // algorithm is PKCS #1's rsaEncryption [PKCS#1] //! // //! // A type that identifies an algorithm (by object identifier) and any associated parameters. //! // This type is defined in [X.509](https://tools.ietf.org/html/rfc5208#ref-X.509) //! PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier //! //! // privateKey is an octet string whose contents are the value of the private key. The //! // interpretation of the contents is defined in the registration of the private-key algorithm. //! // For an RSA private key, for example, the ocntents are a BER encodeing of a value of type //! // RSAPrivateKey. //! PrivateKey ::= OCTET STRING //! //! // attributes is a set of attributes. These are the extended information that is encrypted //! // along with the private-key information. //! Attributes ::= SET OF Attribute //! ``` use super::*; use num_bigint_dig::{traits::ModInverse, BigUint}; use num_traits::identities::One; use rsa::{PublicKeyParts, RSAPrivateKey}; use std::convert::TryInto; impl KeyExt for RSAPrivateKey { fn to_pem_pkcs8(&self) -> Result { let bytes = write_pkcs1(self).ok_or(KeyError::Serialize)?; let oid = yasna::models::ObjectIdentifier::from_slice(&RSA_OID); let contents = yasna::construct_der(|writer| { writer.write_sequence(|writer| { writer.next().write_i64(0); // version is 0 writer.next().write_sequence(|writer| { writer.next().write_oid(&oid); writer.next().write_null(); }); writer.next().write_bytes(&bytes); }); }); let p = pem::Pem { tag: "PRIVATE KEY".to_owned(), contents, }; Ok(pem::encode(&p)) } fn from_pem_pkcs8(pem: &str) -> Result { let data = pem::parse(pem).map_err(|_| KeyError::Pem)?; if data.tag != "PRIVATE KEY" { return Err(KeyError::Kind); } data.try_into().map_err(KeyError::Parse) } fn to_pem_pkcs1(&self) -> Result { let contents = write_pkcs1(self).ok_or(KeyError::Serialize)?; let p = pem::Pem { tag: "RSA PRIVATE KEY".to_owned(), contents, }; Ok(pem::encode(&p)) } fn from_pem_pkcs1(pem: &str) -> Result { let data = pem::parse(pem).map_err(|_| KeyError::Pem)?; if data.tag != "RSA PRIVATE KEY" { return Err(KeyError::Kind); } data.try_into().map_err(KeyError::Parse) } } fn write_pkcs1(rsa: &RSAPrivateKey) -> Option> { let exp1 = rsa.d() % (rsa.primes()[0].clone() - BigUint::one()); let exp2 = rsa.d() % (rsa.primes()[1].clone() - BigUint::one()); let coeff = rsa.primes()[0] .clone() .mod_inverse(rsa.primes()[1].clone())?; Some(yasna::construct_der(|writer| { writer.write_sequence(|writer| { writer.next().write_i64(0); writer.next().write_biguint(&from_dig(rsa.n())); writer.next().write_biguint(&from_dig(rsa.e())); writer.next().write_biguint(&from_dig(rsa.d())); writer.next().write_biguint(&from_dig(&rsa.primes()[0])); writer.next().write_biguint(&from_dig(&rsa.primes()[1])); writer.next().write_biguint(&from_dig(&exp1)); writer.next().write_biguint(&from_dig(&exp2)); writer.next().write_bigint(&int_from_dig(&coeff)); }) })) }