Backport zeroize fix (#266)

* Backport `zeroize` fix

* Update version

* Fix CI

* Remove bench for CI MSRV

* Downgrade rustyline for MSRV

* Downgrade proptest for MSRV

* Downgrade zeroize for MSRV
This commit is contained in:
daxpedda
2022-01-30 16:05:19 -08:00
committed by GitHub
parent 349329cdeb
commit 1012439d2f
10 changed files with 36 additions and 122 deletions
-20
View File
@@ -135,26 +135,6 @@ jobs:
- name: Run expect (which then runs cargo run) - name: Run expect (which then runs cargo run)
run: expect -f scripts/digital_locker.exp run: expect -f scripts/digital_locker.exp
benches:
name: cargo bench compilation
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Run cargo bench --no-run
uses: actions-rs/cargo@v1
with:
command: bench
args: --features "bench" --no-run
clippy: clippy:
name: cargo clippy name: cargo clippy
runs-on: ubuntu-latest runs-on: ubuntu-latest
+4
View File
@@ -1,5 +1,9 @@
# Changelog # Changelog
## 0.6.1 (January 25, 2022)
* Fix `zeroize` implementing `Drop` on `enum`s now
## 0.6.0 (June 30, 2021) ## 0.6.0 (June 30, 2021)
* Synced implementation with draft-irtf-cfrg-opaque-05, which changes * Synced implementation with draft-irtf-cfrg-opaque-05, which changes
+4 -10
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "opaque-ke" name = "opaque-ke"
version = "0.6.0" version = "0.6.1"
repository = "https://github.com/novifinancial/opaque-ke" repository = "https://github.com/novifinancial/opaque-ke"
keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"] keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"]
description = "An implementation of the OPAQUE password-authenticated key exchange protocol" description = "An implementation of the OPAQUE password-authenticated key exchange protocol"
@@ -31,22 +31,16 @@ rand = "0.8"
serde = { version = "1", features = ["derive"], optional = true } serde = { version = "1", features = ["derive"], optional = true }
subtle = { version = "2.3.0", default-features = false } subtle = { version = "2.3.0", default-features = false }
thiserror = "1.0.22" thiserror = "1.0.22"
zeroize = { version = "1.1.1", features = ["zeroize_derive"] } zeroize = { version = "~1.1", features = ["zeroize_derive"] }
[dev-dependencies] [dev-dependencies]
anyhow = "1.0.35" anyhow = "1.0.35"
base64 = "0.13.0" base64 = "0.13.0"
bincode = "1" bincode = "1"
chacha20poly1305 = "0.7.1" chacha20poly1305 = "0.7.1"
criterion = "0.3.3"
hex = "0.4.2" hex = "0.4.2"
lazy_static = "1.4.0" lazy_static = "1.4.0"
serde_json = "1.0.60" serde_json = "1.0.60"
sha2 = "0.9.2" sha2 = "0.9.2"
proptest = "0.10.1" proptest = "0.3"
rustyline = "6.3.0" rustyline = "1"
[[bench]]
name = "oprf"
harness = false
required-features = ["bench"]
+1 -1
View File
@@ -22,7 +22,7 @@ Installation
Add the following line to the dependencies of your `Cargo.toml`: Add the following line to the dependencies of your `Cargo.toml`:
``` ```
opaque-ke = "0.6.0" opaque-ke = "0.6.1"
``` ```
Resources Resources
-68
View File
@@ -1,68 +0,0 @@
// 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.
#[macro_use]
extern crate criterion;
use criterion::Criterion;
use curve25519_dalek::ristretto::RistrettoPoint;
use generic_array::arr;
use opaque_ke::{
group::Group,
oprf::{blind_shim, evaluate_shim, finalize_shim},
};
use rand::{prelude::ThreadRng, thread_rng};
use sha2::Sha512;
fn oprf1(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng();
let input = b"hunter2";
c.bench_function("blind with Ristretto", move |b| {
b.iter(|| {
blind_shim::<_, RistrettoPoint, Sha512>(&input[..], &mut csprng).unwrap();
})
});
}
fn oprf2(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng();
let input = b"hunter2";
let (_, alpha) = blind_shim::<_, RistrettoPoint, Sha512>(&input[..], &mut csprng).unwrap();
let salt_bytes = arr![
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
];
let salt = RistrettoPoint::from_scalar_slice(&salt_bytes).unwrap();
c.bench_function("evaluate with Ristretto", move |b| {
b.iter(|| {
let _beta = evaluate_shim::<RistrettoPoint>(alpha, &salt);
})
});
}
fn oprf3(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng();
let input = b"hunter2";
let (token, alpha) = blind_shim::<_, RistrettoPoint, Sha512>(&input[..], &mut csprng).unwrap();
let salt_bytes = arr![
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
];
let salt = RistrettoPoint::from_scalar_slice(&salt_bytes).unwrap();
let beta = evaluate_shim::<RistrettoPoint>(alpha, &salt);
c.bench_function("finalize with Ristretto", move |b| {
b.iter(|| {
let _res = finalize_shim::<RistrettoPoint, Sha512>(&token, beta).unwrap();
})
});
}
criterion_group!(oprf_benches, oprf1, oprf2, oprf3);
criterion_main!(oprf_benches);
+2 -2
View File
@@ -61,7 +61,7 @@ fn recover_keys_internal<CS: CipherSuite>(
Ok(client_static_keypair) Ok(client_static_keypair)
} }
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Zeroize)] #[derive(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
#[zeroize(drop)] #[zeroize(drop)]
pub(crate) enum InnerEnvelopeMode { pub(crate) enum InnerEnvelopeMode {
Zero = 0, Zero = 0,
@@ -98,7 +98,7 @@ pub(crate) struct Envelope<CS: CipherSuite> {
impl<CS: CipherSuite> Clone for Envelope<CS> { impl<CS: CipherSuite> Clone for Envelope<CS> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
mode: self.mode, mode: self.mode.clone(),
nonce: self.nonce.clone(), nonce: self.nonce.clone(),
hmac: self.hmac.clone(), hmac: self.hmac.clone(),
} }
+1 -1
View File
@@ -170,7 +170,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
)); ));
} }
transcript_hasher.update(ke2_message.mac.to_vec()); transcript_hasher.update(ke2_message.mac);
let mut client_mac = let mut client_mac =
Hmac::<D>::new_from_slice(&km3).map_err(|_| InternalPakeError::HmacError)?; Hmac::<D>::new_from_slice(&km3).map_err(|_| InternalPakeError::HmacError)?;
+8 -8
View File
@@ -144,10 +144,10 @@ impl<G: Group + Debug> KeyPair<G> {
fn uniform_keypair_strategy() -> BoxedStrategy<Self> { fn uniform_keypair_strategy() -> BoxedStrategy<Self> {
// The no_shrink is because keypairs should be fixed -- shrinking would cause a different // 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. // keypair to be generated, which appears to not be very useful.
any::<[u8; 32]>() prop::array::uniform32(0_u8..)
.prop_filter_map("valid random keypair", |seed| { .prop_map(|seed| {
let mut rng = StdRng::from_seed(seed); let mut rng = StdRng::from_seed(seed);
Some(Self::generate_random(&mut rng)) Self::generate_random(&mut rng)
}) })
.no_shrink() .no_shrink()
.boxed() .boxed()
@@ -281,21 +281,21 @@ mod tests {
proptest! { proptest! {
#[test] #[test]
fn test_ristretto_check(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) { fn test_ristretto_check(ref kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
let pk = kp.public(); let pk = kp.public();
prop_assert!(KeyPair::<RistrettoPoint>::check_public_key(pk.clone()).is_ok()); prop_assert!(KeyPair::<RistrettoPoint>::check_public_key(pk.clone()).is_ok());
} }
#[test] #[test]
fn test_ristretto_pub_from_priv(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) { fn test_ristretto_pub_from_priv(ref kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
let pk = kp.public(); let pk = kp.public();
let sk = kp.private(); let sk = kp.private();
prop_assert_eq!(&KeyPair::<RistrettoPoint>::public_from_private(sk), pk); prop_assert_eq!(&KeyPair::<RistrettoPoint>::public_from_private(sk), pk);
} }
#[test] #[test]
fn test_ristretto_dh(kp1 in KeyPair::<RistrettoPoint>::uniform_keypair_strategy(), fn test_ristretto_dh(ref kp1 in KeyPair::<RistrettoPoint>::uniform_keypair_strategy(),
kp2 in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) { ref kp2 in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
let dh1 = KeyPair::<RistrettoPoint>::diffie_hellman(kp1.public().clone(), kp2.private().clone())?; let dh1 = KeyPair::<RistrettoPoint>::diffie_hellman(kp1.public().clone(), kp2.private().clone())?;
let dh2 = KeyPair::<RistrettoPoint>::diffie_hellman(kp2.public().clone(), kp1.private().clone())?; let dh2 = KeyPair::<RistrettoPoint>::diffie_hellman(kp2.public().clone(), kp1.private().clone())?;
@@ -304,7 +304,7 @@ mod tests {
} }
#[test] #[test]
fn test_private_key_slice(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) { fn test_private_key_slice(ref kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
let sk_bytes = kp.private().to_vec(); let sk_bytes = kp.private().to_vec();
let kp2 = KeyPair::<RistrettoPoint>::from_private_key_slice(&sk_bytes)?; let kp2 = KeyPair::<RistrettoPoint>::from_private_key_slice(&sk_bytes)?;
+4
View File
@@ -747,6 +747,10 @@ compile_error!(
please enable one of: u64_backend, u32_backend" please enable one of: u64_backend, u32_backend"
); );
#[cfg(test)]
#[macro_use]
extern crate proptest;
// Error types // Error types
pub mod errors; pub mod errors;
+12 -12
View File
@@ -346,57 +346,57 @@ fn ke3_message_roundtrip() {
proptest! { proptest! {
#[test] #[test]
fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..std::mem::size_of::<usize>())) { fn test_i2osp_os2ip(ref bytes in vec(prop::num::u8::ANY, 0..std::mem::size_of::<usize>())) {
assert_eq!(i2osp(os2ip(&bytes)?, bytes.len()), bytes); assert_eq!(&i2osp(os2ip(&bytes)?, bytes.len()), bytes);
} }
#[test] #[test]
fn test_nocrash_registration_request(bytes in vec(any::<u8>(), 0..200)) { fn test_nocrash_registration_request(ref bytes in vec(prop::num::u8::ANY, 0..200)) {
RegistrationRequest::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); RegistrationRequest::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_registration_response(bytes in vec(any::<u8>(), 0..200)) { fn test_nocrash_registration_response(ref bytes in vec(prop::num::u8::ANY, 0..200)) {
RegistrationResponse::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); RegistrationResponse::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_registration_upload(bytes in vec(any::<u8>(), 0..200)) { fn test_nocrash_registration_upload(ref bytes in vec(prop::num::u8::ANY, 0..200)) {
RegistrationUpload::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); RegistrationUpload::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_credential_request(bytes in vec(any::<u8>(), 0..500)) { fn test_nocrash_credential_request(ref bytes in vec(prop::num::u8::ANY, 0..500)) {
CredentialRequest::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); CredentialRequest::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_credential_response(bytes in vec(any::<u8>(), 0..500)) { fn test_nocrash_credential_response(ref bytes in vec(prop::num::u8::ANY, 0..500)) {
CredentialResponse::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); CredentialResponse::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_credential_finalization(bytes in vec(any::<u8>(), 0..500)) { fn test_nocrash_credential_finalization(ref bytes in vec(prop::num::u8::ANY, 0..500)) {
CredentialFinalization::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); CredentialFinalization::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_client_registration(bytes in vec(any::<u8>(), 0..700)) { fn test_nocrash_client_registration(ref bytes in vec(prop::num::u8::ANY, 0..700)) {
ClientRegistration::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); ClientRegistration::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_server_registration(bytes in vec(any::<u8>(), 0..700)) { fn test_nocrash_server_registration(ref bytes in vec(prop::num::u8::ANY, 0..700)) {
ServerRegistration::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); ServerRegistration::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_client_login(bytes in vec(any::<u8>(), 0..700)) { fn test_nocrash_client_login(ref bytes in vec(prop::num::u8::ANY, 0..700)) {
ClientLogin::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); ClientLogin::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_server_login(bytes in vec(any::<u8>(), 0..700)) { fn test_nocrash_server_login(ref bytes in vec(prop::num::u8::ANY, 0..700)) {
ServerLogin::<Default>::deserialize(&bytes[..]).map_or(true, |_| true); ServerLogin::<Default>::deserialize(&bytes[..]).map_or(true, |_| true);
} }