diff options
author | Brian Warner <warner@lothar.com> | 2017-08-02 12:55:35 -0700 |
---|---|---|
committer | Brian Warner <warner@lothar.com> | 2017-09-21 13:02:12 -0700 |
commit | 861ece4475b823005c310d42725fe59e7b4876ea (patch) | |
tree | 947dfa1d4a849d0eab86f9432c7254a09940ee5f | |
parent | 332e28b02bcad93144614400c5624ea75ed653b3 (diff) | |
download | PAKEs-861ece4475b823005c310d42725fe59e7b4876ea.tar.xz |
move from (unmaintained) rust-crypto to RustCrypto ('sha2' crate)
Also upgrade to curve25519-dalek 0.11, hkdf-0.2, refine error types, add more
tests.
-rw-r--r-- | Cargo.toml | 6 | ||||
-rw-r--r-- | src/lib.rs | 35 | ||||
-rw-r--r-- | src/spake2.rs | 66 |
3 files changed, 67 insertions, 40 deletions
@@ -16,10 +16,10 @@ exclude = [ travis-ci = { repository = "warner/spake2.rs" } [dependencies] -curve25519-dalek = "0.9" +curve25519-dalek = "0.11" rand = "0.3" -#sha2 = "0.4.0" -rust-crypto = "0.2" +sha2 = "0.6" +hkdf = "0.2" num-bigint = "0.1" hex = "0.2" @@ -1,8 +1,8 @@ extern crate rand; extern crate curve25519_dalek; -//extern crate sha2; -extern crate crypto; +extern crate sha2; +extern crate hkdf; extern crate num_bigint; extern crate hex; @@ -15,7 +15,7 @@ pub use spake2::*; #[cfg(test)] mod tests { - use spake2::{SPAKE2, Ed25519Group}; + use spake2::{SPAKE2, SPAKEErr, Ed25519Group, ErrorType}; #[test] fn test_basic() { @@ -29,6 +29,35 @@ mod tests { } #[test] + fn test_mismatch() { + let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(b"password", + b"idA", b"idB"); + let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b(b"password2", + b"idA", b"idB"); + let key1 = s1.finish(msg2.as_slice()).unwrap(); + let key2 = s2.finish(msg1.as_slice()).unwrap(); + assert_ne!(key1, key2); + } + + #[test] + fn test_reflected_message() { + let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(b"password", + b"idA", b"idB"); + let r = s1.finish(msg1.as_slice()); + assert_eq!(r.unwrap_err(), SPAKEErr{kind: ErrorType::BadSide}); + } + + #[test] + fn test_bad_length() { + let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(b"password", + b"idA", b"idB"); + let mut msg2 = Vec::<u8>::with_capacity(msg1.len()+1); + msg2.resize(msg1.len()+1, 0u8); + let r = s1.finish(&msg2); + assert_eq!(r.unwrap_err(), SPAKEErr{kind: ErrorType::WrongLength}); + } + + #[test] fn test_basic_symmetric() { let (s1, msg1) = SPAKE2::<Ed25519Group>::start_symmetric(b"password", b"idS"); diff --git a/src/spake2.rs b/src/spake2.rs index 4a9f470..abd0373 100644 --- a/src/spake2.rs +++ b/src/spake2.rs @@ -1,20 +1,27 @@ #![allow(dead_code)] use curve25519_dalek::scalar::Scalar as c2_Scalar; -use curve25519_dalek::curve::ExtendedPoint as c2_Element; -use curve25519_dalek::constants::ED25519_BASEPOINT; -use curve25519_dalek::curve::CompressedEdwardsY; +use curve25519_dalek::edwards::ExtendedPoint as c2_Element; +use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; +use curve25519_dalek::edwards::CompressedEdwardsY; use rand::{Rng, OsRng}; -//use sha2::{Sha256, Sha512, Digest}; -use crypto::sha2::Sha256; -use crypto::digest::Digest; -use crypto::hkdf; +use sha2::{Sha256, Digest}; +use hkdf::Hkdf; use num_bigint::BigUint; use hex::ToHex; -#[derive(Debug)] -pub struct SPAKEErr ( String ); +#[derive(Debug, PartialEq)] +pub enum ErrorType { + BadSide, + WrongLength, + CorruptMessage, +} + +#[derive(Debug, PartialEq)] +pub struct SPAKEErr { + pub kind: ErrorType, +} pub trait Group { type Scalar; @@ -107,7 +114,7 @@ impl Group for Ed25519Group { fn basepoint_mult(s: &c2_Scalar) -> c2_Element { //c2_Element::basepoint_mult(s) - &ED25519_BASEPOINT * s + &ED25519_BASEPOINT_POINT * s } fn scalarmult(e: &c2_Element, s: &c2_Scalar) -> c2_Element { e * s @@ -134,12 +141,7 @@ fn ed25519_hash_to_scalar(s: &[u8]) -> c2_Scalar { // i = int(h, 16) // i % q - let mut prk = [0u8; 32]; - let digest = Sha256::new(); - hkdf::hkdf_extract(digest, b"", s, &mut prk); - let mut okm = [0u8; 32+16]; - hkdf::hkdf_expand(digest, &prk, b"SPAKE2 pw", &mut okm); - //okm[32+16-2] = 1; + let okm = Hkdf::<Sha256>::new(s, b"").derive(b"SPAKE2 pw", 32+16); println!("expanded: {}{}", "................................", okm.iter().to_hex()); // ok let mut reducible = [0u8; 64]; // little-endian @@ -169,15 +171,15 @@ fn ed25519_hash_ab(password_vec: &[u8], id_a: &[u8], id_b: &[u8], let mut pw_hash = Sha256::new(); pw_hash.input(password_vec); - pw_hash.result(&mut transcript[0..32]); + transcript[0..32].copy_from_slice(&pw_hash.result()); let mut ida_hash = Sha256::new(); ida_hash.input(id_a); - ida_hash.result(&mut transcript[32..64]); + transcript[32..64].copy_from_slice(&ida_hash.result()); let mut idb_hash = Sha256::new(); idb_hash.input(id_b); - idb_hash.result(&mut transcript[64..96]); + transcript[64..96].copy_from_slice(&idb_hash.result()); transcript[96..128].copy_from_slice(first_msg); transcript[128..160].copy_from_slice(second_msg); @@ -188,9 +190,7 @@ fn ed25519_hash_ab(password_vec: &[u8], id_a: &[u8], id_b: &[u8], //let mut hash = G::TranscriptHash::default(); let mut hash = Sha256::new(); hash.input(&transcript); - let mut out = [0u8; 32]; - hash.result(&mut out); - out.to_vec() + hash.result().to_vec() } fn ed25519_hash_symmetric(password_vec: &[u8], id_s: &[u8], @@ -214,11 +214,11 @@ fn ed25519_hash_symmetric(password_vec: &[u8], id_s: &[u8], let mut pw_hash = Sha256::new(); pw_hash.input(password_vec); - pw_hash.result(&mut transcript[0..32]); + transcript[0..32].copy_from_slice(&pw_hash.result()); let mut ids_hash = Sha256::new(); ids_hash.input(id_s); - ids_hash.result(&mut transcript[32..64]); + transcript[32..64].copy_from_slice(&ids_hash.result()); if msg_u < msg_v { transcript[64..96].copy_from_slice(msg_u); @@ -231,9 +231,7 @@ fn ed25519_hash_symmetric(password_vec: &[u8], id_s: &[u8], let mut hash = Sha256::new(); hash.input(&transcript); - let mut out = [0u8; 32]; - hash.result(&mut out); - out.to_vec() + hash.result().to_vec() } /* "session type pattern" */ @@ -345,28 +343,28 @@ impl<G: Group> SPAKE2<G> { pub fn finish(self, msg2: &[u8]) -> Result<Vec<u8>, SPAKEErr> { if msg2.len() != 1 + G::element_length() { - return Err(SPAKEErr(String::from("inbound message is the wrong length"))) + return Err(SPAKEErr{kind: ErrorType::WrongLength}); } let msg_side = msg2[0]; match self.side { Side::A => match msg_side { 0x42 => (), // 'B' - _ => return Err(SPAKEErr(String::from("bad side"))), + _ => return Err(SPAKEErr{kind: ErrorType::BadSide}), }, Side::B => match msg_side { 0x41 => (), // 'A' - _ => return Err(SPAKEErr(String::from("bad side"))), + _ => return Err(SPAKEErr{kind: ErrorType::BadSide}), }, Side::Symmetric => match msg_side { 0x53 => (), // 'S' - _ => return Err(SPAKEErr(String::from("bad side"))), + _ => return Err(SPAKEErr{kind: ErrorType::BadSide}), }, } let msg2_element = match G::bytes_to_element(&msg2[1..]) { Some(x) => x, - None => {return Err(SPAKEErr(String::from("message corrupted")))}, + None => {return Err(SPAKEErr{kind: ErrorType::CorruptMessage})}, }; // a: K = (Y+N*(-pw))*x @@ -415,7 +413,7 @@ mod test { "random_scalar()" function, which results in some particular scalar. */ use curve25519_dalek::scalar::Scalar; - use curve25519_dalek::constants::ED25519_BASEPOINT; + use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; use spake2::{SPAKE2, Ed25519Group}; use hex::ToHex; use super::*; @@ -441,7 +439,7 @@ mod test { fn test_serialize_basepoint() { // make sure elements are serialized same as the python library let exp = "5866666666666666666666666666666666666666666666666666666666666666"; - let base_vec = ED25519_BASEPOINT.compress_edwards().as_bytes().to_vec(); + let base_vec = ED25519_BASEPOINT_POINT.compress_edwards().as_bytes().to_vec(); let base_hex = base_vec.to_hex(); println!("exp: {:?}", exp); println!("got: {:?}", base_hex); |