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
use base64;
use ring::digest::{digest, SHA256, SHA256_OUTPUT_LEN};
use ring::hmac::{self, SigningContext, SigningKey};
use ring::pbkdf2;
macro_rules! parse_part {
($iter:expr, $field:ident, $key:expr) => {
if let Some(part) = $iter.next() {
if part.len() < 2 {
return Err(Error::Protocol(Kind::ExpectedField(Field::$field)));
} else if &part.as_bytes()[..2] == $key {
&part[2..]
} else {
return Err(Error::Protocol(Kind::ExpectedField(Field::$field)));
}
} else {
return Err(Error::Protocol(Kind::ExpectedField(Field::$field)));
}
};
}
pub fn hash_password(password: &str, iterations: u16, salt: &[u8]) -> [u8; SHA256_OUTPUT_LEN] {
let mut salted_password = [0u8; SHA256_OUTPUT_LEN];
pbkdf2::derive(
&SHA256,
u32::from(iterations),
salt,
password.as_bytes(),
&mut salted_password,
);
salted_password
}
pub fn find_proofs(
gs2header: &str,
client_first_bare: &str,
server_first: &str,
salted_password: &[u8],
nonce: &str,
) -> ([u8; SHA256_OUTPUT_LEN], hmac::Signature) {
fn sign_slice(key: &SigningKey, slice: &[&[u8]]) -> hmac::Signature {
let mut signature_context = SigningContext::with_key(key);
for item in slice {
signature_context.update(item);
}
signature_context.sign()
}
let client_final_without_proof =
format!("c={},r={}", base64::encode(gs2header.as_bytes()), nonce);
let auth_message = [
client_first_bare.as_bytes(),
b",",
server_first.as_bytes(),
b",",
client_final_without_proof.as_bytes(),
];
let salted_password_signing_key = SigningKey::new(&SHA256, salted_password);
let client_key = hmac::sign(&salted_password_signing_key, b"Client Key");
let server_key = hmac::sign(&salted_password_signing_key, b"Server Key");
let stored_key = digest(&SHA256, client_key.as_ref());
let stored_key_signing_key = SigningKey::new(&SHA256, stored_key.as_ref());
let client_signature = sign_slice(&stored_key_signing_key, &auth_message);
let server_signature_signing_key = SigningKey::new(&SHA256, server_key.as_ref());
let server_signature = sign_slice(&server_signature_signing_key, &auth_message);
let mut client_proof = [0u8; SHA256_OUTPUT_LEN];
let xor_iter = client_key
.as_ref()
.iter()
.zip(client_signature.as_ref())
.map(|(k, s)| k ^ s);
for (p, x) in client_proof.iter_mut().zip(xor_iter) {
*p = x
}
(client_proof, server_signature)
}