pkcs5/
pbes1.rs

1//! Password-Based Encryption Scheme 1 as defined in [RFC 8018 Section 6.1].
2//!
3//! [RFC 8018 Section 6.1]: https://tools.ietf.org/html/rfc8018#section-6.1
4
5use crate::AlgorithmIdentifierRef;
6use der::{
7    asn1::{AnyRef, ObjectIdentifier, OctetStringRef},
8    Decode, DecodeValue, Encode, EncodeValue, ErrorKind, Length, Reader, Sequence, Tag, Writer,
9};
10
11/// `pbeWithMD2AndDES-CBC` Object Identifier (OID).
12pub const PBE_WITH_MD2_AND_DES_CBC_OID: ObjectIdentifier =
13    ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.1");
14
15/// `pbeWithMD2AndRC2-CBC` Object Identifier (OID).
16pub const PBE_WITH_MD2_AND_RC2_CBC_OID: ObjectIdentifier =
17    ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.4");
18
19/// `pbeWithMD5AndDES-CBC` Object Identifier (OID).
20pub const PBE_WITH_MD5_AND_DES_CBC_OID: ObjectIdentifier =
21    ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.3");
22
23/// `pbeWithMD5AndRC2-CBC` Object Identifier (OID).
24pub const PBE_WITH_MD5_AND_RC2_CBC_OID: ObjectIdentifier =
25    ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.6");
26
27/// `pbeWithSHA1AndDES-CBC` Object Identifier (OID).
28pub const PBE_WITH_SHA1_AND_DES_CBC_OID: ObjectIdentifier =
29    ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.10");
30
31/// `pbeWithSHA1AndRC2-CBC` Object Identifier (OID).
32pub const PBE_WITH_SHA1_AND_RC2_CBC_OID: ObjectIdentifier =
33    ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.11");
34
35/// Length of a PBES1 salt (as defined in the `PBEParameter` ASN.1 message).
36pub const SALT_LENGTH: usize = 8;
37
38/// Password-Based Encryption Scheme 1 algorithms as defined in [RFC 8018 Appendix A.C].
39///
40/// ```text
41/// PBES1Algorithms ALGORITHM-IDENTIFIER ::= {
42///    {PBEParameter IDENTIFIED BY pbeWithMD2AndDES-CBC}  |
43///    {PBEParameter IDENTIFIED BY pbeWithMD2AndRC2-CBC}  |
44///    {PBEParameter IDENTIFIED BY pbeWithMD5AndDES-CBC}  |
45///    {PBEParameter IDENTIFIED BY pbeWithMD5AndRC2-CBC}  |
46///    {PBEParameter IDENTIFIED BY pbeWithSHA1AndDES-CBC} |
47///    {PBEParameter IDENTIFIED BY pbeWithSHA1AndRC2-CBC},
48///    ...
49/// }
50/// ```
51///
52/// [RFC 8018 Appendix A.C]: https://datatracker.ietf.org/doc/html/rfc8018#appendix-C
53#[derive(Clone, Debug, Eq, PartialEq)]
54pub struct Algorithm {
55    /// Encryption scheme.
56    pub encryption: EncryptionScheme,
57
58    /// Scheme parameters.
59    pub parameters: Parameters,
60}
61
62impl Algorithm {
63    /// Get the [`ObjectIdentifier`] (a.k.a OID) for this algorithm.
64    pub fn oid(&self) -> ObjectIdentifier {
65        self.encryption.oid()
66    }
67}
68
69impl<'a> DecodeValue<'a> for Algorithm {
70    fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
71        AlgorithmIdentifierRef::decode_value(reader, header)?.try_into()
72    }
73}
74
75impl EncodeValue for Algorithm {
76    fn value_len(&self) -> der::Result<Length> {
77        self.encryption.encoded_len()? + self.parameters.encoded_len()?
78    }
79
80    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
81        self.encryption.encode(writer)?;
82        self.parameters.encode(writer)?;
83        Ok(())
84    }
85}
86
87impl Sequence<'_> for Algorithm {}
88
89impl<'a> TryFrom<AlgorithmIdentifierRef<'a>> for Algorithm {
90    type Error = der::Error;
91
92    fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result<Self> {
93        // Ensure that we have a supported PBES1 algorithm identifier
94        let encryption = EncryptionScheme::try_from(alg.oid)
95            .map_err(|_| der::Tag::ObjectIdentifier.value_error())?;
96
97        let parameters = alg
98            .parameters
99            .ok_or_else(|| Tag::OctetString.value_error())?
100            .try_into()?;
101
102        Ok(Self {
103            encryption,
104            parameters,
105        })
106    }
107}
108
109/// Password-Based Encryption Scheme 1 parameters as defined in [RFC 8018 Appendix A.3].
110///
111/// ```text
112/// PBEParameter ::= SEQUENCE {
113///    salt OCTET STRING (SIZE(8)),
114///    iterationCount INTEGER }
115/// ```
116///
117/// [RFC 8018 Appendix A.3]: https://tools.ietf.org/html/rfc8018#appendix-A.3
118#[derive(Clone, Debug, Eq, PartialEq)]
119pub struct Parameters {
120    /// Salt value
121    pub salt: [u8; SALT_LENGTH],
122
123    /// Iteration count
124    pub iteration_count: u16,
125}
126
127impl<'a> DecodeValue<'a> for Parameters {
128    fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
129        AnyRef::decode_value(reader, header)?.try_into()
130    }
131}
132
133impl EncodeValue for Parameters {
134    fn value_len(&self) -> der::Result<Length> {
135        OctetStringRef::new(&self.salt)?.encoded_len()? + self.iteration_count.encoded_len()?
136    }
137
138    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
139        OctetStringRef::new(&self.salt)?.encode(writer)?;
140        self.iteration_count.encode(writer)?;
141        Ok(())
142    }
143}
144
145impl Sequence<'_> for Parameters {}
146
147impl TryFrom<AnyRef<'_>> for Parameters {
148    type Error = der::Error;
149
150    fn try_from(any: AnyRef<'_>) -> der::Result<Parameters> {
151        any.sequence(|reader| {
152            Ok(Parameters {
153                salt: OctetStringRef::decode(reader)?
154                    .as_bytes()
155                    .try_into()
156                    .map_err(|_| der::Tag::OctetString.value_error())?,
157                iteration_count: reader.decode()?,
158            })
159        })
160    }
161}
162
163/// Password-Based Encryption Scheme 1 ciphersuites as defined in [RFC 8018 Appendix A.3].
164///
165/// [RFC 8018 Appendix A.3]: https://tools.ietf.org/html/rfc8018#appendix-A.3
166#[derive(Copy, Clone, Debug, Eq, PartialEq)]
167pub enum EncryptionScheme {
168    /// `pbeWithMD2AndDES-CBC`
169    PbeWithMd2AndDesCbc,
170
171    /// `pbeWithMD2AndRC2-CBC`
172    PbeWithMd2AndRc2Cbc,
173
174    /// `pbeWithMD5AndDES-CBC`
175    PbeWithMd5AndDesCbc,
176
177    /// `pbeWithMD5AndRC2-CBC`
178    PbeWithMd5AndRc2Cbc,
179
180    /// `pbeWithSHA1AndDES-CBC`
181    PbeWithSha1AndDesCbc,
182
183    /// `pbeWithSHA1AndRC2-CBC`
184    PbeWithSha1AndRc2Cbc,
185}
186
187impl TryFrom<ObjectIdentifier> for EncryptionScheme {
188    type Error = der::Error;
189
190    fn try_from(oid: ObjectIdentifier) -> der::Result<Self> {
191        match oid {
192            PBE_WITH_MD2_AND_DES_CBC_OID => Ok(Self::PbeWithMd2AndDesCbc),
193            PBE_WITH_MD2_AND_RC2_CBC_OID => Ok(Self::PbeWithMd2AndRc2Cbc),
194            PBE_WITH_MD5_AND_DES_CBC_OID => Ok(Self::PbeWithMd5AndDesCbc),
195            PBE_WITH_MD5_AND_RC2_CBC_OID => Ok(Self::PbeWithMd5AndRc2Cbc),
196            PBE_WITH_SHA1_AND_DES_CBC_OID => Ok(Self::PbeWithSha1AndDesCbc),
197            PBE_WITH_SHA1_AND_RC2_CBC_OID => Ok(Self::PbeWithSha1AndRc2Cbc),
198            _ => Err(ErrorKind::OidUnknown { oid }.into()),
199        }
200    }
201}
202
203impl EncryptionScheme {
204    /// Get the [`SymmetricCipher`] to be used.
205    pub fn cipher(self) -> SymmetricCipher {
206        match self {
207            Self::PbeWithMd2AndDesCbc => SymmetricCipher::DesCbc,
208            Self::PbeWithMd2AndRc2Cbc => SymmetricCipher::Rc2Cbc,
209            Self::PbeWithMd5AndDesCbc => SymmetricCipher::DesCbc,
210            Self::PbeWithMd5AndRc2Cbc => SymmetricCipher::Rc2Cbc,
211            Self::PbeWithSha1AndDesCbc => SymmetricCipher::DesCbc,
212            Self::PbeWithSha1AndRc2Cbc => SymmetricCipher::Rc2Cbc,
213        }
214    }
215
216    /// Get the [`DigestAlgorithm`] to be used.
217    pub fn digest(self) -> DigestAlgorithm {
218        match self {
219            Self::PbeWithMd2AndDesCbc => DigestAlgorithm::Md2,
220            Self::PbeWithMd2AndRc2Cbc => DigestAlgorithm::Md2,
221            Self::PbeWithMd5AndDesCbc => DigestAlgorithm::Md5,
222            Self::PbeWithMd5AndRc2Cbc => DigestAlgorithm::Md5,
223            Self::PbeWithSha1AndDesCbc => DigestAlgorithm::Sha1,
224            Self::PbeWithSha1AndRc2Cbc => DigestAlgorithm::Sha1,
225        }
226    }
227
228    /// Get the [`ObjectIdentifier`] (a.k.a OID) for this algorithm.
229    pub fn oid(self) -> ObjectIdentifier {
230        match self {
231            Self::PbeWithMd2AndDesCbc => PBE_WITH_MD2_AND_DES_CBC_OID,
232            Self::PbeWithMd2AndRc2Cbc => PBE_WITH_MD2_AND_RC2_CBC_OID,
233            Self::PbeWithMd5AndDesCbc => PBE_WITH_MD5_AND_DES_CBC_OID,
234            Self::PbeWithMd5AndRc2Cbc => PBE_WITH_MD5_AND_RC2_CBC_OID,
235            Self::PbeWithSha1AndDesCbc => PBE_WITH_SHA1_AND_DES_CBC_OID,
236            Self::PbeWithSha1AndRc2Cbc => PBE_WITH_SHA1_AND_RC2_CBC_OID,
237        }
238    }
239}
240
241impl Encode for EncryptionScheme {
242    fn encoded_len(&self) -> der::Result<Length> {
243        self.oid().encoded_len()
244    }
245
246    fn encode(&self, writer: &mut impl Writer) -> der::Result<()> {
247        self.oid().encode(writer)
248    }
249}
250
251/// Digest algorithms supported by PBES1.
252#[derive(Copy, Clone, Debug, Eq, PartialEq)]
253pub enum DigestAlgorithm {
254    /// MD2
255    Md2,
256
257    /// MD5
258    Md5,
259
260    /// SHA-1
261    Sha1,
262}
263
264/// Symmetric encryption ciphers supported by PBES1.
265#[derive(Copy, Clone, Debug, Eq, PartialEq)]
266pub enum SymmetricCipher {
267    /// DES in CBC mode
268    DesCbc,
269
270    /// RC2 in CBC mode
271    Rc2Cbc,
272}