aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Warner <warner@lothar.com>2017-08-02 12:55:35 -0700
committerBrian Warner <warner@lothar.com>2017-09-21 13:02:12 -0700
commit861ece4475b823005c310d42725fe59e7b4876ea (patch)
tree947dfa1d4a849d0eab86f9432c7254a09940ee5f
parent332e28b02bcad93144614400c5624ea75ed653b3 (diff)
downloadPAKEs-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.toml6
-rw-r--r--src/lib.rs35
-rw-r--r--src/spake2.rs66
3 files changed, 67 insertions, 40 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 5344171..f2a286f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/src/lib.rs b/src/lib.rs
index 9083473..beffd19 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);