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