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 ed25519_generate() -> Result<(SecureSeed, [u8; 32]), CryptoError> {
110 use p256::elliptic_curve::rand_core::{OsRng, RngCore};
111 let mut seed = [0u8; 32];
112 OsRng.fill_bytes(&mut seed);
113 let public_key = Self::ed25519_public_key(&seed)?;
114 Ok((SecureSeed::new(seed), public_key))
115 }
116
117 pub fn p256_public_key_from_seed(seed: &[u8; 32]) -> Result<Vec<u8>, CryptoError> {
118 use p256::ecdsa::SigningKey;
119
120 let signing_key = SigningKey::from_slice(seed)
121 .map_err(|e| CryptoError::InvalidPrivateKey(format!("P-256: {e}")))?;
122 let verifying_key = p256::ecdsa::VerifyingKey::from(&signing_key);
123 let compressed = verifying_key.to_encoded_point(true);
124 Ok(compressed.as_bytes().to_vec())
125 }
126}
127
128#[async_trait]
129impl CryptoProvider for RingCryptoProvider {
130 async fn verify_p256(
131 &self,
132 pubkey: &[u8],
133 message: &[u8],
134 signature: &[u8],
135 ) -> Result<(), CryptoError> {
136 Self::p256_verify(pubkey, message, signature)
137 }
138
139 async fn verify_ed25519(
140 &self,
141 pubkey: &[u8],
142 message: &[u8],
143 signature: &[u8],
144 ) -> Result<(), CryptoError> {
145 if pubkey.len() != ED25519_PUBLIC_KEY_LEN {
146 return Err(CryptoError::InvalidKeyLength {
147 expected: ED25519_PUBLIC_KEY_LEN,
148 actual: pubkey.len(),
149 });
150 }
151
152 let pubkey = pubkey.to_vec();
153 let message = message.to_vec();
154 let signature = signature.to_vec();
155
156 tokio::task::spawn_blocking(move || {
157 let peer_public_key = UnparsedPublicKey::new(&ED25519, &pubkey);
158 peer_public_key
159 .verify(&message, &signature)
160 .map_err(|_| CryptoError::InvalidSignature)
161 })
162 .await
163 .map_err(|_| CryptoError::OperationFailed("Verification task panicked".into()))?
164 }
165
166 async fn sign_ed25519(
167 &self,
168 seed: &SecureSeed,
169 message: &[u8],
170 ) -> Result<Vec<u8>, CryptoError> {
171 let seed_bytes = *seed.as_bytes();
172 let message = message.to_vec();
173
174 tokio::task::spawn_blocking(move || {
177 let keypair = Ed25519KeyPair::from_seed_unchecked(&seed_bytes)
178 .map_err(|e| CryptoError::InvalidPrivateKey(format!("{e}")))?;
179 Ok(keypair.sign(&message).as_ref().to_vec())
180 })
181 .await
182 .map_err(|_| CryptoError::OperationFailed("Signing task panicked".into()))?
183 }
184
185 async fn generate_ed25519_keypair(&self) -> Result<(SecureSeed, [u8; 32]), CryptoError> {
186 tokio::task::spawn_blocking(move || {
187 let rng = SystemRandom::new();
188 let pkcs8_doc = Ed25519KeyPair::generate_pkcs8(&rng)
189 .map_err(|_| CryptoError::OperationFailed("Key generation failed".into()))?;
190 let keypair = Ed25519KeyPair::from_pkcs8(pkcs8_doc.as_ref())
191 .map_err(|e| CryptoError::OperationFailed(format!("Parse generated key: {e}")))?;
192
193 let public_key: [u8; 32] = keypair
194 .public_key()
195 .as_ref()
196 .try_into()
197 .map_err(|_| CryptoError::OperationFailed("Public key not 32 bytes".into()))?;
198
199 let pkcs8_bytes = pkcs8_doc.as_ref();
202 let seed: [u8; 32] = pkcs8_bytes[16..48]
203 .try_into()
204 .map_err(|_| CryptoError::OperationFailed("Seed extraction failed".into()))?;
205
206 Ok((SecureSeed::new(seed), public_key))
207 })
208 .await
209 .map_err(|_| CryptoError::OperationFailed("Keygen task panicked".into()))?
210 }
211
212 async fn ed25519_public_key_from_seed(
213 &self,
214 seed: &SecureSeed,
215 ) -> Result<[u8; 32], CryptoError> {
216 let seed_bytes = *seed.as_bytes();
217
218 tokio::task::spawn_blocking(move || {
219 let keypair = Ed25519KeyPair::from_seed_unchecked(&seed_bytes)
220 .map_err(|e| CryptoError::InvalidPrivateKey(format!("{e}")))?;
221 keypair
222 .public_key()
223 .as_ref()
224 .try_into()
225 .map_err(|_| CryptoError::OperationFailed("Public key not 32 bytes".into()))
226 })
227 .await
228 .map_err(|_| CryptoError::OperationFailed("Public key extraction panicked".into()))?
229 }
230
231 async fn sign_p256(&self, seed: &SecureSeed, message: &[u8]) -> Result<Vec<u8>, CryptoError> {
232 Self::p256_sign(seed.as_bytes(), message)
236 }
237
238 async fn generate_p256_keypair(&self) -> Result<(SecureSeed, Vec<u8>), CryptoError> {
239 Self::p256_generate()
240 }
241
242 async fn p256_public_key_from_seed(&self, seed: &SecureSeed) -> Result<Vec<u8>, CryptoError> {
243 Self::p256_public_key_from_seed(seed.as_bytes())
244 }
245
246 async fn aead_encrypt(
247 &self,
248 key: &[u8; 32],
249 nonce: &[u8; 12],
250 aad: &[u8],
251 plaintext: &[u8],
252 ) -> Result<Vec<u8>, CryptoError> {
253 use chacha20poly1305::{
254 ChaCha20Poly1305, Nonce,
255 aead::{Aead, KeyInit, Payload},
256 };
257
258 let cipher = ChaCha20Poly1305::new(key.into());
259 let nonce = Nonce::from_slice(nonce);
260 cipher
261 .encrypt(
262 nonce,
263 Payload {
264 msg: plaintext,
265 aad,
266 },
267 )
268 .map_err(|e| CryptoError::OperationFailed(format!("AEAD encrypt: {e}")))
269 }
270
271 async fn aead_decrypt(
272 &self,
273 key: &[u8; 32],
274 nonce: &[u8; 12],
275 aad: &[u8],
276 ciphertext: &[u8],
277 ) -> Result<Vec<u8>, CryptoError> {
278 use chacha20poly1305::{
279 ChaCha20Poly1305, Nonce,
280 aead::{Aead, KeyInit, Payload},
281 };
282
283 let cipher = ChaCha20Poly1305::new(key.into());
284 let nonce = Nonce::from_slice(nonce);
285 cipher
286 .decrypt(
287 nonce,
288 Payload {
289 msg: ciphertext,
290 aad,
291 },
292 )
293 .map_err(|_| CryptoError::InvalidSignature)
296 }
297
298 async fn hkdf_sha256_expand(
299 &self,
300 ikm: &[u8],
301 salt: &[u8],
302 info: &[u8],
303 out_len: usize,
304 ) -> Result<Vec<u8>, CryptoError> {
305 use hkdf::Hkdf;
306 use sha2::Sha256;
307
308 if out_len > 255 * 32 {
310 return Err(CryptoError::OperationFailed(
311 "HKDF-SHA256 output length exceeds 255 * 32 = 8160 bytes".into(),
312 ));
313 }
314
315 let hk = Hkdf::<Sha256>::new(if salt.is_empty() { None } else { Some(salt) }, ikm);
316 let mut out = vec![0u8; out_len];
317 hk.expand(info, &mut out)
318 .map_err(|e| CryptoError::OperationFailed(format!("HKDF-SHA256 expand: {e}")))?;
319 Ok(out)
320 }
321
322 async fn hkdf_sha384_expand(
323 &self,
324 ikm: &[u8],
325 salt: &[u8],
326 info: &[u8],
327 out_len: usize,
328 ) -> Result<Vec<u8>, CryptoError> {
329 use hkdf::Hkdf;
330 use sha2::Sha384;
331
332 if out_len > 255 * 48 {
333 return Err(CryptoError::OperationFailed(
334 "HKDF-SHA384 output length exceeds 255 * 48 = 12240 bytes".into(),
335 ));
336 }
337
338 let hk = Hkdf::<Sha384>::new(if salt.is_empty() { None } else { Some(salt) }, ikm);
339 let mut out = vec![0u8; out_len];
340 hk.expand(info, &mut out)
341 .map_err(|e| CryptoError::OperationFailed(format!("HKDF-SHA384 expand: {e}")))?;
342 Ok(out)
343 }
344
345 async fn hmac_sha256_compute(&self, key: &[u8], msg: &[u8]) -> Result<[u8; 32], CryptoError> {
346 use hmac::{Hmac, Mac};
347 use sha2::Sha256;
348
349 let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(key)
350 .map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA256 key: {e}")))?;
351 mac.update(msg);
352 let tag = mac.finalize().into_bytes();
353 let out: [u8; 32] = tag.into();
354 Ok(out)
355 }
356
357 async fn hmac_sha256_verify(
358 &self,
359 key: &[u8],
360 msg: &[u8],
361 tag: &[u8],
362 ) -> Result<(), CryptoError> {
363 use hmac::{Hmac, Mac};
364 use sha2::Sha256;
365
366 let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(key)
367 .map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA256 key: {e}")))?;
368 mac.update(msg);
369 mac.verify_slice(tag)
371 .map_err(|_| CryptoError::InvalidSignature)
372 }
373
374 async fn hmac_sha384_compute(&self, key: &[u8], msg: &[u8]) -> Result<[u8; 48], CryptoError> {
375 use hmac::{Hmac, Mac};
376 use sha2::Sha384;
377
378 let mut mac = <Hmac<Sha384> as Mac>::new_from_slice(key)
379 .map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA384 key: {e}")))?;
380 mac.update(msg);
381 let tag = mac.finalize().into_bytes();
382 let out: [u8; 48] = tag.into();
383 Ok(out)
384 }
385
386 async fn hmac_sha384_verify(
387 &self,
388 key: &[u8],
389 msg: &[u8],
390 tag: &[u8],
391 ) -> Result<(), CryptoError> {
392 use hmac::{Hmac, Mac};
393 use sha2::Sha384;
394
395 let mut mac = <Hmac<Sha384> as Mac>::new_from_slice(key)
396 .map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA384 key: {e}")))?;
397 mac.update(msg);
398 mac.verify_slice(tag)
399 .map_err(|_| CryptoError::InvalidSignature)
400 }
401}