3 use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
4 use curve25519_dalek::edwards::CompressedEdwardsY;
5 use curve25519_dalek::edwards::EdwardsPoint as c2_Element;
6 use curve25519_dalek::scalar::Scalar as c2_Scalar;
9 use num_bigint::BigUint;
10 use rand::{CryptoRng, OsRng, Rng};
11 use sha2::{Digest, Sha256};
17 /* "newtype pattern": it's a Vec<u8>, but only used for a specific argument
18 * type, to distinguish between ones that are meant as passwords, and ones
19 * that are meant as identity strings */
21 #[derive(PartialEq, Eq, Clone)]
22 pub struct Password(Vec<u8>);
24 pub fn new(p: &[u8]) -> Password {
28 impl Deref for Password {
29 type Target = Vec<u8>;
30 fn deref(&self) -> &Vec<u8> {
35 #[derive(PartialEq, Eq, Clone)]
36 pub struct Identity(Vec<u8>);
37 impl Deref for Identity {
38 type Target = Vec<u8>;
39 fn deref(&self) -> &Vec<u8> {
44 pub fn new(p: &[u8]) -> Identity {
49 #[derive(Debug, PartialEq, Eq)]
56 #[derive(Debug, PartialEq, Eq)]
64 //type Element: Add<Output=Self::Element>
65 // + Mul<Self::Scalar, Output=Self::Element>;
66 // const element_length: usize; // in unstable, or u8
67 //type ElementBytes : Index<usize, Output=u8>+IndexMut<usize>; // later
69 fn const_m() -> Self::Element;
70 fn const_n() -> Self::Element;
71 fn const_s() -> Self::Element;
72 fn hash_to_scalar(s: &[u8]) -> Self::Scalar;
73 fn random_scalar<T>(cspring: &mut T) -> Self::Scalar
76 fn scalar_neg(s: &Self::Scalar) -> Self::Scalar;
77 fn element_to_bytes(e: &Self::Element) -> Vec<u8>;
78 fn bytes_to_element(b: &[u8]) -> Option<Self::Element>;
79 fn element_length() -> usize;
80 fn basepoint_mult(s: &Self::Scalar) -> Self::Element;
81 fn scalarmult(e: &Self::Element, s: &Self::Scalar) -> Self::Element;
82 fn add(a: &Self::Element, b: &Self::Element) -> Self::Element;
85 #[derive(Debug, PartialEq, Eq)]
86 pub struct Ed25519Group;
88 impl Group for Ed25519Group {
89 type Scalar = c2_Scalar;
90 type Element = c2_Element;
91 //type ElementBytes = Vec<u8>;
92 //type ElementBytes = [u8; 32];
94 type TranscriptHash = Sha256;
96 fn const_m() -> c2_Element {
97 // python -c "import binascii, spake2; b=binascii.hexlify(spake2.ParamsEd25519.M.to_bytes()); print(', '.join(['0x'+b[i:i+2] for i in range(0,len(b),2)]))"
98 // 15cfd18e385952982b6a8f8c7854963b58e34388c8e6dae891db756481a02312
100 0x15, 0xcf, 0xd1, 0x8e, 0x38, 0x59, 0x52, 0x98, 0x2b, 0x6a, 0x8f, 0x8c, 0x78, 0x54,
101 0x96, 0x3b, 0x58, 0xe3, 0x43, 0x88, 0xc8, 0xe6, 0xda, 0xe8, 0x91, 0xdb, 0x75, 0x64,
102 0x81, 0xa0, 0x23, 0x12,
107 fn const_n() -> c2_Element {
108 // python -c "import binascii, spake2; b=binascii.hexlify(spake2.ParamsEd25519.N.to_bytes()); print(', '.join(['0x'+b[i:i+2] for i in range(0,len(b),2)]))"
109 // f04f2e7eb734b2a8f8b472eaf9c3c632576ac64aea650b496a8a20ff00e583c3
111 0xf0, 0x4f, 0x2e, 0x7e, 0xb7, 0x34, 0xb2, 0xa8, 0xf8, 0xb4, 0x72, 0xea, 0xf9, 0xc3,
112 0xc6, 0x32, 0x57, 0x6a, 0xc6, 0x4a, 0xea, 0x65, 0x0b, 0x49, 0x6a, 0x8a, 0x20, 0xff,
113 0x00, 0xe5, 0x83, 0xc3,
118 fn const_s() -> c2_Element {
119 // python -c "import binascii, spake2; b=binascii.hexlify(spake2.ParamsEd25519.S.to_bytes()); print(', '.join(['0x'+b[i:i+2] for i in range(0,len(b),2)]))"
120 // 6f00dae87c1be1a73b5922ef431cd8f57879569c222d22b1cd71e8546ab8e6f1
122 0x6f, 0x00, 0xda, 0xe8, 0x7c, 0x1b, 0xe1, 0xa7, 0x3b, 0x59, 0x22, 0xef, 0x43, 0x1c,
123 0xd8, 0xf5, 0x78, 0x79, 0x56, 0x9c, 0x22, 0x2d, 0x22, 0xb1, 0xcd, 0x71, 0xe8, 0x54,
124 0x6a, 0xb8, 0xe6, 0xf1,
129 fn hash_to_scalar(s: &[u8]) -> c2_Scalar {
130 ed25519_hash_to_scalar(s)
132 fn random_scalar<T>(cspring: &mut T) -> c2_Scalar
136 c2_Scalar::random(cspring)
138 fn scalar_neg(s: &c2_Scalar) -> c2_Scalar {
141 fn element_to_bytes(s: &c2_Element) -> Vec<u8> {
142 s.compress().as_bytes().to_vec()
144 fn element_length() -> usize {
147 fn bytes_to_element(b: &[u8]) -> Option<c2_Element> {
151 //let mut bytes: [u8; 32] =
152 let mut bytes = [0u8; 32];
153 bytes.copy_from_slice(b);
154 let cey = CompressedEdwardsY(bytes);
155 // CompressedEdwardsY::new(b)
159 fn basepoint_mult(s: &c2_Scalar) -> c2_Element {
160 //c2_Element::basepoint_mult(s)
161 ED25519_BASEPOINT_POINT * s
163 fn scalarmult(e: &c2_Element, s: &c2_Scalar) -> c2_Element {
167 fn add(a: &c2_Element, b: &c2_Element) -> c2_Element {
173 fn decimal_to_scalar(d: &[u8]) -> c2_Scalar {
174 let bytes = BigUint::parse_bytes(d, 10).unwrap().to_bytes_le();
175 assert_eq!(bytes.len(), 32);
176 let mut b2 = [0u8; 32];
177 b2.copy_from_slice(&bytes);
178 c2_Scalar::from_bytes_mod_order(b2)
181 fn ed25519_hash_to_scalar(s: &[u8]) -> c2_Scalar {
182 //c2_Scalar::hash_from_bytes::<Sha512>(&s)
184 // h = HKDF(salt=b"", ikm=s, hash=SHA256, info=b"SPAKE2 pw", len=32+16)
188 let mut okm = [0u8; 32+16];
189 Hkdf::<Sha256>::extract(Some(b""), s).expand(b"SPAKE2 pw", &mut okm).unwrap();
190 //println!("expanded: {}{}", "................................", okm.iter().to_hex()); // ok
192 let mut reducible = [0u8; 64]; // little-endian
193 for (i, x) in okm.iter().enumerate().take(32 + 16) {
194 reducible[32 + 16 - 1 - i] = *x;
196 //println!("reducible: {}", reducible.iter().to_hex());
197 c2_Scalar::from_bytes_mod_order_wide(&reducible)
198 //let reduced = c2_Scalar::reduce(&reducible);
199 //println!("reduced: {}", reduced.as_bytes().to_hex());
212 assert_eq!(first_msg.len(), 32);
213 assert_eq!(second_msg.len(), 32);
214 // the transcript is fixed-length, made up of 6 32-byte values:
215 // byte 0-31 : sha256(pw)
216 // byte 32-63 : sha256(idA)
217 // byte 64-95 : sha256(idB)
218 // byte 96-127 : X_msg
219 // byte 128-159: Y_msg
220 // byte 160-191: K_bytes
221 let mut transcript = [0u8; 6 * 32];
223 let mut pw_hash = Sha256::new();
224 pw_hash.input(password_vec);
225 transcript[0..32].copy_from_slice(&pw_hash.result());
227 let mut ida_hash = Sha256::new();
228 ida_hash.input(id_a);
229 transcript[32..64].copy_from_slice(&ida_hash.result());
231 let mut idb_hash = Sha256::new();
232 idb_hash.input(id_b);
233 transcript[64..96].copy_from_slice(&idb_hash.result());
235 transcript[96..128].copy_from_slice(first_msg);
236 transcript[128..160].copy_from_slice(second_msg);
237 transcript[160..192].copy_from_slice(key_bytes);
239 //println!("transcript: {:?}", transcript.iter().to_hex());
241 //let mut hash = G::TranscriptHash::default();
242 let mut hash = Sha256::new();
243 hash.input(&transcript);
244 hash.result().to_vec()
247 fn ed25519_hash_symmetric(
254 assert_eq!(msg_u.len(), 32);
255 assert_eq!(msg_v.len(), 32);
256 // # since we don't know which side is which, we must sort the messages
257 // first_msg, second_msg = sorted([msg1, msg2])
258 // transcript = b"".join([sha256(pw).digest(),
259 // sha256(idSymmetric).digest(),
260 // first_msg, second_msg, K_bytes])
262 // the transcript is fixed-length, made up of 5 32-byte values:
263 // byte 0-31 : sha256(pw)
264 // byte 32-63 : sha256(idSymmetric)
265 // byte 64-95 : X_msg
266 // byte 96-127 : Y_msg
267 // byte 128-159: K_bytes
268 let mut transcript = [0u8; 5 * 32];
270 let mut pw_hash = Sha256::new();
271 pw_hash.input(password_vec);
272 transcript[0..32].copy_from_slice(&pw_hash.result());
274 let mut ids_hash = Sha256::new();
275 ids_hash.input(id_s);
276 transcript[32..64].copy_from_slice(&ids_hash.result());
279 transcript[64..96].copy_from_slice(msg_u);
280 transcript[96..128].copy_from_slice(msg_v);
282 transcript[64..96].copy_from_slice(msg_v);
283 transcript[96..128].copy_from_slice(msg_u);
285 transcript[128..160].copy_from_slice(key_bytes);
287 let mut hash = Sha256::new();
288 hash.input(&transcript);
289 hash.result().to_vec()
292 /* "session type pattern" */
294 #[derive(Debug, PartialEq, Eq)]
301 // we implement a custom Debug below, to avoid revealing secrets in a dump
302 #[derive(PartialEq, Eq)]
303 pub struct SPAKE2<G: Group> {
304 //where &G::Scalar: Neg {
306 xy_scalar: G::Scalar,
307 password_vec: Vec<u8>,
312 password_scalar: G::Scalar,
315 impl<G: Group> SPAKE2<G> {
322 xy_scalar: G::Scalar,
323 ) -> (SPAKE2<G>, Vec<u8>) {
324 //let password_scalar: G::Scalar = hash_to_scalar::<G::Scalar>(password);
325 let password_scalar: G::Scalar = G::hash_to_scalar(&password);
329 // sym: X = B*x * S*pw
330 let blinding = match side {
331 Side::A => G::const_m(),
332 Side::B => G::const_n(),
333 Side::Symmetric => G::const_s(),
335 let m1: G::Element = G::add(
336 &G::basepoint_mult(&xy_scalar),
337 &G::scalarmult(&blinding, &password_scalar),
339 //let m1: G::Element = &G::basepoint_mult(&x) + &(blinding * &password_scalar);
340 let msg1: Vec<u8> = G::element_to_bytes(&m1);
341 let mut password_vec = Vec::new();
342 password_vec.extend_from_slice(&password);
343 let mut id_a_copy = Vec::new();
344 id_a_copy.extend_from_slice(&id_a);
345 let mut id_b_copy = Vec::new();
346 id_b_copy.extend_from_slice(&id_b);
347 let mut id_s_copy = Vec::new();
348 id_s_copy.extend_from_slice(&id_s);
350 let mut msg_and_side = Vec::new();
351 msg_and_side.push(match side {
352 Side::A => 0x41, // 'A'
353 Side::B => 0x42, // 'B'
354 Side::Symmetric => 0x53, // 'S'
356 msg_and_side.extend_from_slice(&msg1);
362 password_vec, // string
367 password_scalar, // scalar
377 xy_scalar: G::Scalar,
378 ) -> (SPAKE2<G>, Vec<u8>) {
379 Self::start_internal(
393 xy_scalar: G::Scalar,
394 ) -> (SPAKE2<G>, Vec<u8>) {
395 Self::start_internal(
405 fn start_symmetric_internal(
408 xy_scalar: G::Scalar,
409 ) -> (SPAKE2<G>, Vec<u8>) {
410 Self::start_internal(
420 pub fn start_a(password: &Password, id_a: &Identity, id_b: &Identity) -> (SPAKE2<G>, Vec<u8>) {
421 let mut cspring: OsRng = OsRng::new().unwrap();
422 let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
423 Self::start_a_internal(&password, &id_a, &id_b, xy_scalar)
426 pub fn start_b(password: &Password, id_a: &Identity, id_b: &Identity) -> (SPAKE2<G>, Vec<u8>) {
427 let mut cspring: OsRng = OsRng::new().unwrap();
428 let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
429 Self::start_b_internal(&password, &id_a, &id_b, xy_scalar)
432 pub fn start_symmetric(password: &Password, id_s: &Identity) -> (SPAKE2<G>, Vec<u8>) {
433 let mut cspring: OsRng = OsRng::new().unwrap();
434 let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
435 Self::start_symmetric_internal(&password, &id_s, xy_scalar)
438 pub fn finish(self, msg2: &[u8]) -> Result<Vec<u8>, SPAKEErr> {
439 if msg2.len() != 1 + G::element_length() {
440 return Err(SPAKEErr {
441 kind: ErrorType::WrongLength,
444 let msg_side = msg2[0];
447 Side::A => match msg_side {
450 return Err(SPAKEErr {
451 kind: ErrorType::BadSide,
455 Side::B => match msg_side {
458 return Err(SPAKEErr {
459 kind: ErrorType::BadSide,
463 Side::Symmetric => match msg_side {
466 return Err(SPAKEErr {
467 kind: ErrorType::BadSide,
473 let msg2_element = match G::bytes_to_element(&msg2[1..]) {
476 return Err(SPAKEErr {
477 kind: ErrorType::CorruptMessage,
482 // a: K = (Y+N*(-pw))*x
483 // b: K = (X+M*(-pw))*y
484 let unblinding = match self.side {
485 Side::A => G::const_n(),
486 Side::B => G::const_m(),
487 Side::Symmetric => G::const_s(),
489 let tmp1 = G::scalarmult(&unblinding, &G::scalar_neg(&self.password_scalar));
490 let tmp2 = G::add(&msg2_element, &tmp1);
491 let key_element = G::scalarmult(&tmp2, &self.xy_scalar);
492 let key_bytes = G::element_to_bytes(&key_element);
494 // key = H(H(pw) + H(idA) + H(idB) + X + Y + K)
495 //transcript = b"".join([sha256(pw).digest(),
496 // sha256(idA).digest(), sha256(idB).digest(),
497 // X_msg, Y_msg, K_bytes])
498 //key = sha256(transcript).digest()
499 // note that both sides must use the same order
502 Side::A => ed25519_hash_ab(
506 self.msg1.as_slice(),
510 Side::B => ed25519_hash_ab(
515 self.msg1.as_slice(),
518 Side::Symmetric => ed25519_hash_symmetric(
529 fn maybe_utf8(s: &[u8]) -> String {
530 match String::from_utf8(s.to_vec()) {
531 Ok(m) => format!("(s={})", m),
532 Err(_) => format!("(hex={})", hex::encode(s)),
536 impl<G: Group> fmt::Debug for SPAKE2<G> {
537 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
540 "SPAKE2(G=?, side={:?}, idA={}, idB={}, idS={})",
542 maybe_utf8(&self.id_a),
543 maybe_utf8(&self.id_b),
544 maybe_utf8(&self.id_s)
551 /* This compares results against the python compatibility tests:
552 spake2.test.test_compat.SPAKE2.test_asymmetric . The python test passes a
553 deterministic RNG (used only for tests, of course) into the per-Group
554 "random_scalar()" function, which results in some particular scalar.
557 use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
559 use spake2::{Ed25519Group, SPAKE2};
561 // the python tests show the long-integer form of scalars. the rust code
562 // wants an array of bytes (little-endian). Make sure the way we convert
563 // things works correctly.
568 b"2238329342913194256032495932344128051776374960164957527413114840482143558222";
569 let t1_scalar = decimal_to_scalar(t1_decimal);
570 let t1_bytes = t1_scalar.to_bytes();
572 0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2,
573 0x7d, 0x52, 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, 0xd4, 0x49, 0xf4, 0xa8,
574 0x79, 0xd9, 0xf2, 0x04,
576 assert_eq!(t1_bytes, expected);
577 //println!("t1_scalar is {:?}", t1_scalar);
581 fn test_serialize_basepoint() {
582 // make sure elements are serialized same as the python library
583 let exp = "5866666666666666666666666666666666666666666666666666666666666666";
584 let base_vec = ED25519_BASEPOINT_POINT.compress().as_bytes().to_vec();
585 let base_hex = hex::encode(base_vec);
586 println!("exp: {:?}", exp);
587 println!("got: {:?}", base_hex);
588 assert_eq!(exp, base_hex);
592 fn test_password_to_scalar() {
593 let password = Password::new(b"password");
594 let expected_pw_scalar = decimal_to_scalar(
595 b"3515301705789368674385125653994241092664323519848410154015274772661223168839",
597 let pw_scalar = Ed25519Group::hash_to_scalar(&password);
598 println!("exp: {:?}", hex::encode(expected_pw_scalar.as_bytes()));
599 println!("got: {:?}", hex::encode(pw_scalar.as_bytes()));
600 assert_eq!(&pw_scalar, &expected_pw_scalar);
605 let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(
606 &Password::new(b"password"),
607 &Identity::new(b"idA"),
608 &Identity::new(b"idB"),
610 assert_eq!(msg1.len(), 1 + 32);
611 let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b(
612 &Password::new(b"password"),
613 &Identity::new(b"idA"),
614 &Identity::new(b"idB"),
616 assert_eq!(msg2.len(), 1 + 32);
617 let key1 = s1.finish(&msg2).unwrap();
618 let key2 = s2.finish(&msg1).unwrap();
619 assert_eq!(key1.len(), 32);
620 assert_eq!(key2.len(), 32);
622 let (s1, msg1) = SPAKE2::<Ed25519Group>::start_symmetric(
623 &Password::new(b"password"),
624 &Identity::new(b"idS"),
626 assert_eq!(msg1.len(), 1 + 32);
627 let (s2, msg2) = SPAKE2::<Ed25519Group>::start_symmetric(
628 &Password::new(b"password"),
629 &Identity::new(b"idS"),
631 assert_eq!(msg2.len(), 1 + 32);
632 let key1 = s1.finish(&msg2).unwrap();
633 let key2 = s2.finish(&msg1).unwrap();
634 assert_eq!(key1.len(), 32);
635 assert_eq!(key2.len(), 32);
640 let key = ed25519_hash_ab(
644 b"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // len=32
645 b"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
646 b"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK",
648 let expected_key = "d59d9ba920f7092565cec747b08d5b2e981d553ac32fde0f25e5b4a4cfca3efd";
649 assert_eq!(hex::encode(key), expected_key);
653 fn test_hash_symmetric() {
654 let key = ed25519_hash_symmetric(
657 b"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
658 b"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
659 b"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK",
661 let expected_key = "b0b31e4401aae37d91a9a8bf6fbb1298cafc005ff9142e3ffc5b9799fb11128b";
662 assert_eq!(hex::encode(key), expected_key);
666 fn test_asymmetric() {
667 let scalar_a = decimal_to_scalar(
668 b"2611694063369306139794446498317402240796898290761098242657700742213257926693",
670 let scalar_b = decimal_to_scalar(
671 b"7002393159576182977806091886122272758628412261510164356026361256515836884383",
673 let expected_pw_scalar = decimal_to_scalar(
674 b"3515301705789368674385125653994241092664323519848410154015274772661223168839",
677 println!("scalar_a is {}", hex::encode(scalar_a.as_bytes()));
679 let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a_internal(
680 &Password::new(b"password"),
681 &Identity::new(b"idA"),
682 &Identity::new(b"idB"),
685 let expected_msg1 = "416fc960df73c9cf8ed7198b0c9534e2e96a5984bfc5edc023fd24dacf371f2af9";
688 println!("xys1: {:?}", hex::encode(s1.xy_scalar.as_bytes()));
690 println!("pws1: {:?}", hex::encode(s1.password_scalar.as_bytes()));
691 println!("exp : {:?}", hex::encode(expected_pw_scalar.as_bytes()));
693 println!("msg1: {:?}", hex::encode(&msg1));
694 println!("exp : {:?}", expected_msg1);
698 hex::encode(expected_pw_scalar.as_bytes()),
699 hex::encode(s1.password_scalar.as_bytes())
701 assert_eq!(hex::encode(&msg1), expected_msg1);
703 let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b_internal(
704 &Password::new(b"password"),
705 &Identity::new(b"idA"),
706 &Identity::new(b"idB"),
709 assert_eq!(expected_pw_scalar, s2.password_scalar);
712 "42354e97b88406922b1df4bea1d7870f17aed3dba7c720b313edae315b00959309"
715 let key1 = s1.finish(&msg2).unwrap();
716 let key2 = s2.finish(&msg1).unwrap();
717 assert_eq!(key1, key2);
720 "712295de7219c675ddd31942184aa26e0a957cf216bc230d165b215047b520c1"
726 let (s1, _msg1) = SPAKE2::<Ed25519Group>::start_a(
727 &Password::new(b"password"),
728 &Identity::new(b"idA"),
729 &Identity::new(b"idB"),
731 println!("s1: {:?}", s1);
732 let (s2, _msg1) = SPAKE2::<Ed25519Group>::start_symmetric(
733 &Password::new(b"password"),
734 &Identity::new(b"idS"),
736 println!("s2: {:?}", s2);