1mod 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
27pub const AES_128_CBC_OID: ObjectIdentifier =
30 ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.2");
31
32pub const AES_192_CBC_OID: ObjectIdentifier =
35 ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.22");
36
37pub const AES_256_CBC_OID: ObjectIdentifier =
40 ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.42");
41
42pub const AES_128_GCM_OID: ObjectIdentifier =
44 ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.6");
45
46pub const AES_256_GCM_OID: ObjectIdentifier =
48 ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.46");
49
50#[cfg(feature = "des-insecure")]
52pub const DES_CBC_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.7");
53
54#[cfg(feature = "3des")]
56pub const DES_EDE3_CBC_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.3.7");
57
58pub const PBES2_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.13");
62
63const AES_BLOCK_SIZE: usize = 16;
65
66const GCM_NONCE_SIZE: usize = 12;
68
69#[cfg(any(feature = "3des", feature = "des-insecure"))]
71const DES_BLOCK_SIZE: usize = 8;
72
73#[derive(Clone, Debug, Eq, PartialEq)]
95pub struct Parameters {
96 pub kdf: Kdf,
98
99 pub encryption: EncryptionScheme,
101}
102
103impl Parameters {
104 #[cfg(all(feature = "pbes2", feature = "rand_core"))]
106 const DEFAULT_IV_LEN: usize = AES_BLOCK_SIZE;
107
108 #[cfg(all(feature = "pbes2", feature = "rand_core"))]
110 const DEFAULT_SALT_LEN: usize = 16;
111
112 #[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 #[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 #[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 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 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[cfg(all(feature = "alloc", feature = "pbes2"))]
349 pub fn encrypt(&self, password: impl AsRef<[u8]>, plaintext: &[u8]) -> Result<Vec<u8>> {
350 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 #[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#[derive(Copy, Clone, Debug, Eq, PartialEq)]
421#[non_exhaustive]
422pub enum EncryptionScheme {
423 Aes128Cbc {
425 iv: [u8; AES_BLOCK_SIZE],
427 },
428
429 Aes192Cbc {
431 iv: [u8; AES_BLOCK_SIZE],
433 },
434
435 Aes256Cbc {
437 iv: [u8; AES_BLOCK_SIZE],
439 },
440
441 Aes128Gcm {
443 nonce: [u8; GCM_NONCE_SIZE],
445 },
446
447 Aes256Gcm {
449 nonce: [u8; GCM_NONCE_SIZE],
451 },
452
453 #[cfg(feature = "3des")]
455 DesEde3Cbc {
456 iv: [u8; DES_BLOCK_SIZE],
458 },
459
460 #[cfg(feature = "des-insecure")]
462 DesCbc {
463 iv: [u8; DES_BLOCK_SIZE],
465 },
466}
467
468impl EncryptionScheme {
469 #[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 #[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 #[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 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}