1#![allow(clippy::disallowed_methods)]
5
6use async_trait::async_trait;
7
8use crate::provider::{CryptoError, CryptoProvider, ED25519_PUBLIC_KEY_LEN, SecureSeed};
9use ring::rand::SystemRandom;
10use ring::signature::{ED25519, Ed25519KeyPair, KeyPair, UnparsedPublicKey};
11
12pub struct RingCryptoProvider;
25
26impl RingCryptoProvider {
27 pub fn p256_generate() -> Result<(SecureSeed, Vec<u8>), CryptoError> {
29 use p256::ecdsa::SigningKey;
30 use p256::elliptic_curve::rand_core::OsRng;
31
32 let signing_key = SigningKey::random(&mut OsRng);
33 let verifying_key = p256::ecdsa::VerifyingKey::from(&signing_key);
34
35 let compressed = verifying_key.to_encoded_point(true);
37 let pubkey_bytes = compressed.as_bytes().to_vec();
38
39 let scalar_bytes = signing_key.to_bytes();
41 let mut seed = [0u8; 32];
42 seed.copy_from_slice(&scalar_bytes);
43
44 Ok((SecureSeed::new(seed), pubkey_bytes))
45 }
46
47 pub fn p256_sign(seed: &[u8; 32], message: &[u8]) -> Result<Vec<u8>, CryptoError> {
49 use p256::ecdsa::{SigningKey, signature::Signer};
50
51 let signing_key = SigningKey::from_slice(seed)
52 .map_err(|e| CryptoError::InvalidPrivateKey(format!("P-256: {e}")))?;
53
54 let signature: p256::ecdsa::Signature = signing_key.sign(message);
55 Ok(signature.to_bytes().to_vec())
56 }
57
58 pub fn ed25519_verify(
60 pubkey: &[u8],
61 message: &[u8],
62 signature: &[u8],
63 ) -> Result<(), CryptoError> {
64 let pk = ring::signature::UnparsedPublicKey::new(&ring::signature::ED25519, pubkey);
67 pk.verify(message, signature)
68 .map_err(|_| CryptoError::InvalidSignature)
69 }
70
71 pub fn ed25519_sign(seed: &[u8; 32], message: &[u8]) -> Result<Vec<u8>, CryptoError> {
78 let kp = Ed25519KeyPair::from_seed_unchecked(seed)
79 .map_err(|e| CryptoError::InvalidPrivateKey(format!("Ed25519: {e}")))?;
80 Ok(kp.sign(message).as_ref().to_vec())
81 }
82
83 pub fn ed25519_public_key(seed: &[u8; 32]) -> Result<[u8; 32], CryptoError> {
85 let kp = Ed25519KeyPair::from_seed_unchecked(seed)
86 .map_err(|e| CryptoError::OperationFailed(format!("Ed25519 pubkey: {e}")))?;
87 kp.public_key()
88 .as_ref()
89 .try_into()
90 .map_err(|_| CryptoError::OperationFailed("Ed25519 public key not 32 bytes".into()))
91 }
92
93 pub fn p256_verify(pubkey: &[u8], message: &[u8], signature: &[u8]) -> Result<(), CryptoError> {
95 use p256::ecdsa::{Signature, VerifyingKey, signature::Verifier};
96
97 let vk = VerifyingKey::from_sec1_bytes(pubkey)
98 .map_err(|e| CryptoError::OperationFailed(format!("P-256 key parse: {e}")))?;
99
100 let sig = Signature::from_slice(signature)
101 .map_err(|e| CryptoError::OperationFailed(format!("P-256 sig parse: {e}")))?;
102
103 vk.verify(message, &sig)
104 .map_err(|_| CryptoError::InvalidSignature)
105 }
106
107 pub fn p256_public_key_from_seed(seed: &[u8; 32]) -> Result<Vec<u8>, CryptoError> {
109 use p256::ecdsa::SigningKey;
110
111 let signing_key = SigningKey::from_slice(seed)
112 .map_err(|e| CryptoError::InvalidPrivateKey(format!("P-256: {e}")))?;
113 let verifying_key = p256::ecdsa::VerifyingKey::from(&signing_key);
114 let compressed = verifying_key.to_encoded_point(true);
115 Ok(compressed.as_bytes().to_vec())
116 }
117}
118
119#[async_trait]
120impl CryptoProvider for RingCryptoProvider {
121 async fn verify_p256(
122 &self,
123 pubkey: &[u8],
124 message: &[u8],
125 signature: &[u8],
126 ) -> Result<(), CryptoError> {
127 Self::p256_verify(pubkey, message, signature)
128 }
129
130 async fn verify_ed25519(
131 &self,
132 pubkey: &[u8],
133 message: &[u8],
134 signature: &[u8],
135 ) -> Result<(), CryptoError> {
136 if pubkey.len() != ED25519_PUBLIC_KEY_LEN {
137 return Err(CryptoError::InvalidKeyLength {
138 expected: ED25519_PUBLIC_KEY_LEN,
139 actual: pubkey.len(),
140 });
141 }
142
143 let pubkey = pubkey.to_vec();
144 let message = message.to_vec();
145 let signature = signature.to_vec();
146
147 tokio::task::spawn_blocking(move || {
148 let peer_public_key = UnparsedPublicKey::new(&ED25519, &pubkey);
149 peer_public_key
150 .verify(&message, &signature)
151 .map_err(|_| CryptoError::InvalidSignature)
152 })
153 .await
154 .map_err(|_| CryptoError::OperationFailed("Verification task panicked".into()))?
155 }
156
157 async fn sign_ed25519(
158 &self,
159 seed: &SecureSeed,
160 message: &[u8],
161 ) -> Result<Vec<u8>, CryptoError> {
162 let seed_bytes = *seed.as_bytes();
163 let message = message.to_vec();
164
165 tokio::task::spawn_blocking(move || {
168 let keypair = Ed25519KeyPair::from_seed_unchecked(&seed_bytes)
169 .map_err(|e| CryptoError::InvalidPrivateKey(format!("{e}")))?;
170 Ok(keypair.sign(&message).as_ref().to_vec())
171 })
172 .await
173 .map_err(|_| CryptoError::OperationFailed("Signing task panicked".into()))?
174 }
175
176 async fn generate_ed25519_keypair(&self) -> Result<(SecureSeed, [u8; 32]), CryptoError> {
177 tokio::task::spawn_blocking(move || {
178 let rng = SystemRandom::new();
179 let pkcs8_doc = Ed25519KeyPair::generate_pkcs8(&rng)
180 .map_err(|_| CryptoError::OperationFailed("Key generation failed".into()))?;
181 let keypair = Ed25519KeyPair::from_pkcs8(pkcs8_doc.as_ref())
182 .map_err(|e| CryptoError::OperationFailed(format!("Parse generated key: {e}")))?;
183
184 let public_key: [u8; 32] = keypair
185 .public_key()
186 .as_ref()
187 .try_into()
188 .map_err(|_| CryptoError::OperationFailed("Public key not 32 bytes".into()))?;
189
190 let pkcs8_bytes = pkcs8_doc.as_ref();
193 let seed: [u8; 32] = pkcs8_bytes[16..48]
194 .try_into()
195 .map_err(|_| CryptoError::OperationFailed("Seed extraction failed".into()))?;
196
197 Ok((SecureSeed::new(seed), public_key))
198 })
199 .await
200 .map_err(|_| CryptoError::OperationFailed("Keygen task panicked".into()))?
201 }
202
203 async fn ed25519_public_key_from_seed(
204 &self,
205 seed: &SecureSeed,
206 ) -> Result<[u8; 32], CryptoError> {
207 let seed_bytes = *seed.as_bytes();
208
209 tokio::task::spawn_blocking(move || {
210 let keypair = Ed25519KeyPair::from_seed_unchecked(&seed_bytes)
211 .map_err(|e| CryptoError::InvalidPrivateKey(format!("{e}")))?;
212 keypair
213 .public_key()
214 .as_ref()
215 .try_into()
216 .map_err(|_| CryptoError::OperationFailed("Public key not 32 bytes".into()))
217 })
218 .await
219 .map_err(|_| CryptoError::OperationFailed("Public key extraction panicked".into()))?
220 }
221
222 async fn sign_p256(&self, seed: &SecureSeed, message: &[u8]) -> Result<Vec<u8>, CryptoError> {
223 Self::p256_sign(seed.as_bytes(), message)
227 }
228
229 async fn generate_p256_keypair(&self) -> Result<(SecureSeed, Vec<u8>), CryptoError> {
230 Self::p256_generate()
231 }
232
233 async fn p256_public_key_from_seed(&self, seed: &SecureSeed) -> Result<Vec<u8>, CryptoError> {
234 Self::p256_public_key_from_seed(seed.as_bytes())
235 }
236
237 async fn aead_encrypt(
238 &self,
239 key: &[u8; 32],
240 nonce: &[u8; 12],
241 aad: &[u8],
242 plaintext: &[u8],
243 ) -> Result<Vec<u8>, CryptoError> {
244 use chacha20poly1305::{
245 ChaCha20Poly1305, Nonce,
246 aead::{Aead, KeyInit, Payload},
247 };
248
249 let cipher = ChaCha20Poly1305::new(key.into());
250 let nonce = Nonce::from_slice(nonce);
251 cipher
252 .encrypt(
253 nonce,
254 Payload {
255 msg: plaintext,
256 aad,
257 },
258 )
259 .map_err(|e| CryptoError::OperationFailed(format!("AEAD encrypt: {e}")))
260 }
261
262 async fn aead_decrypt(
263 &self,
264 key: &[u8; 32],
265 nonce: &[u8; 12],
266 aad: &[u8],
267 ciphertext: &[u8],
268 ) -> Result<Vec<u8>, CryptoError> {
269 use chacha20poly1305::{
270 ChaCha20Poly1305, Nonce,
271 aead::{Aead, KeyInit, Payload},
272 };
273
274 let cipher = ChaCha20Poly1305::new(key.into());
275 let nonce = Nonce::from_slice(nonce);
276 cipher
277 .decrypt(
278 nonce,
279 Payload {
280 msg: ciphertext,
281 aad,
282 },
283 )
284 .map_err(|_| CryptoError::InvalidSignature)
287 }
288
289 async fn hkdf_sha256_expand(
290 &self,
291 ikm: &[u8],
292 salt: &[u8],
293 info: &[u8],
294 out_len: usize,
295 ) -> Result<Vec<u8>, CryptoError> {
296 use hkdf::Hkdf;
297 use sha2::Sha256;
298
299 if out_len > 255 * 32 {
301 return Err(CryptoError::OperationFailed(
302 "HKDF-SHA256 output length exceeds 255 * 32 = 8160 bytes".into(),
303 ));
304 }
305
306 let hk = Hkdf::<Sha256>::new(if salt.is_empty() { None } else { Some(salt) }, ikm);
307 let mut out = vec![0u8; out_len];
308 hk.expand(info, &mut out)
309 .map_err(|e| CryptoError::OperationFailed(format!("HKDF-SHA256 expand: {e}")))?;
310 Ok(out)
311 }
312
313 async fn hkdf_sha384_expand(
314 &self,
315 ikm: &[u8],
316 salt: &[u8],
317 info: &[u8],
318 out_len: usize,
319 ) -> Result<Vec<u8>, CryptoError> {
320 use hkdf::Hkdf;
321 use sha2::Sha384;
322
323 if out_len > 255 * 48 {
324 return Err(CryptoError::OperationFailed(
325 "HKDF-SHA384 output length exceeds 255 * 48 = 12240 bytes".into(),
326 ));
327 }
328
329 let hk = Hkdf::<Sha384>::new(if salt.is_empty() { None } else { Some(salt) }, ikm);
330 let mut out = vec![0u8; out_len];
331 hk.expand(info, &mut out)
332 .map_err(|e| CryptoError::OperationFailed(format!("HKDF-SHA384 expand: {e}")))?;
333 Ok(out)
334 }
335
336 async fn hmac_sha256_compute(&self, key: &[u8], msg: &[u8]) -> Result<[u8; 32], CryptoError> {
337 use hmac::{Hmac, Mac};
338 use sha2::Sha256;
339
340 let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(key)
341 .map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA256 key: {e}")))?;
342 mac.update(msg);
343 let tag = mac.finalize().into_bytes();
344 let out: [u8; 32] = tag.into();
345 Ok(out)
346 }
347
348 async fn hmac_sha256_verify(
349 &self,
350 key: &[u8],
351 msg: &[u8],
352 tag: &[u8],
353 ) -> Result<(), CryptoError> {
354 use hmac::{Hmac, Mac};
355 use sha2::Sha256;
356
357 let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(key)
358 .map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA256 key: {e}")))?;
359 mac.update(msg);
360 mac.verify_slice(tag)
362 .map_err(|_| CryptoError::InvalidSignature)
363 }
364
365 async fn hmac_sha384_compute(&self, key: &[u8], msg: &[u8]) -> Result<[u8; 48], CryptoError> {
366 use hmac::{Hmac, Mac};
367 use sha2::Sha384;
368
369 let mut mac = <Hmac<Sha384> as Mac>::new_from_slice(key)
370 .map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA384 key: {e}")))?;
371 mac.update(msg);
372 let tag = mac.finalize().into_bytes();
373 let out: [u8; 48] = tag.into();
374 Ok(out)
375 }
376
377 async fn hmac_sha384_verify(
378 &self,
379 key: &[u8],
380 msg: &[u8],
381 tag: &[u8],
382 ) -> Result<(), CryptoError> {
383 use hmac::{Hmac, Mac};
384 use sha2::Sha384;
385
386 let mut mac = <Hmac<Sha384> as Mac>::new_from_slice(key)
387 .map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA384 key: {e}")))?;
388 mac.update(msg);
389 mac.verify_slice(tag)
390 .map_err(|_| CryptoError::InvalidSignature)
391 }
392}