1use alloc::boxed::Box;
2#[cfg(feature = "signing")]
3use alloc::vec::Vec;
4
5use ed25519_dalek::Signature;
6use paseto_core::PasetoError;
7use paseto_core::key::{HasKey, KeyType};
8use paseto_core::pae::{WriteBytes, pre_auth_encode};
9use paseto_core::version::Public;
10#[cfg(feature = "signing")]
11use paseto_core::version::Secret;
12
13#[cfg(feature = "signing")]
14use super::{PreAuthEncodeDigest, SecretKey};
15use super::{PublicKey, V4};
16
17#[cfg(feature = "verifying")]
18impl HasKey<Public> for V4 {
19 type Key = PublicKey;
20
21 fn decode(bytes: &[u8]) -> Result<PublicKey, PasetoError> {
22 let key = bytes.try_into().map_err(|_| PasetoError::InvalidKey)?;
23 ed25519_dalek::VerifyingKey::from_bytes(&key)
24 .map(PublicKey)
25 .map_err(|_| PasetoError::InvalidKey)
26 }
27 fn encode(key: &PublicKey) -> Box<[u8]> {
28 key.0.as_bytes().to_vec().into_boxed_slice()
29 }
30}
31
32#[cfg(feature = "signing")]
33impl HasKey<Secret> for V4 {
34 type Key = SecretKey;
35
36 fn decode(bytes: &[u8]) -> Result<SecretKey, PasetoError> {
37 let (secret_key, verifying_key) = bytes
38 .split_first_chunk::<32>()
39 .ok_or(PasetoError::InvalidKey)?;
40
41 let esk = ed25519_dalek::hazmat::ExpandedSecretKey::from(secret_key);
42
43 let verifying_key = <V4 as HasKey<Public>>::decode(verifying_key)?;
44 let pubkey = ed25519_dalek::VerifyingKey::from(&esk);
45
46 if pubkey != verifying_key.0 {
47 return Err(PasetoError::InvalidKey);
48 }
49
50 Ok(SecretKey(*secret_key, esk))
51 }
52 fn encode(key: &SecretKey) -> Box<[u8]> {
53 let pubkey = ed25519_dalek::VerifyingKey::from(&key.1);
54 let mut bytes = Vec::with_capacity(64);
55 bytes.extend_from_slice(&key.0);
56 bytes.extend_from_slice(pubkey.as_bytes());
57 bytes.into_boxed_slice()
58 }
59}
60
61#[cfg(feature = "signing")]
62impl Clone for super::SecretKey {
63 fn clone(&self) -> Self {
64 let esk = ed25519_dalek::hazmat::ExpandedSecretKey {
65 scalar: self.1.scalar,
66 hash_prefix: self.1.hash_prefix,
67 };
68 Self(self.0, esk)
69 }
70}
71
72#[cfg(feature = "signing")]
73impl paseto_core::version::SealingVersion<Public> for V4 {
74 fn unsealing_key(key: &SecretKey) -> PublicKey {
75 PublicKey((&key.1).into())
76 }
77
78 fn random() -> Result<SecretKey, PasetoError> {
79 let mut secret_key = [0; 32];
80 getrandom::fill(&mut secret_key).map_err(|_| PasetoError::CryptoError)?;
81
82 let esk = ed25519_dalek::hazmat::ExpandedSecretKey::from(&secret_key);
83 Ok(SecretKey(secret_key, esk))
84 }
85
86 fn nonce() -> Result<Vec<u8>, PasetoError> {
87 Ok(Vec::with_capacity(32))
88 }
89
90 fn dangerous_seal_with_nonce(
91 key: &SecretKey,
92 encoding: &'static str,
93 mut payload: Vec<u8>,
94 footer: &[u8],
95 aad: &[u8],
96 ) -> Result<Vec<u8>, PasetoError> {
97 let signature = preauth_secret(&key.1, encoding, &payload, footer, aad);
98 payload.extend_from_slice(&signature.to_bytes());
99 Ok(payload)
100 }
101}
102
103#[cfg(feature = "verifying")]
104impl paseto_core::version::UnsealingVersion<Public> for V4 {
105 fn unseal<'a>(
106 key: &PublicKey,
107 encoding: &'static str,
108 payload: &'a mut [u8],
109 footer: &[u8],
110 aad: &[u8],
111 ) -> Result<&'a [u8], PasetoError> {
112 let len = payload.len();
113 if len < 64 {
114 return Err(PasetoError::InvalidToken);
115 }
116
117 let (cleartext, tag) = payload.split_at(len - 64);
118 let signature = Signature::from_bytes(tag.try_into().unwrap());
119 let verifier = key
120 .0
121 .verify_stream(&signature)
122 .map_err(|_| PasetoError::CryptoError)?;
123
124 preauth_public(verifier, encoding, cleartext, footer, aad)
125 .finalize_and_verify()
126 .map_err(|_| PasetoError::CryptoError)?;
127
128 Ok(cleartext)
129 }
130}
131
132fn preauth_public(
133 verifier: ed25519_dalek::StreamVerifier,
134 encoding: &'static str,
135 cleartext: &[u8],
136 footer: &[u8],
137 aad: &[u8],
138) -> ed25519_dalek::StreamVerifier {
139 #[repr(transparent)]
140 pub struct StreamVerifier(pub ed25519_dalek::StreamVerifier);
141
142 impl WriteBytes for StreamVerifier {
143 fn write(&mut self, slice: &[u8]) {
144 self.0.update(slice);
145 }
146 }
147
148 let mut sv = StreamVerifier(verifier);
149 pre_auth_encode(
150 [
151 &[
152 "v4".as_bytes(),
153 encoding.as_bytes(),
154 Public::HEADER.as_bytes(),
155 ],
156 &[cleartext],
157 &[footer],
158 &[aad],
159 ],
160 &mut sv,
161 );
162
163 sv.0
164}
165
166#[cfg(feature = "signing")]
167fn preauth_secret(
168 esk: &ed25519_dalek::hazmat::ExpandedSecretKey,
169 encoding: &'static str,
170 cleartext: &[u8],
171 footer: &[u8],
172 aad: &[u8],
173) -> Signature {
174 let vk = ed25519_dalek::VerifyingKey::from(esk);
175
176 ed25519_dalek::hazmat::raw_sign_byupdate::<sha2::Sha512, _>(
177 esk,
178 |ctx| {
179 pre_auth_encode(
180 [
181 &[
182 "v4".as_bytes(),
183 encoding.as_bytes(),
184 Public::HEADER.as_bytes(),
185 ],
186 &[cleartext],
187 &[footer],
188 &[aad],
189 ],
190 PreAuthEncodeDigest(ctx),
191 );
192 Ok(())
193 },
194 &vk,
195 )
196 .expect("should not error")
197}