2020-06-05 09:35:14 -07:00
|
|
|
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
|
//
|
|
|
|
|
// This source code is licensed under the MIT license found in the
|
|
|
|
|
// LICENSE file in the root directory of this source tree.
|
|
|
|
|
|
|
|
|
|
//! Contains the keypair types that must be supplied for the OPAQUE API
|
|
|
|
|
|
2021-06-04 16:29:58 -07:00
|
|
|
#![allow(unsafe_code)]
|
|
|
|
|
|
2021-08-22 12:28:19 -07:00
|
|
|
use crate::errors::{InternalError, ProtocolError};
|
2021-10-25 02:54:32 -07:00
|
|
|
use crate::key_exchange::group::KeGroup;
|
2021-08-12 06:25:07 +02:00
|
|
|
use alloc::vec::Vec;
|
|
|
|
|
use core::fmt::Debug;
|
|
|
|
|
use core::ops::Deref;
|
2021-06-04 16:29:58 -07:00
|
|
|
use generic_array::typenum::Unsigned;
|
2021-07-06 13:27:13 +02:00
|
|
|
use generic_array::{ArrayLength, GenericArray};
|
2021-02-11 18:10:48 -08:00
|
|
|
use rand::{CryptoRng, RngCore};
|
2021-04-29 16:22:23 -05:00
|
|
|
use zeroize::Zeroize;
|
2020-06-05 09:35:14 -07:00
|
|
|
|
|
|
|
|
/// A Keypair trait with public-private verification
|
2021-07-06 14:17:44 +02:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serialize",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
2021-07-16 13:54:10 +02:00
|
|
|
serde(bound(
|
|
|
|
|
deserialize = "S: serde::Deserialize<'de>",
|
|
|
|
|
serialize = "S: serde::Serialize"
|
|
|
|
|
))
|
2021-07-06 14:17:44 +02:00
|
|
|
)]
|
2021-10-25 02:54:32 -07:00
|
|
|
pub struct KeyPair<KG: KeGroup, S: SecretKey<KG> = PrivateKey<KG>> {
|
|
|
|
|
pk: PublicKey<KG>,
|
2021-07-16 13:54:10 +02:00
|
|
|
sk: S,
|
2021-01-25 13:20:36 -08:00
|
|
|
}
|
2020-06-05 09:35:14 -07:00
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup, S: SecretKey<KG>> Clone for KeyPair<KG, S> {
|
2021-07-16 13:54:10 +02:00
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
pk: self.pk.clone(),
|
|
|
|
|
sk: self.sk.clone(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup, S: SecretKey<KG> + Debug> Debug for KeyPair<KG, S> {
|
2021-08-12 06:25:07 +02:00
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
2021-07-16 13:54:10 +02:00
|
|
|
f.debug_struct("KeyPair")
|
|
|
|
|
.field("pk", &self.pk)
|
|
|
|
|
.field("sk", &self.sk)
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup, S: SecretKey<KG> + PartialEq> PartialEq for KeyPair<KG, S> {
|
2021-07-16 13:54:10 +02:00
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
|
self.pk.eq(&other.pk) && self.sk.eq(&other.sk)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup, S: SecretKey<KG> + Eq> Eq for KeyPair<KG, S> {}
|
2021-07-16 13:54:10 +02:00
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup, S: SecretKey<KG> + core::hash::Hash> core::hash::Hash for KeyPair<KG, S> {
|
2021-08-12 06:25:07 +02:00
|
|
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
2021-07-16 13:54:10 +02:00
|
|
|
self.pk.hash(state);
|
|
|
|
|
self.sk.hash(state);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-22 15:48:36 +02:00
|
|
|
|
2021-07-07 13:31:47 +02:00
|
|
|
// This can't be derived because of the use of a generic parameter
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup, S: SecretKey<KG>> Zeroize for KeyPair<KG, S> {
|
2021-06-04 16:29:58 -07:00
|
|
|
fn zeroize(&mut self) {
|
|
|
|
|
self.pk.zeroize();
|
|
|
|
|
self.sk.zeroize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup, S: SecretKey<KG>> Drop for KeyPair<KG, S> {
|
2021-06-04 16:29:58 -07:00
|
|
|
fn drop(&mut self) {
|
|
|
|
|
self.zeroize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup, S: SecretKey<KG>> KeyPair<KG, S> {
|
2020-06-05 09:35:14 -07:00
|
|
|
/// The public key component
|
2021-10-25 02:54:32 -07:00
|
|
|
pub fn public(&self) -> &PublicKey<KG> {
|
2021-01-25 13:20:36 -08:00
|
|
|
&self.pk
|
|
|
|
|
}
|
2020-06-05 09:35:14 -07:00
|
|
|
|
|
|
|
|
/// The private key component
|
2021-07-16 13:54:10 +02:00
|
|
|
pub fn private(&self) -> &S {
|
2021-01-25 13:20:36 -08:00
|
|
|
&self.sk
|
|
|
|
|
}
|
2020-06-05 09:35:14 -07:00
|
|
|
|
|
|
|
|
/// Check whether a public key is valid. This is meant to be applied on
|
|
|
|
|
/// material provided through the network which fits the key
|
|
|
|
|
/// representation (i.e. can be mapped to a curve point), but presents
|
|
|
|
|
/// some risk - e.g. small subgroup check
|
2021-10-25 02:54:32 -07:00
|
|
|
pub(crate) fn check_public_key(key: PublicKey<KG>) -> Result<PublicKey<KG>, InternalError> {
|
|
|
|
|
KG::from_pk_slice(GenericArray::from_slice(&key.0)).map(|_| key)
|
2021-01-25 13:20:36 -08:00
|
|
|
}
|
2020-06-05 09:35:14 -07:00
|
|
|
|
2021-01-15 15:36:37 -08:00
|
|
|
/// Obtains a KeyPair from a slice representing the private key
|
2021-07-20 11:49:37 +02:00
|
|
|
pub fn from_private_key_slice(input: &[u8]) -> Result<Self, ProtocolError<S::Error>> {
|
2021-07-20 14:16:53 +02:00
|
|
|
Self::from_private_key(S::deserialize(input)?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Obtains a KeyPair from a private key
|
|
|
|
|
pub fn from_private_key(sk: S) -> Result<Self, ProtocolError<S::Error>> {
|
2021-07-16 13:54:10 +02:00
|
|
|
let pk = sk.public_key()?;
|
2021-07-06 14:17:44 +02:00
|
|
|
Ok(Self { pk, sk })
|
2021-01-15 15:36:37 -08:00
|
|
|
}
|
2021-07-16 13:54:10 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> KeyPair<KG> {
|
2021-07-16 13:54:10 +02:00
|
|
|
/// Generating a random key pair given a cryptographic rng
|
2021-10-25 02:54:32 -07:00
|
|
|
pub(crate) fn generate_random<R: RngCore + CryptoRng>(
|
|
|
|
|
rng: &mut R,
|
|
|
|
|
) -> Result<Self, InternalError> {
|
|
|
|
|
let sk = KG::random_sk(rng);
|
|
|
|
|
let pk = KG::public_key(&sk);
|
|
|
|
|
Ok(Self {
|
2021-07-16 13:54:10 +02:00
|
|
|
pk: PublicKey(Key(pk.to_arr())),
|
2021-10-25 02:54:32 -07:00
|
|
|
sk: PrivateKey(Key(sk)),
|
|
|
|
|
})
|
2021-06-04 16:29:58 -07:00
|
|
|
}
|
2020-06-19 11:08:29 -04:00
|
|
|
}
|
2020-06-12 17:45:39 -04:00
|
|
|
|
2021-08-17 05:11:53 +02:00
|
|
|
#[cfg(test)]
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup + Debug> KeyPair<KG> {
|
2020-06-12 17:45:39 -04:00
|
|
|
/// Test-only strategy returning a proptest Strategy based on
|
|
|
|
|
/// generate_random
|
2021-08-17 05:11:53 +02:00
|
|
|
fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy<Self> {
|
|
|
|
|
use proptest::prelude::*;
|
|
|
|
|
use rand::{rngs::StdRng, SeedableRng};
|
|
|
|
|
|
2020-06-12 17:45:39 -04:00
|
|
|
// The no_shrink is because keypairs should be fixed -- shrinking would cause a different
|
|
|
|
|
// keypair to be generated, which appears to not be very useful.
|
|
|
|
|
any::<[u8; 32]>()
|
|
|
|
|
.prop_filter_map("valid random keypair", |seed| {
|
|
|
|
|
let mut rng = StdRng::from_seed(seed);
|
2021-10-25 02:54:32 -07:00
|
|
|
Some(Self::generate_random(&mut rng).unwrap())
|
2020-06-12 17:45:39 -04:00
|
|
|
})
|
|
|
|
|
.no_shrink()
|
|
|
|
|
.boxed()
|
|
|
|
|
}
|
2020-06-05 09:35:14 -07:00
|
|
|
}
|
|
|
|
|
|
2021-02-11 18:10:48 -08:00
|
|
|
/// A minimalist key type built around a \[u8; 32\]
|
2021-07-07 13:28:31 +02:00
|
|
|
#[cfg_attr(
|
|
|
|
|
feature = "serialize",
|
|
|
|
|
derive(serde::Deserialize, serde::Serialize),
|
|
|
|
|
serde(bound = "")
|
|
|
|
|
)]
|
2020-06-05 09:35:14 -07:00
|
|
|
#[repr(transparent)]
|
2021-07-07 13:28:31 +02:00
|
|
|
pub struct Key<L: ArrayLength<u8>>(GenericArray<u8, L>);
|
|
|
|
|
|
|
|
|
|
impl<L: ArrayLength<u8>> Clone for Key<L> {
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Self(self.0.clone())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<L: ArrayLength<u8>> Debug for Key<L> {
|
2021-08-12 06:25:07 +02:00
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
2021-07-07 13:28:31 +02:00
|
|
|
f.debug_tuple("Key").field(&self.0).finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<L: ArrayLength<u8>> Eq for Key<L> {}
|
|
|
|
|
|
|
|
|
|
impl<L: ArrayLength<u8>> PartialEq for Key<L> {
|
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
|
self.0.eq(&other.0)
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-05 09:35:14 -07:00
|
|
|
|
2021-08-12 06:25:07 +02:00
|
|
|
impl<L: ArrayLength<u8>> core::hash::Hash for Key<L> {
|
|
|
|
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
2021-07-07 13:28:31 +02:00
|
|
|
self.0.hash(state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This can't be derived because of the use of a generic parameter
|
|
|
|
|
impl<L: ArrayLength<u8>> Zeroize for Key<L> {
|
|
|
|
|
fn zeroize(&mut self) {
|
|
|
|
|
self.0.zeroize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<L: ArrayLength<u8>> Drop for Key<L> {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
self.zeroize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<L: ArrayLength<u8>> Deref for Key<L> {
|
|
|
|
|
type Target = GenericArray<u8, L>;
|
2020-06-05 09:35:14 -07:00
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
|
&self.0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 10:48:29 +02:00
|
|
|
// Don't make it implement SizedBytes so that it's not constructible outside of this module.
|
2021-07-07 13:28:31 +02:00
|
|
|
impl<L: ArrayLength<u8>> Key<L> {
|
2021-08-17 05:11:53 +02:00
|
|
|
/// Convert to bytes
|
|
|
|
|
pub fn to_arr(&self) -> GenericArray<u8, L> {
|
|
|
|
|
self.0.clone()
|
2021-06-15 10:48:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Wrapper around a Key to enforce that it's a private one.
|
2021-06-22 15:48:36 +02:00
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
|
2021-06-15 10:48:29 +02:00
|
|
|
#[repr(transparent)]
|
2021-10-25 02:54:32 -07:00
|
|
|
pub struct PrivateKey<KG: KeGroup>(Key<KG::SkLen>);
|
2021-07-06 13:27:13 +02:00
|
|
|
|
|
|
|
|
impl_clone_for!(
|
2021-10-25 02:54:32 -07:00
|
|
|
tuple PrivateKey<KG: KeGroup>,
|
2021-07-07 13:28:31 +02:00
|
|
|
[0],
|
2021-07-06 13:27:13 +02:00
|
|
|
);
|
|
|
|
|
impl_debug_eq_hash_for!(
|
2021-10-25 02:54:32 -07:00
|
|
|
tuple PrivateKey<KG: KeGroup>,
|
2021-07-07 13:28:31 +02:00
|
|
|
[0],
|
2021-07-06 13:27:13 +02:00
|
|
|
);
|
2021-06-15 10:48:29 +02:00
|
|
|
|
2021-07-07 13:31:47 +02:00
|
|
|
// This can't be derived because of the use of a generic parameter
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> Zeroize for PrivateKey<KG> {
|
2021-07-06 13:27:13 +02:00
|
|
|
fn zeroize(&mut self) {
|
2021-07-07 13:28:31 +02:00
|
|
|
self.0.zeroize();
|
2021-07-06 13:27:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> Drop for PrivateKey<KG> {
|
2021-07-06 13:27:13 +02:00
|
|
|
fn drop(&mut self) {
|
|
|
|
|
self.zeroize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> Deref for PrivateKey<KG> {
|
|
|
|
|
type Target = Key<KG::SkLen>;
|
2021-06-15 10:48:29 +02:00
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
2021-07-07 13:28:31 +02:00
|
|
|
&self.0
|
2021-07-06 13:27:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> PrivateKey<KG> {
|
2021-08-17 05:11:53 +02:00
|
|
|
/// Convert from bytes
|
2021-10-25 02:54:32 -07:00
|
|
|
pub fn from_arr(key_bytes: GenericArray<u8, KG::SkLen>) -> Self {
|
2021-08-17 05:11:53 +02:00
|
|
|
PrivateKey(Key(key_bytes))
|
2020-06-05 09:35:14 -07:00
|
|
|
}
|
|
|
|
|
|
2021-08-17 05:11:53 +02:00
|
|
|
/// Convert from slice
|
2021-08-22 12:28:19 -07:00
|
|
|
pub fn from_bytes(key_bytes: &[u8]) -> Result<Self, InternalError> {
|
2021-10-25 02:54:32 -07:00
|
|
|
if key_bytes.len() == KG::SkLen::USIZE {
|
2021-08-17 05:11:53 +02:00
|
|
|
Ok(Self::from_arr(GenericArray::from_slice(key_bytes).clone()))
|
|
|
|
|
} else {
|
2021-08-22 12:28:19 -07:00
|
|
|
Err(InternalError::InvalidByteSequence)
|
2021-08-17 05:11:53 +02:00
|
|
|
}
|
2021-06-15 10:48:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 13:54:10 +02:00
|
|
|
/// A trait specifying the requirements for a private key container
|
2021-10-25 02:54:32 -07:00
|
|
|
pub trait SecretKey<KG: KeGroup>: Clone + Sized + Zeroize {
|
2021-08-22 12:28:19 -07:00
|
|
|
/// Custom error type that can be passed down to `InternalError::Custom`
|
2021-07-20 11:49:37 +02:00
|
|
|
type Error;
|
|
|
|
|
|
2021-07-16 13:54:10 +02:00
|
|
|
/// Diffie-Hellman key exchange implementation
|
2021-10-25 02:54:32 -07:00
|
|
|
fn diffie_hellman(&self, pk: PublicKey<KG>) -> Result<Vec<u8>, InternalError<Self::Error>>;
|
2021-07-16 13:54:10 +02:00
|
|
|
|
|
|
|
|
/// Returns public key from private key
|
2021-10-25 02:54:32 -07:00
|
|
|
fn public_key(&self) -> Result<PublicKey<KG>, InternalError<Self::Error>>;
|
2021-07-16 13:54:10 +02:00
|
|
|
|
|
|
|
|
/// Serialization into bytes
|
|
|
|
|
fn serialize(&self) -> Vec<u8>;
|
|
|
|
|
|
|
|
|
|
/// Deserialization from bytes
|
2021-08-22 12:28:19 -07:00
|
|
|
fn deserialize(input: &[u8]) -> Result<Self, InternalError<Self::Error>>;
|
2021-07-16 13:54:10 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> SecretKey<KG> for PrivateKey<KG> {
|
2021-08-12 06:25:07 +02:00
|
|
|
type Error = core::convert::Infallible;
|
2021-07-20 11:49:37 +02:00
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
fn diffie_hellman(&self, pk: PublicKey<KG>) -> Result<Vec<u8>, InternalError> {
|
|
|
|
|
let pk = KG::from_pk_slice(&pk)?;
|
|
|
|
|
Ok(pk.diffie_hellman(self).to_vec())
|
2021-07-16 13:54:10 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
fn public_key(&self) -> Result<PublicKey<KG>, InternalError> {
|
|
|
|
|
Ok(PublicKey(Key(KG::public_key(&self.0).to_arr())))
|
2021-07-16 13:54:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn serialize(&self) -> Vec<u8> {
|
|
|
|
|
self.to_vec()
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-22 12:28:19 -07:00
|
|
|
fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
|
|
|
|
|
PrivateKey::from_bytes(input).map_err(InternalError::from)
|
2021-07-16 13:54:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 10:48:29 +02:00
|
|
|
/// Wrapper around a Key to enforce that it's a public one.
|
2021-06-22 15:48:36 +02:00
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
|
2021-06-15 10:48:29 +02:00
|
|
|
#[repr(transparent)]
|
2021-10-25 02:54:32 -07:00
|
|
|
pub struct PublicKey<KG: KeGroup>(Key<KG::PkLen>);
|
2021-06-15 10:48:29 +02:00
|
|
|
|
2021-07-06 13:27:13 +02:00
|
|
|
impl_clone_for!(
|
2021-10-25 02:54:32 -07:00
|
|
|
tuple PublicKey<KG: KeGroup>,
|
2021-07-07 13:28:31 +02:00
|
|
|
[0],
|
2021-07-06 13:27:13 +02:00
|
|
|
);
|
|
|
|
|
impl_debug_eq_hash_for!(
|
2021-10-25 02:54:32 -07:00
|
|
|
tuple PublicKey<KG: KeGroup>,
|
2021-07-07 13:28:31 +02:00
|
|
|
[0],
|
2021-07-06 13:27:13 +02:00
|
|
|
);
|
|
|
|
|
|
2021-07-07 13:28:31 +02:00
|
|
|
// This can't be derived because of the use of a generic parameter
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> Zeroize for PublicKey<KG> {
|
2021-07-06 13:27:13 +02:00
|
|
|
fn zeroize(&mut self) {
|
2021-07-07 13:28:31 +02:00
|
|
|
self.0.zeroize();
|
2021-07-06 13:27:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> Drop for PublicKey<KG> {
|
2021-07-06 13:27:13 +02:00
|
|
|
fn drop(&mut self) {
|
|
|
|
|
self.zeroize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> Deref for PublicKey<KG> {
|
|
|
|
|
type Target = Key<KG::PkLen>;
|
2021-06-15 10:48:29 +02:00
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
2021-07-07 13:28:31 +02:00
|
|
|
&self.0
|
2021-06-15 10:48:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
impl<KG: KeGroup> PublicKey<KG> {
|
2021-08-17 05:11:53 +02:00
|
|
|
/// Convert from bytes
|
2021-10-25 02:54:32 -07:00
|
|
|
pub fn from_arr(key_bytes: GenericArray<u8, KG::PkLen>) -> Self {
|
2021-08-17 05:11:53 +02:00
|
|
|
Self(Key(key_bytes))
|
2021-06-15 10:48:29 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-17 05:11:53 +02:00
|
|
|
/// Convert from slice
|
2021-08-22 12:28:19 -07:00
|
|
|
pub fn from_bytes(key_bytes: &[u8]) -> Result<Self, InternalError> {
|
2021-10-25 02:54:32 -07:00
|
|
|
if key_bytes.len() == KG::PkLen::USIZE {
|
2021-08-17 05:11:53 +02:00
|
|
|
Ok(Self::from_arr(GenericArray::from_slice(key_bytes).clone()))
|
|
|
|
|
} else {
|
2021-08-22 12:28:19 -07:00
|
|
|
Err(InternalError::InvalidByteSequence)
|
2021-08-17 05:11:53 +02:00
|
|
|
}
|
2020-06-05 09:35:14 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-12 17:45:39 -04:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2021-06-04 16:29:58 -07:00
|
|
|
use crate::errors::*;
|
2021-08-12 06:25:07 +02:00
|
|
|
use core::slice::from_raw_parts;
|
2021-01-25 13:20:36 -08:00
|
|
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
2021-06-04 16:29:58 -07:00
|
|
|
use generic_array::typenum::Unsigned;
|
2021-08-17 05:11:53 +02:00
|
|
|
use proptest::prelude::*;
|
2021-06-04 16:29:58 -07:00
|
|
|
use rand::rngs::OsRng;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_zeroize_key() -> Result<(), ProtocolError> {
|
2021-10-25 02:54:32 -07:00
|
|
|
let key_len = <RistrettoPoint as KeGroup>::PkLen::USIZE;
|
|
|
|
|
let mut key = Key::<<RistrettoPoint as KeGroup>::PkLen>(GenericArray::clone_from_slice(
|
2021-08-12 06:25:07 +02:00
|
|
|
&alloc::vec![
|
2021-07-07 13:28:31 +02:00
|
|
|
1u8;
|
|
|
|
|
key_len
|
2021-08-12 06:25:07 +02:00
|
|
|
],
|
|
|
|
|
));
|
2021-06-04 16:29:58 -07:00
|
|
|
let ptr = key.as_ptr();
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
Zeroize::zeroize(&mut key);
|
2021-06-04 16:29:58 -07:00
|
|
|
|
|
|
|
|
let bytes = unsafe { from_raw_parts(ptr, key_len) };
|
|
|
|
|
assert!(bytes.iter().all(|&x| x == 0));
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_zeroize_keypair() -> Result<(), ProtocolError> {
|
|
|
|
|
let mut rng = OsRng;
|
2021-10-25 02:54:32 -07:00
|
|
|
let mut keypair = KeyPair::<RistrettoPoint>::generate_random(&mut rng)?;
|
|
|
|
|
let pk_ptr = keypair.pk.as_ptr();
|
|
|
|
|
let sk_ptr = keypair.sk.as_ptr();
|
|
|
|
|
let pk_len = <RistrettoPoint as KeGroup>::PkLen::USIZE;
|
|
|
|
|
let sk_len = <RistrettoPoint as KeGroup>::SkLen::USIZE;
|
2021-06-04 16:29:58 -07:00
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
Zeroize::zeroize(&mut keypair);
|
2021-06-04 16:29:58 -07:00
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
let pk_bytes = unsafe { from_raw_parts(pk_ptr, pk_len) };
|
|
|
|
|
let sk_bytes = unsafe { from_raw_parts(sk_ptr, sk_len) };
|
|
|
|
|
|
|
|
|
|
assert!(pk_bytes.iter().all(|&x| x == 0));
|
|
|
|
|
assert!(sk_bytes.iter().all(|&x| x == 0));
|
2021-06-04 16:29:58 -07:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2020-06-12 18:16:02 -04:00
|
|
|
|
|
|
|
|
proptest! {
|
|
|
|
|
#[test]
|
2021-01-25 13:20:36 -08:00
|
|
|
fn test_ristretto_check(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
|
2020-06-12 18:16:02 -04:00
|
|
|
let pk = kp.public();
|
2021-01-25 13:20:36 -08:00
|
|
|
prop_assert!(KeyPair::<RistrettoPoint>::check_public_key(pk.clone()).is_ok());
|
2020-06-12 18:16:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2021-01-25 13:20:36 -08:00
|
|
|
fn test_ristretto_pub_from_priv(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
|
2020-06-12 18:16:02 -04:00
|
|
|
let pk = kp.public();
|
|
|
|
|
let sk = kp.private();
|
2021-07-16 13:54:10 +02:00
|
|
|
prop_assert_eq!(&sk.public_key()?, pk);
|
2020-06-12 18:16:02 -04:00
|
|
|
}
|
|
|
|
|
|
2020-06-12 18:46:08 -04:00
|
|
|
#[test]
|
2021-01-25 13:20:36 -08:00
|
|
|
fn test_ristretto_dh(kp1 in KeyPair::<RistrettoPoint>::uniform_keypair_strategy(),
|
|
|
|
|
kp2 in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
|
2020-06-12 18:46:08 -04:00
|
|
|
|
2021-07-16 13:54:10 +02:00
|
|
|
let dh1 = kp2.private().diffie_hellman(kp1.public().clone())?;
|
|
|
|
|
let dh2 = kp1.private().diffie_hellman(kp2.public().clone())?;
|
2020-06-12 18:46:08 -04:00
|
|
|
|
2021-01-25 13:20:36 -08:00
|
|
|
prop_assert_eq!(dh1, dh2);
|
2020-06-12 18:46:08 -04:00
|
|
|
}
|
2021-01-15 15:36:37 -08:00
|
|
|
|
|
|
|
|
#[test]
|
2021-01-25 13:20:36 -08:00
|
|
|
fn test_private_key_slice(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
|
2021-01-15 15:36:37 -08:00
|
|
|
let sk_bytes = kp.private().to_vec();
|
|
|
|
|
|
2021-01-25 13:20:36 -08:00
|
|
|
let kp2 = KeyPair::<RistrettoPoint>::from_private_key_slice(&sk_bytes)?;
|
2021-01-15 15:36:37 -08:00
|
|
|
let kp2_private_bytes = kp2.private().to_vec();
|
|
|
|
|
|
|
|
|
|
prop_assert_eq!(sk_bytes, kp2_private_bytes);
|
|
|
|
|
}
|
2020-06-12 18:16:02 -04:00
|
|
|
}
|
2021-07-20 14:16:59 +02:00
|
|
|
|
|
|
|
|
#[test]
|
2021-08-12 06:25:07 +02:00
|
|
|
fn remote_key() {
|
2021-07-20 14:16:59 +02:00
|
|
|
use crate::{
|
|
|
|
|
CipherSuite, ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult,
|
|
|
|
|
ClientLoginStartResult, ClientRegistration, ClientRegistrationFinishParameters,
|
|
|
|
|
ClientRegistrationFinishResult, ClientRegistrationStartResult, ServerLogin,
|
|
|
|
|
ServerLoginStartParameters, ServerLoginStartResult, ServerRegistration,
|
|
|
|
|
ServerRegistrationStartResult, ServerSetup,
|
|
|
|
|
};
|
|
|
|
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
use rand::rngs::OsRng;
|
|
|
|
|
|
|
|
|
|
struct Default;
|
|
|
|
|
|
|
|
|
|
impl CipherSuite for Default {
|
2021-08-04 21:24:46 +02:00
|
|
|
type OprfGroup = RistrettoPoint;
|
|
|
|
|
type KeGroup = RistrettoPoint;
|
2021-07-20 14:16:59 +02:00
|
|
|
type KeyExchange = crate::key_exchange::tripledh::TripleDH;
|
|
|
|
|
type Hash = sha2::Sha512;
|
|
|
|
|
type SlowHash = crate::slow_hash::NoOpHash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Zeroize)]
|
|
|
|
|
struct RemoteKey(PrivateKey<RistrettoPoint>);
|
|
|
|
|
|
|
|
|
|
impl SecretKey<RistrettoPoint> for RemoteKey {
|
2021-08-12 06:25:07 +02:00
|
|
|
type Error = core::convert::Infallible;
|
2021-07-20 14:16:59 +02:00
|
|
|
|
|
|
|
|
fn diffie_hellman(
|
|
|
|
|
&self,
|
|
|
|
|
pk: PublicKey<RistrettoPoint>,
|
2021-08-22 12:28:19 -07:00
|
|
|
) -> Result<Vec<u8>, InternalError<Self::Error>> {
|
2021-07-20 14:16:59 +02:00
|
|
|
self.0.diffie_hellman(pk)
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-22 12:28:19 -07:00
|
|
|
fn public_key(&self) -> Result<PublicKey<RistrettoPoint>, InternalError<Self::Error>> {
|
2021-07-20 14:16:59 +02:00
|
|
|
self.0.public_key()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn serialize(&self) -> Vec<u8> {
|
|
|
|
|
self.0.serialize()
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-22 12:28:19 -07:00
|
|
|
fn deserialize(input: &[u8]) -> Result<Self, InternalError<Self::Error>> {
|
2021-07-20 14:16:59 +02:00
|
|
|
PrivateKey::deserialize(input).map(Self)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PASSWORD: &str = "password";
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
let sk = RistrettoPoint::random_sk(&mut OsRng);
|
|
|
|
|
let sk = RemoteKey(PrivateKey(Key(sk)));
|
2021-08-12 06:25:07 +02:00
|
|
|
let keypair = KeyPair::from_private_key(sk).unwrap();
|
2021-07-20 14:16:59 +02:00
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
let server_setup =
|
|
|
|
|
ServerSetup::<Default, RemoteKey>::new_with_key(&mut OsRng, keypair).unwrap();
|
2021-07-20 14:16:59 +02:00
|
|
|
|
|
|
|
|
let ClientRegistrationStartResult {
|
|
|
|
|
message,
|
|
|
|
|
state: client,
|
2021-08-12 06:25:07 +02:00
|
|
|
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
2021-07-30 14:00:23 +02:00
|
|
|
let ServerRegistrationStartResult { message, .. } =
|
2021-08-12 06:25:07 +02:00
|
|
|
ServerRegistration::start(&server_setup, message, &[]).unwrap();
|
|
|
|
|
let ClientRegistrationFinishResult { message, .. } = client
|
|
|
|
|
.finish(
|
|
|
|
|
&mut OsRng,
|
|
|
|
|
message,
|
2021-09-02 11:28:21 +02:00
|
|
|
ClientRegistrationFinishParameters::default(),
|
2021-08-12 06:25:07 +02:00
|
|
|
)
|
|
|
|
|
.unwrap();
|
2021-07-20 14:16:59 +02:00
|
|
|
let file = ServerRegistration::finish(message);
|
|
|
|
|
|
|
|
|
|
let ClientLoginStartResult {
|
|
|
|
|
message,
|
|
|
|
|
state: client,
|
2021-08-12 06:25:07 +02:00
|
|
|
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
2021-07-20 14:16:59 +02:00
|
|
|
let ServerLoginStartResult {
|
|
|
|
|
message,
|
|
|
|
|
state: server,
|
2021-07-30 12:54:16 +02:00
|
|
|
..
|
2021-07-20 14:16:59 +02:00
|
|
|
} = ServerLogin::start(
|
|
|
|
|
&mut OsRng,
|
|
|
|
|
&server_setup,
|
|
|
|
|
Some(file),
|
|
|
|
|
message,
|
|
|
|
|
&[],
|
|
|
|
|
ServerLoginStartParameters::default(),
|
2021-08-12 06:25:07 +02:00
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let ClientLoginFinishResult { message, .. } = client
|
2021-09-02 11:28:21 +02:00
|
|
|
.finish(message, ClientLoginFinishParameters::default())
|
2021-08-12 06:25:07 +02:00
|
|
|
.unwrap();
|
|
|
|
|
server.finish(message).unwrap();
|
2021-07-20 14:16:59 +02:00
|
|
|
}
|
2020-06-12 17:45:39 -04:00
|
|
|
}
|