Last active
June 14, 2023 13:35
-
-
Save jedisct1/b4060c9d83254f52aa3609e7f28301f4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Cargo.toml b/Cargo.toml | |
index 5f580b6..d0f55d0 100644 | |
--- a/Cargo.toml | |
+++ b/Cargo.toml | |
@@ -1,7 +1,12 @@ | |
[package] | |
name = "prio" | |
version = "0.12.2" | |
-authors = ["Josh Aas <[email protected]>", "Tim Geoghegan <[email protected]>", "Christopher Patton <[email protected]", "Karl Tarbe <[email protected]>"] | |
+authors = [ | |
+ "Josh Aas <[email protected]>", | |
+ "Tim Geoghegan <[email protected]>", | |
+ "Christopher Patton <[email protected]", | |
+ "Karl Tarbe <[email protected]>", | |
+] | |
edition = "2021" | |
exclude = ["/supply-chain"] | |
description = "Implementation of the Prio aggregation system core: https://crypto.stanford.edu/prio/" | |
@@ -35,7 +40,9 @@ rayon = { version = "1.7.0", optional = true } | |
# dependencies required if feature "prio2" is enabled | |
aes-gcm = { version = "^0.10", optional = true } | |
-ring = { version = "0.16.20", optional = true } | |
+p256 = { version = "0.13.2", features = ["ecdh", "std"], optional = true } | |
+hmac-sha256 = { version = "1.1.6", optional = true } | |
+generic-array = { version = "0.14.4", optional = true } | |
[dev-dependencies] | |
assert_matches = "1.5.0" | |
@@ -56,11 +63,17 @@ zipf = "7.0.0" | |
hex-literal = "0.4.1" | |
[features] | |
-default = ["crypto-dependencies"] | |
+default = ["crypto-dependencies", "prio2"] | |
experimental = ["bitvec", "fiat-crypto", "fixed"] | |
test-util = ["rand", "serde_json"] | |
multithreaded = ["rayon"] | |
-prio2 = ["crypto-dependencies", "aes-gcm", "ring"] | |
+prio2 = [ | |
+ "crypto-dependencies", | |
+ "aes-gcm", | |
+ "p256", | |
+ "hmac-sha256", | |
+ "generic-array", | |
+] | |
crypto-dependencies = ["aes", "ctr", "cmac"] | |
[workspace] | |
diff --git a/src/encrypt.rs b/src/encrypt.rs | |
index e69134d..80cc14f 100644 | |
--- a/src/encrypt.rs | |
+++ b/src/encrypt.rs | |
@@ -7,7 +7,8 @@ use crate::prng::PrngError; | |
use aes::{cipher::typenum::U16, Aes128}; | |
use aes_gcm::{aead::generic_array::GenericArray, AeadInPlace, AesGcm, KeyInit}; | |
use base64::{engine::Engine, prelude::BASE64_STANDARD}; | |
-use ring::agreement; | |
+use hmac_sha256::Hash as Sha256; | |
+use p256::ecdh::EphemeralSecret; | |
type Aes128Gcm = AesGcm<Aes128, U16>; | |
@@ -82,20 +83,17 @@ impl PrivateKey { | |
/// This uses ECIES with X9.63 key derivation function and AES-GCM for the | |
/// symmetic encryption and MAC. | |
pub fn encrypt_share(share: &[u8], key: &PublicKey) -> Result<Vec<u8>, EncryptError> { | |
- let rng = ring::rand::SystemRandom::new(); | |
- let ephemeral_priv = agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) | |
- .map_err(|_| EncryptError::KeyAgreement)?; | |
- let peer_public = agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key.0); | |
- let ephemeral_pub = ephemeral_priv | |
- .compute_public_key() | |
- .map_err(|_| EncryptError::KeyAgreement)?; | |
- | |
- let symmetric_key_bytes = agreement::agree_ephemeral( | |
- ephemeral_priv, | |
- &peer_public, | |
- EncryptError::KeyAgreement, | |
- |material| Ok(x963_kdf(material, ephemeral_pub.as_ref())), | |
- )?; | |
+ let mut rng = rand::thread_rng(); | |
+ let ephemeral_priv = EphemeralSecret::random(&mut rng); | |
+ let peer_public = | |
+ p256::PublicKey::from_sec1_bytes(&key.0).map_err(|_| EncryptError::KeyAgreement)?; | |
+ let ephemeral_pub: p256::elliptic_curve::PublicKey<p256::NistP256> = | |
+ ephemeral_priv.public_key(); | |
+ let material = ephemeral_priv.diffie_hellman(&peer_public); | |
+ let symmetric_key_bytes = x963_kdf( | |
+ material.raw_secret_bytes().as_slice(), | |
+ ephemeral_pub.to_sec1_bytes().as_ref(), | |
+ ); | |
let in_out = share.to_owned(); | |
let encrypted = encrypt_aes_gcm( | |
@@ -103,9 +101,9 @@ pub fn encrypt_share(share: &[u8], key: &PublicKey) -> Result<Vec<u8>, EncryptEr | |
&symmetric_key_bytes[16..], | |
in_out, | |
)?; | |
- | |
- let mut output = Vec::with_capacity(encrypted.len() + ephemeral_pub.as_ref().len()); | |
- output.extend_from_slice(ephemeral_pub.as_ref()); | |
+ let ephemeral_pub_bytes = ephemeral_pub.to_sec1_bytes(); | |
+ let mut output = Vec::with_capacity(encrypted.len() + ephemeral_pub_bytes.len()); | |
+ output.extend_from_slice(&ephemeral_pub_bytes); | |
output.extend_from_slice(&encrypted); | |
Ok(output) | |
@@ -121,23 +119,19 @@ pub fn decrypt_share(share: &[u8], key: &PrivateKey) -> Result<Vec<u8>, EncryptE | |
} | |
let empheral_pub_bytes: &[u8] = &share[0..PUBLICKEY_LENGTH]; | |
- let ephemeral_pub = | |
- agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, empheral_pub_bytes); | |
+ let ephemeral_pub = p256::PublicKey::from_sec1_bytes(empheral_pub_bytes) | |
+ .map_err(|_| EncryptError::Decryption)?; | |
- let fake_rng = ring::test::rand::FixedSliceRandom { | |
- // private key consists of the public key + private scalar | |
- bytes: &key.0[PUBLICKEY_LENGTH..], | |
- }; | |
- | |
- let private_key = agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &fake_rng) | |
- .map_err(|_| EncryptError::KeyAgreement)?; | |
- | |
- let symmetric_key_bytes = agreement::agree_ephemeral( | |
- private_key, | |
- &ephemeral_pub, | |
- EncryptError::KeyAgreement, | |
- |material| Ok(x963_kdf(material, empheral_pub_bytes)), | |
- )?; | |
+ let fk = p256::SecretKey::from_bytes(generic_array::GenericArray::from_slice( | |
+ &key.0[PUBLICKEY_LENGTH..], | |
+ )) | |
+ .map_err(|_| EncryptError::Decryption)?; | |
+ let private_key: EphemeralSecret = unsafe { std::mem::transmute(fk) }; // Unfortunately, no public API exists to do this | |
+ let material = private_key.diffie_hellman(&ephemeral_pub); | |
+ let symmetric_key_bytes = x963_kdf( | |
+ material.raw_secret_bytes().as_ref(), | |
+ ephemeral_pub.to_sec1_bytes().as_ref(), | |
+ ); | |
// in_out is the AES-GCM ciphertext+tag, wihtout the ephemeral EC pubkey | |
let in_out = share[PUBLICKEY_LENGTH..].to_owned(); | |
@@ -149,13 +143,12 @@ pub fn decrypt_share(share: &[u8], key: &PrivateKey) -> Result<Vec<u8>, EncryptE | |
} | |
fn x963_kdf(z: &[u8], shared_info: &[u8]) -> [u8; 32] { | |
- let mut hasher = ring::digest::Context::new(&ring::digest::SHA256); | |
+ let mut hasher = Sha256::new(); | |
hasher.update(z); | |
hasher.update(&1u32.to_be_bytes()); | |
hasher.update(shared_info); | |
- let digest = hasher.finish(); | |
- // unwrap never fails because SHA256 output len is 32 | |
- digest.as_ref().try_into().unwrap() | |
+ let digest = hasher.finalize(); | |
+ digest | |
} | |
fn decrypt_aes_gcm(key: &[u8], nonce: &[u8], mut data: Vec<u8>) -> Result<Vec<u8>, EncryptError> { | |
diff --git a/src/prng.rs b/src/prng.rs | |
index bc98593..19edd01 100644 | |
--- a/src/prng.rs | |
+++ b/src/prng.rs | |
@@ -173,7 +173,7 @@ mod tests { | |
let random_bytes = FieldPrio2::slice_into_byte_vec(&random_data); | |
- let digest = ring::digest::digest(&ring::digest::SHA256, &random_bytes); | |
+ let digest = hmac_sha256::Hash::hash(&random_bytes); | |
assert_eq!(BASE64_STANDARD.encode(digest), hash_base64); | |
} | |
diff --git a/src/vdaf/prio2.rs b/src/vdaf/prio2.rs | |
index 3a154c2..8d8edf2 100644 | |
--- a/src/vdaf/prio2.rs | |
+++ b/src/vdaf/prio2.rs | |
@@ -16,7 +16,7 @@ use crate::{ | |
ShareDecodingParameter, Vdaf, VdafError, | |
}, | |
}; | |
-use ring::hmac; | |
+use hmac_sha256::HMAC; | |
use std::{ | |
convert::{TryFrom, TryInto}, | |
io::Cursor, | |
@@ -218,8 +218,8 @@ impl Aggregator<32, 16> for Prio2 { | |
// distributed to the Aggregators after they receive their input shares. In a VDAF, shared | |
// randomness is derived from a nonce selected by the client. For Prio2 we compute the | |
// query using HMAC-SHA256 evaluated over the nonce. | |
- let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, agg_key); | |
- let hmac_tag = hmac::sign(&hmac_key, nonce); | |
+ let hmac_tag = HMAC::mac(nonce, agg_key); | |
+ | |
let query_rand = Prng::from_prio2_seed(hmac_tag.as_ref().try_into().unwrap()) | |
.next() | |
.unwrap(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment