1 //! PKCS#8 `EncryptedPrivateKeyInfo` 2 3 use crate::{Error, Result}; 4 use core::fmt; 5 use der::{asn1::OctetStringRef, Decode, DecodeValue, Encode, Header, Reader, Sequence}; 6 use pkcs5::EncryptionScheme; 7 8 #[cfg(feature = "alloc")] 9 use der::SecretDocument; 10 11 #[cfg(feature = "encryption")] 12 use { 13 pkcs5::pbes2, 14 rand_core::{CryptoRng, RngCore}, 15 }; 16 17 #[cfg(feature = "pem")] 18 use der::pem::PemLabel; 19 20 /// PKCS#8 `EncryptedPrivateKeyInfo`. 21 /// 22 /// ASN.1 structure containing a PKCS#5 [`EncryptionScheme`] identifier for a 23 /// password-based symmetric encryption scheme and encrypted private key data. 24 /// 25 /// ## Schema 26 /// Structure described in [RFC 5208 Section 6]: 27 /// 28 /// ```text 29 /// EncryptedPrivateKeyInfo ::= SEQUENCE { 30 /// encryptionAlgorithm EncryptionAlgorithmIdentifier, 31 /// encryptedData EncryptedData } 32 /// 33 /// EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier 34 /// 35 /// EncryptedData ::= OCTET STRING 36 /// ``` 37 /// 38 /// [RFC 5208 Section 6]: https://tools.ietf.org/html/rfc5208#section-6 39 #[cfg_attr(docsrs, doc(cfg(feature = "pkcs5")))] 40 #[derive(Clone, Eq, PartialEq)] 41 pub struct EncryptedPrivateKeyInfo<'a> { 42 /// Algorithm identifier describing a password-based symmetric encryption 43 /// scheme used to encrypt the `encrypted_data` field. 44 pub encryption_algorithm: EncryptionScheme<'a>, 45 46 /// Private key data 47 pub encrypted_data: &'a [u8], 48 } 49 50 impl<'a> EncryptedPrivateKeyInfo<'a> { 51 /// Attempt to decrypt this encrypted private key using the provided 52 /// password to derive an encryption key. 53 #[cfg(feature = "encryption")] 54 #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] decrypt(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument>55 pub fn decrypt(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument> { 56 Ok(self 57 .encryption_algorithm 58 .decrypt(password, self.encrypted_data)? 59 .try_into()?) 60 } 61 62 /// Encrypt the given ASN.1 DER document using a symmetric encryption key 63 /// derived from the provided password. 64 #[cfg(feature = "encryption")] 65 #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] encrypt( mut rng: impl CryptoRng + RngCore, password: impl AsRef<[u8]>, doc: &[u8], ) -> Result<SecretDocument>66 pub(crate) fn encrypt( 67 mut rng: impl CryptoRng + RngCore, 68 password: impl AsRef<[u8]>, 69 doc: &[u8], 70 ) -> Result<SecretDocument> { 71 let mut salt = [0u8; 16]; 72 rng.fill_bytes(&mut salt); 73 74 let mut iv = [0u8; 16]; 75 rng.fill_bytes(&mut iv); 76 77 let pbes2_params = pbes2::Parameters::scrypt_aes256cbc(Default::default(), &salt, &iv)?; 78 EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, doc) 79 } 80 81 /// Encrypt this private key using a symmetric encryption key derived 82 /// from the provided password and [`pbes2::Parameters`]. 83 #[cfg(feature = "encryption")] 84 #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] encrypt_with( pbes2_params: pbes2::Parameters<'a>, password: impl AsRef<[u8]>, doc: &[u8], ) -> Result<SecretDocument>85 pub(crate) fn encrypt_with( 86 pbes2_params: pbes2::Parameters<'a>, 87 password: impl AsRef<[u8]>, 88 doc: &[u8], 89 ) -> Result<SecretDocument> { 90 let encrypted_data = pbes2_params.encrypt(password, doc)?; 91 92 EncryptedPrivateKeyInfo { 93 encryption_algorithm: pbes2_params.into(), 94 encrypted_data: &encrypted_data, 95 } 96 .try_into() 97 } 98 } 99 100 impl<'a> DecodeValue<'a> for EncryptedPrivateKeyInfo<'a> { decode_value<R: Reader<'a>>( reader: &mut R, header: Header, ) -> der::Result<EncryptedPrivateKeyInfo<'a>>101 fn decode_value<R: Reader<'a>>( 102 reader: &mut R, 103 header: Header, 104 ) -> der::Result<EncryptedPrivateKeyInfo<'a>> { 105 reader.read_nested(header.length, |reader| { 106 Ok(Self { 107 encryption_algorithm: reader.decode()?, 108 encrypted_data: OctetStringRef::decode(reader)?.as_bytes(), 109 }) 110 }) 111 } 112 } 113 114 impl<'a> Sequence<'a> for EncryptedPrivateKeyInfo<'a> { fields<F, T>(&self, f: F) -> der::Result<T> where F: FnOnce(&[&dyn Encode]) -> der::Result<T>,115 fn fields<F, T>(&self, f: F) -> der::Result<T> 116 where 117 F: FnOnce(&[&dyn Encode]) -> der::Result<T>, 118 { 119 f(&[ 120 &self.encryption_algorithm, 121 &OctetStringRef::new(self.encrypted_data)?, 122 ]) 123 } 124 } 125 126 impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> { 127 type Error = Error; 128 try_from(bytes: &'a [u8]) -> Result<Self>129 fn try_from(bytes: &'a [u8]) -> Result<Self> { 130 Ok(Self::from_der(bytes)?) 131 } 132 } 133 134 impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 136 f.debug_struct("EncryptedPrivateKeyInfo") 137 .field("encryption_algorithm", &self.encryption_algorithm) 138 .finish_non_exhaustive() 139 } 140 } 141 142 #[cfg(feature = "alloc")] 143 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs5"))))] 144 impl TryFrom<EncryptedPrivateKeyInfo<'_>> for SecretDocument { 145 type Error = Error; 146 try_from(encrypted_private_key: EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument>147 fn try_from(encrypted_private_key: EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument> { 148 SecretDocument::try_from(&encrypted_private_key) 149 } 150 } 151 152 #[cfg(feature = "alloc")] 153 #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs5"))))] 154 impl TryFrom<&EncryptedPrivateKeyInfo<'_>> for SecretDocument { 155 type Error = Error; 156 try_from(encrypted_private_key: &EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument>157 fn try_from(encrypted_private_key: &EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument> { 158 Ok(Self::encode_msg(encrypted_private_key)?) 159 } 160 } 161 162 #[cfg(feature = "pem")] 163 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] 164 impl PemLabel for EncryptedPrivateKeyInfo<'_> { 165 const PEM_LABEL: &'static str = "ENCRYPTED PRIVATE KEY"; 166 } 167