2023-05-22 23:04:26 -07:00
|
|
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
2021-10-25 02:54:32 -07:00
|
|
|
//
|
2023-05-22 23:04:26 -07:00
|
|
|
// This source code is dual-licensed under either the MIT license found in the
|
|
|
|
|
// LICENSE-MIT file in the root directory of this source tree or the Apache
|
2021-12-03 14:38:11 -08:00
|
|
|
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
2023-05-22 23:04:26 -07:00
|
|
|
// of this source tree. You may select, at your option, one of the above-listed
|
|
|
|
|
// licenses.
|
2021-10-25 02:54:32 -07:00
|
|
|
|
2022-01-06 06:19:02 +01:00
|
|
|
//! Includes the KeGroup trait and definitions for the key exchange groups
|
2021-10-25 02:54:32 -07:00
|
|
|
|
2022-12-19 18:03:11 +01:00
|
|
|
#[cfg(feature = "curve25519")]
|
|
|
|
|
pub mod curve25519;
|
2022-02-25 07:13:22 +01:00
|
|
|
mod elliptic_curve;
|
|
|
|
|
#[cfg(feature = "ristretto255")]
|
|
|
|
|
pub mod ristretto255;
|
|
|
|
|
|
|
|
|
|
use digest::core_api::BlockSizeUser;
|
2023-03-05 05:31:07 +01:00
|
|
|
use digest::{FixedOutput, HashMarker, OutputSizeUser};
|
2022-04-17 16:23:31 -07:00
|
|
|
use generic_array::sequence::Concat;
|
2023-03-05 05:31:07 +01:00
|
|
|
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
|
2021-10-25 02:54:32 -07:00
|
|
|
use generic_array::{ArrayLength, GenericArray};
|
|
|
|
|
use rand::{CryptoRng, RngCore};
|
2022-04-02 01:10:00 +02:00
|
|
|
use zeroize::Zeroize;
|
2021-10-25 02:54:32 -07:00
|
|
|
|
2022-01-06 06:19:02 +01:00
|
|
|
use crate::errors::InternalError;
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
/// A group representation for use in the key exchange
|
2022-02-25 07:13:22 +01:00
|
|
|
pub trait KeGroup {
|
|
|
|
|
/// Public key
|
2022-04-02 01:10:00 +02:00
|
|
|
type Pk: Copy + Zeroize;
|
2021-10-25 02:54:32 -07:00
|
|
|
/// Length of the public key
|
2022-02-25 07:13:22 +01:00
|
|
|
type PkLen: ArrayLength<u8>;
|
|
|
|
|
/// Secret key
|
2022-04-02 01:10:00 +02:00
|
|
|
type Sk: Copy + Zeroize;
|
2021-10-25 02:54:32 -07:00
|
|
|
/// Length of the secret key
|
2022-02-25 07:13:22 +01:00
|
|
|
type SkLen: ArrayLength<u8>;
|
|
|
|
|
|
|
|
|
|
/// Serializes `self`
|
2022-04-02 01:10:00 +02:00
|
|
|
fn serialize_pk(pk: Self::Pk) -> GenericArray<u8, Self::PkLen>;
|
2021-10-25 02:54:32 -07:00
|
|
|
|
|
|
|
|
/// Return a public key from its fixed-length bytes representation
|
2022-04-02 01:10:00 +02:00
|
|
|
fn deserialize_pk(bytes: &[u8]) -> Result<Self::Pk, InternalError>;
|
2021-10-25 02:54:32 -07:00
|
|
|
|
|
|
|
|
/// Generate a random secret key
|
2022-02-25 07:13:22 +01:00
|
|
|
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk;
|
|
|
|
|
|
|
|
|
|
/// Hashes a slice of pseudo-random bytes to a scalar
|
|
|
|
|
///
|
|
|
|
|
/// # Errors
|
|
|
|
|
/// [`InternalError::HashToScalar`] if the `input` is empty or longer then
|
|
|
|
|
/// [`u16::MAX`].
|
2023-03-05 05:31:07 +01:00
|
|
|
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Sk, InternalError>
|
2022-02-25 07:13:22 +01:00
|
|
|
where
|
2023-03-05 05:31:07 +01:00
|
|
|
H: BlockSizeUser + Default + FixedOutput + HashMarker,
|
2022-02-25 07:13:22 +01:00
|
|
|
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
|
2021-10-25 02:54:32 -07:00
|
|
|
|
2022-04-17 16:23:31 -07:00
|
|
|
/// Corresponds to the DeriveAuthKeyPair() function defined in
|
|
|
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-08.html#section-6.4.2>
|
|
|
|
|
///
|
|
|
|
|
/// Note that we cannot call the voprf crate directly since we need to
|
|
|
|
|
/// ensure that the KeGroup is used for the hash_to_scalar operation (as
|
|
|
|
|
/// opposed to the OprfGroup).
|
|
|
|
|
fn derive_auth_keypair<CS: voprf::CipherSuite>(
|
2023-05-23 08:04:01 +02:00
|
|
|
seed: GenericArray<u8, Self::SkLen>,
|
2022-04-17 16:23:31 -07:00
|
|
|
info: &[u8],
|
|
|
|
|
) -> Result<Self::Sk, InternalError>
|
|
|
|
|
where
|
|
|
|
|
<CS::Hash as OutputSizeUser>::OutputSize:
|
|
|
|
|
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
|
|
|
|
{
|
2023-03-05 05:31:07 +01:00
|
|
|
let dst_1 = GenericArray::from(STR_DERIVE_KEYPAIR)
|
|
|
|
|
.concat(STR_OPRF.into())
|
|
|
|
|
.concat([voprf::Mode::Oprf.to_u8()].into())
|
|
|
|
|
.concat([b'-'].into());
|
|
|
|
|
let dst_2 = CS::ID.as_bytes();
|
2022-04-17 16:23:31 -07:00
|
|
|
|
|
|
|
|
let info_len = i2osp_2(info.len())
|
|
|
|
|
.map_err(|_| InternalError::OprfError(voprf::Error::DeriveKeyPair))?;
|
|
|
|
|
|
|
|
|
|
for counter in 0_u8..=u8::MAX {
|
|
|
|
|
// deriveInput = seed || I2OSP(len(info), 2) || info
|
|
|
|
|
// skS = G.HashToScalar(deriveInput || I2OSP(counter, 1), DST = "DeriveKeyPair"
|
|
|
|
|
// || contextString)
|
|
|
|
|
let sk_s = Self::hash_to_scalar::<CS::Hash>(
|
2023-05-23 08:04:01 +02:00
|
|
|
&[&seed, &info_len, info, &counter.to_be_bytes()],
|
2023-03-05 05:31:07 +01:00
|
|
|
&[&dst_1, dst_2],
|
2022-04-17 16:23:31 -07:00
|
|
|
)
|
|
|
|
|
.map_err(|_| InternalError::OprfError(voprf::Error::DeriveKeyPair))?;
|
|
|
|
|
|
|
|
|
|
if !bool::from(Self::is_zero_scalar(sk_s)) {
|
|
|
|
|
return Ok(sk_s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Err(InternalError::OprfError(voprf::Error::DeriveKeyPair))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns `true` if the scalar is zero.
|
|
|
|
|
fn is_zero_scalar(scalar: Self::Sk) -> subtle::Choice;
|
|
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
/// Return a public key from its secret key
|
2022-04-02 01:10:00 +02:00
|
|
|
fn public_key(sk: Self::Sk) -> Self::Pk;
|
2022-02-25 07:13:22 +01:00
|
|
|
|
|
|
|
|
/// Diffie-Hellman key exchange
|
2022-04-02 01:10:00 +02:00
|
|
|
fn diffie_hellman(pk: Self::Pk, sk: Self::Sk) -> GenericArray<u8, Self::PkLen>;
|
2021-10-25 02:54:32 -07:00
|
|
|
|
|
|
|
|
/// Serializes `self`
|
2022-04-02 01:10:00 +02:00
|
|
|
fn serialize_sk(sk: Self::Sk) -> GenericArray<u8, Self::SkLen>;
|
2021-10-25 02:54:32 -07:00
|
|
|
|
2022-02-25 07:13:22 +01:00
|
|
|
/// Return a public key from its fixed-length bytes representation
|
2022-04-02 01:10:00 +02:00
|
|
|
fn deserialize_sk(bytes: &[u8]) -> Result<Self::Sk, InternalError>;
|
2021-10-25 02:54:32 -07:00
|
|
|
}
|
2022-04-17 16:23:31 -07:00
|
|
|
|
|
|
|
|
// Helper functions used to compute DeriveAuthKeyPair() (taken from the voprf
|
|
|
|
|
// crate)
|
|
|
|
|
|
2023-03-05 05:31:07 +01:00
|
|
|
const STR_OPRF: [u8; 7] = *b"OPRFV1-";
|
2022-04-17 16:23:31 -07:00
|
|
|
const STR_DERIVE_KEYPAIR: [u8; 13] = *b"DeriveKeyPair";
|
|
|
|
|
|
|
|
|
|
fn i2osp_2(input: usize) -> Result<[u8; 2], InternalError> {
|
|
|
|
|
u16::try_from(input)
|
|
|
|
|
.map(|input| input.to_be_bytes())
|
|
|
|
|
.map_err(|_| InternalError::OprfInternalError(voprf::InternalError::I2osp))
|
|
|
|
|
}
|