Skip to content

Commit

Permalink
Fixups to keep in sync with draft-10
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinlewi committed Oct 10, 2024
1 parent df29524 commit eb782ec
Show file tree
Hide file tree
Showing 12 changed files with 453 additions and 1,504 deletions.
25 changes: 2 additions & 23 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,7 @@
# Changelog

## 3.0.0-pre.5 (September 18, 2024)
* Increased MSRV to 1.74
* Updated voprf dependency

## 3.0.0-pre.4 (July 25, 2023)
* Updated voprf and curve25519-dalek dependencies

## 3.0.0-pre.3 (June 7, 2023)
* Adjusted curve25519 support logic
* Adjusted key generation logic to be in line with commit 727b9ac of
https://github.com/cfrg/draft-irtf-cfrg-opaque
* Updated voprf dependency

## 3.0.0-pre.2 (March 14, 2023)
* Updated VOPRF to draft 19
* Added P384 testing support
* Increased MSRV to 1.65
* Updating dependencies

## 3.0.0-pre.1 (February 8, 2023)
* Renaming of X25519 to Curve25519
* Increased MSRV to 1.60
* Updating dependencies
## 2.1.0-pre.1 (October 10, 2024)
* Updated dependencies: voprf v0.4.1, curve25519-dalek v4

## 2.0.0 (September 21, 2022)
* Synced implementation with draft-irtf-cfrg-opaque-10
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ name = "opaque-ke"
readme = "README.md"
repository = "https://github.com/facebook/opaque-ke"
rust-version = "1.74"
version = "3.0.0-pre.5"
version = "2.1.0-pre.1"

[features]
argon2 = ["dep:argon2"]
Expand Down Expand Up @@ -39,7 +39,7 @@ serde = { version = "1", default-features = false, features = [
"derive",
], optional = true }
subtle = { version = "2.3", default-features = false }
voprf = { version = "0.5", default-features = false, features = ["danger"] }
voprf = { version = "0.4.1", default-features = false, features = ["danger"] }
zeroize = { version = "1.5", features = ["zeroize_derive"] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Installation
Add the following line to the dependencies of your `Cargo.toml`:

```
opaque-ke = "3.0.0-pre.5"
opaque-ke = "2.1.0-pre.1"
```

### Minimum Supported Rust Version
Expand All @@ -40,7 +40,7 @@ Resources
---------

- [OPAQUE academic publication](https://eprint.iacr.org/2018/163.pdf), including formal definitions and a proof of security
- [draft-irtf-cfrg-opaque-16](https://datatracker.ietf.org/doc/draft-irtf-cfrg-opaque/16/), containing a detailed (byte-level) specification for OPAQUE
- [draft-irtf-cfrg-opaque-10](https://datatracker.ietf.org/doc/draft-irtf-cfrg-opaque/10/), containing a detailed (byte-level) specification for OPAQUE
- ["Let's talk about PAKE"](https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/), an introductory blog post written by Matthew Green that covers OPAQUE
- [@serenity-kit/opaque](https://github.com/serenity-kit/opaque), a WebAssembly package for this library
- [opaque-wasm](https://github.com/marucjmar/opaque-wasm), a WebAssembly package for this library. A comparison between `@serenity-kit/opaque` and `opaque-wasm` can be found [here](https://opaque-documentation.netlify.app/docs/faq#how-does-it-compare-to-opaque-wasm)
Expand Down
57 changes: 28 additions & 29 deletions src/key_exchange/group/curve25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
//! Key Exchange group implementation for Curve25519

use curve25519_dalek::montgomery::MontgomeryPoint;
use curve25519_dalek::scalar::{self, Scalar};
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::Identity;
use digest::core_api::BlockSizeUser;
use digest::{FixedOutput, HashMarker, OutputSizeUser};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32};
use digest::{FixedOutput, HashMarker};
use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64};
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use subtle::ConstantTimeEq;
Expand All @@ -28,7 +29,7 @@ pub struct Curve25519;
impl KeGroup for Curve25519 {
type Pk = MontgomeryPoint;
type PkLen = U32;
type Sk = [u8; 32];
type Sk = Scalar;
type SkLen = U32;

fn serialize_pk(pk: Self::Pk) -> GenericArray<u8, Self::PkLen> {
Expand All @@ -46,61 +47,59 @@ impl KeGroup for Curve25519 {

fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
loop {
// Sample 32 random bytes and then clamp, as described in https://cr.yp.to/ecdh.html
let mut scalar_bytes = [0u8; 32];
let mut scalar_bytes = [0u8; 64];
rng.fill_bytes(&mut scalar_bytes);
let scalar = scalar::clamp_integer(scalar_bytes);
let scalar = Scalar::from_bytes_mod_order_wide(&scalar_bytes);

if scalar != Scalar::ZERO.to_bytes() {
if scalar != Scalar::ZERO {
break scalar;
}
}
}

fn hash_to_scalar<'a, H>(_input: &[&[u8]], _dst: &[&[u8]]) -> Result<Self::Sk, InternalError>
// Implements the `HashToScalar()` function from
// <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-09.html#section-4.1>
fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
unimplemented!()
}
let mut uniform_bytes = GenericArray::<_, U64>::default();
ExpandMsgXmd::<H>::expand_message(input, &[dst], 64)
.map_err(|_| InternalError::HashToScalar)?
.fill_bytes(&mut uniform_bytes);

fn derive_auth_keypair<CS: voprf::CipherSuite>(
seed: GenericArray<u8, Self::SkLen>,
_info: &[u8],
) -> Result<Self::Sk, InternalError>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
Ok(scalar::clamp_integer(seed.into()))
let scalar = Scalar::from_bytes_mod_order_wide(&uniform_bytes.into());

if scalar == Scalar::ZERO {
Err(InternalError::HashToScalar)
} else {
Ok(scalar)
}
}

fn is_zero_scalar(scalar: Self::Sk) -> subtle::Choice {
scalar.ct_eq(&Scalar::ZERO.to_bytes())
scalar.ct_eq(&Scalar::ZERO)
}

fn public_key(sk: Self::Sk) -> Self::Pk {
MontgomeryPoint::mul_base_clamped(sk)
MontgomeryPoint::mul_base(&sk)
}

fn diffie_hellman(pk: Self::Pk, sk: Self::Sk) -> GenericArray<u8, Self::PkLen> {
Self::serialize_pk(pk.mul_clamped(sk))
Self::serialize_pk(sk * pk)
}

fn serialize_sk(sk: Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.into()
sk.to_bytes().into()
}

fn deserialize_sk(bytes: &[u8]) -> Result<Self::Sk, InternalError> {
bytes
.try_into()
.ok()
.and_then(|bytes| {
let scalar = scalar::clamp_integer(bytes);
(scalar == bytes).then_some(scalar)
})
.filter(|scalar| scalar != &Scalar::ZERO.to_bytes())
.and_then(|bytes| Scalar::from_canonical_bytes(bytes).into())
.filter(|scalar| scalar != &Scalar::ZERO)
.ok_or(InternalError::PointError)
}
}
4 changes: 2 additions & 2 deletions src/key_exchange/group/elliptic_curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ where

// Implements the `HashToScalar()` function from
// <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#section-4>
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Sk, InternalError>
fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
Self::hash_to_scalar::<ExpandMsgXmd<H>>(input, dst)
Self::hash_to_scalar::<ExpandMsgXmd<H>>(input, &[dst])
.map_err(|_| InternalError::HashToScalar)
.and_then(|scalar| {
if bool::from(scalar.is_zero()) {
Expand Down
37 changes: 28 additions & 9 deletions src/key_exchange/group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub mod ristretto255;
use digest::core_api::BlockSizeUser;
use digest::{FixedOutput, HashMarker, OutputSizeUser};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::typenum::{IsLess, IsLessOrEqual, U11, U256};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use zeroize::Zeroize;
Expand Down Expand Up @@ -49,7 +49,7 @@ pub trait KeGroup {
/// # Errors
/// [`InternalError::HashToScalar`] if the `input` is empty or longer then
/// [`u16::MAX`].
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Sk, InternalError>
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
Expand All @@ -69,11 +69,8 @@ pub trait KeGroup {
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
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();
let context_string = create_context_string::<CS>(voprf::Mode::Oprf);
let dst = GenericArray::from(STR_DERIVE_KEYPAIR).concat(context_string);

let info_len = i2osp_2(info.len())
.map_err(|_| InternalError::OprfError(voprf::Error::DeriveKeyPair))?;
Expand All @@ -84,7 +81,7 @@ pub trait KeGroup {
// || contextString)
let sk_s = Self::hash_to_scalar::<CS::Hash>(
&[&seed, &info_len, info, &counter.to_be_bytes()],
&[&dst_1, dst_2],
&dst,
)
.map_err(|_| InternalError::OprfError(voprf::Error::DeriveKeyPair))?;

Expand Down Expand Up @@ -115,9 +112,31 @@ pub trait KeGroup {
// Helper functions used to compute DeriveAuthKeyPair() (taken from the voprf
// crate)

const STR_OPRF: [u8; 7] = *b"OPRFV1-";
const STR_VOPRF: [u8; 8] = *b"VOPRF10-";
const STR_DERIVE_KEYPAIR: [u8; 13] = *b"DeriveKeyPair";

/// Generates the contextString parameter as defined in
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
fn create_context_string<CS: voprf::CipherSuite>(mode: voprf::Mode) -> GenericArray<u8, U11>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
// FIXME: this should be in voprf library
let cs_id_u16: u16 = match CS::ID {
"ristretto255-SHA512" => 0x0001,
"decaf448-SHAKE256" => 0x0002,
"P256-SHA256" => 0x0003,
"P384-SHA384" => 0x0004,
"P521-SHA512" => 0x0005,
_ => panic!("Incompatible ciphersuite: {}", CS::ID),
};

GenericArray::from(STR_VOPRF)
.concat([mode.to_u8()].into())
.concat(cs_id_u16.to_be_bytes().into())
}

fn i2osp_2(input: usize) -> Result<[u8; 2], InternalError> {
u16::try_from(input)
.map(|input| input.to_be_bytes())
Expand Down
4 changes: 2 additions & 2 deletions src/key_exchange/group/ristretto255.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ impl KeGroup for Ristretto255 {

// Implements the `HashToScalar()` function from
// <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#section-4>
fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Sk, InternalError>
fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
<voprf::Ristretto255 as Group>::hash_to_scalar::<H>(input, dst)
<voprf::Ristretto255 as Group>::hash_to_scalar::<H>(input, &[dst])
.map_err(InternalError::OprfInternalError)
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! An implementation of the OPAQUE asymmetric password authentication key
//! exchange protocol
//!
//! Note: This implementation is in sync with [draft-irtf-cfrg-opaque-16](https://datatracker.ietf.org/doc/draft-irtf-cfrg-opaque/16/),
//! Note: This implementation is in sync with [draft-irtf-cfrg-opaque-10](https://datatracker.ietf.org/doc/draft-irtf-cfrg-opaque/10/),
//! but this specification is subject to change, until the final version
//! published by the IETF.
//!
Expand Down
Loading

0 comments on commit eb782ec

Please sign in to comment.