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 debug_info = serde_json::to_string(&claims).unwrap();
83
84 tracing::info!("unencoded token {}", debug_info);
85
86 let token = Jwt::new(claims, header);
87
88 self.sign_json_web_token(token)
89 }
90
91 #[instrument(skip(token))]
92 pub fn sign_json_web_token<C, H>(&self, token: Jwt<C, H>) -> Result<Jws, Error>
93 where
94 C: fmt::Debug + Serialize,
95 H: fmt::Debug + Serialize,
96 {
97 let mut signing_key: SigningKey<Sha256> = SigningKey::new((*self.inner).clone());
98
99 let encoded_token: String = token
101 .to_string()
102 .map_err(|source| Error::JwtSerializationError { source })?;
103
104 tracing::info!("encoded token {}", encoded_token);
105
106 let signature: Box<[u8]> = {
107 let msg: &[u8] = encoded_token.as_bytes();
108
109 let signature: Signature = signing_key.sign(msg);
110
111 signature.to_bytes()
112 };
113
114 let jws = Jws::new(encoded_token.as_str(), signature.as_ref());
115
116 Ok(jws)
117 }
118
119 #[instrument]
120 pub fn generate<R>(rng: &mut R) -> Result<Self, Error>
121 where
122 R: CryptoRng + RngCore + fmt::Debug,
123 {
124 const BITS: usize = 2048;
125
126 let inner: Arc<RsaPrivateKey> = {
127 let inner =
128 RsaPrivateKey::new(rng, BITS).map_err(|source| Error::KeyGenError { source })?;
129
130 Arc::new(inner)
131 };
132
133 let id: Arc<str> = {
134 let id = Uuid::now_v7();
135 let id = id.to_string();
136 let id = id.as_str();
137
138 id.into()
139 };
140
141 let key = Self { id, inner };
142
143 Ok(key)
144 }
145
146 #[instrument]
147 pub fn to_json_web_key(&self) -> JsonWebKey {
148 let key_id: Box<str> = (*self.id.clone()).into();
149 let pubkey = self.pubkey();
150
151 let exponent: Box<[u8]> = pubkey.e().to_bytes_be().into();
152 let modulus: Box<[u8]> = pubkey.n().to_bytes_be().into();
153
154 let rwk = RsaWebKey {
155 exponent,
156 key_id,
157 modulus,
158 ..RsaWebKey::default()
159 };
160
161 JsonWebKey::RS256(rwk)
162 }
163
164 #[instrument]
165 pub fn to_json(&self) -> Result<serde_json::Value, Error> {
166 let jwk: JsonWebKey = self.to_json_web_key();
167
168 let json_val: serde_json::Value = serde_json::to_value(jwk)?;
169
170 Ok(json_val)
171 }
172
173 #[instrument(skip(jws))]
174 pub fn verify_json_web_signature(&self, jws: &Jws) -> Result<(), Error> {
175 let key: VerifyingKey<Sha256> = VerifyingKey::new(self.pubkey());
176
177 let signature: Signature = {
178 let sig: Cow<[u8]> = jws.signature();
179 Signature::try_from(sig.as_ref())?
180 };
181
182 let msg: Cow<str> = jws.encoded_token();
183
184 key.verify(msg.as_bytes(), &signature)?;
185
186 Ok(())
187 }
188
189 pub(crate) fn from_bytes(bytes: Zeroizing<Vec<u8>>, id: Arc<str>) -> Result<Self, Error> {
190 let inner: Arc<RsaPrivateKey> = {
191 let inner = RsaPrivateKey::from_pkcs8_der(&bytes)?;
192
193 Arc::new(inner)
194 };
195
196 let key = Self { id, inner };
197
198 Ok(key)
199 }
200
201 pub(crate) fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
202 let doc: SecretDocument = self.inner.to_pkcs8_der()?;
203
204 let bytes: Zeroizing<Vec<u8>> = doc.to_bytes();
205
206 Ok(bytes)
207 }
208
209 fn pubkey(&self) -> RsaPublicKey {
210 RsaPublicKey::from(self.inner.as_ref())
211 }
212}
213
214impl fmt::Debug for PrivateKey {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 f.debug_struct("PrivateKey")
217 .field("id", &self.id)
218 .finish_non_exhaustive()
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225 use crate::seed::Seed;
226
227 #[test]
228 fn test_generate() {
229 let seed = Seed::from(1);
230 let mut rng = seed.rng();
231
232 assert!(WebKey::generate(&mut rng).is_ok())
233 }
234}