Skip to main content

uselesskey_rustcrypto/
lib.rs

1#![forbid(unsafe_code)]
2
3//! Integration between uselesskey test fixtures and the RustCrypto ecosystem.
4//!
5//! This crate provides extension traits that convert uselesskey fixtures into
6//! native RustCrypto types, making it easy to use test fixtures with code
7//! that depends on the RustCrypto crates directly.
8//!
9//! # Features
10//!
11//! Enable the key types you need:
12//!
13//! - `rsa` - RSA keypairs -> `rsa::RsaPrivateKey` / `rsa::RsaPublicKey`
14//! - `ecdsa` - ECDSA keypairs -> `p256::ecdsa::SigningKey` / `p384::ecdsa::SigningKey`
15//! - `ed25519` - Ed25519 keypairs -> `ed25519_dalek::SigningKey` / `VerifyingKey`
16//! - `hmac` - HMAC secrets -> `hmac::Hmac<Sha256>` / `Sha384` / `Sha512`
17//! - `all` - All of the above
18//!
19//! # Example: RSA sign and verify
20//!
21#![cfg_attr(feature = "rsa", doc = "```")]
22#![cfg_attr(not(feature = "rsa"), doc = "```ignore")]
23//! use uselesskey_core::Factory;
24//! use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
25//! use uselesskey_rustcrypto::RustCryptoRsaExt;
26//! use rsa::pkcs1v15::SigningKey;
27//! use rsa::signature::{Signer, Verifier};
28//! use rsa::sha2::Sha256;
29//!
30//! let fx = Factory::random();
31//! let keypair = fx.rsa("test", RsaSpec::rs256());
32//!
33//! let private_key = keypair.rsa_private_key();
34//! let signing_key = SigningKey::<Sha256>::new_unprefixed(private_key);
35//! let signature = signing_key.sign(b"hello world");
36//!
37//! let public_key = keypair.rsa_public_key();
38//! let verifying_key = rsa::pkcs1v15::VerifyingKey::<Sha256>::new_unprefixed(public_key);
39//! verifying_key.verify(b"hello world", &signature).unwrap();
40//! ```
41
42// =========================================================================
43// RSA
44// =========================================================================
45
46/// Extension trait to convert uselesskey RSA fixtures into RustCrypto `rsa` types.
47///
48/// # Examples
49///
50/// ```
51/// use uselesskey_core::Factory;
52/// use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
53/// use uselesskey_rustcrypto::RustCryptoRsaExt;
54///
55/// let fx = Factory::random();
56/// let keypair = fx.rsa("my-service", RsaSpec::rs256());
57///
58/// let private = keypair.rsa_private_key();
59/// let public = keypair.rsa_public_key();
60///
61/// // Verify the key is usable
62/// use rsa::signature::Signer;
63/// let signing_key = rsa::pkcs1v15::SigningKey::<rsa::sha2::Sha256>::new_unprefixed(private);
64/// let _sig = signing_key.sign(b"test");
65/// ```
66#[cfg(feature = "rsa")]
67pub trait RustCryptoRsaExt {
68    /// Convert the RSA fixture to an `rsa::RsaPrivateKey`.
69    fn rsa_private_key(&self) -> rsa::RsaPrivateKey;
70
71    /// Derive the `rsa::RsaPublicKey` from the fixture's private key.
72    fn rsa_public_key(&self) -> rsa::RsaPublicKey;
73}
74
75#[cfg(feature = "rsa")]
76impl RustCryptoRsaExt for uselesskey_rsa::RsaKeyPair {
77    fn rsa_private_key(&self) -> rsa::RsaPrivateKey {
78        use rsa::pkcs8::DecodePrivateKey;
79        rsa::RsaPrivateKey::from_pkcs8_der(self.private_key_pkcs8_der())
80            .expect("valid RSA PKCS#8 DER")
81    }
82
83    fn rsa_public_key(&self) -> rsa::RsaPublicKey {
84        rsa::RsaPublicKey::from(self.rsa_private_key())
85    }
86}
87
88// =========================================================================
89// ECDSA
90// =========================================================================
91
92/// Extension trait to convert uselesskey ECDSA fixtures into RustCrypto `p256`/`p384` types.
93///
94/// Call the method matching your curve. Calling a P-256 method on a P-384 key (or vice versa)
95/// will panic.
96///
97/// # Examples
98///
99/// ```
100/// use uselesskey_core::Factory;
101/// use uselesskey_ecdsa::{EcdsaFactoryExt, EcdsaSpec};
102/// use uselesskey_rustcrypto::RustCryptoEcdsaExt;
103/// use p256::ecdsa::signature::{Signer, Verifier};
104///
105/// let fx = Factory::random();
106/// let keypair = fx.ecdsa("my-service", EcdsaSpec::es256());
107///
108/// let signing_key = keypair.p256_signing_key();
109/// let signature: p256::ecdsa::Signature = signing_key.sign(b"hello");
110///
111/// let verifying_key = keypair.p256_verifying_key();
112/// verifying_key.verify(b"hello", &signature).unwrap();
113/// ```
114#[cfg(feature = "ecdsa")]
115pub trait RustCryptoEcdsaExt {
116    /// Get the P-256 signing key. Panics if the key is not P-256.
117    fn p256_signing_key(&self) -> p256::ecdsa::SigningKey;
118
119    /// Get the P-256 verifying key. Panics if the key is not P-256.
120    fn p256_verifying_key(&self) -> p256::ecdsa::VerifyingKey;
121
122    /// Get the P-384 signing key. Panics if the key is not P-384.
123    fn p384_signing_key(&self) -> p384::ecdsa::SigningKey;
124
125    /// Get the P-384 verifying key. Panics if the key is not P-384.
126    fn p384_verifying_key(&self) -> p384::ecdsa::VerifyingKey;
127}
128
129#[cfg(feature = "ecdsa")]
130impl RustCryptoEcdsaExt for uselesskey_ecdsa::EcdsaKeyPair {
131    fn p256_signing_key(&self) -> p256::ecdsa::SigningKey {
132        assert!(
133            matches!(self.spec(), uselesskey_ecdsa::EcdsaSpec::Es256),
134            "expected P-256 key, got {:?}",
135            self.spec()
136        );
137        use p256::pkcs8::DecodePrivateKey;
138        p256::ecdsa::SigningKey::from_pkcs8_der(self.private_key_pkcs8_der())
139            .expect("valid P-256 PKCS#8 DER")
140    }
141
142    fn p256_verifying_key(&self) -> p256::ecdsa::VerifyingKey {
143        *self.p256_signing_key().verifying_key()
144    }
145
146    fn p384_signing_key(&self) -> p384::ecdsa::SigningKey {
147        assert!(
148            matches!(self.spec(), uselesskey_ecdsa::EcdsaSpec::Es384),
149            "expected P-384 key, got {:?}",
150            self.spec()
151        );
152        use p384::pkcs8::DecodePrivateKey;
153        p384::ecdsa::SigningKey::from_pkcs8_der(self.private_key_pkcs8_der())
154            .expect("valid P-384 PKCS#8 DER")
155    }
156
157    fn p384_verifying_key(&self) -> p384::ecdsa::VerifyingKey {
158        *self.p384_signing_key().verifying_key()
159    }
160}
161
162// =========================================================================
163// Ed25519
164// =========================================================================
165
166/// Extension trait to convert uselesskey Ed25519 fixtures into `ed25519-dalek` types.
167///
168/// # Examples
169///
170/// ```
171/// use uselesskey_core::Factory;
172/// use uselesskey_ed25519::{Ed25519FactoryExt, Ed25519Spec};
173/// use uselesskey_rustcrypto::RustCryptoEd25519Ext;
174/// use ed25519_dalek::{Signer, Verifier};
175///
176/// let fx = Factory::random();
177/// let keypair = fx.ed25519("my-service", Ed25519Spec::new());
178///
179/// let signing_key = keypair.ed25519_signing_key();
180/// let signature = signing_key.sign(b"hello");
181///
182/// let verifying_key = keypair.ed25519_verifying_key();
183/// verifying_key.verify(b"hello", &signature).unwrap();
184/// ```
185#[cfg(feature = "ed25519")]
186pub trait RustCryptoEd25519Ext {
187    /// Convert the Ed25519 fixture to an `ed25519_dalek::SigningKey`.
188    fn ed25519_signing_key(&self) -> ed25519_dalek::SigningKey;
189
190    /// Derive the `ed25519_dalek::VerifyingKey` from the fixture.
191    fn ed25519_verifying_key(&self) -> ed25519_dalek::VerifyingKey;
192}
193
194#[cfg(feature = "ed25519")]
195impl RustCryptoEd25519Ext for uselesskey_ed25519::Ed25519KeyPair {
196    fn ed25519_signing_key(&self) -> ed25519_dalek::SigningKey {
197        use ed25519_dalek::pkcs8::DecodePrivateKey;
198        ed25519_dalek::SigningKey::from_pkcs8_der(self.private_key_pkcs8_der())
199            .expect("valid Ed25519 PKCS#8 DER")
200    }
201
202    fn ed25519_verifying_key(&self) -> ed25519_dalek::VerifyingKey {
203        self.ed25519_signing_key().verifying_key()
204    }
205}
206
207// =========================================================================
208// HMAC
209// =========================================================================
210
211/// Extension trait to convert uselesskey HMAC fixtures into `hmac::Hmac` types.
212///
213/// # Examples
214///
215/// ```
216/// use uselesskey_core::Factory;
217/// use uselesskey_hmac::{HmacFactoryExt, HmacSpec};
218/// use uselesskey_rustcrypto::RustCryptoHmacExt;
219/// use hmac::Mac;
220///
221/// let fx = Factory::random();
222/// let secret = fx.hmac("my-service", HmacSpec::hs256());
223///
224/// let mut mac = secret.hmac_sha256();
225/// mac.update(b"hello");
226/// let result = mac.finalize();
227/// assert_eq!(result.into_bytes().len(), 32);
228/// ```
229#[cfg(feature = "hmac")]
230pub trait RustCryptoHmacExt {
231    /// Create an `Hmac<Sha256>` from the HMAC secret.
232    fn hmac_sha256(&self) -> hmac::Hmac<sha2::Sha256>;
233
234    /// Create an `Hmac<Sha384>` from the HMAC secret.
235    fn hmac_sha384(&self) -> hmac::Hmac<sha2::Sha384>;
236
237    /// Create an `Hmac<Sha512>` from the HMAC secret.
238    fn hmac_sha512(&self) -> hmac::Hmac<sha2::Sha512>;
239}
240
241#[cfg(feature = "hmac")]
242impl RustCryptoHmacExt for uselesskey_hmac::HmacSecret {
243    fn hmac_sha256(&self) -> hmac::Hmac<sha2::Sha256> {
244        use hmac::KeyInit;
245        hmac::Hmac::<sha2::Sha256>::new_from_slice(self.secret_bytes())
246            .expect("HMAC accepts any key length")
247    }
248
249    fn hmac_sha384(&self) -> hmac::Hmac<sha2::Sha384> {
250        use hmac::KeyInit;
251        hmac::Hmac::<sha2::Sha384>::new_from_slice(self.secret_bytes())
252            .expect("HMAC accepts any key length")
253    }
254
255    fn hmac_sha512(&self) -> hmac::Hmac<sha2::Sha512> {
256        use hmac::KeyInit;
257        hmac::Hmac::<sha2::Sha512>::new_from_slice(self.secret_bytes())
258            .expect("HMAC accepts any key length")
259    }
260}
261
262// =========================================================================
263// Tests
264// =========================================================================
265
266#[cfg(test)]
267mod tests {
268    use std::sync::OnceLock;
269    use uselesskey_core::{Factory, Seed};
270
271    static FX: OnceLock<Factory> = OnceLock::new();
272
273    fn fx() -> Factory {
274        FX.get_or_init(|| {
275            let seed = Seed::from_env_value("uselesskey-rustcrypto-inline-test-seed-v1")
276                .expect("test seed should always parse");
277            Factory::deterministic(seed)
278        })
279        .clone()
280    }
281
282    #[cfg(feature = "rsa")]
283    mod rsa_tests {
284        use crate::RustCryptoRsaExt;
285        use rsa::pkcs1v15::{SigningKey, VerifyingKey};
286        use rsa::sha2::Sha256;
287        use rsa::signature::{Signer, Verifier};
288        use uselesskey_core::Factory;
289        use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
290
291        #[test]
292        fn test_rsa_sign_verify() {
293            let fx = super::fx();
294            let keypair = fx.rsa("test", RsaSpec::rs256());
295
296            let private_key = keypair.rsa_private_key();
297            let signing_key = SigningKey::<Sha256>::new_unprefixed(private_key);
298            let signature = signing_key.sign(b"test message");
299
300            let public_key = keypair.rsa_public_key();
301            let verifying_key = VerifyingKey::<Sha256>::new_unprefixed(public_key);
302            verifying_key
303                .verify(b"test message", &signature)
304                .expect("verify");
305        }
306
307        #[test]
308        fn test_rsa_deterministic() {
309            use uselesskey_core::Seed;
310
311            let seed = Seed::from_env_value("test-seed").unwrap();
312            let fx = Factory::deterministic(seed);
313            let keypair = fx.rsa("det-test", RsaSpec::rs256());
314
315            let private_key = keypair.rsa_private_key();
316            let signing_key = SigningKey::<Sha256>::new_unprefixed(private_key);
317            let signature = signing_key.sign(b"deterministic");
318
319            let public_key = keypair.rsa_public_key();
320            let verifying_key = VerifyingKey::<Sha256>::new_unprefixed(public_key);
321            verifying_key
322                .verify(b"deterministic", &signature)
323                .expect("verify");
324        }
325    }
326
327    #[cfg(feature = "ecdsa")]
328    mod ecdsa_tests {
329        use crate::RustCryptoEcdsaExt;
330        use uselesskey_core::Factory;
331        use uselesskey_ecdsa::{EcdsaFactoryExt, EcdsaSpec};
332
333        #[test]
334        fn test_p256_sign_verify() {
335            use p256::ecdsa::signature::{Signer, Verifier};
336
337            let fx = Factory::random();
338            let keypair = fx.ecdsa("test", EcdsaSpec::es256());
339
340            let signing_key = keypair.p256_signing_key();
341            let signature: p256::ecdsa::Signature = signing_key.sign(b"test message");
342
343            let verifying_key = keypair.p256_verifying_key();
344            verifying_key
345                .verify(b"test message", &signature)
346                .expect("verify");
347        }
348
349        #[test]
350        fn test_p384_sign_verify() {
351            use p384::ecdsa::signature::{Signer, Verifier};
352
353            let fx = Factory::random();
354            let keypair = fx.ecdsa("test", EcdsaSpec::es384());
355
356            let signing_key = keypair.p384_signing_key();
357            let signature: p384::ecdsa::Signature = signing_key.sign(b"test message");
358
359            let verifying_key = keypair.p384_verifying_key();
360            verifying_key
361                .verify(b"test message", &signature)
362                .expect("verify");
363        }
364
365        #[test]
366        #[should_panic(expected = "expected P-384")]
367        fn test_p384_on_p256_key_panics() {
368            let fx = Factory::random();
369            let keypair = fx.ecdsa("test", EcdsaSpec::es256());
370            let _ = keypair.p384_signing_key();
371        }
372
373        #[test]
374        #[should_panic(expected = "expected P-256")]
375        fn test_p256_on_p384_key_panics() {
376            let fx = Factory::random();
377            let keypair = fx.ecdsa("test", EcdsaSpec::es384());
378            let _ = keypair.p256_signing_key();
379        }
380    }
381
382    #[cfg(feature = "ed25519")]
383    mod ed25519_tests {
384        use crate::RustCryptoEd25519Ext;
385        use ed25519_dalek::Signer;
386        use ed25519_dalek::Verifier;
387        use uselesskey_core::Factory;
388        use uselesskey_ed25519::{Ed25519FactoryExt, Ed25519Spec};
389
390        #[test]
391        fn test_ed25519_sign_verify() {
392            let fx = Factory::random();
393            let keypair = fx.ed25519("test", Ed25519Spec::new());
394
395            let signing_key = keypair.ed25519_signing_key();
396            let signature = signing_key.sign(b"test message");
397
398            let verifying_key = keypair.ed25519_verifying_key();
399            verifying_key
400                .verify(b"test message", &signature)
401                .expect("verify");
402        }
403    }
404
405    #[cfg(feature = "hmac")]
406    mod hmac_tests {
407        use crate::RustCryptoHmacExt;
408        use hmac::Mac;
409        use uselesskey_core::Factory;
410        use uselesskey_hmac::{HmacFactoryExt, HmacSpec};
411
412        #[test]
413        fn test_hmac_sha256() {
414            let fx = Factory::random();
415            let secret = fx.hmac("test", HmacSpec::hs256());
416
417            let mut mac = secret.hmac_sha256();
418            mac.update(b"test message");
419            let result = mac.finalize();
420
421            // Verify with a fresh instance
422            let mut mac2 = secret.hmac_sha256();
423            mac2.update(b"test message");
424            mac2.verify(&result.into_bytes()).expect("verify");
425        }
426
427        #[test]
428        fn test_hmac_sha384() {
429            let fx = Factory::random();
430            let secret = fx.hmac("test", HmacSpec::hs384());
431
432            let mut mac = secret.hmac_sha384();
433            mac.update(b"test message");
434            let result = mac.finalize();
435
436            let mut mac2 = secret.hmac_sha384();
437            mac2.update(b"test message");
438            mac2.verify(&result.into_bytes()).expect("verify");
439        }
440
441        #[test]
442        fn test_hmac_sha512() {
443            let fx = Factory::random();
444            let secret = fx.hmac("test", HmacSpec::hs512());
445
446            let mut mac = secret.hmac_sha512();
447            mac.update(b"test message");
448            let result = mac.finalize();
449
450            let mut mac2 = secret.hmac_sha512();
451            mac2.update(b"test message");
452            mac2.verify(&result.into_bytes()).expect("verify");
453        }
454    }
455}