uselesskey 0.2.0

Deterministic cryptographic key and certificate fixtures for Rust tests. Seed-stable, cached, scanner-safe.
Documentation

uselesskey

Crates.io docs.rs CI License: MIT OR Apache-2.0

Deterministic cryptographic test fixtures for Rust — stop committing PEM/DER blobs into your repos.

uselesskey is a test-fixture factory that generates cryptographic key material and X.509 certificates at runtime. It is not a crypto library — it replaces committed secret-shaped blobs with a single dev-dependency.

Do not use for production keys. Deterministic keys are predictable by design. Even random-mode keys are intended for tests only.

Why?

Secret scanners have changed the game for test fixtures:

Approach Drawback
Check in PEM files Triggers GitGuardian / GitHub push protection
Generate keys ad-hoc No caching → slow RSA keygen, no determinism
Use raw crypto crates Boilerplate for PEM/DER encoding, no negative fixtures

This crate replaces "security policy + docs + exceptions" with one dev-dependency.

Quick Start

[dev-dependencies]
uselesskey = "0.2"
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};

let fx = Factory::random();
let rsa = fx.rsa("my-service", RsaSpec::rs256());

let private_pem = rsa.private_key_pkcs8_pem();
let public_der  = rsa.public_key_spki_der();

Deterministic Mode

Same seed + same label + same spec = identical output every time, regardless of call order:

use uselesskey::{Factory, Seed, RsaFactoryExt, RsaSpec};

let seed = Seed::from_env_value("my-test-seed").unwrap();
let fx = Factory::deterministic(seed);
let rsa = fx.rsa("issuer", RsaSpec::rs256());

Or read the seed from an environment variable in CI:

use uselesskey::Factory;

let fx = Factory::deterministic_from_env("USELESSKEY_SEED")
    .unwrap_or_else(|_| Factory::random());

Supported Key Types

Algorithm Feature Extension Trait Spec Constructor
RSA 2048+ rsa (default) RsaFactoryExt RsaSpec::rs256()
ECDSA P-256 / P-384 ecdsa EcdsaFactoryExt EcdsaSpec::es256() / es384()
Ed25519 ed25519 Ed25519FactoryExt Ed25519Spec::new()
HMAC hmac HmacFactoryExt HmacSpec::hs256() / hs384() / hs512()
OpenPGP pgp PgpFactoryExt PgpSpec::rsa_2048() / ed25519()
Tokens token TokenFactoryExt TokenSpec::api_key() / bearer() / oauth_access_token()
X.509 Certs x509 X509FactoryExt X509Spec::self_signed(cn) / ChainSpec::new(cn)

Feature Flags

Feature Description
rsa RSA keypairs (enabled by default)
ecdsa ECDSA P-256 / P-384 keypairs
ed25519 Ed25519 keypairs
hmac HMAC secrets
pgp OpenPGP armored + binary keyblocks
token API key, bearer token, OAuth access token fixtures
x509 X.509 self-signed certificates and certificate chains
jwk JWK / JWKS output for enabled key types
all-keys All key algorithms (rsa + ecdsa + ed25519 + hmac + pgp)
full Everything (all-keys + token + x509 + jwk)

Output Formats

Every key type provides:

  • PKCS#8 PEM / DER — private keys
  • SPKI PEM / DER — public keys
  • Tempfileswrite_* methods for libraries that need file paths
  • JWK / JWKS — with the jwk feature

X.509 certificates additionally provide PEM / DER cert output, identity PEM (cert + key), and chain PEM (leaf + intermediate).

Negative Fixtures

Test error-handling paths with intentionally broken material:

use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
use uselesskey::negative::CorruptPem;

let fx = Factory::random();
let rsa = fx.rsa("test", RsaSpec::rs256());

let bad_pem   = rsa.private_key_pkcs8_pem_corrupt(CorruptPem::BadBase64);
let truncated = rsa.private_key_pkcs8_der_truncated(32);
let mismatch  = rsa.mismatched_public_key_spki_der();

X.509 chains support expired certs, hostname mismatch, unknown CA, and revoked leaf (with CRL):

use uselesskey::{Factory, X509FactoryExt, ChainSpec};

let fx = Factory::random();
let chain = fx.x509_chain("svc", ChainSpec::new("test.example.com"));

let expired    = chain.expired_leaf();
let wrong_host = chain.hostname_mismatch("wrong.example.com");
let unknown_ca = chain.unknown_ca();
let revoked    = chain.revoked_leaf();

Adapter Crates

Adapter crates bridge uselesskey fixtures to third-party library types. They are separate crates (not features) to avoid coupling versioning.

Crate Provides
uselesskey-jsonwebtoken jsonwebtoken::EncodingKey / DecodingKey
uselesskey-rustls rustls ServerConfig / ClientConfig builders
uselesskey-tonic tonic::transport TLS identity / config for gRPC
uselesskey-ring ring 0.17 native signing key types
uselesskey-rustcrypto RustCrypto native types (rsa::RsaPrivateKey, etc.)
uselesskey-aws-lc-rs aws-lc-rs native types

Microcrate Architecture

uselesskey is a facade crate that re-exports from a family of focused crates. If you only need one key type and want to minimize compile time, depend on the implementation crate directly:

Crate Purpose
uselesskey-core Factory, derivation, caching
uselesskey-rsa RSA keypairs
uselesskey-ecdsa ECDSA P-256 / P-384
uselesskey-ed25519 Ed25519
uselesskey-hmac HMAC secrets
uselesskey-x509 X.509 certificates

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.