use super::*;
use ::p256::{
elliptic_curve::{
sec1::{FromEncodedPoint, ToEncodedPoint},
Field,
},
ProjectivePoint, Scalar,
};
use rand_core::{CryptoRng, RngCore};
pub struct P256Provider {}
impl P256Provider {
pub fn new() -> Self {
Self {}
}
}
impl EcdhProvider for P256Provider {
type SecretKey = P256SecretKey;
fn generate_keypair<R>(&mut self, rng: &mut R) -> (Self::SecretKey, PublicKey)
where
R: RngCore + CryptoRng,
{
let scalar = Scalar::random(rng);
let secret = P256SecretKey { inner: scalar };
let public = ProjectivePoint::generator() * scalar;
let public = public.to_affine();
let public = public.to_encoded_point(false);
let mut public_bytes = [0; 64];
public_bytes.copy_from_slice(&public.as_bytes()[1..]);
let public = PublicKey(public_bytes);
(secret, public)
}
}
pub struct P256SecretKey {
inner: Scalar,
}
impl P256SecretKey {
#[cfg(test)]
fn from_test_data(bytes: [u8; 32]) -> Self {
Self {
inner: Scalar::from_bytes_reduced((&bytes).into()),
}
}
}
impl SecretKey for P256SecretKey {
fn agree(self, foreign_key: &PublicKey) -> Result<SharedSecret, InvalidPublicKey> {
let mut encoded = [0; 65];
encoded[0] = 0x04; encoded[1..].copy_from_slice(&foreign_key.0);
let foreign_key =
::p256::EncodedPoint::from_bytes(&encoded).map_err(|_| InvalidPublicKey::new())?;
let affine = ::p256::AffinePoint::from_encoded_point(&foreign_key);
if affine.is_none() {
return Err(InvalidPublicKey::new());
}
let mul_point = ProjectivePoint::from(affine.unwrap()) * self.inner;
let uncomp_point = ::p256::EncodedPoint::from(mul_point.to_affine());
let mut secret = [0; 32];
secret.copy_from_slice(&uncomp_point.as_bytes()[1..32 + 1]);
Ok(SharedSecret(secret))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ecdh::SecretKey;
#[test]
fn testsuite() {
crate::ecdh::run_tests(P256Provider::new());
}
#[test]
fn test_vectors() {
fn parse_into(mut slice: &mut [u8], s: &str) {
for s_word in s.split_whitespace() {
assert_eq!(s_word.len(), 8);
let target = &mut slice[..4];
for i in 0..4 {
target[i] = u8::from_str_radix(&s_word[i * 2..i * 2 + 2], 16).unwrap();
}
slice = &mut slice[4..];
}
assert!(slice.is_empty());
}
const PRIV_A: &str =
"3f49f6d4 a3c55f38 74c9b3e3 d2103f50 4aff607b eb40b799 5899b8a6 cd3c1abd";
const PUB_A_X: &str =
"20b003d2 f297be2c 5e2c83a7 e9f9a5b9 eff49111 acf4fddb cc030148 0e359de6";
const PUB_A_Y: &str =
"dc809c49 652aeb6d 63329abf 5a52155c 766345c2 8fed3024 741c8ed0 1589d28b";
const PRIV_B: &str =
"55188b3d 32f6bb9a 900afcfb eed4e72a 59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd";
const PUB_B_X: &str =
"1ea1f0f0 1faf1d96 09592284 f19e4c00 47b58afd 8615a69f 559077b2 2faaa190";
const PUB_B_Y: &str =
"4c55f33e 429dad37 7356703a 9ab85160 472d1130 e28e3676 5f89aff9 15b1214a";
const DHKEY: &str =
"ec0234a3 57c8ad05 341010a6 0a397d9b 99796b13 b4f866f1 868d34f3 73bfa698";
let mut priv_a = [0; 32];
parse_into(&mut priv_a, PRIV_A);
let key_a = P256SecretKey::from_test_data(priv_a);
let mut pub_a_bytes = [0; 64];
parse_into(&mut pub_a_bytes[..32], PUB_A_X);
parse_into(&mut pub_a_bytes[32..], PUB_A_Y);
let pub_a = PublicKey(pub_a_bytes);
let mut priv_b = [0; 32];
parse_into(&mut priv_b, PRIV_B);
let key_b = P256SecretKey::from_test_data(priv_b);
let mut pub_b_bytes = [0; 64];
parse_into(&mut pub_b_bytes[..32], PUB_B_X);
parse_into(&mut pub_b_bytes[32..], PUB_B_Y);
let pub_b = PublicKey(pub_b_bytes);
let shared_a = key_a.agree(&pub_b).unwrap();
let shared_b = key_b.agree(&pub_a).unwrap();
let mut dhkey = [0; 32];
parse_into(&mut dhkey, DHKEY);
assert_eq!(&shared_a.0, &shared_b.0);
assert_eq!(&shared_a.0, &dhkey);
}
}