Skip to main content
This is unreleased documentation for the main (development) branch of crypto-glue.

pkcs5/
pbes2.rs

1//! Password-Based Encryption Scheme 2 as defined in [RFC 8018 Section 6.2].
2//!
3//! [RFC 8018 Section 6.2]: https://tools.ietf.org/html/rfc8018#section-6.2
4
5mod kdf;
6
7#[cfg(feature = "pbes2")]
8mod encryption;
9
10pub use self::kdf::{
11    HMAC_WITH_SHA1_OID, HMAC_WITH_SHA256_OID, Kdf, PBKDF2_OID, Pbkdf2Params, Pbkdf2Prf, SCRYPT_OID,
12    Salt, ScryptParams,
13};
14
15use crate::{AlgorithmIdentifierRef, Error, Result};
16use der::{
17    Decode, DecodeValue, Encode, EncodeValue, ErrorKind, Length, Reader, Sequence, Tag, Writer,
18    asn1::{AnyRef, ObjectIdentifier, OctetStringRef},
19};
20
21#[cfg(all(feature = "pbes2", feature = "rand_core"))]
22use rand_core::TryCryptoRng;
23
24#[cfg(all(feature = "alloc", feature = "pbes2"))]
25use alloc::vec::Vec;
26
27/// 128-bit Advanced Encryption Standard (AES) algorithm with Cipher-Block
28/// Chaining (CBC) mode of operation.
29pub const AES_128_CBC_OID: ObjectIdentifier =
30    ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.2");
31
32/// 192-bit Advanced Encryption Standard (AES) algorithm with Cipher-Block
33/// Chaining (CBC) mode of operation.
34pub const AES_192_CBC_OID: ObjectIdentifier =
35    ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.22");
36
37/// 256-bit Advanced Encryption Standard (AES) algorithm with Cipher-Block
38/// Chaining (CBC) mode of operation.
39pub const AES_256_CBC_OID: ObjectIdentifier =
40    ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.42");
41
42/// 128-bit Advanced Encryption Standard (AES) algorithm with Galois Counter Mode
43pub const AES_128_GCM_OID: ObjectIdentifier =
44    ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.6");
45
46/// 256-bit Advanced Encryption Standard (AES) algorithm with Galois Counter Mode
47pub const AES_256_GCM_OID: ObjectIdentifier =
48    ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.46");
49
50/// DES operating in CBC mode
51#[cfg(feature = "des-insecure")]
52pub const DES_CBC_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.7");
53
54/// Triple DES operating in CBC mode
55#[cfg(feature = "3des")]
56pub const DES_EDE3_CBC_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.3.7");
57
58/// Password-Based Encryption Scheme 2 (PBES2) OID.
59///
60/// <https://tools.ietf.org/html/rfc8018#section-6.2>
61pub const PBES2_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.13");
62
63/// AES cipher block size
64const AES_BLOCK_SIZE: usize = 16;
65
66/// Recommended GCM nonce size.
67const GCM_NONCE_SIZE: usize = 12;
68
69/// DES / Triple DES block size
70#[cfg(any(feature = "3des", feature = "des-insecure"))]
71const DES_BLOCK_SIZE: usize = 8;
72
73/// Password-Based Encryption Scheme 2 parameters as defined in [RFC 8018 Appendix A.4].
74///
75/// ```text
76///  PBES2-params ::= SEQUENCE {
77///       keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
78///       encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
79/// ```
80///
81/// These define a set of algorithms for password-based key derivation, as well as a salt value
82/// (typically randomly generated) to provide to the KDF algorithm, along with an encryption
83/// algorithm and its associated IV/nonce (typically randomly generated).
84///
85/// <div class="warning">
86/// <strong>Security Warning</strong>
87///
88/// This type should not be used to encrypt multiple plaintexts under the same IV/salt values.
89///
90/// Instead, new values should be randomly generated for every usage.
91/// </div>
92///
93/// [RFC 8018 Appendix A.4]: https://tools.ietf.org/html/rfc8018#appendix-A.4
94#[derive(Clone, Debug, Eq, PartialEq)]
95pub struct Parameters {
96    /// Key derivation function
97    pub kdf: Kdf,
98
99    /// Encryption scheme
100    pub encryption: EncryptionScheme,
101}
102
103impl Parameters {
104    /// Default length of an initialization vector.
105    #[cfg(all(feature = "pbes2", feature = "rand_core"))]
106    const DEFAULT_IV_LEN: usize = AES_BLOCK_SIZE;
107
108    /// Default length of a salt for password hashing.
109    #[cfg(all(feature = "pbes2", feature = "rand_core"))]
110    const DEFAULT_SALT_LEN: usize = 16;
111
112    /// Generate PBES2 parameters using recommended algorithm settings and parameters (salt/IV)
113    /// generated using the system's secure random number generator.
114    ///
115    /// # Panics
116    /// In the event the system's secure random generator experiences an internal failure.
117    #[cfg(all(feature = "pbes2", feature = "getrandom"))]
118    #[must_use]
119    #[track_caller]
120    pub fn generate() -> Self {
121        Self::generate_recommended(&mut getrandom::SysRng).expect("random generation failure")
122    }
123
124    /// Generate PBES2 parameters using the recommended algorithm settings and a randomly generated
125    /// salt and IV.
126    ///
127    /// This is currently an alias for [`Parameters::generate_scrypt`]. See that method
128    /// for more information.
129    ///
130    /// # Errors
131    /// Returns [`Error::Rng`] in the event the random number generator `R` fails.
132    #[cfg(all(feature = "pbes2", feature = "rand_core"))]
133    pub fn generate_recommended<R: TryCryptoRng>(rng: &mut R) -> Result<Self> {
134        Self::generate_scrypt(rng)
135    }
136
137    /// Generate PBES2 parameters using PBKDF2 as the password hashing
138    /// algorithm, using that algorithm's recommended algorithm settings
139    /// (OWASP recommended default: 600,000 rounds) along with a randomly
140    /// generated salt and IV.
141    ///
142    /// This will use AES-256-CBC as the encryption algorithm and SHA-256 as
143    /// the hash function for PBKDF2.
144    ///
145    /// # Errors
146    /// Returns [`Error::Rng`] in the event the random number generator `R` fails.
147    #[cfg(all(feature = "pbes2", feature = "rand_core"))]
148    pub fn generate_pbkdf2<R: TryCryptoRng>(rng: &mut R) -> Result<Self> {
149        let mut iv = [0u8; Self::DEFAULT_IV_LEN];
150        rng.try_fill_bytes(&mut iv).map_err(|_| Error::Rng)?;
151
152        let mut salt = [0u8; Self::DEFAULT_SALT_LEN];
153        rng.try_fill_bytes(&mut salt).map_err(|_| Error::Rng)?;
154
155        Self::generate_pbkdf2_sha256_aes256cbc(Pbkdf2Params::DEFAULT_SHA256_ITERATIONS, &salt, iv)
156    }
157
158    /// Initialize PBES2 parameters using PBKDF2-SHA256 as the password-based
159    /// key derivation function and AES-128-CBC as the symmetric cipher.
160    ///
161    /// # Errors
162    /// Propagates errors from [`Pbkdf2Params::hmac_sha256`].
163    pub fn generate_pbkdf2_sha256_aes128cbc(
164        pbkdf2_iterations: u32,
165        pbkdf2_salt: &[u8],
166        aes_iv: [u8; AES_BLOCK_SIZE],
167    ) -> Result<Self> {
168        let kdf = Pbkdf2Params::hmac_sha256(pbkdf2_iterations, pbkdf2_salt)?.into();
169        let encryption = EncryptionScheme::Aes128Cbc { iv: aes_iv };
170        Ok(Self { kdf, encryption })
171    }
172
173    /// Initialize PBES2 parameters using PBKDF2-SHA256 as the password-based
174    /// key derivation function and AES-256-CBC as the symmetric cipher.
175    ///
176    /// # Errors
177    /// Propagates errors from [`Pbkdf2Params::hmac_sha256`].
178    pub fn generate_pbkdf2_sha256_aes256cbc(
179        pbkdf2_iterations: u32,
180        pbkdf2_salt: &[u8],
181        aes_iv: [u8; AES_BLOCK_SIZE],
182    ) -> Result<Self> {
183        let kdf = Pbkdf2Params::hmac_sha256(pbkdf2_iterations, pbkdf2_salt)?.into();
184        let encryption = EncryptionScheme::Aes256Cbc { iv: aes_iv };
185        Ok(Self { kdf, encryption })
186    }
187
188    /// Generate PBES2 parameters using scrypt as the password hashing
189    /// algorithm, using that algorithm's recommended algorithm settings
190    /// along with a randomly generated salt and IV.
191    ///
192    /// This will use AES-256-CBC as the encryption algorithm.
193    ///
194    /// scrypt parameters are deliberately chosen to retain compatibility with
195    /// OpenSSL v3. See [RustCrypto/formats#1205] for more information.
196    /// Parameter choices are as follows:
197    ///
198    /// - `log_n`: 14
199    /// - `r`: 8
200    /// - `p`: 1
201    /// - salt length: 16
202    ///
203    /// [RustCrypto/formats#1205]: https://github.com/RustCrypto/formats/issues/1205
204    ///
205    /// # Errors
206    /// Returns [`Error::Rng`] in the event the random number generator `R` fails.
207    #[cfg(all(feature = "pbes2", feature = "rand_core"))]
208    #[cfg(feature = "rand_core")]
209    pub fn generate_scrypt<R: TryCryptoRng>(rng: &mut R) -> Result<Self> {
210        let mut iv = [0u8; Self::DEFAULT_IV_LEN];
211        rng.try_fill_bytes(&mut iv).map_err(|_| Error::Rng)?;
212
213        let mut salt = [0u8; Self::DEFAULT_SALT_LEN];
214        rng.try_fill_bytes(&mut salt).map_err(|_| Error::Rng)?;
215
216        let params = scrypt::Params::new(
217            ScryptParams::DEFAULT_LOG_N,
218            ScryptParams::DEFAULT_R,
219            ScryptParams::DEFAULT_P,
220        )
221        .map_err(|_| Error::AlgorithmParametersInvalid { oid: SCRYPT_OID })?;
222
223        Self::generate_scrypt_aes256cbc(params, &salt, iv)
224    }
225
226    /// Initialize PBES2 parameters using scrypt as the password-based
227    /// key derivation function and AES-128-CBC as the symmetric cipher.
228    ///
229    /// For more information on scrypt parameters, see documentation for the
230    /// [`scrypt::Params`] struct.
231    ///
232    /// # Errors
233    /// Propagates errors from [`ScryptParams::from_params_and_salt`].
234    // TODO(tarcieri): encapsulate `scrypt::Params`?
235    #[cfg(feature = "pbes2")]
236    pub fn generate_scrypt_aes128cbc(
237        params: scrypt::Params,
238        salt: &[u8],
239        aes_iv: [u8; AES_BLOCK_SIZE],
240    ) -> Result<Self> {
241        let kdf = ScryptParams::from_params_and_salt(params, salt)?.into();
242        let encryption = EncryptionScheme::Aes128Cbc { iv: aes_iv };
243        Ok(Self { kdf, encryption })
244    }
245
246    /// Initialize PBES2 parameters using scrypt as the password-based
247    /// key derivation function and AES-256-CBC as the symmetric cipher.
248    ///
249    /// For more information on scrypt parameters, see documentation for the
250    /// [`scrypt::Params`] struct.
251    ///
252    /// When in doubt, use `Default::default()` as the [`scrypt::Params`].
253    /// This also avoids the need to import the type from the `scrypt` crate.
254    ///
255    /// # Errors
256    /// Propagates errors from [`ScryptParams::from_params_and_salt`].
257    // TODO(tarcieri): encapsulate `scrypt::Params`?
258    #[cfg(feature = "pbes2")]
259    pub fn generate_scrypt_aes256cbc(
260        params: scrypt::Params,
261        salt: &[u8],
262        aes_iv: [u8; AES_BLOCK_SIZE],
263    ) -> Result<Self> {
264        let kdf = ScryptParams::from_params_and_salt(params, salt)?.into();
265        let encryption = EncryptionScheme::Aes256Cbc { iv: aes_iv };
266        Ok(Self { kdf, encryption })
267    }
268
269    /// Initialize PBES2 parameters using scrypt as the password-based
270    /// key derivation function and AES-128-GCM as the symmetric cipher.
271    ///
272    /// For more information on scrypt parameters, see documentation for the
273    /// [`scrypt::Params`] struct.
274    ///
275    /// # Errors
276    /// Propagates errors from [`ScryptParams::from_params_and_salt`].
277    // TODO(tarcieri): encapsulate `scrypt::Params`?
278    #[cfg(feature = "pbes2")]
279    pub fn scrypt_aes128gcm(
280        params: scrypt::Params,
281        salt: &[u8],
282        gcm_nonce: [u8; GCM_NONCE_SIZE],
283    ) -> Result<Self> {
284        let kdf = ScryptParams::from_params_and_salt(params, salt)?.into();
285        let encryption = EncryptionScheme::Aes128Gcm { nonce: gcm_nonce };
286        Ok(Self { kdf, encryption })
287    }
288
289    /// Initialize PBES2 parameters using scrypt as the password-based
290    /// key derivation function and AES-256-GCM as the symmetric cipher.
291    ///
292    /// For more information on scrypt parameters, see documentation for the
293    /// [`scrypt::Params`] struct.
294    ///
295    /// # Errors
296    /// Propagates errors from [`ScryptParams::from_params_and_salt`].
297    // TODO(tarcieri): encapsulate `scrypt::Params`?
298    #[cfg(feature = "pbes2")]
299    pub fn scrypt_aes256gcm(
300        params: scrypt::Params,
301        salt: &[u8],
302        gcm_nonce: [u8; GCM_NONCE_SIZE],
303    ) -> Result<Self> {
304        let kdf = ScryptParams::from_params_and_salt(params, salt)?.into();
305        let encryption = EncryptionScheme::Aes256Gcm { nonce: gcm_nonce };
306        Ok(Self { kdf, encryption })
307    }
308
309    /// Attempt to decrypt the given ciphertext, allocating and returning a
310    /// byte vector containing the plaintext.
311    ///
312    /// # Errors
313    /// Returns [`Error::UnsupportedAlgorithm`] if support for the requested algorithm has not been
314    /// enabled in this crate's features.
315    #[cfg(all(feature = "alloc", feature = "pbes2"))]
316    pub fn decrypt(&self, password: impl AsRef<[u8]>, ciphertext: &[u8]) -> Result<Vec<u8>> {
317        let mut buffer = ciphertext.to_vec();
318        let pt_len = self.decrypt_in_place(password, &mut buffer)?.len();
319        buffer.truncate(pt_len);
320        Ok(buffer)
321    }
322
323    /// Attempt to decrypt the given ciphertext in-place using a key derived
324    /// from the provided password and this scheme's parameters.
325    ///
326    /// Returns an error if the algorithm specified in this scheme's parameters
327    /// is unsupported, or if the ciphertext is malformed (e.g. not a multiple
328    /// of a block mode's padding).
329    ///
330    /// # Errors
331    /// Returns [`Error::UnsupportedAlgorithm`] if support for the requested algorithm has not been
332    /// enabled in this crate's features.
333    #[cfg(feature = "pbes2")]
334    pub fn decrypt_in_place<'a>(
335        &self,
336        password: impl AsRef<[u8]>,
337        buffer: &'a mut [u8],
338    ) -> Result<&'a [u8]> {
339        encryption::decrypt_in_place(self, password, buffer)
340    }
341
342    /// Encrypt the given plaintext, allocating and returning a vector
343    /// containing the ciphertext.
344    ///
345    /// # Errors
346    /// Returns [`Error::UnsupportedAlgorithm`] if support for the requested algorithm has not been
347    /// enabled in this crate's features.
348    #[cfg(all(feature = "alloc", feature = "pbes2"))]
349    pub fn encrypt(&self, password: impl AsRef<[u8]>, plaintext: &[u8]) -> Result<Vec<u8>> {
350        // TODO(tarcieri): support non-AES ciphers?
351        let mut buffer = Vec::with_capacity(plaintext.len() + AES_BLOCK_SIZE);
352        buffer.extend_from_slice(plaintext);
353        buffer.extend_from_slice(&[0u8; AES_BLOCK_SIZE]);
354
355        let ct_len = self
356            .encrypt_in_place(password, &mut buffer, plaintext.len())?
357            .len();
358
359        buffer.truncate(ct_len);
360        Ok(buffer)
361    }
362
363    /// Encrypt the given plaintext in-place using a key derived from the
364    /// provided password and this scheme's parameters, writing the ciphertext
365    /// into the same buffer.
366    ///
367    /// # Errors
368    /// Returns [`Error::UnsupportedAlgorithm`] if support for the requested algorithm has not been
369    /// enabled in this crate's features.
370    #[cfg(feature = "pbes2")]
371    pub fn encrypt_in_place<'a>(
372        &self,
373        password: impl AsRef<[u8]>,
374        buffer: &'a mut [u8],
375        pos: usize,
376    ) -> Result<&'a [u8]> {
377        encryption::encrypt_in_place(self, password, buffer, pos)
378    }
379}
380
381impl<'a> DecodeValue<'a> for Parameters {
382    type Error = der::Error;
383
384    fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
385        AnyRef::decode_value(reader, header)?.try_into()
386    }
387}
388
389impl EncodeValue for Parameters {
390    fn value_len(&self) -> der::Result<Length> {
391        self.kdf.encoded_len()? + self.encryption.encoded_len()?
392    }
393
394    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
395        self.kdf.encode(writer)?;
396        self.encryption.encode(writer)?;
397        Ok(())
398    }
399}
400
401impl Sequence<'_> for Parameters {}
402
403impl TryFrom<AnyRef<'_>> for Parameters {
404    type Error = der::Error;
405
406    fn try_from(any: AnyRef<'_>) -> der::Result<Self> {
407        any.sequence(|params| {
408            let kdf = AlgorithmIdentifierRef::decode(params)?;
409            let encryption = AlgorithmIdentifierRef::decode(params)?;
410
411            Ok(Self {
412                kdf: kdf.try_into()?,
413                encryption: encryption.try_into()?,
414            })
415        })
416    }
417}
418
419/// Symmetric encryption scheme used by PBES2.
420#[derive(Copy, Clone, Debug, Eq, PartialEq)]
421#[non_exhaustive]
422pub enum EncryptionScheme {
423    /// AES-128 in CBC mode
424    Aes128Cbc {
425        /// Initialization vector
426        iv: [u8; AES_BLOCK_SIZE],
427    },
428
429    /// AES-192 in CBC mode
430    Aes192Cbc {
431        /// Initialization vector
432        iv: [u8; AES_BLOCK_SIZE],
433    },
434
435    /// AES-256 in CBC mode
436    Aes256Cbc {
437        /// Initialization vector
438        iv: [u8; AES_BLOCK_SIZE],
439    },
440
441    /// AES-128 in CBC mode
442    Aes128Gcm {
443        /// GCM nonce
444        nonce: [u8; GCM_NONCE_SIZE],
445    },
446
447    /// AES-256 in GCM mode
448    Aes256Gcm {
449        /// GCM nonce
450        nonce: [u8; GCM_NONCE_SIZE],
451    },
452
453    /// 3-Key Triple DES in CBC mode
454    #[cfg(feature = "3des")]
455    DesEde3Cbc {
456        /// Initialisation vector
457        iv: [u8; DES_BLOCK_SIZE],
458    },
459
460    /// DES in CBC mode
461    #[cfg(feature = "des-insecure")]
462    DesCbc {
463        /// Initialisation vector
464        iv: [u8; DES_BLOCK_SIZE],
465    },
466}
467
468impl EncryptionScheme {
469    /// Get the size of a key used by this algorithm in bytes.
470    #[must_use]
471    pub fn key_size(&self) -> usize {
472        match self {
473            Self::Aes128Cbc { .. } => 16,
474            Self::Aes192Cbc { .. } => 24,
475            Self::Aes256Cbc { .. } => 32,
476            Self::Aes128Gcm { .. } => 16,
477            Self::Aes256Gcm { .. } => 32,
478            #[cfg(feature = "des-insecure")]
479            Self::DesCbc { .. } => 8,
480            #[cfg(feature = "3des")]
481            Self::DesEde3Cbc { .. } => 24,
482        }
483    }
484
485    /// Get the [`ObjectIdentifier`] (a.k.a OID) for this algorithm.
486    #[must_use]
487    pub fn oid(&self) -> ObjectIdentifier {
488        match self {
489            Self::Aes128Cbc { .. } => AES_128_CBC_OID,
490            Self::Aes192Cbc { .. } => AES_192_CBC_OID,
491            Self::Aes256Cbc { .. } => AES_256_CBC_OID,
492            Self::Aes128Gcm { .. } => AES_128_GCM_OID,
493            Self::Aes256Gcm { .. } => AES_256_GCM_OID,
494            #[cfg(feature = "des-insecure")]
495            Self::DesCbc { .. } => DES_CBC_OID,
496            #[cfg(feature = "3des")]
497            Self::DesEde3Cbc { .. } => DES_EDE3_CBC_OID,
498        }
499    }
500
501    /// Convenience function to turn the OID (see [`oid`](Self::oid))
502    /// of this [`EncryptionScheme`] into error case
503    /// [`Error::AlgorithmParametersInvalid`]
504    #[must_use]
505    pub fn to_alg_params_invalid(&self) -> Error {
506        Error::AlgorithmParametersInvalid { oid: self.oid() }
507    }
508}
509
510impl<'a> Decode<'a> for EncryptionScheme {
511    type Error = der::Error;
512
513    fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> {
514        AlgorithmIdentifierRef::decode(reader).and_then(TryInto::try_into)
515    }
516}
517
518impl TryFrom<AlgorithmIdentifierRef<'_>> for EncryptionScheme {
519    type Error = der::Error;
520
521    fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result<Self> {
522        // TODO(tarcieri): support for non-AES algorithms?
523        let iv = match alg.parameters {
524            Some(params) => params.decode_as::<&OctetStringRef>()?.as_bytes(),
525            None => return Err(Tag::OctetString.value_error().into()),
526        };
527
528        match alg.oid {
529            AES_128_CBC_OID => Ok(Self::Aes128Cbc {
530                iv: iv.try_into().map_err(|_| Tag::OctetString.value_error())?,
531            }),
532            AES_192_CBC_OID => Ok(Self::Aes192Cbc {
533                iv: iv.try_into().map_err(|_| Tag::OctetString.value_error())?,
534            }),
535            AES_256_CBC_OID => Ok(Self::Aes256Cbc {
536                iv: iv.try_into().map_err(|_| Tag::OctetString.value_error())?,
537            }),
538            AES_128_GCM_OID => Ok(Self::Aes128Gcm {
539                nonce: iv.try_into().map_err(|_| Tag::OctetString.value_error())?,
540            }),
541            AES_256_GCM_OID => Ok(Self::Aes256Gcm {
542                nonce: iv.try_into().map_err(|_| Tag::OctetString.value_error())?,
543            }),
544            #[cfg(feature = "des-insecure")]
545            DES_CBC_OID => Ok(Self::DesCbc {
546                iv: iv[0..DES_BLOCK_SIZE]
547                    .try_into()
548                    .map_err(|_| Tag::OctetString.value_error())?,
549            }),
550            #[cfg(feature = "3des")]
551            DES_EDE3_CBC_OID => Ok(Self::DesEde3Cbc {
552                iv: iv[0..DES_BLOCK_SIZE]
553                    .try_into()
554                    .map_err(|_| Tag::OctetString.value_error())?,
555            }),
556            oid => Err(ErrorKind::OidUnknown { oid }.into()),
557        }
558    }
559}
560
561impl<'a> TryFrom<&'a EncryptionScheme> for AlgorithmIdentifierRef<'a> {
562    type Error = der::Error;
563
564    fn try_from(scheme: &'a EncryptionScheme) -> der::Result<Self> {
565        let parameters = OctetStringRef::new(match scheme {
566            EncryptionScheme::Aes128Cbc { iv } => iv.as_slice(),
567            EncryptionScheme::Aes192Cbc { iv } => iv.as_slice(),
568            EncryptionScheme::Aes256Cbc { iv } => iv.as_slice(),
569            EncryptionScheme::Aes128Gcm { nonce } => nonce.as_slice(),
570            EncryptionScheme::Aes256Gcm { nonce } => nonce.as_slice(),
571            #[cfg(feature = "des-insecure")]
572            EncryptionScheme::DesCbc { iv } => iv.as_slice(),
573            #[cfg(feature = "3des")]
574            EncryptionScheme::DesEde3Cbc { iv } => iv.as_slice(),
575        })?;
576
577        Ok(AlgorithmIdentifierRef {
578            oid: scheme.oid(),
579            parameters: Some(parameters.into()),
580        })
581    }
582}
583
584impl Encode for EncryptionScheme {
585    fn encoded_len(&self) -> der::Result<Length> {
586        AlgorithmIdentifierRef::try_from(self)?.encoded_len()
587    }
588
589    fn encode(&self, writer: &mut impl Writer) -> der::Result<()> {
590        AlgorithmIdentifierRef::try_from(self)?.encode(writer)
591    }
592}