Merge pull request #78 from huitseeker/secure_postprocessing

Uses conditional compilation to make sure postprocessing is only avai…
This commit is contained in:
François Garillot
2020-11-04 20:17:02 -05:00
committed by GitHub
3 changed files with 69 additions and 73 deletions
+23 -39
View File
@@ -577,37 +577,25 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
&Vec::new(), &Vec::new(),
password, password,
blinding_factor_rng, blinding_factor_rng,
#[cfg(test)]
std::convert::identity,
) )
} }
/// Same as ClientRegistration::start, but also accepts a username and server name as input /// Same as ClientRegistration::start, but also accepts a username and
/// server name as input
/// as well as an optional postprocessing function for the blinding factor(used in tests)
pub fn start_with_user_and_server_name<R: RngCore + CryptoRng>( pub fn start_with_user_and_server_name<R: RngCore + CryptoRng>(
user_name: &[u8], user_name: &[u8],
server_name: &[u8], server_name: &[u8],
password: &[u8], password: &[u8],
blinding_factor_rng: &mut R, blinding_factor_rng: &mut R,
#[cfg(test)] postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar,
) -> Result<(RegisterFirstMessage<CS::Group>, Self), ProtocolError> { ) -> Result<(RegisterFirstMessage<CS::Group>, Self), ProtocolError> {
Self::start_with_user_and_server_name_and_postprocessing( let (token, alpha) = oprf::blind::<R, CS::Group>(
user_name,
server_name,
password,
blinding_factor_rng,
std::convert::identity,
)
}
/// Same as ClientRegistration::start, but also accepts a username and server name as input as well as
/// an optional postprocessing function for the blinding factor
pub fn start_with_user_and_server_name_and_postprocessing<R: RngCore + CryptoRng>(
user_name: &[u8],
server_name: &[u8],
password: &[u8],
blinding_factor_rng: &mut R,
postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar,
) -> Result<(RegisterFirstMessage<CS::Group>, Self), ProtocolError> {
let (token, alpha) = oprf::blind_with_postprocessing::<R, CS::Group>(
&password, &password,
blinding_factor_rng, blinding_factor_rng,
#[cfg(test)]
postprocess, postprocess,
)?; )?;
@@ -1037,35 +1025,31 @@ impl<CS: CipherSuite> ClientLogin<CS> {
password: &[u8], password: &[u8],
rng: &mut R, rng: &mut R,
) -> Result<(LoginFirstMessage<CS>, Self), ProtocolError> { ) -> Result<(LoginFirstMessage<CS>, Self), ProtocolError> {
Self::start_with_user_and_server_name(&Vec::new(), &Vec::new(), password, rng) Self::start_with_user_and_server_name(
&Vec::new(),
&Vec::new(),
password,
rng,
#[cfg(test)]
std::convert::identity,
)
} }
/// Same as start, but allows the user to supply a username and server name /// Same as start, but allows the user to supply a username and server name
/// and, in tests, a postprocessing function
pub fn start_with_user_and_server_name<R: RngCore + CryptoRng>( pub fn start_with_user_and_server_name<R: RngCore + CryptoRng>(
user_name: &[u8], user_name: &[u8],
server_name: &[u8], server_name: &[u8],
password: &[u8], password: &[u8],
rng: &mut R, rng: &mut R,
#[cfg(test)] postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar,
) -> Result<(LoginFirstMessage<CS>, Self), ProtocolError> { ) -> Result<(LoginFirstMessage<CS>, Self), ProtocolError> {
Self::start_with_user_and_server_name_and_postprocessing( let (token, alpha) = oprf::blind::<R, CS::Group>(
user_name, &password,
server_name,
password,
rng, rng,
std::convert::identity, #[cfg(test)]
) postprocess,
} )?;
/// Same as start, but allows the user to supply a username and server name and postprocessing function
pub fn start_with_user_and_server_name_and_postprocessing<R: RngCore + CryptoRng>(
user_name: &[u8],
server_name: &[u8],
password: &[u8],
rng: &mut R,
postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar,
) -> Result<(LoginFirstMessage<CS>, Self), ProtocolError> {
let (token, alpha) =
oprf::blind_with_postprocessing::<R, CS::Group>(&password, rng, postprocess)?;
let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(alpha.to_arr().to_vec(), rng)?; let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(alpha.to_arr().to_vec(), rng)?;
+27 -17
View File
@@ -23,14 +23,18 @@ static STR_VOPRF: &[u8] = b"VOPRF05";
/// message is sent from the client (who holds the input) to the server (who holds the OPRF key). /// message is sent from the client (who holds the input) to the server (who holds the OPRF key).
/// The client can also pass in an optional "pepper" string to be mixed in with the input through /// The client can also pass in an optional "pepper" string to be mixed in with the input through
/// an HKDF computation. /// an HKDF computation.
pub(crate) fn blind_with_postprocessing<R: RngCore + CryptoRng, G: GroupWithMapToCurve>( pub(crate) fn blind<R: RngCore + CryptoRng, G: GroupWithMapToCurve>(
input: &[u8], input: &[u8],
blinding_factor_rng: &mut R, blinding_factor_rng: &mut R,
postprocess: fn(G::Scalar) -> G::Scalar, #[cfg(test)] postprocess: fn(G::Scalar) -> G::Scalar,
) -> Result<(Token<G>, G), InternalPakeError> { ) -> Result<(Token<G>, G), InternalPakeError> {
let mapped_point = G::map_to_curve(input, Some(STR_VOPRF)); // TODO: add contextString from RFC let mapped_point = G::map_to_curve(input, Some(STR_VOPRF)); // TODO: add contextString from RFC
let blinding_factor = G::random_scalar(blinding_factor_rng); let blinding_factor = G::random_scalar(blinding_factor_rng);
#[cfg(test)]
let blind = postprocess(blinding_factor); let blind = postprocess(blinding_factor);
#[cfg(not(test))]
let blind = blinding_factor;
let blind_token = mapped_point * &blind; let blind_token = mapped_point * &blind;
Ok(( Ok((
Token { Token {
@@ -60,23 +64,34 @@ pub(crate) fn unblind_and_finalize<G: Group, H: Hash>(
Ok(prk) Ok(prk)
} }
// Benchmarking shims ////////////////////////
// Benchmarking shims //
////////////////////////
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
#[doc(hidden)]
#[inline] #[inline]
pub fn blind_shim<R: RngCore + CryptoRng, G: GroupWithMapToCurve>( pub fn blind_shim<R: RngCore + CryptoRng, G: GroupWithMapToCurve>(
input: &[u8], input: &[u8],
blinding_factor_rng: &mut R, blinding_factor_rng: &mut R,
) -> Result<(Token<G>, G), InternalPakeError> { ) -> Result<(Token<G>, G), InternalPakeError> {
blind_with_postprocessing(input, blinding_factor_rng, std::convert::identity) blind(
input,
blinding_factor_rng,
#[cfg(test)]
std::convert::identity,
)
} }
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
#[doc(hidden)]
#[inline] #[inline]
pub fn evaluate_shim<G: Group>(point: G, oprf_key: &G::Scalar) -> Result<G, InternalPakeError> { pub fn evaluate_shim<G: Group>(point: G, oprf_key: &G::Scalar) -> Result<G, InternalPakeError> {
evaluate(point, oprf_key) evaluate(point, oprf_key)
} }
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
#[doc(hidden)]
#[inline] #[inline]
pub fn unblind_and_finalize_shim<G: Group, H: Hash>( pub fn unblind_and_finalize_shim<G: Group, H: Hash>(
token: &Token<G>, token: &Token<G>,
@@ -85,8 +100,10 @@ pub fn unblind_and_finalize_shim<G: Group, H: Hash>(
unblind_and_finalize::<G, H>(token, point) unblind_and_finalize::<G, H>(token, point)
} }
// Tests ///////////
// ===== // Tests //
// ===== //
///////////
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@@ -117,11 +134,8 @@ mod tests {
fn oprf_retrieval() -> Result<(), InternalPakeError> { fn oprf_retrieval() -> Result<(), InternalPakeError> {
let input = b"hunter2"; let input = b"hunter2";
let mut rng = OsRng; let mut rng = OsRng;
let (token, alpha) = blind_with_postprocessing::<_, RistrettoPoint>( let (token, alpha) =
&input[..], blind::<_, RistrettoPoint>(&input[..], &mut rng, std::convert::identity)?;
&mut rng,
std::convert::identity,
)?;
let oprf_key_bytes = arr![ let oprf_key_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, 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, 24, 25, 26, 27, 28, 29, 30, 31, 32,
@@ -139,12 +153,8 @@ mod tests {
let mut rng = OsRng; let mut rng = OsRng;
let mut input = vec![0u8; 64]; let mut input = vec![0u8; 64];
rng.fill_bytes(&mut input); rng.fill_bytes(&mut input);
let (token, alpha) = blind_with_postprocessing::<_, RistrettoPoint>( let (token, alpha) =
&input, blind::<_, RistrettoPoint>(&input, &mut rng, std::convert::identity).unwrap();
&mut rng,
std::convert::identity,
)
.unwrap();
let res = unblind_and_finalize::<RistrettoPoint, sha2::Sha256>(&token, alpha).unwrap(); let res = unblind_and_finalize::<RistrettoPoint, sha2::Sha256>(&token, alpha).unwrap();
let (hashed_input, _) = Hkdf::<Sha512>::extract(Some(STR_VOPRF), &input); let (hashed_input, _) = Hkdf::<Sha512>::extract(Some(STR_VOPRF), &input);
+19 -17
View File
@@ -254,6 +254,7 @@ where
id_s, id_s,
password, password,
&mut blinding_factor_registration_rng, &mut blinding_factor_registration_rng,
std::convert::identity,
) )
.unwrap(); .unwrap();
let r1_bytes = r1.serialize().to_vec(); let r1_bytes = r1.serialize().to_vec();
@@ -291,6 +292,7 @@ where
id_s, id_s,
password, password,
&mut client_login_start_rng, &mut client_login_start_rng,
std::convert::identity,
) )
.unwrap(); .unwrap();
let l1_bytes = l1.serialize().to_vec(); let l1_bytes = l1.serialize().to_vec();
@@ -362,14 +364,15 @@ fn postprocess_blinding_factor<G: Group>(_: G::Scalar) -> G::Scalar {
fn test_r1() -> Result<(), PakeError> { fn test_r1() -> Result<(), PakeError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let mut rng = OsRng; let mut rng = OsRng;
let (r1, client_registration) = ClientRegistration::<X255193dhNoSlowHash>::start_with_user_and_server_name_and_postprocessing( let (r1, client_registration) =
&parameters.id_u, ClientRegistration::<X255193dhNoSlowHash>::start_with_user_and_server_name(
&parameters.id_s, &parameters.id_u,
&parameters.password, &parameters.id_s,
&mut rng, &parameters.password,
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>, &mut rng,
) postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
.unwrap(); )
.unwrap();
assert_eq!(hex::encode(&parameters.r1), hex::encode(r1.serialize())); assert_eq!(hex::encode(&parameters.r1), hex::encode(r1.serialize()));
assert_eq!( assert_eq!(
hex::encode(&parameters.client_registration_state), hex::encode(&parameters.client_registration_state),
@@ -452,15 +455,14 @@ fn test_l1() -> Result<(), PakeError> {
] ]
.concat(); .concat();
let mut client_login_start_rng = CycleRng::new(client_login_start); let mut client_login_start_rng = CycleRng::new(client_login_start);
let (l1, client_login) = let (l1, client_login) = ClientLogin::<X255193dhNoSlowHash>::start_with_user_and_server_name(
ClientLogin::<X255193dhNoSlowHash>::start_with_user_and_server_name_and_postprocessing( &parameters.id_u,
&parameters.id_u, &parameters.id_s,
&parameters.id_s, &parameters.password,
&parameters.password, &mut client_login_start_rng,
&mut client_login_start_rng, postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>, )
) .unwrap();
.unwrap();
assert_eq!(hex::encode(&parameters.l1), hex::encode(l1.serialize())); assert_eq!(hex::encode(&parameters.l1), hex::encode(l1.serialize()));
assert_eq!( assert_eq!(
hex::encode(&parameters.client_login_state), hex::encode(&parameters.client_login_state),