#![forbid(unsafe_code)]
use bergshamra_core::Error;
pub fn ecdh_p256(
originator_public: &[u8],
recipient_private: &p256::SecretKey,
) -> Result<Vec<u8>, Error> {
kryptering::keyagreement::ecdh_p256(originator_public, recipient_private)
.map_err(crate::map_kryptering_err)
}
pub fn ecdh_p384(
originator_public: &[u8],
recipient_private: &p384::SecretKey,
) -> Result<Vec<u8>, Error> {
kryptering::keyagreement::ecdh_p384(originator_public, recipient_private)
.map_err(crate::map_kryptering_err)
}
pub fn ecdh_p521(
originator_public: &[u8],
recipient_private: &p521::SecretKey,
) -> Result<Vec<u8>, Error> {
kryptering::keyagreement::ecdh_p521(originator_public, recipient_private)
.map_err(crate::map_kryptering_err)
}
pub fn ecdh_x25519(originator_public: &[u8], recipient_private: &[u8]) -> Result<Vec<u8>, Error> {
kryptering::keyagreement::ecdh_x25519(originator_public, recipient_private)
.map_err(crate::map_kryptering_err)
}
pub fn dh_compute(
other_public: &[u8],
my_private: &[u8],
p: &[u8],
q: Option<&[u8]>,
) -> Result<Vec<u8>, Error> {
kryptering::hazmat::dh::compute(other_public, my_private, p, q)
.map_err(crate::map_kryptering_err)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn x25519_roundtrip() {
let alice_secret = x25519_dalek::StaticSecret::random_from_rng(rand::thread_rng());
let alice_public = x25519_dalek::PublicKey::from(&alice_secret);
let bob_secret = x25519_dalek::StaticSecret::random_from_rng(rand::thread_rng());
let bob_public = x25519_dalek::PublicKey::from(&bob_secret);
let shared_alice = ecdh_x25519(bob_public.as_bytes(), alice_secret.as_bytes()).unwrap();
let shared_bob = ecdh_x25519(alice_public.as_bytes(), bob_secret.as_bytes()).unwrap();
assert_eq!(shared_alice, shared_bob);
assert_eq!(shared_alice.len(), 32);
}
#[test]
fn x25519_invalid_public_key_length() {
let secret = [0u8; 32];
let short_pub = [0u8; 16];
let err = ecdh_x25519(&short_pub, &secret).unwrap_err();
assert!(
err.to_string().contains("invalid X25519 public key length"),
"unexpected error: {err}"
);
}
#[test]
fn x25519_invalid_private_key_length() {
let pub_key = [0u8; 32];
let short_priv = [0u8; 16];
let err = ecdh_x25519(&pub_key, &short_priv).unwrap_err();
assert!(
err.to_string()
.contains("invalid X25519 private key length"),
"unexpected error: {err}"
);
}
#[test]
fn x25519_deterministic() {
let alice_secret = x25519_dalek::StaticSecret::random_from_rng(rand::thread_rng());
let bob_secret = x25519_dalek::StaticSecret::random_from_rng(rand::thread_rng());
let bob_public = x25519_dalek::PublicKey::from(&bob_secret);
let shared1 = ecdh_x25519(bob_public.as_bytes(), alice_secret.as_bytes()).unwrap();
let shared2 = ecdh_x25519(bob_public.as_bytes(), alice_secret.as_bytes()).unwrap();
assert_eq!(shared1, shared2);
}
}