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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use super::*;
use super::super::symmetric::Digest;
use sodiumoxide::crypto::scalarmult::curve25519;
use sodiumoxide::crypto::hash::sha256;
use sodiumoxide::utils::memzero;
use sodiumoxide::randombytes;
pub fn gen_keypair() -> (PublicKey, SecretKey) {
let mut sk_bytes_raw = randombytes::randombytes(sha256::BLOCKBYTES);
let mut sk_hash = sha256::hash(&sk_bytes_raw);
let &mut sha256::Digest(ref mut sk_bytes) = &mut sk_hash;
let sk = curve25519::Scalar::from_slice(&sk_bytes[0..curve25519::SCALARBYTES]).unwrap();
let pk = curve25519::scalarmult_base(&sk);
memzero(sk_bytes);
memzero(sk_bytes_raw.as_mut_slice());
(pk, sk)
}
pub fn key_exchange(pub_key: &PublicKey, sec_key: &SecretKey, other_pub_key: &PublicKey, is_client: bool) -> Digest {
let point_on_curve = curve25519::scalarmult(sec_key, pub_key);
let curve25519::GroupElement(ref point_on_curve_bytes) = point_on_curve;
let &curve25519::GroupElement(ref pub_key_bytes) = pub_key;
let &curve25519::GroupElement(ref other_pub_key_bytes) = other_pub_key;
let mut thing_to_hash = vec![];
thing_to_hash.extend_from_slice(point_on_curve_bytes);
if is_client {
thing_to_hash.extend_from_slice(pub_key_bytes);
thing_to_hash.extend_from_slice(other_pub_key_bytes);
} else {
thing_to_hash.extend_from_slice(other_pub_key_bytes);
thing_to_hash.extend_from_slice(pub_key_bytes);
}
let shared_secret = Digest{ digest: sha256::hash(&thing_to_hash) };
memzero(&mut thing_to_hash);
shared_secret
}
#[cfg(test)]
mod tests {
use super::*;
extern crate sodiumoxide;
#[test]
fn key_exchange_test() {
sodiumoxide::init();
let (pk1, sk1) = gen_keypair();
let (pk2, sk2) = gen_keypair();
let k1 = key_exchange(&pk2, &sk1, &pk1, true);
let k2 = key_exchange(&pk1, &sk2, &pk2, false);
assert_eq!(k1, k2);
}
}