pkcs8/
encrypted_private_key_info.rs

1//! PKCS#8 `EncryptedPrivateKeyInfo`
2
3use crate::{Error, Result};
4use core::fmt;
5use der::{
6    asn1::OctetStringRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader,
7    Sequence, Writer,
8};
9use pkcs5::EncryptionScheme;
10
11#[cfg(feature = "alloc")]
12use der::SecretDocument;
13
14#[cfg(feature = "encryption")]
15use {
16    pkcs5::pbes2,
17    rand_core::{CryptoRng, RngCore},
18};
19
20#[cfg(feature = "pem")]
21use 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)]
43pub 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
52impl<'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")]
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")]
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    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
99impl<'a> DecodeValue<'a> for 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
113impl EncodeValue for EncryptedPrivateKeyInfo<'_> {
114    fn value_len(&self) -> der::Result<Length> {
115        self.encryption_algorithm.encoded_len()?
116            + OctetStringRef::new(self.encrypted_data)?.encoded_len()?
117    }
118
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
126impl<'a> Sequence<'a> for EncryptedPrivateKeyInfo<'a> {}
127
128impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> {
129    type Error = Error;
130
131    fn try_from(bytes: &'a [u8]) -> Result<Self> {
132        Ok(Self::from_der(bytes)?)
133    }
134}
135
136impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> {
137    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")]
145impl TryFrom<EncryptedPrivateKeyInfo<'_>> for SecretDocument {
146    type Error = Error;
147
148    fn try_from(encrypted_private_key: EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument> {
149        SecretDocument::try_from(&encrypted_private_key)
150    }
151}
152
153#[cfg(feature = "alloc")]
154impl TryFrom<&EncryptedPrivateKeyInfo<'_>> for SecretDocument {
155    type Error = Error;
156
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")]
163impl PemLabel for EncryptedPrivateKeyInfo<'_> {
164    const PEM_LABEL: &'static str = "ENCRYPTED PRIVATE KEY";
165}