1mod salt;
4
5pub use self::salt::Salt;
6
7use crate::{AlgorithmIdentifierRef, Error, Result};
8use der::{
9 Decode, DecodeValue, Encode, EncodeValue, ErrorKind, Length, Reader, Sequence, Tag, Tagged,
10 Writer,
11 asn1::{AnyRef, ObjectIdentifier},
12};
13
14pub const PBKDF2_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.12");
16
17pub const HMAC_WITH_SHA1_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.2.7");
19
20pub const HMAC_WITH_SHA224_OID: ObjectIdentifier =
22 ObjectIdentifier::new_unwrap("1.2.840.113549.2.8");
23
24pub const HMAC_WITH_SHA256_OID: ObjectIdentifier =
26 ObjectIdentifier::new_unwrap("1.2.840.113549.2.9");
27
28pub const HMAC_WITH_SHA384_OID: ObjectIdentifier =
30 ObjectIdentifier::new_unwrap("1.2.840.113549.2.10");
31
32pub const HMAC_WITH_SHA512_OID: ObjectIdentifier =
34 ObjectIdentifier::new_unwrap("1.2.840.113549.2.11");
35
36pub const SCRYPT_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11591.4.11");
40
41type ScryptCost = u64;
43
44#[derive(Clone, Debug, Eq, PartialEq)]
46#[non_exhaustive]
47pub enum Kdf {
48 Pbkdf2(Pbkdf2Params),
50
51 Scrypt(ScryptParams),
53}
54
55impl Kdf {
56 #[must_use]
59 pub fn key_length(&self) -> Option<u16> {
60 match self {
61 Self::Pbkdf2(params) => params.key_length,
62 Self::Scrypt(params) => params.key_length,
63 }
64 }
65
66 #[must_use]
68 pub fn oid(&self) -> ObjectIdentifier {
69 match self {
70 Self::Pbkdf2(_) => PBKDF2_OID,
71 Self::Scrypt(_) => SCRYPT_OID,
72 }
73 }
74
75 #[must_use]
77 pub fn pbkdf2(&self) -> Option<&Pbkdf2Params> {
78 match self {
79 Self::Pbkdf2(params) => Some(params),
80 _ => None,
81 }
82 }
83
84 #[must_use]
86 pub fn scrypt(&self) -> Option<&ScryptParams> {
87 match self {
88 Self::Scrypt(params) => Some(params),
89 _ => None,
90 }
91 }
92
93 #[must_use]
95 pub fn is_pbkdf2(&self) -> bool {
96 self.pbkdf2().is_some()
97 }
98
99 #[must_use]
101 pub fn is_scrypt(&self) -> bool {
102 self.scrypt().is_some()
103 }
104
105 #[must_use]
108 pub fn to_alg_params_invalid(&self) -> Error {
109 Error::AlgorithmParametersInvalid { oid: self.oid() }
110 }
111}
112
113impl<'a> DecodeValue<'a> for Kdf {
114 type Error = der::Error;
115
116 fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
117 AlgorithmIdentifierRef::decode_value(reader, header)?.try_into()
118 }
119}
120
121impl EncodeValue for Kdf {
122 fn value_len(&self) -> der::Result<Length> {
123 self.oid().encoded_len()?
124 + match self {
125 Self::Pbkdf2(params) => params.encoded_len()?,
126 Self::Scrypt(params) => params.encoded_len()?,
127 }
128 }
129
130 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
131 self.oid().encode(writer)?;
132
133 match self {
134 Self::Pbkdf2(params) => params.encode(writer)?,
135 Self::Scrypt(params) => params.encode(writer)?,
136 }
137
138 Ok(())
139 }
140}
141
142impl Sequence<'_> for Kdf {}
143
144impl From<Pbkdf2Params> for Kdf {
145 fn from(params: Pbkdf2Params) -> Self {
146 Kdf::Pbkdf2(params)
147 }
148}
149
150impl From<ScryptParams> for Kdf {
151 fn from(params: ScryptParams) -> Self {
152 Kdf::Scrypt(params)
153 }
154}
155
156impl TryFrom<AlgorithmIdentifierRef<'_>> for Kdf {
157 type Error = der::Error;
158
159 fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result<Self> {
160 if let Some(params) = alg.parameters {
161 match alg.oid {
162 PBKDF2_OID => params.try_into().map(Self::Pbkdf2),
163 SCRYPT_OID => params.try_into().map(Self::Scrypt),
164 oid => Err(ErrorKind::OidUnknown { oid }.into()),
165 }
166 } else {
167 Err(Tag::OctetString.value_error().into())
168 }
169 }
170}
171
172#[derive(Clone, Copy, Debug, Eq, PartialEq)]
189pub struct Pbkdf2Params {
190 pub salt: Salt,
193
194 pub iteration_count: u32,
196
197 pub key_length: Option<u16>,
199
200 pub prf: Pbkdf2Prf,
202}
203
204impl Pbkdf2Params {
205 pub const MAX_ITERATION_COUNT: u32 = 100_000_000;
215
216 #[cfg(all(feature = "pbes2", feature = "rand_core"))]
218 pub(super) const DEFAULT_SHA256_ITERATIONS: u32 = 600_000;
219
220 const INVALID_ERR: Error = Error::AlgorithmParametersInvalid { oid: PBKDF2_OID };
221
222 pub fn hmac_sha256(iteration_count: u32, salt: &[u8]) -> Result<Self> {
228 if iteration_count > Self::MAX_ITERATION_COUNT {
229 return Err(Self::INVALID_ERR);
230 }
231
232 Ok(Self {
233 salt: salt.try_into().map_err(|_| Self::INVALID_ERR)?,
234 iteration_count,
235 key_length: None,
236 prf: Pbkdf2Prf::HmacWithSha256,
237 })
238 }
239}
240
241impl<'a> DecodeValue<'a> for Pbkdf2Params {
242 type Error = der::Error;
243 fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
244 AnyRef::decode_value(reader, header)?.try_into()
245 }
246}
247
248impl EncodeValue for Pbkdf2Params {
249 fn value_len(&self) -> der::Result<Length> {
250 let len = self.salt.encoded_len()?
251 + self.iteration_count.encoded_len()?
252 + self.key_length.encoded_len()?;
253
254 if self.prf == Pbkdf2Prf::default() {
255 len
256 } else {
257 len + self.prf.encoded_len()?
258 }
259 }
260
261 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
262 self.salt.encode(writer)?;
263 self.iteration_count.encode(writer)?;
264 self.key_length.encode(writer)?;
265
266 if self.prf == Pbkdf2Prf::default() {
267 Ok(())
268 } else {
269 self.prf.encode(writer)
270 }
271 }
272}
273
274impl Sequence<'_> for Pbkdf2Params {}
275
276impl TryFrom<AnyRef<'_>> for Pbkdf2Params {
277 type Error = der::Error;
278
279 fn try_from(any: AnyRef<'_>) -> der::Result<Self> {
280 any.sequence(|reader| {
281 Ok(Self {
283 salt: reader.decode()?,
284 iteration_count: reader.decode()?,
285 key_length: reader.decode()?,
286 prf: Option::<AlgorithmIdentifierRef<'_>>::decode(reader)?
287 .map(TryInto::try_into)
288 .transpose()?
289 .unwrap_or_default(),
290 })
291 })
292 }
293}
294
295#[derive(Copy, Clone, Debug, Eq, PartialEq)]
297#[non_exhaustive]
298pub enum Pbkdf2Prf {
299 HmacWithSha1,
301
302 HmacWithSha224,
304
305 HmacWithSha256,
307
308 HmacWithSha384,
310
311 HmacWithSha512,
313}
314
315impl Pbkdf2Prf {
316 #[must_use]
318 pub fn oid(self) -> ObjectIdentifier {
319 match self {
320 Self::HmacWithSha1 => HMAC_WITH_SHA1_OID,
321 Self::HmacWithSha224 => HMAC_WITH_SHA224_OID,
322 Self::HmacWithSha256 => HMAC_WITH_SHA256_OID,
323 Self::HmacWithSha384 => HMAC_WITH_SHA384_OID,
324 Self::HmacWithSha512 => HMAC_WITH_SHA512_OID,
325 }
326 }
327}
328
329impl Default for Pbkdf2Prf {
338 fn default() -> Self {
339 Self::HmacWithSha1
340 }
341}
342
343impl TryFrom<AlgorithmIdentifierRef<'_>> for Pbkdf2Prf {
344 type Error = der::Error;
345
346 fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result<Self> {
347 if let Some(params) = alg.parameters {
348 if !params.is_null() {
350 return Err(params.tag().value_error().into());
351 }
352 }
353
354 match alg.oid {
355 HMAC_WITH_SHA1_OID => Ok(Self::HmacWithSha1),
356 HMAC_WITH_SHA224_OID => Ok(Self::HmacWithSha224),
357 HMAC_WITH_SHA256_OID => Ok(Self::HmacWithSha256),
358 HMAC_WITH_SHA384_OID => Ok(Self::HmacWithSha384),
359 HMAC_WITH_SHA512_OID => Ok(Self::HmacWithSha512),
360 oid => Err(ErrorKind::OidUnknown { oid }.into()),
361 }
362 }
363}
364
365impl From<Pbkdf2Prf> for AlgorithmIdentifierRef<'_> {
366 fn from(prf: Pbkdf2Prf) -> Self {
367 let parameters = der::asn1::Null;
369
370 AlgorithmIdentifierRef {
371 oid: prf.oid(),
372 parameters: Some(parameters.into()),
373 }
374 }
375}
376
377impl Encode for Pbkdf2Prf {
378 fn encoded_len(&self) -> der::Result<Length> {
379 AlgorithmIdentifierRef::from(*self).encoded_len()
380 }
381
382 fn encode(&self, writer: &mut impl Writer) -> der::Result<()> {
383 AlgorithmIdentifierRef::from(*self).encode(writer)
384 }
385}
386
387#[derive(Clone, Copy, Debug, Eq, PartialEq)]
401pub struct ScryptParams {
402 pub salt: Salt,
404
405 pub cost_parameter: ScryptCost,
407
408 pub block_size: u16,
410
411 pub parallelization: u16,
413
414 pub key_length: Option<u16>,
416}
417
418impl ScryptParams {
419 #[cfg(all(feature = "pbes2", feature = "rand_core"))]
422 pub(super) const DEFAULT_LOG_N: u8 = 14;
423 #[cfg(all(feature = "pbes2", feature = "rand_core"))]
424 pub(super) const DEFAULT_R: u32 = 8;
425 #[cfg(all(feature = "pbes2", feature = "rand_core"))]
426 pub(super) const DEFAULT_P: u32 = 1;
427
428 #[cfg(feature = "pbes2")]
429 const INVALID_ERR: Error = Error::AlgorithmParametersInvalid { oid: SCRYPT_OID };
430
431 #[cfg(feature = "pbes2")]
438 pub fn from_params_and_salt(params: scrypt::Params, salt: &[u8]) -> Result<Self> {
439 Ok(Self {
440 salt: salt.try_into().map_err(|_| Self::INVALID_ERR)?,
441 cost_parameter: 1 << params.log_n(),
442 block_size: params.r().try_into().map_err(|_| Self::INVALID_ERR)?,
443 parallelization: params.p().try_into().map_err(|_| Self::INVALID_ERR)?,
444 key_length: None,
445 })
446 }
447}
448
449impl<'a> DecodeValue<'a> for ScryptParams {
450 type Error = der::Error;
451
452 fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
453 AnyRef::decode_value(reader, header)?.try_into()
454 }
455}
456
457impl EncodeValue for ScryptParams {
458 fn value_len(&self) -> der::Result<Length> {
459 self.salt.encoded_len()?
460 + self.cost_parameter.encoded_len()?
461 + self.block_size.encoded_len()?
462 + self.parallelization.encoded_len()?
463 + self.key_length.encoded_len()?
464 }
465
466 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
467 self.salt.encode(writer)?;
468 self.cost_parameter.encode(writer)?;
469 self.block_size.encode(writer)?;
470 self.parallelization.encode(writer)?;
471 self.key_length.encode(writer)?;
472 Ok(())
473 }
474}
475
476impl Sequence<'_> for ScryptParams {}
477
478impl TryFrom<AnyRef<'_>> for ScryptParams {
479 type Error = der::Error;
480
481 fn try_from(any: AnyRef<'_>) -> der::Result<Self> {
482 any.sequence(|reader| {
483 Ok(Self {
484 salt: reader.decode()?,
485 cost_parameter: reader.decode()?,
486 block_size: reader.decode()?,
487 parallelization: reader.decode()?,
488 key_length: reader.decode()?,
489 })
490 })
491 }
492}
493
494#[cfg(feature = "pbes2")]
495impl TryFrom<ScryptParams> for scrypt::Params {
496 type Error = Error;
497
498 fn try_from(params: ScryptParams) -> Result<scrypt::Params> {
499 scrypt::Params::try_from(¶ms)
500 }
501}
502
503#[cfg(feature = "pbes2")]
504impl TryFrom<&ScryptParams> for scrypt::Params {
505 type Error = Error;
506
507 #[allow(clippy::unwrap_in_result, reason = "invariant should hold")]
508 fn try_from(params: &ScryptParams) -> Result<scrypt::Params> {
509 let n = params.cost_parameter;
511 let log_n =
512 u8::try_from(ScryptCost::BITS - n.leading_zeros() - 1).expect("should always fit");
513
514 if 1 << log_n != n {
515 return Err(ScryptParams::INVALID_ERR);
516 }
517
518 scrypt::Params::new(
519 log_n,
520 params.block_size.into(),
521 params.parallelization.into(),
522 )
523 .map_err(|_| ScryptParams::INVALID_ERR)
524 }
525}