Skip to main content

asjeeves_encryption/
web_key.rs

1use std::borrow::Cow;
2use std::fmt;
3use std::sync::Arc;
4
5use json_web_key::prelude::*;
6use json_web_tolkien::jws::Jws;
7use json_web_tolkien::jwt::Jwt;
8use json_web_tolkien::prelude::Algorithm;
9use rand_core::{CryptoRng, RngCore};
10use rsa::pkcs1v15::{Signature, SigningKey, VerifyingKey};
11use rsa::pkcs8::{DecodePrivateKey, EncodePrivateKey, SecretDocument};
12use rsa::sha2::Sha256;
13use rsa::signature::{SignatureEncoding, SignerMut, Verifier};
14use rsa::traits::PublicKeyParts;
15use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
16use serde::{Deserialize, Serialize};
17use tracing::instrument;
18use uuid::Uuid;
19use zeroize::Zeroizing;
20
21use crate::error::Error;
22use crate::prelude::Sensitive;
23
24pub type WebKey = PrivateKey;
25
26#[derive(Clone, PartialEq)]
27pub struct PrivateKey {
28    inner: Arc<RsaPrivateKey>,
29    id: Arc<str>,
30}
31
32impl PrivateKey {
33    #[instrument(skip(ciphertext))]
34    pub fn decrypt_bytes(&self, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
35        let dec_bytes: Vec<u8> = self
36            .inner
37            .decrypt(Pkcs1v15Encrypt, ciphertext)
38            .map_err(|source| Error::DecryptionError { source })?;
39
40        Ok(dec_bytes)
41    }
42
43    #[instrument]
44    pub fn encrypt_bytes<R>(
45        &self,
46        bytes: Sensitive<Box<[u8]>>,
47        rng: &mut R,
48    ) -> Result<Vec<u8>, Error>
49    where
50        R: CryptoRng + RngCore + fmt::Debug,
51    {
52        let enc_bytes: Vec<u8> = self
53            .pubkey()
54            .encrypt(rng, Pkcs1v15Encrypt, &bytes)
55            .map_err(|source| Error::EncryptionError { source })?;
56
57        Ok(enc_bytes)
58    }
59
60    pub fn id(&self) -> &str {
61        self.id.as_ref()
62    }
63
64    #[instrument]
65    pub fn sign_claims<C>(&self, claims: C) -> Result<Jws, Error>
66    where
67        C: fmt::Debug + for<'de> Deserialize<'de> + Serialize,
68    {
69        #[derive(Clone, Debug, Deserialize, Serialize)]
70        struct Header {
71            alg: Algorithm,
72            kid: Box<str>,
73            typ: Box<str>,
74        }
75
76        let header = Header {
77            alg: Algorithm::RS256,
78            kid: self.id.as_ref().into(),
79            typ: "JWT".into(),
80        };
81
82        let token = Jwt::new(claims, header);
83
84        self.sign_json_web_token(token)
85    }
86
87    #[instrument(skip(token))]
88    pub fn sign_json_web_token<C, H>(&self, token: Jwt<C, H>) -> Result<Jws, Error>
89    where
90        C: fmt::Debug + Serialize,
91        H: fmt::Debug + Serialize,
92    {
93        let mut signing_key: SigningKey<Sha256> = SigningKey::new((*self.inner).clone());
94
95        let encoded_token: String = token
96            .to_string()
97            .map_err(|source| Error::JwtSerializationError { source })?;
98
99        let signature: Box<[u8]> = {
100            let msg: &[u8] = encoded_token.as_bytes();
101
102            let signature: Signature = signing_key.sign(msg);
103
104            signature.to_bytes()
105        };
106
107        let jws = Jws::new(encoded_token.as_str(), signature.as_ref());
108
109        Ok(jws)
110    }
111
112    #[instrument]
113    pub fn generate<R>(rng: &mut R) -> Result<Self, Error>
114    where
115        R: CryptoRng + RngCore + fmt::Debug,
116    {
117        const BITS: usize = 2048;
118
119        let inner: Arc<RsaPrivateKey> = {
120            let inner =
121                RsaPrivateKey::new(rng, BITS).map_err(|source| Error::KeyGenError { source })?;
122
123            Arc::new(inner)
124        };
125
126        let id: Arc<str> = {
127            let id = Uuid::now_v7();
128            let id = id.to_string();
129            let id = id.as_str();
130
131            id.into()
132        };
133
134        let key = Self { id, inner };
135
136        Ok(key)
137    }
138
139    #[instrument]
140    pub fn to_json_web_key(&self) -> JsonWebKey {
141        let key_id: Box<str> = (*self.id.clone()).into();
142        let pubkey = self.pubkey();
143
144        let exponent: Box<[u8]> = pubkey.e().to_bytes_be().into();
145        let modulus: Box<[u8]> = pubkey.n().to_bytes_be().into();
146
147        let rwk = RsaWebKey {
148            exponent,
149            key_id,
150            modulus,
151            ..RsaWebKey::default()
152        };
153
154        JsonWebKey::RS256(rwk)
155    }
156
157    #[instrument]
158    pub fn to_json(&self) -> Result<serde_json::Value, Error> {
159        let jwk: JsonWebKey = self.to_json_web_key();
160
161        let json_val: serde_json::Value = serde_json::to_value(jwk)?;
162
163        Ok(json_val)
164    }
165
166    #[instrument(skip(jws))]
167    pub fn verify_json_web_signature(&self, jws: &Jws) -> Result<(), Error> {
168        let key: VerifyingKey<Sha256> = VerifyingKey::new(self.pubkey());
169
170        let signature: Signature = {
171            let sig: Cow<[u8]> = jws.signature();
172            Signature::try_from(sig.as_ref())?
173        };
174
175        let msg: Cow<str> = jws.encoded_token();
176
177        key.verify(msg.as_bytes(), &signature)?;
178
179        Ok(())
180    }
181
182    pub(crate) fn from_bytes(bytes: Zeroizing<Vec<u8>>, id: Arc<str>) -> Result<Self, Error> {
183        let inner: Arc<RsaPrivateKey> = {
184            let inner = RsaPrivateKey::from_pkcs8_der(&bytes)?;
185
186            Arc::new(inner)
187        };
188
189        let key = Self { id, inner };
190
191        Ok(key)
192    }
193
194    pub(crate) fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
195        let doc: SecretDocument = self.inner.to_pkcs8_der()?;
196
197        let bytes: Zeroizing<Vec<u8>> = doc.to_bytes();
198
199        Ok(bytes)
200    }
201
202    fn pubkey(&self) -> RsaPublicKey {
203        RsaPublicKey::from(self.inner.as_ref())
204    }
205}
206
207impl fmt::Debug for PrivateKey {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        f.debug_struct("PrivateKey")
210            .field("id", &self.id)
211            .finish_non_exhaustive()
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218    use crate::seed::Seed;
219
220    #[test]
221    fn it_should_enc_and_decrypt() {
222        let seed = Seed::from(1);
223        let mut rng = seed.rng();
224
225        let key = WebKey::generate(&mut rng).unwrap();
226
227        let unenc = Sensitive::new(vec![1u8, 2u8].into_boxed_slice());
228
229        let enc = key.encrypt_bytes(unenc, &mut rng).unwrap();
230
231        let dec = key.decrypt_bytes(&enc).unwrap();
232
233        assert_eq!(vec![1u8, 2u8], dec);
234    }
235}