1use alloc::boxed::Box;
2use alloc::vec::Vec;
3
4use cipher::StreamCipher;
5use generic_array::sequence::Split;
6use hmac::Mac;
7use paseto_core::PasetoError;
8use paseto_core::key::HasKey;
9use paseto_core::paserk::{PkeSealingVersion, PkeUnsealingVersion};
10use paseto_core::version::{PkePublic, PkeSecret, Public, Secret};
11use sha2::Digest;
12
13use super::{LocalKey, PublicKey, SecretKey, V3};
14
15impl HasKey<PkePublic> for V3 {
16 type Key = PublicKey;
17 fn decode(bytes: &[u8]) -> Result<PublicKey, PasetoError> {
18 <V3 as HasKey<Public>>::decode(bytes)
19 }
20 fn encode(key: &PublicKey) -> Box<[u8]> {
21 <V3 as HasKey<Public>>::encode(key)
22 }
23}
24
25impl HasKey<PkeSecret> for V3 {
26 type Key = SecretKey;
27 fn decode(bytes: &[u8]) -> Result<SecretKey, PasetoError> {
28 <V3 as HasKey<Secret>>::decode(bytes)
29 }
30 fn encode(key: &SecretKey) -> Box<[u8]> {
31 <V3 as HasKey<Secret>>::encode(key)
32 }
33}
34
35impl PkeSealingVersion for V3 {
36 fn seal_key(sealing_key: &PublicKey, key: LocalKey) -> Result<Box<[u8]>, PasetoError> {
37 use cipher::KeyIvInit;
38 use p384::EncodedPoint;
39 use p384::ecdh::diffie_hellman;
40 use p384::elliptic_curve::sec1::ToEncodedPoint;
41
42 let pk = sealing_key.0.to_encoded_point(true);
43
44 let esk = p384::SecretKey::from(SecretKey::random()?.0);
45 let epk: EncodedPoint = esk.public_key().to_encoded_point(true);
46
47 let xk = diffie_hellman(esk.to_nonzero_scalar(), sealing_key.0.as_affine());
48
49 let mut ek = sha2::Sha384::new();
50 ek.update(b"\x01k3.seal.");
51 ek.update(xk.raw_secret_bytes());
52 ek.update(epk);
53 ek.update(pk.as_bytes());
54 let (ek, n) = ek.finalize().split();
55
56 let mut ak = sha2::Sha384::new();
57 ak.update(b"\x02k3.seal.");
58 ak.update(xk.raw_secret_bytes());
59 ak.update(epk);
60 ak.update(pk.as_bytes());
61 let ak = ak.finalize();
62
63 let mut edk = key.0;
64 ctr::Ctr64BE::<aes::Aes256>::new(&ek, &n).apply_keystream(&mut edk);
65
66 let mut tag = hmac::Hmac::<sha2::Sha384>::new_from_slice(&ak).unwrap();
67 tag.update(b"k3.seal.");
68 tag.update(epk.as_bytes());
69 tag.update(&edk);
70 let tag = tag.finalize().into_bytes();
71
72 let mut output = Vec::with_capacity(48 + 49 + 32);
73 output.extend_from_slice(&tag);
74 output.extend_from_slice(epk.as_bytes());
75 output.extend_from_slice(&edk);
76
77 Ok(output.into_boxed_slice())
78 }
79}
80
81impl PkeUnsealingVersion for V3 {
82 fn unseal_key(
83 unsealing_key: &SecretKey,
84 mut key_data: Box<[u8]>,
85 ) -> Result<LocalKey, PasetoError> {
86 use cipher::KeyIvInit;
87 use p384::ecdh::diffie_hellman;
88 use p384::{AffinePoint, EncodedPoint};
89
90 let (tag, key_data) = key_data
91 .split_first_chunk_mut::<48>()
92 .ok_or(PasetoError::InvalidKey)?;
93 let (epk, edk) = key_data
94 .split_first_chunk_mut::<49>()
95 .ok_or(PasetoError::InvalidKey)?;
96
97 let epk: &[u8; 49] = &*epk;
98 let edk: &mut [u8; 32] = edk.try_into().map_err(|_| PasetoError::InvalidKey)?;
99
100 let sk = p384::SecretKey::from(&unsealing_key.0);
101
102 let pk: EncodedPoint = sk.public_key().into();
103 let pk = pk.compress();
104
105 let epk_point = EncodedPoint::from_bytes(epk).map_err(|_| PasetoError::CryptoError)?;
106 let epk_point = AffinePoint::try_from(&epk_point).map_err(|_| PasetoError::CryptoError)?;
107
108 let xk = diffie_hellman(sk.to_nonzero_scalar(), epk_point);
109
110 let mut ak = sha2::Sha384::new();
111 ak.update(b"\x02k3.seal.");
112 ak.update(xk.raw_secret_bytes());
113 ak.update(epk);
114 ak.update(pk.as_bytes());
115 let ak = ak.finalize();
116
117 let mut t2 = hmac::Hmac::<sha2::Sha384>::new_from_slice(&ak).unwrap();
118 t2.update(b"k3.seal.");
119 t2.update(epk);
120 t2.update(edk);
121
122 t2.verify((&*tag).into())
124 .map_err(|_| PasetoError::CryptoError)?;
125
126 let mut ek = sha2::Sha384::new();
127 ek.update(b"\x01k3.seal.");
128 ek.update(xk.raw_secret_bytes());
129 ek.update(epk);
130 ek.update(pk.as_bytes());
131 let (ek, n) = ek.finalize().split();
132
133 ctr::Ctr64BE::<aes::Aes256>::new(&ek, &n).apply_keystream(edk);
134
135 Ok(LocalKey(*edk))
136 }
137}