paseto_v1/core/
pie_wrap.rs

1use alloc::vec::Vec;
2
3use cipher::StreamCipher;
4use digest::Mac;
5use generic_array::GenericArray;
6use generic_array::sequence::Split;
7use generic_array::typenum::U48;
8use paseto_core::PasetoError;
9use paseto_core::paserk::PieWrapVersion;
10
11use super::{LocalKey, V1};
12
13impl LocalKey {
14    fn wrap_keys(&self, nonce: &[u8; 32]) -> (ctr::Ctr64BE<aes::Aes256>, hmac::Hmac<sha2::Sha384>) {
15        use cipher::KeyIvInit;
16        use digest::Mac;
17
18        let (ek, n2) = kdf(&self.0, 0x80, nonce).split();
19        let ak = kdf(&self.0, 0x81, nonce);
20
21        let cipher = ctr::Ctr64BE::<aes::Aes256>::new(&ek, &n2);
22        let mac = hmac::Hmac::new_from_slice(&ak[..32]).expect("key should be valid");
23        (cipher, mac)
24    }
25}
26
27impl PieWrapVersion for V1 {
28    fn pie_wrap_key(
29        header: &'static str,
30        wrapping_key: &super::LocalKey,
31        mut key_data: Vec<u8>,
32    ) -> Result<Vec<u8>, PasetoError> {
33        let mut nonce = [0u8; 32];
34        getrandom::fill(&mut nonce).map_err(|_| PasetoError::CryptoError)?;
35
36        let (mut cipher, mut mac) = wrapping_key.wrap_keys(&nonce);
37
38        cipher.apply_keystream(&mut key_data);
39        auth(&mut mac, header, &nonce, &key_data);
40
41        let mut out = Vec::with_capacity(80 + key_data.len());
42        out.extend_from_slice(&mac.finalize().into_bytes());
43        out.extend_from_slice(&nonce);
44        out.extend_from_slice(&key_data);
45        Ok(out)
46    }
47
48    fn pie_unwrap_key<'key>(
49        header: &'static str,
50        wrapping_key: &super::LocalKey,
51        key_data: &'key mut [u8],
52    ) -> Result<&'key [u8], PasetoError> {
53        let (tag, ciphertext) = key_data
54            .split_first_chunk_mut()
55            .ok_or(PasetoError::InvalidKey)?;
56        let (nonce, ciphertext) = ciphertext
57            .split_first_chunk_mut()
58            .ok_or(PasetoError::InvalidKey)?;
59        let tag: &[u8; 48] = tag;
60
61        let (mut cipher, mut mac) = wrapping_key.wrap_keys(nonce);
62        auth(&mut mac, header, nonce, ciphertext);
63        mac.verify(tag.into())
64            .map_err(|_| PasetoError::CryptoError)?;
65
66        cipher.apply_keystream(ciphertext);
67
68        Ok(ciphertext)
69    }
70}
71
72fn kdf(key: &[u8], sep: u8, nonce: &[u8]) -> GenericArray<u8, U48> {
73    let mut mac = hmac::Hmac::<sha2::Sha384>::new_from_slice(key).expect("key should be valid");
74    mac.update(&[sep]);
75    mac.update(nonce);
76    mac.finalize().into_bytes()
77}
78
79fn auth(
80    mac: &mut hmac::Hmac<sha2::Sha384>,
81    encoding: &'static str,
82    nonce: &[u8],
83    ciphertext: &[u8],
84) {
85    mac.update(b"k1");
86    mac.update(encoding.as_bytes());
87    mac.update(nonce);
88    mac.update(ciphertext);
89}