1use alloc::boxed::Box;
2#[cfg(feature = "signing")]
3use alloc::vec::Vec;
4
5use digest::Digest;
6use paseto_core::PasetoError;
7use paseto_core::key::HasKey;
8use paseto_core::pae::{WriteBytes, pre_auth_encode};
9use paseto_core::version::Public;
10use rsa::pss::Signature;
11#[cfg(feature = "signing")]
12use rsa::rand_core::OsRng;
13use rsa::traits::PublicKeyParts;
14
15#[cfg(feature = "signing")]
16use super::SecretKey;
17use super::{PublicKey, V1};
18
19impl HasKey<Public> for V1 {
20 type Key = PublicKey;
21
22 fn decode(bytes: &[u8]) -> Result<PublicKey, PasetoError> {
23 use rsa::pkcs8::spki::DecodePublicKey;
24
25 let key = if let Ok(key) = rsa::RsaPublicKey::from_public_key_der(bytes) {
26 key
27 } else {
28 let s = str::from_utf8(bytes).map_err(|_| PasetoError::InvalidKey)?;
29 rsa::RsaPublicKey::from_public_key_pem(s).map_err(|_| PasetoError::InvalidKey)?
30 };
31
32 if key.n().bits() != 2048 {
33 return Err(PasetoError::InvalidKey);
34 }
35
36 Ok(PublicKey(rsa::pss::VerifyingKey::new(key)))
37 }
38 fn encode(key: &PublicKey) -> Box<[u8]> {
39 use rsa::pkcs8::spki::EncodePublicKey;
40
41 key.0
42 .to_public_key_der()
43 .expect("encoding to spki der should succeed")
44 .into_vec()
45 .into_boxed_slice()
46 }
47}
48
49#[cfg(feature = "signing")]
50impl HasKey<paseto_core::version::Secret> for V1 {
51 type Key = SecretKey;
52
53 fn decode(bytes: &[u8]) -> Result<SecretKey, PasetoError> {
54 use rsa::pkcs1::DecodeRsaPrivateKey;
55
56 let key = if let Ok(key) = rsa::RsaPrivateKey::from_pkcs1_der(bytes) {
57 key
58 } else {
59 let s = str::from_utf8(bytes).map_err(|_| PasetoError::InvalidKey)?;
60 rsa::RsaPrivateKey::from_pkcs1_pem(s).map_err(|_| PasetoError::InvalidKey)?
61 };
62
63 if key.n().bits() != 2048 {
64 return Err(PasetoError::InvalidKey);
65 }
66
67 Ok(SecretKey(rsa::pss::SigningKey::new(key)))
68 }
69 fn encode(key: &SecretKey) -> Box<[u8]> {
70 use rsa::pkcs1::EncodeRsaPrivateKey;
71
72 key.0
73 .to_pkcs1_der()
74 .expect("encoding to pkcs1 der should succeed")
75 .as_bytes()
76 .to_vec()
77 .into_boxed_slice()
78 }
79}
80
81#[cfg(feature = "signing")]
82impl SecretKey {
83 pub(crate) fn random() -> Result<Self, PasetoError> {
84 use rsa::rand_core::OsRng;
85
86 rsa::pss::SigningKey::random(&mut OsRng, 2048)
87 .map_err(|_| PasetoError::InvalidKey)
88 .map(Self)
89 }
90}
91
92#[cfg(feature = "signing")]
93impl paseto_core::version::SealingVersion<Public> for V1 {
94 fn unsealing_key(key: &SecretKey) -> PublicKey {
95 use rsa::signature::Keypair;
96
97 PublicKey(key.0.verifying_key())
98 }
99
100 fn random() -> Result<SecretKey, PasetoError> {
101 SecretKey::random()
102 }
103
104 fn nonce() -> Result<Vec<u8>, PasetoError> {
105 Ok(Vec::with_capacity(96))
106 }
107
108 fn dangerous_seal_with_nonce(
109 key: &SecretKey,
110 encoding: &'static str,
111 mut payload: Vec<u8>,
112 footer: &[u8],
113 aad: &[u8],
114 ) -> Result<Vec<u8>, PasetoError> {
115 use rsa::signature::RandomizedDigestSigner;
116
117 if !aad.is_empty() {
118 return Err(PasetoError::ClaimsError);
119 }
120
121 let digest = preauth_public(encoding, &payload, footer);
122 let signature: Box<[u8]> = key
123 .0
124 .try_sign_digest_with_rng(&mut OsRng, digest)
125 .map_err(|_| PasetoError::CryptoError)?
126 .into();
127
128 payload.extend_from_slice(&signature);
129
130 Ok(payload)
131 }
132}
133
134impl paseto_core::version::UnsealingVersion<Public> for V1 {
135 fn unseal<'a>(
136 key: &PublicKey,
137 encoding: &'static str,
138 payload: &'a mut [u8],
139 footer: &[u8],
140 aad: &[u8],
141 ) -> Result<&'a [u8], PasetoError> {
142 use rsa::signature::DigestVerifier;
143
144 if !aad.is_empty() {
145 return Err(PasetoError::ClaimsError);
146 }
147
148 let (cleartext, tag) = payload
149 .split_last_chunk::<256>()
150 .ok_or(PasetoError::InvalidToken)?;
151
152 let signature = Signature::try_from(&tag[..]).map_err(|_| PasetoError::InvalidToken)?;
153 let digest = preauth_public(encoding, cleartext, footer);
154 DigestVerifier::<sha2::Sha384, Signature>::verify_digest(&key.0, digest, &signature)
155 .map_err(|_| PasetoError::CryptoError)?;
156
157 Ok(cleartext)
158 }
159}
160fn preauth_public(encoding: &'static str, cleartext: &[u8], footer: &[u8]) -> sha2::Sha384 {
161 use paseto_core::key::KeyType;
162 struct Context(sha2::Sha384);
163 impl WriteBytes for Context {
164 fn write(&mut self, slice: &[u8]) {
165 self.0.update(slice);
166 }
167 }
168
169 let mut ctx = Context(sha2::Sha384::new());
170 pre_auth_encode(
171 [
172 &[
173 "v1".as_bytes(),
174 encoding.as_bytes(),
175 Public::HEADER.as_bytes(),
176 ],
177 &[cleartext],
178 &[footer],
179 ],
180 &mut ctx,
181 );
182 ctx.0
183}