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