1use alloc::boxed::Box;
2#[cfg(feature = "signing")]
3use alloc::vec::Vec;
4
5use digest::Digest;
6use p384::ecdsa::Signature;
7use paseto_core::PasetoError;
8use paseto_core::key::HasKey;
9use paseto_core::pae::{WriteBytes, pre_auth_encode};
10use paseto_core::version::Public;
11
12#[cfg(feature = "signing")]
13use super::SecretKey;
14use super::{PublicKey, V3};
15
16impl HasKey<Public> for V3 {
17 type Key = PublicKey;
18
19 fn decode(bytes: &[u8]) -> Result<PublicKey, PasetoError> {
20 p384::ecdsa::VerifyingKey::from_sec1_bytes(bytes)
21 .map(PublicKey)
22 .map_err(|_| PasetoError::InvalidKey)
23 }
24 fn encode(key: &PublicKey) -> Box<[u8]> {
25 key.0
26 .to_encoded_point(true)
27 .as_bytes()
28 .to_vec()
29 .into_boxed_slice()
30 }
31}
32
33#[cfg(feature = "signing")]
34impl HasKey<paseto_core::version::Secret> for V3 {
35 type Key = SecretKey;
36
37 fn decode(bytes: &[u8]) -> Result<SecretKey, PasetoError> {
38 if bytes.len() != 48 {
39 return Err(PasetoError::InvalidKey);
40 }
41 let sk = p384::SecretKey::from_slice(bytes).map_err(|_| PasetoError::InvalidKey)?;
42 Ok(SecretKey(sk.into()))
43 }
44 fn encode(key: &SecretKey) -> Box<[u8]> {
45 key.0.to_bytes().to_vec().into_boxed_slice()
46 }
47}
48
49#[cfg(feature = "signing")]
50impl SecretKey {
51 pub(crate) fn random() -> Result<Self, PasetoError> {
52 let mut bytes = generic_array::GenericArray::default();
53 loop {
54 getrandom::fill(&mut bytes).map_err(|_| PasetoError::CryptoError)?;
55 if let Ok(key) = p384::ecdsa::SigningKey::from_bytes(&bytes).map(Self) {
56 break Ok(key);
57 }
58 }
59 }
60}
61
62#[cfg(feature = "signing")]
63impl paseto_core::version::SealingVersion<Public> for V3 {
64 fn unsealing_key(key: &SecretKey) -> PublicKey {
65 PublicKey(*key.0.verifying_key())
66 }
67
68 fn random() -> Result<SecretKey, PasetoError> {
69 SecretKey::random()
70 }
71
72 fn nonce() -> Result<Vec<u8>, PasetoError> {
73 Ok(Vec::with_capacity(96))
74 }
75
76 fn dangerous_seal_with_nonce(
77 key: &SecretKey,
78 encoding: &'static str,
79 mut payload: Vec<u8>,
80 footer: &[u8],
81 aad: &[u8],
82 ) -> Result<Vec<u8>, PasetoError> {
83 use p384::ecdsa::signature::DigestSigner;
84
85 let digest = preauth_public(key.0.verifying_key(), encoding, &payload, footer, aad);
86 let signature: Signature = key.0.sign_digest(digest);
87 let signature = signature.normalize_s().unwrap_or(signature);
88
89 payload.extend_from_slice(&signature.to_bytes());
90
91 Ok(payload)
92 }
93}
94
95impl paseto_core::version::UnsealingVersion<Public> for V3 {
96 fn unseal<'a>(
97 key: &PublicKey,
98 encoding: &'static str,
99 payload: &'a mut [u8],
100 footer: &[u8],
101 aad: &[u8],
102 ) -> Result<&'a [u8], PasetoError> {
103 use p384::ecdsa::signature::DigestVerifier;
104
105 let (cleartext, tag) = payload
106 .split_last_chunk::<96>()
107 .ok_or(PasetoError::InvalidToken)?;
108
109 let signature =
110 Signature::from_bytes(tag[..].into()).map_err(|_| PasetoError::InvalidToken)?;
111 let digest = preauth_public(&key.0, encoding, cleartext, footer, aad);
112 DigestVerifier::<sha2::Sha384, Signature>::verify_digest(&key.0, digest, &signature)
113 .map_err(|_| PasetoError::CryptoError)?;
114
115 Ok(cleartext)
116 }
117}
118fn preauth_public(
119 key: &p384::ecdsa::VerifyingKey,
120 encoding: &'static str,
121 cleartext: &[u8],
122 footer: &[u8],
123 aad: &[u8],
124) -> sha2::Sha384 {
125 use paseto_core::key::KeyType;
126 struct Context(sha2::Sha384);
127 impl WriteBytes for Context {
128 fn write(&mut self, slice: &[u8]) {
129 self.0.update(slice);
130 }
131 }
132
133 let key = key.to_encoded_point(true);
134
135 let mut ctx = Context(sha2::Sha384::new());
136 pre_auth_encode(
137 [
138 &[key.as_bytes()],
139 &[
140 "v3".as_bytes(),
141 encoding.as_bytes(),
142 Public::HEADER.as_bytes(),
143 ],
144 &[cleartext],
145 &[footer],
146 &[aad],
147 ],
148 &mut ctx,
149 );
150 ctx.0
151}