paseto_v4/core/
public.rs

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}