paseto_v1/core/
pke.rs

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};
11use rsa::BigUint;
12use rsa::hazmat::{rsa_decrypt_and_check, rsa_encrypt};
13use rsa::traits::PublicKeyParts;
14use sha2::Digest;
15use zerocopy::IntoBytes;
16
17use super::{LocalKey, V1};
18
19#[derive(Clone)]
20pub struct PkeSecretKey(rsa::RsaPrivateKey);
21
22#[derive(Clone)]
23pub struct PkePublicKey(rsa::RsaPublicKey);
24
25impl HasKey<PkePublic> for V1 {
26    type Key = PkePublicKey;
27    fn decode(bytes: &[u8]) -> Result<PkePublicKey, PasetoError> {
28        use rsa::pkcs8::spki::DecodePublicKey;
29
30        let key = if let Ok(key) = rsa::RsaPublicKey::from_public_key_der(bytes) {
31            key
32        } else {
33            let s = str::from_utf8(bytes).map_err(|_| PasetoError::InvalidKey)?;
34            rsa::RsaPublicKey::from_public_key_pem(s).map_err(|_| PasetoError::InvalidKey)?
35        };
36
37        if key.n().bits() != 4096 {
38            return Err(PasetoError::InvalidKey);
39        }
40
41        Ok(PkePublicKey(key))
42    }
43    fn encode(key: &PkePublicKey) -> Box<[u8]> {
44        use rsa::pkcs8::spki::EncodePublicKey;
45
46        key.0
47            .to_public_key_der()
48            .expect("encoding to spki der should succeed")
49            .into_vec()
50            .into_boxed_slice()
51    }
52}
53
54impl HasKey<PkeSecret> for V1 {
55    type Key = PkeSecretKey;
56    fn decode(bytes: &[u8]) -> Result<PkeSecretKey, PasetoError> {
57        use rsa::pkcs1::DecodeRsaPrivateKey;
58
59        let key = if let Ok(key) = rsa::RsaPrivateKey::from_pkcs1_der(bytes) {
60            key
61        } else {
62            let s = str::from_utf8(bytes).map_err(|_| PasetoError::InvalidKey)?;
63            rsa::RsaPrivateKey::from_pkcs1_pem(s).map_err(|_| PasetoError::InvalidKey)?
64        };
65
66        if key.n().bits() != 4096 {
67            return Err(PasetoError::InvalidKey);
68        }
69
70        Ok(PkeSecretKey(key))
71    }
72    fn encode(key: &PkeSecretKey) -> Box<[u8]> {
73        use rsa::pkcs1::EncodeRsaPrivateKey;
74
75        key.0
76            .to_pkcs1_der()
77            .expect("encoding to pkcs1 der should succeed")
78            .to_bytes()
79            .to_vec()
80            .into_boxed_slice()
81    }
82}
83
84impl PkeSealingVersion for V1 {
85    fn seal_key(sealing_key: &PkePublicKey, key: LocalKey) -> Result<Box<[u8]>, PasetoError> {
86        use cipher::KeyIvInit;
87
88        let mut r = vec![0u8; 512];
89        getrandom::fill(&mut r).map_err(|_| PasetoError::CryptoError)?;
90        r[0] &= 0x7f;
91        r[0] |= 0x40;
92        let c = rsa_encrypt(&sealing_key.0, &BigUint::from_bytes_be(&r))
93            .map_err(|_| PasetoError::CryptoError)?
94            .to_bytes_be();
95
96        let k = sha2::Sha384::digest(&c);
97
98        let mut mac =
99            hmac::Hmac::<sha2::Sha384>::new_from_slice(&k[..]).expect("hmac accepts all key sizes");
100        mac.update(b"\x01k1.seal.");
101        mac.update(r.as_bytes());
102        let (ek, n) = mac.finalize_reset().into_bytes().split();
103
104        mac.update(b"\x02k1.seal.");
105        mac.update(r.as_bytes());
106        let ak = mac.finalize().into_bytes();
107
108        let mut edk = key.0;
109        ctr::Ctr64BE::<aes::Aes256>::new(&ek, &n).apply_keystream(&mut edk);
110
111        let mut tag = hmac::Hmac::<sha2::Sha384>::new_from_slice(&ak).unwrap();
112        tag.update(b"k1.seal.");
113        tag.update(c.as_bytes());
114        tag.update(&edk);
115        let tag = tag.finalize().into_bytes();
116
117        let mut output = Vec::with_capacity(48 + 32 + 512);
118        output.extend_from_slice(&tag);
119        output.extend_from_slice(&edk);
120        output.extend_from_slice(c.as_bytes());
121
122        Ok(output.into_boxed_slice())
123    }
124}
125
126impl PkeUnsealingVersion for V1 {
127    fn unseal_key(
128        unsealing_key: &PkeSecretKey,
129        mut key_data: Box<[u8]>,
130    ) -> Result<LocalKey, PasetoError> {
131        use cipher::KeyIvInit;
132
133        let (tag, key_data) = key_data
134            .split_first_chunk_mut::<48>()
135            .ok_or(PasetoError::InvalidKey)?;
136        let (edk, c) = key_data
137            .split_last_chunk_mut::<512>()
138            .ok_or(PasetoError::InvalidKey)?;
139
140        let c: &[u8] = &*c;
141        let edk: &mut [u8; 32] = edk.try_into().map_err(|_| PasetoError::InvalidKey)?;
142
143        let r = rsa_decrypt_and_check::<rsa::rand_core::OsRng>(
144            &unsealing_key.0,
145            None,
146            &BigUint::from_bytes_be(c),
147        )
148        .map_err(|_| PasetoError::CryptoError)?
149        .to_bytes_be();
150
151        let k = sha2::Sha384::digest(c);
152
153        let mut mac =
154            hmac::Hmac::<sha2::Sha384>::new_from_slice(&k[..]).expect("hmac accepts all key sizes");
155
156        mac.update(b"\x02k1.seal.");
157        mac.update(r.as_bytes());
158        let ak = mac.finalize_reset().into_bytes();
159
160        let mut t2 = hmac::Hmac::<sha2::Sha384>::new_from_slice(&ak).unwrap();
161        t2.update(b"k1.seal.");
162        t2.update(c);
163        t2.update(edk);
164
165        // step 6: Compare t2 with t, using a constant-time compare function. If it does not match, abort.
166        t2.verify((&*tag).into())
167            .map_err(|_| PasetoError::CryptoError)?;
168
169        mac.update(b"\x01k1.seal.");
170        mac.update(r.as_bytes());
171        let (ek, n) = mac.finalize().into_bytes().split();
172
173        ctr::Ctr64BE::<aes::Aes256>::new(&ek, &n).apply_keystream(edk);
174
175        Ok(LocalKey(*edk))
176    }
177}