asjeeves_encryption/
web_key.rs1use 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}