pub mod aead;
pub mod agreement;
pub mod digest;
pub mod error;
pub mod hkdf;
pub mod hmac;
pub mod rand;
pub mod signature;
pub(crate) mod spki;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sha256_digest_known_vector() {
let d = digest::digest(&digest::SHA256, b"");
assert_eq!(d.as_ref().len(), 32);
assert_eq!(
d.as_ref(),
&[
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
0x78, 0x52, 0xb8, 0x55,
]
);
}
#[test]
fn sha256_digest_incremental() {
let mut ctx = digest::Context::new(&digest::SHA256);
ctx.update(b"abc");
let d = ctx.finish();
assert_eq!(
d.as_ref(),
&[
0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
0xf2, 0x00, 0x15, 0xad,
]
);
}
#[test]
fn hmac_sha256_sign_verify_roundtrip() {
let key = hmac::Key::new(hmac::HMAC_SHA256, b"my-secret-key");
let tag = hmac::sign(&key, b"hello world");
let result = hmac::verify(&key, b"hello world", tag.as_ref());
assert!(result.is_ok());
}
#[test]
fn hmac_sha256_wrong_data_rejected() {
let key = hmac::Key::new(hmac::HMAC_SHA256, b"my-secret-key");
let tag = hmac::sign(&key, b"hello world");
let result = hmac::verify(&key, b"hello WORLD", tag.as_ref());
assert!(result.is_err());
}
#[test]
fn hkdf_sha256_expand_known_length() {
struct Len32;
impl hkdf::KeyType for Len32 {
fn len(&self) -> usize {
32
}
}
let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, b"test-salt");
let prk = salt.extract(b"input-keying-material");
let mut out = [0u8; 32];
prk.expand(&[b"info"], Len32)
.unwrap()
.fill(&mut out)
.unwrap();
assert_ne!(out, [0u8; 32]);
}
#[test]
fn x25519_agreement_roundtrip() {
let rng = rand::SystemRandom::new();
let alice = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng).unwrap();
let alice_pub = alice.compute_public_key().unwrap();
let bob = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng).unwrap();
let bob_pub = bob.compute_public_key().unwrap();
let alice_secret = agreement::agree_ephemeral(
alice,
&agreement::UnparsedPublicKey::new(&agreement::X25519, bob_pub.as_ref()),
(),
|s| Ok::<Vec<u8>, ()>(s.to_vec()),
)
.unwrap();
let bob_secret = agreement::agree_ephemeral(
bob,
&agreement::UnparsedPublicKey::new(&agreement::X25519, alice_pub.as_ref()),
(),
|s| Ok::<Vec<u8>, ()>(s.to_vec()),
)
.unwrap();
assert_eq!(alice_secret, bob_secret);
assert!(!alice_secret.is_empty());
}
#[test]
fn aes_128_gcm_seal_open_roundtrip() {
let key_bytes = [0u8; 16];
let key = aead::UnboundKey::new(&aead::AES_128_GCM, &key_bytes).unwrap();
let lsk = aead::LessSafeKey::new(key);
let nonce = aead::Nonce::assume_unique_for_key([0u8; 12]);
let aad = aead::Aad::from(b"additional data".as_ref());
let plaintext = b"hello aead world!";
let mut in_out = plaintext.to_vec();
lsk.seal_in_place_append_tag(nonce, &aad, &mut in_out)
.unwrap();
assert!(in_out.len() > plaintext.len());
let nonce2 = aead::Nonce::assume_unique_for_key([0u8; 12]);
let aad2 = aead::Aad::from(b"additional data".as_ref());
let result = lsk.open_in_place(nonce2, &aad2, &mut in_out).unwrap();
assert_eq!(result, plaintext);
}
#[test]
fn ed25519_sign_verify() {
let keypair = signature::Ed25519KeyPair::generate().unwrap();
let msg = b"sign this message";
let sig = keypair.sign(msg).expect("Ed25519 sign failed");
let pub_key_bytes = keypair.public_key();
let result = signature::verify(&signature::ED25519, pub_key_bytes, msg, sig.as_ref());
assert!(result.is_ok(), "Ed25519 verification failed");
}
#[test]
fn aead_tampered_ciphertext_fails() {
let key = aead::UnboundKey::new(&aead::AES_128_GCM, &[0u8; 16]).unwrap();
let lsk = aead::LessSafeKey::new(key);
let mut in_out = b"secret".to_vec();
lsk.seal_in_place_append_tag(
aead::Nonce::assume_unique_for_key([0u8; 12]),
&aead::Aad::from(b"".as_ref()),
&mut in_out,
)
.unwrap();
in_out[0] ^= 0xff; assert!(lsk
.open_in_place(
aead::Nonce::assume_unique_for_key([0u8; 12]),
&aead::Aad::from(b"".as_ref()),
&mut in_out,
)
.is_err());
}
#[test]
fn ecdsa_wrong_key_verify_fails() {
let rng = rand::SystemRandom::new();
let kp1 = signature::EcdsaKeyPair::generate(&signature::ECDSA_P256_SHA256_ASN1).unwrap();
let kp2 = signature::EcdsaKeyPair::generate(&signature::ECDSA_P256_SHA256_ASN1).unwrap();
let msg = b"test message";
let sig = kp1.sign(&rng, msg).unwrap();
assert!(signature::verify(
&signature::ECDSA_P256_SHA256_ASN1,
kp2.public_key(),
msg,
sig.as_ref(),
)
.is_err());
}
#[test]
fn agreement_wrong_length_peer_key_fails() {
let rng = rand::SystemRandom::new();
let alice = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng).unwrap();
let result = agreement::agree_ephemeral(
alice,
&agreement::UnparsedPublicKey::new(&agreement::X25519, &[0u8; 31]),
(),
|_| Ok::<(), ()>(()),
);
assert!(result.is_err());
}
#[test]
fn agreement_ec_compressed_point_rejected() {
let rng = rand::SystemRandom::new();
let alice = agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng).unwrap();
let mut bad = [0u8; 65];
bad[0] = 0x02; let result = agreement::agree_ephemeral(
alice,
&agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &bad),
(),
|_| Ok::<(), ()>(()),
);
assert!(result.is_err());
}
}