bc_components/encrypted_key/
pbkdf2_params.rs

1use anyhow::Result;
2use bc_crypto::{hash::pbkdf2_hmac_sha512, pbkdf2_hmac_sha256};
3use dcbor::prelude::*;
4
5use super::{HashType, KeyDerivation, KeyDerivationMethod, SALT_LEN};
6use crate::{EncryptedMessage, Nonce, Salt, SymmetricKey};
7
8/// Struct representing PBKDF2 parameters.
9///
10/// CDDL:
11/// ```cddl
12/// PBKDF2Params = [1, Salt, iterations: uint, HashType]
13/// ```
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct PBKDF2Params {
16    salt: Salt,
17    iterations: u32,
18    hash_type: HashType,
19}
20
21impl PBKDF2Params {
22    pub fn new() -> Self {
23        Self::new_opt(
24            Salt::new_with_len(SALT_LEN).unwrap(),
25            100_000,
26            HashType::SHA256,
27        )
28    }
29
30    pub fn new_opt(salt: Salt, iterations: u32, hash_type: HashType) -> Self {
31        Self { salt, iterations, hash_type }
32    }
33
34    pub fn salt(&self) -> &Salt { &self.salt }
35
36    pub fn iterations(&self) -> u32 { self.iterations }
37
38    pub fn hash_type(&self) -> HashType { self.hash_type }
39}
40
41impl Default for PBKDF2Params {
42    fn default() -> Self { Self::new() }
43}
44
45impl KeyDerivation for PBKDF2Params {
46    const INDEX: usize = KeyDerivationMethod::PBKDF2 as usize;
47
48    fn lock(
49        &mut self,
50        content_key: &SymmetricKey,
51        secret: impl AsRef<[u8]>,
52    ) -> Result<EncryptedMessage> {
53        let derived_key: SymmetricKey = (match self.hash_type {
54            HashType::SHA256 => {
55                pbkdf2_hmac_sha256(secret, &self.salt, self.iterations, 32)
56            }
57            HashType::SHA512 => {
58                pbkdf2_hmac_sha512(secret, &self.salt, self.iterations, 32)
59            }
60        })
61        .try_into()
62        .unwrap();
63        let encoded_method: Vec<u8> = self.to_cbor_data();
64        Ok(derived_key.encrypt(
65            content_key,
66            Some(encoded_method),
67            Option::<Nonce>::None,
68        ))
69    }
70
71    fn unlock(
72        &self,
73        encrypted_message: &EncryptedMessage,
74        secret: impl AsRef<[u8]>,
75    ) -> Result<SymmetricKey> {
76        let derived_key: SymmetricKey = (match self.hash_type {
77            HashType::SHA256 => {
78                pbkdf2_hmac_sha256(secret, &self.salt, self.iterations, 32)
79            }
80            HashType::SHA512 => {
81                pbkdf2_hmac_sha512(secret, &self.salt, self.iterations, 32)
82            }
83        })
84        .try_into()?;
85        derived_key.decrypt(encrypted_message)?.try_into()
86    }
87}
88
89impl std::fmt::Display for PBKDF2Params {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "PBKDF2({})", self.hash_type)
92    }
93}
94
95impl From<PBKDF2Params> for CBOR {
96    fn from(val: PBKDF2Params) -> Self {
97        vec![
98            CBOR::from(PBKDF2Params::INDEX),
99            val.salt.into(),
100            val.iterations.into(),
101            val.hash_type.into(),
102        ]
103        .into()
104    }
105}
106
107impl TryFrom<CBOR> for PBKDF2Params {
108    type Error = dcbor::Error;
109
110    fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
111        let a = cbor.try_into_array()?;
112        a.len()
113            .eq(&4)
114            .then_some(())
115            .ok_or_else(|| dcbor::Error::msg("Invalid PBKDF2Params"))?;
116        let mut iter = a.into_iter();
117        let _index: usize = iter
118            .next()
119            .ok_or_else(|| dcbor::Error::msg("Missing index"))?
120            .try_into()?;
121        let salt: Salt = iter
122            .next()
123            .ok_or_else(|| dcbor::Error::msg("Missing salt"))?
124            .try_into()?;
125        let iterations: u32 = iter
126            .next()
127            .ok_or_else(|| dcbor::Error::msg("Missing iterations"))?
128            .try_into()?;
129        let hash_type: HashType = iter
130            .next()
131            .ok_or_else(|| dcbor::Error::msg("Missing hash type"))?
132            .try_into()?;
133        Ok(Self { salt, iterations, hash_type })
134    }
135}