aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs48
-rw-r--r--src/spake2.rs159
2 files changed, 160 insertions, 47 deletions
diff --git a/src/lib.rs b/src/lib.rs
index dfc4b23..030498e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,12 +10,20 @@ pub use spake2::*;
#[cfg(test)]
mod tests {
- use spake2::{Ed25519Group, ErrorType, SPAKE2, SPAKEErr};
+ use spake2::{Ed25519Group, ErrorType, Identity, Password, SPAKE2, SPAKEErr};
#[test]
fn test_basic() {
- let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(b"password", b"idA", b"idB");
- let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b(b"password", b"idA", b"idB");
+ let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
+ let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
let key1 = s1.finish(msg2.as_slice()).unwrap();
let key2 = s2.finish(msg1.as_slice()).unwrap();
assert_eq!(key1, key2);
@@ -23,8 +31,16 @@ 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 (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
+ let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b(
+ &Password::new(b"password2"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
let key1 = s1.finish(msg2.as_slice()).unwrap();
let key2 = s2.finish(msg1.as_slice()).unwrap();
assert_ne!(key1, key2);
@@ -32,7 +48,11 @@ mod tests {
#[test]
fn test_reflected_message() {
- let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(b"password", b"idA", b"idB");
+ let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
let r = s1.finish(msg1.as_slice());
assert_eq!(
r.unwrap_err(),
@@ -44,7 +64,11 @@ mod tests {
#[test]
fn test_bad_length() {
- let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(b"password", b"idA", b"idB");
+ let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
let mut msg2 = Vec::<u8>::with_capacity(msg1.len() + 1);
msg2.resize(msg1.len() + 1, 0u8);
let r = s1.finish(&msg2);
@@ -58,8 +82,14 @@ mod tests {
#[test]
fn test_basic_symmetric() {
- let (s1, msg1) = SPAKE2::<Ed25519Group>::start_symmetric(b"password", b"idS");
- let (s2, msg2) = SPAKE2::<Ed25519Group>::start_symmetric(b"password", b"idS");
+ let (s1, msg1) = SPAKE2::<Ed25519Group>::start_symmetric(
+ &Password::new(b"password"),
+ &Identity::new(b"idS"),
+ );
+ let (s2, msg2) = SPAKE2::<Ed25519Group>::start_symmetric(
+ &Password::new(b"password"),
+ &Identity::new(b"idS"),
+ );
let key1 = s1.finish(msg2.as_slice()).unwrap();
let key2 = s2.finish(msg1.as_slice()).unwrap();
assert_eq!(key1, key2);
diff --git a/src/spake2.rs b/src/spake2.rs
index 31be328..fe416cb 100644
--- a/src/spake2.rs
+++ b/src/spake2.rs
@@ -10,9 +10,42 @@ use num_bigint::BigUint;
use rand::{CryptoRng, OsRng, Rng};
use sha2::{Digest, Sha256};
use std::fmt;
+use std::ops::Deref;
//use hex::ToHex;
+/* "newtype pattern": it's a Vec<u8>, but only used for a specific argument
+ * type, to distinguish between ones that are meant as passwords, and ones
+ * that are meant as identity strings */
+
+#[derive(PartialEq, Eq, Clone)]
+pub struct Password(Vec<u8>);
+impl Password {
+ pub fn new(p: &[u8]) -> Password {
+ Password(p.to_vec())
+ }
+}
+impl Deref for Password {
+ type Target = Vec<u8>;
+ fn deref(&self) -> &Vec<u8> {
+ &self.0
+ }
+}
+
+#[derive(PartialEq, Eq, Clone)]
+pub struct Identity(Vec<u8>);
+impl Deref for Identity {
+ type Target = Vec<u8>;
+ fn deref(&self) -> &Vec<u8> {
+ &self.0
+ }
+}
+impl Identity {
+ pub fn new(p: &[u8]) -> Identity {
+ Identity(p.to_vec())
+ }
+}
+
#[derive(Debug, PartialEq, Eq)]
pub enum ErrorType {
BadSide,
@@ -281,14 +314,14 @@ pub struct SPAKE2<G: Group> {
impl<G: Group> SPAKE2<G> {
fn start_internal(
side: Side,
- password: &[u8],
- id_a: &[u8],
- id_b: &[u8],
- id_s: &[u8],
+ password: &Password,
+ id_a: &Identity,
+ id_b: &Identity,
+ id_s: &Identity,
xy_scalar: G::Scalar,
) -> (SPAKE2<G>, Vec<u8>) {
//let password_scalar: G::Scalar = hash_to_scalar::<G::Scalar>(password);
- let password_scalar: G::Scalar = G::hash_to_scalar(password);
+ let password_scalar: G::Scalar = G::hash_to_scalar(&password);
// a: X = B*x + M*pw
// b: Y = B*y + N*pw
@@ -305,13 +338,13 @@ impl<G: Group> SPAKE2<G> {
//let m1: G::Element = &G::basepoint_mult(&x) + &(blinding * &password_scalar);
let msg1: Vec<u8> = G::element_to_bytes(&m1);
let mut password_vec = Vec::new();
- password_vec.extend_from_slice(password);
+ password_vec.extend_from_slice(&password);
let mut id_a_copy = Vec::new();
- id_a_copy.extend_from_slice(id_a);
+ id_a_copy.extend_from_slice(&id_a);
let mut id_b_copy = Vec::new();
- id_b_copy.extend_from_slice(id_b);
+ id_b_copy.extend_from_slice(&id_b);
let mut id_s_copy = Vec::new();
- id_s_copy.extend_from_slice(id_s);
+ id_s_copy.extend_from_slice(&id_s);
let mut msg_and_side = Vec::new();
msg_and_side.push(match side {
@@ -337,47 +370,68 @@ impl<G: Group> SPAKE2<G> {
}
fn start_a_internal(
- password: &[u8],
- id_a: &[u8],
- id_b: &[u8],
+ password: &Password,
+ id_a: &Identity,
+ id_b: &Identity,
xy_scalar: G::Scalar,
) -> (SPAKE2<G>, Vec<u8>) {
- Self::start_internal(Side::A, password, id_a, id_b, b"", xy_scalar)
+ Self::start_internal(
+ Side::A,
+ &password,
+ &id_a,
+ &id_b,
+ &Identity::new(b""),
+ xy_scalar,
+ )
}
fn start_b_internal(
- password: &[u8],
- id_a: &[u8],
- id_b: &[u8],
+ password: &Password,
+ id_a: &Identity,
+ id_b: &Identity,
xy_scalar: G::Scalar,
) -> (SPAKE2<G>, Vec<u8>) {
- Self::start_internal(Side::B, password, id_a, id_b, b"", xy_scalar)
+ Self::start_internal(
+ Side::B,
+ &password,
+ &id_a,
+ &id_b,
+ &Identity::new(b""),
+ xy_scalar,
+ )
}
fn start_symmetric_internal(
- password: &[u8],
- id_s: &[u8],
+ password: &Password,
+ id_s: &Identity,
xy_scalar: G::Scalar,
) -> (SPAKE2<G>, Vec<u8>) {
- Self::start_internal(Side::Symmetric, password, b"", b"", id_s, xy_scalar)
+ Self::start_internal(
+ Side::Symmetric,
+ &password,
+ &Identity::new(b""),
+ &Identity::new(b""),
+ &id_s,
+ xy_scalar,
+ )
}
- pub fn start_a(password: &[u8], id_a: &[u8], id_b: &[u8]) -> (SPAKE2<G>, Vec<u8>) {
+ pub fn start_a(password: &Password, id_a: &Identity, id_b: &Identity) -> (SPAKE2<G>, Vec<u8>) {
let mut cspring: OsRng = OsRng::new().unwrap();
let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
- Self::start_a_internal(password, id_a, id_b, xy_scalar)
+ Self::start_a_internal(&password, &id_a, &id_b, xy_scalar)
}
- pub fn start_b(password: &[u8], id_a: &[u8], id_b: &[u8]) -> (SPAKE2<G>, Vec<u8>) {
+ pub fn start_b(password: &Password, id_a: &Identity, id_b: &Identity) -> (SPAKE2<G>, Vec<u8>) {
let mut cspring: OsRng = OsRng::new().unwrap();
let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
- Self::start_b_internal(password, id_a, id_b, xy_scalar)
+ Self::start_b_internal(&password, &id_a, &id_b, xy_scalar)
}
- pub fn start_symmetric(password: &[u8], id_s: &[u8]) -> (SPAKE2<G>, Vec<u8>) {
+ pub fn start_symmetric(password: &Password, id_s: &Identity) -> (SPAKE2<G>, Vec<u8>) {
let mut cspring: OsRng = OsRng::new().unwrap();
let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
- Self::start_symmetric_internal(password, id_s, xy_scalar)
+ Self::start_symmetric_internal(&password, &id_s, xy_scalar)
}
pub fn finish(self, msg2: &[u8]) -> Result<Vec<u8>, SPAKEErr> {
@@ -535,11 +589,11 @@ mod test {
#[test]
fn test_password_to_scalar() {
- let password = b"password";
+ let password = Password::new(b"password");
let expected_pw_scalar = decimal_to_scalar(
b"3515301705789368674385125653994241092664323519848410154015274772661223168839",
);
- let pw_scalar = Ed25519Group::hash_to_scalar(password);
+ let pw_scalar = Ed25519Group::hash_to_scalar(&password);
println!("exp: {:?}", hex::encode(expected_pw_scalar.as_bytes()));
println!("got: {:?}", hex::encode(pw_scalar.as_bytes()));
assert_eq!(&pw_scalar, &expected_pw_scalar);
@@ -547,18 +601,32 @@ mod test {
#[test]
fn test_sizes() {
- let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(b"password", b"idA", b"idB");
+ let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
assert_eq!(msg1.len(), 1 + 32);
- let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b(b"password", b"idA", b"idB");
+ let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
assert_eq!(msg2.len(), 1 + 32);
let key1 = s1.finish(&msg2).unwrap();
let key2 = s2.finish(&msg1).unwrap();
assert_eq!(key1.len(), 32);
assert_eq!(key2.len(), 32);
- let (s1, msg1) = SPAKE2::<Ed25519Group>::start_symmetric(b"password", b"idS");
+ let (s1, msg1) = SPAKE2::<Ed25519Group>::start_symmetric(
+ &Password::new(b"password"),
+ &Identity::new(b"idS"),
+ );
assert_eq!(msg1.len(), 1 + 32);
- let (s2, msg2) = SPAKE2::<Ed25519Group>::start_symmetric(b"password", b"idS");
+ let (s2, msg2) = SPAKE2::<Ed25519Group>::start_symmetric(
+ &Password::new(b"password"),
+ &Identity::new(b"idS"),
+ );
assert_eq!(msg2.len(), 1 + 32);
let key1 = s1.finish(&msg2).unwrap();
let key2 = s2.finish(&msg1).unwrap();
@@ -607,8 +675,12 @@ mod test {
println!("scalar_a is {}", hex::encode(scalar_a.as_bytes()));
- let (s1, msg1) =
- SPAKE2::<Ed25519Group>::start_a_internal(b"password", b"idA", b"idB", scalar_a);
+ let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a_internal(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ scalar_a,
+ );
let expected_msg1 = "416fc960df73c9cf8ed7198b0c9534e2e96a5984bfc5edc023fd24dacf371f2af9";
println!();
@@ -627,8 +699,12 @@ mod test {
);
assert_eq!(hex::encode(&msg1), expected_msg1);
- let (s2, msg2) =
- SPAKE2::<Ed25519Group>::start_b_internal(b"password", b"idA", b"idB", scalar_b);
+ let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b_internal(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ scalar_b,
+ );
assert_eq!(expected_pw_scalar, s2.password_scalar);
assert_eq!(
hex::encode(&msg2),
@@ -646,9 +722,16 @@ mod test {
#[test]
fn test_debug() {
- let (s1, _msg1) = SPAKE2::<Ed25519Group>::start_a(b"password", b"idA", b"idB");
+ let (s1, _msg1) = SPAKE2::<Ed25519Group>::start_a(
+ &Password::new(b"password"),
+ &Identity::new(b"idA"),
+ &Identity::new(b"idB"),
+ );
println!("s1: {:?}", s1);
- let (s2, _msg1) = SPAKE2::<Ed25519Group>::start_symmetric(b"password", b"idS");
+ let (s2, _msg1) = SPAKE2::<Ed25519Group>::start_symmetric(
+ &Password::new(b"password"),
+ &Identity::new(b"idS"),
+ );
println!("s2: {:?}", s2);
}