This commit is contained in:
parent
6a65e43ca9
commit
5f11d476b6
17 changed files with 475 additions and 348 deletions
|
|
@ -190,24 +190,24 @@ mod tests {
|
|||
|
||||
#[cfg(all(feature = "mlkem-tls", feature = "hkdf", feature = "chacha20poly1305"))]
|
||||
#[test]
|
||||
fn encrypt_for_roundtrip() {
|
||||
fn encrypt_for_roundtrip() -> Result<(), CryptoError> {
|
||||
let kr = Keyring::generate();
|
||||
let blob = encrypt_for(
|
||||
EncryptionType::MlKemChaCha20Poly1305,
|
||||
&kr.public_key_bundle(),
|
||||
b"secret payload",
|
||||
b"aad",
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
assert_eq!(blob[0], EncryptionType::ML_KEM_CHACHA20POLY1305);
|
||||
|
||||
let pt = decrypt_with(&blob, &kr, b"aad").unwrap();
|
||||
let pt = decrypt_with(&blob, &kr, b"aad")?;
|
||||
assert_eq!(pt, b"secret payload");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "mlkem-tls", feature = "hkdf", feature = "chacha20poly1305"))]
|
||||
#[test]
|
||||
fn decrypt_with_wrong_keyring_fails() {
|
||||
fn decrypt_with_wrong_keyring_fails() -> Result<(), CryptoError> {
|
||||
let kr = Keyring::generate();
|
||||
let other = Keyring::generate();
|
||||
let blob = encrypt_for(
|
||||
|
|
@ -215,23 +215,23 @@ mod tests {
|
|||
&kr.public_key_bundle(),
|
||||
b"secret",
|
||||
b"aad",
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
assert!(decrypt_with(&blob, &other, b"aad").is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "mlkem-tls", feature = "hkdf", feature = "chacha20poly1305"))]
|
||||
#[test]
|
||||
fn decrypt_with_wrong_aad_fails() {
|
||||
fn decrypt_with_wrong_aad_fails() -> Result<(), CryptoError> {
|
||||
let kr = Keyring::generate();
|
||||
let blob = encrypt_for(
|
||||
EncryptionType::MlKemChaCha20Poly1305,
|
||||
&kr.public_key_bundle(),
|
||||
b"secret",
|
||||
b"right",
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
assert!(decrypt_with(&blob, &kr, b"wrong").is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "mlkem-tls", feature = "hkdf", feature = "chacha20poly1305"))]
|
||||
|
|
|
|||
|
|
@ -498,13 +498,14 @@ impl Keyring {
|
|||
use crate::error::CryptoError;
|
||||
let mut offset = 0;
|
||||
let read_key = |offset: &mut usize| -> Result<Vec<u8>, CryptoError> {
|
||||
let len = u16::from_be_bytes(
|
||||
bytes
|
||||
.get(*offset..*offset + 2)
|
||||
.ok_or(CryptoError::InvalidKeyLength)?
|
||||
.try_into()
|
||||
.expect("slice is 2 bytes, verified above"),
|
||||
) as usize;
|
||||
let slice = bytes
|
||||
.get(*offset..*offset + 2)
|
||||
.ok_or(CryptoError::InvalidKeyLength)?;
|
||||
let len = if let Ok(arr) = <[u8; 2]>::try_from(slice) {
|
||||
u16::from_be_bytes(arr)
|
||||
} else {
|
||||
return Err(CryptoError::InvalidKeyLength);
|
||||
} as usize;
|
||||
*offset += 2;
|
||||
let key = bytes
|
||||
.get(*offset..*offset + len)
|
||||
|
|
@ -712,14 +713,14 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn public_key_bundle_roundtrip() {
|
||||
fn public_key_bundle_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let kem = KemPublicKey::new(vec![1u8; 32]);
|
||||
let pq = SignaturePqPublicKey::new(vec![2u8; 64]);
|
||||
let cl = SignaturePublicKey::new(vec![3u8; 32]);
|
||||
|
||||
let bundle = PublicKeyBundle::new(kem, pq, cl);
|
||||
let bytes = bundle.as_bytes();
|
||||
let recovered = PublicKeyBundle::from_bytes(&bytes).unwrap();
|
||||
let recovered = PublicKeyBundle::from_bytes(&bytes)?;
|
||||
|
||||
assert_eq!(
|
||||
bundle.kem_public_key.as_bytes(),
|
||||
|
|
@ -733,22 +734,24 @@ mod tests {
|
|||
bundle.sig_cl_public_key.as_bytes(),
|
||||
recovered.sig_cl_public_key.as_bytes()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_key_bundle_try_from_roundtrip() {
|
||||
fn public_key_bundle_try_from_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let bundle = PublicKeyBundle::new(
|
||||
KemPublicKey::new(vec![0xABu8; 48]),
|
||||
SignaturePqPublicKey::new(vec![0xCDu8; 96]),
|
||||
SignaturePublicKey::new(vec![0xEFu8; 32]),
|
||||
);
|
||||
let bytes: Vec<u8> = Vec::from(&bundle);
|
||||
let recovered = PublicKeyBundle::try_from(bytes.as_slice()).unwrap();
|
||||
let recovered = PublicKeyBundle::try_from(bytes.as_slice())?;
|
||||
assert_eq!(bundle.as_bytes(), recovered.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyring_roundtrip() {
|
||||
fn keyring_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let keyring = Keyring::new(
|
||||
KemPublicKey::new(vec![1u8; 32]),
|
||||
KemPrivateKey::new(vec![2u8; 32]),
|
||||
|
|
@ -758,7 +761,7 @@ mod tests {
|
|||
SignaturePrivateKey::new(vec![6u8; 32]),
|
||||
);
|
||||
let bytes = keyring.to_bytes();
|
||||
let recovered = Keyring::from_bytes(&bytes).unwrap();
|
||||
let recovered = Keyring::from_bytes(&bytes)?;
|
||||
assert_eq!(
|
||||
keyring.kem_public_key.as_bytes(),
|
||||
recovered.kem_public_key.as_bytes()
|
||||
|
|
@ -771,10 +774,11 @@ mod tests {
|
|||
keyring.sig_cl_public_key.as_bytes(),
|
||||
recovered.sig_cl_public_key.as_bytes()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyring_try_from_roundtrip() {
|
||||
fn keyring_try_from_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let keyring = Keyring::new(
|
||||
KemPublicKey::new(vec![0u8; 16]),
|
||||
KemPrivateKey::new(vec![1u8; 16]),
|
||||
|
|
@ -784,21 +788,23 @@ mod tests {
|
|||
SignaturePrivateKey::new(vec![5u8; 16]),
|
||||
);
|
||||
let bytes: Vec<u8> = Vec::from(&keyring);
|
||||
let recovered = Keyring::try_from(bytes.as_slice()).unwrap();
|
||||
let recovered = Keyring::try_from(bytes.as_slice())?;
|
||||
assert_eq!(keyring.to_bytes(), recovered.to_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hex_roundtrip() {
|
||||
fn hex_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let key = KemPublicKey::new(vec![0xDE, 0xAD, 0xBE, 0xEF]);
|
||||
let hex = key.to_hex();
|
||||
assert_eq!(hex, "deadbeef");
|
||||
let recovered = KemPublicKey::from_hex(&hex).unwrap();
|
||||
let recovered = KemPublicKey::from_hex(&hex)?;
|
||||
assert_eq!(key.as_bytes(), recovered.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyring_hex_roundtrip() {
|
||||
fn keyring_hex_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let keyring = Keyring::new(
|
||||
KemPublicKey::new(vec![1u8; 16]),
|
||||
KemPrivateKey::new(vec![2u8; 16]),
|
||||
|
|
@ -808,12 +814,13 @@ mod tests {
|
|||
SignaturePrivateKey::new(vec![6u8; 16]),
|
||||
);
|
||||
let hex = keyring.to_hex();
|
||||
let recovered = Keyring::from_hex(&hex).unwrap();
|
||||
let recovered = Keyring::from_hex(&hex)?;
|
||||
assert_eq!(keyring.to_bytes(), recovered.to_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyring_base64_roundtrip() {
|
||||
fn keyring_base64_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let keyring = Keyring::new(
|
||||
KemPublicKey::new(vec![1u8; 16]),
|
||||
KemPrivateKey::new(vec![2u8; 16]),
|
||||
|
|
@ -823,20 +830,22 @@ mod tests {
|
|||
SignaturePrivateKey::new(vec![6u8; 16]),
|
||||
);
|
||||
let b64 = keyring.to_base64();
|
||||
let recovered = Keyring::from_base64(&b64).unwrap();
|
||||
let recovered = Keyring::from_base64(&b64)?;
|
||||
assert_eq!(keyring.to_bytes(), recovered.to_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_key_bundle_base64_roundtrip() {
|
||||
fn public_key_bundle_base64_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let bundle = PublicKeyBundle::new(
|
||||
KemPublicKey::new(vec![1u8; 32]),
|
||||
SignaturePqPublicKey::new(vec![2u8; 64]),
|
||||
SignaturePublicKey::new(vec![3u8; 32]),
|
||||
);
|
||||
let b64 = bundle.to_base64();
|
||||
let recovered = PublicKeyBundle::from_base64(&b64).unwrap();
|
||||
let recovered = PublicKeyBundle::from_base64(&b64)?;
|
||||
assert_eq!(bundle.as_bytes(), recovered.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -69,13 +69,14 @@ mod tests {
|
|||
|
||||
#[cfg(feature = "chacha20poly1305")]
|
||||
#[test]
|
||||
fn aead_encrypt_decrypt() {
|
||||
fn aead_encrypt_decrypt() -> Result<(), CryptoError> {
|
||||
use crate::aead::{AeadDecrypt, AeadEncrypt, ChaCha20Poly1305};
|
||||
let key = [0xAB; 32];
|
||||
let cipher = ChaCha20Poly1305::new(key);
|
||||
let ct = cipher.encrypt(b"hello world", b"aad").unwrap();
|
||||
let pt = cipher.decrypt(&ct, b"aad").unwrap();
|
||||
let ct = cipher.encrypt(b"hello world", b"aad")?;
|
||||
let pt = cipher.decrypt(&ct, b"aad")?;
|
||||
assert_eq!(pt, b"hello world");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "chacha20poly1305")]
|
||||
|
|
@ -84,7 +85,7 @@ mod tests {
|
|||
use crate::aead::{AeadDecrypt, AeadEncrypt, ChaCha20Poly1305};
|
||||
let cipher_a = ChaCha20Poly1305::new([0xAB; 32]);
|
||||
let cipher_b = ChaCha20Poly1305::new([0xCD; 32]);
|
||||
let ct = cipher_a.encrypt(b"hello", b"").unwrap();
|
||||
let ct = cipher_a.encrypt(b"hello", b"").expect("encryption should succeed");
|
||||
assert!(cipher_b.decrypt(&ct, b"").is_err());
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +94,9 @@ mod tests {
|
|||
fn aead_wrong_aad_fails() {
|
||||
use crate::aead::{AeadDecrypt, AeadEncrypt, ChaCha20Poly1305};
|
||||
let cipher = ChaCha20Poly1305::new([0xAB; 32]);
|
||||
let ct = cipher.encrypt(b"hello", b"correct-aad").unwrap();
|
||||
let ct = cipher
|
||||
.encrypt(b"hello", b"correct-aad")
|
||||
.expect("encryption should succeed");
|
||||
assert!(cipher.decrypt(&ct, b"wrong-aad").is_err());
|
||||
}
|
||||
|
||||
|
|
@ -102,12 +105,12 @@ mod tests {
|
|||
fn ed25519_sign_verify() {
|
||||
let (signer, sk, pk) = Ed25519Signer::generate();
|
||||
let msg = b"test message";
|
||||
let sig = signer.sign(msg).unwrap();
|
||||
signer.verify(msg, &sig).unwrap();
|
||||
verify_ed25519(&pk, msg, &sig).unwrap();
|
||||
let sig = signer.sign(msg).expect("signing should succeed");
|
||||
signer.verify(msg, &sig).expect("verification should succeed");
|
||||
verify_ed25519(&pk, msg, &sig).expect("verification should succeed");
|
||||
|
||||
let loaded = Ed25519Signer::new(&sk).unwrap();
|
||||
loaded.verify(msg, &sig).unwrap();
|
||||
let loaded = Ed25519Signer::new(&sk).expect("signer loading should succeed");
|
||||
loaded.verify(msg, &sig).expect("verification should succeed");
|
||||
}
|
||||
|
||||
#[cfg(feature = "ed25519-dalek")]
|
||||
|
|
@ -115,7 +118,7 @@ mod tests {
|
|||
fn ed25519_wrong_sig_fails() {
|
||||
let (signer, _, pk) = Ed25519Signer::generate();
|
||||
let msg = b"test message";
|
||||
let sig = signer.sign(msg).unwrap();
|
||||
let sig = signer.sign(msg).expect("signing should succeed");
|
||||
assert!(verify_ed25519(&pk, b"wrong message", &sig).is_err());
|
||||
}
|
||||
|
||||
|
|
@ -124,12 +127,12 @@ mod tests {
|
|||
fn mldsa_sign_verify() {
|
||||
let (signer, sk, pk) = MlDsaSigner::generate();
|
||||
let msg = b"test message";
|
||||
let sig = signer.sign(msg).unwrap();
|
||||
signer.verify(msg, &sig).unwrap();
|
||||
verify_ml_dsa(&pk, msg, &sig).unwrap();
|
||||
let sig = signer.sign(msg).expect("signing should succeed");
|
||||
signer.verify(msg, &sig).expect("verification should succeed");
|
||||
verify_ml_dsa(&pk, msg, &sig).expect("verification should succeed");
|
||||
|
||||
let loaded = MlDsaSigner::new(&sk, &pk).unwrap();
|
||||
loaded.verify(msg, &sig).unwrap();
|
||||
let loaded = MlDsaSigner::new(&sk, &pk).expect("signer loading should succeed");
|
||||
loaded.verify(msg, &sig).expect("verification should succeed");
|
||||
}
|
||||
|
||||
#[cfg(feature = "ml-dsa")]
|
||||
|
|
@ -137,7 +140,7 @@ mod tests {
|
|||
fn mldsa_wrong_sig_fails() {
|
||||
let (signer, _, pk) = MlDsaSigner::generate();
|
||||
let msg = b"test message";
|
||||
let sig = signer.sign(msg).unwrap();
|
||||
let sig = signer.sign(msg).expect("signing should succeed");
|
||||
assert!(verify_ml_dsa(&pk, b"wrong message", &sig).is_err());
|
||||
}
|
||||
|
||||
|
|
@ -148,9 +151,10 @@ mod tests {
|
|||
|
||||
let (ed_signer, _, _) = Ed25519Signer::generate();
|
||||
let (ml_signer, _, _) = MlDsaSigner::generate();
|
||||
let dual = sign_dual(ed_signer.signing_key(), ml_signer.signing_key(), b"msg").unwrap();
|
||||
let dual = sign_dual(ed_signer.signing_key(), ml_signer.signing_key(), b"msg")
|
||||
.expect("dual signing should succeed");
|
||||
dual.verify(ed_signer.verifying_key(), ml_signer.verifying_key(), b"msg")
|
||||
.unwrap();
|
||||
.expect("dual verification should succeed");
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "ed25519-dalek", feature = "ml-dsa"))]
|
||||
|
|
@ -160,7 +164,8 @@ mod tests {
|
|||
|
||||
let (ed_signer, _, _) = Ed25519Signer::generate();
|
||||
let (ml_signer, _, _) = MlDsaSigner::generate();
|
||||
let dual = sign_dual(ed_signer.signing_key(), ml_signer.signing_key(), b"msg").unwrap();
|
||||
let dual = sign_dual(ed_signer.signing_key(), ml_signer.signing_key(), b"msg")
|
||||
.expect("dual signing should succeed");
|
||||
assert!(
|
||||
dual.verify(
|
||||
ed_signer.verifying_key(),
|
||||
|
|
@ -174,18 +179,22 @@ mod tests {
|
|||
#[cfg(feature = "hkdf")]
|
||||
#[test]
|
||||
fn hkdf_expand_produces_key() {
|
||||
let key = derive_encryption_key(b"ikm", b"salt", b"context").unwrap();
|
||||
let key = derive_encryption_key(b"ikm", b"salt", b"context")
|
||||
.expect("key derivation should succeed");
|
||||
assert_eq!(key.len(), 32);
|
||||
|
||||
let expanded = hkdf_expand(b"ikm", b"salt", b"info", 64).unwrap();
|
||||
let expanded = hkdf_expand(b"ikm", b"salt", b"info", 64)
|
||||
.expect("HKDF expansion should succeed");
|
||||
assert_eq!(expanded.len(), 64);
|
||||
}
|
||||
|
||||
#[cfg(feature = "hkdf")]
|
||||
#[test]
|
||||
fn hkdf_different_info_different_key() {
|
||||
let a = derive_encryption_key(b"ikm", b"salt", b"info-a").unwrap();
|
||||
let b = derive_encryption_key(b"ikm", b"salt", b"info-b").unwrap();
|
||||
let a = derive_encryption_key(b"ikm", b"salt", b"info-a")
|
||||
.expect("key derivation should succeed");
|
||||
let b = derive_encryption_key(b"ikm", b"salt", b"info-b")
|
||||
.expect("key derivation should succeed");
|
||||
assert_ne!(a, b);
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +264,7 @@ mod tests {
|
|||
fn keyring_serialize_roundtrip() {
|
||||
let kr = Keyring::generate();
|
||||
let bytes = kr.to_bytes();
|
||||
let loaded = Keyring::from_bytes(&bytes).unwrap();
|
||||
let loaded = Keyring::from_bytes(&bytes).expect("keyring roundtrip should succeed");
|
||||
assert_eq!(
|
||||
kr.kem_public_key.as_bytes(),
|
||||
loaded.kem_public_key.as_bytes()
|
||||
|
|
@ -276,7 +285,8 @@ mod tests {
|
|||
let kr = Keyring::generate();
|
||||
let bundle = kr.public_key_bundle();
|
||||
let bytes = bundle.as_bytes();
|
||||
let loaded = PublicKeyBundle::from_bytes(&bytes).unwrap();
|
||||
let loaded =
|
||||
PublicKeyBundle::from_bytes(&bytes).expect("bundle roundtrip should succeed");
|
||||
assert_eq!(
|
||||
bundle.kem_public_key.as_bytes(),
|
||||
loaded.kem_public_key.as_bytes()
|
||||
|
|
@ -295,8 +305,8 @@ mod tests {
|
|||
#[test]
|
||||
fn hybrid_kem_roundtrip() {
|
||||
let (sk, pk) = HybridKem::generate_keypair();
|
||||
let enc = HybridKem::encapsulate(&pk).unwrap();
|
||||
let ss = HybridKem::decapsulate(&sk, &enc.ciphertext).unwrap();
|
||||
let enc = HybridKem::encapsulate(&pk).expect("encapsulation should succeed");
|
||||
let ss = HybridKem::decapsulate(&sk, &enc.ciphertext).expect("decapsulation should succeed");
|
||||
assert_eq!(enc.shared_secret, ss);
|
||||
}
|
||||
|
||||
|
|
@ -309,8 +319,8 @@ mod tests {
|
|||
let kr = Keyring::generate();
|
||||
let entities = vec![kr.public_key_bundle()];
|
||||
let msg = b"secret data";
|
||||
let ct = encrypt_multi(msg, b"aad", &entities).unwrap();
|
||||
let pt = decrypt_multi(&ct, b"aad", &kr).unwrap();
|
||||
let ct = encrypt_multi(msg, b"aad", &entities).expect("multi encrypt should succeed");
|
||||
let pt = decrypt_multi(&ct, b"aad", &kr).expect("multi decrypt should succeed");
|
||||
assert_eq!(pt, msg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue