Skip to content

Commit 00d7d43

Browse files
authored
Bump digest, sha-1, and sha2 dependencies to v0.9 (#37)
1 parent 9f42267 commit 00d7d43

4 files changed

Lines changed: 132 additions & 66 deletions

File tree

srp/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ categories = ["cryptography", "authentication"]
1313
[dependencies]
1414
num-bigint = "0.2"
1515
generic-array = "0.12"
16-
digest = "0.8"
16+
digest = "0.9"
1717
lazy_static = "1.2"
1818

1919
[dev-dependencies]
2020
rand = "0.6"
21-
sha2 = "0.8"
22-
sha-1 = "0.8"
21+
sha2 = "0.9"
22+
sha-1 = "0.9"
2323

2424
[badges]
2525
travis-ci = { repository = "RustCrypto/PAKEs" }

srp/src/client.rs

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@
5858
//! ```
5959
use std::marker::PhantomData;
6060

61-
use digest::Digest;
62-
use generic_array::GenericArray;
61+
use digest::{Digest, Output};
6362
use num_bigint::BigUint;
6463

6564
use crate::tools::powm;
@@ -77,29 +76,25 @@ pub struct SrpClient<'a, D: Digest> {
7776

7877
/// SRP client state after handshake with the server.
7978
pub struct SrpClientVerifier<D: Digest> {
80-
proof: GenericArray<u8, D::OutputSize>,
81-
server_proof: GenericArray<u8, D::OutputSize>,
82-
key: GenericArray<u8, D::OutputSize>,
79+
proof: Output<D>,
80+
server_proof: Output<D>,
81+
key: Output<D>,
8382
}
8483

8584
/// Compute user private key as described in the RFC 5054. Consider using proper
8685
/// password hashing algorithm instead.
87-
pub fn srp_private_key<D: Digest>(
88-
username: &[u8],
89-
password: &[u8],
90-
salt: &[u8],
91-
) -> GenericArray<u8, D::OutputSize> {
86+
pub fn srp_private_key<D: Digest>(username: &[u8], password: &[u8], salt: &[u8]) -> Output<D> {
9287
let p = {
9388
let mut d = D::new();
94-
d.input(username);
95-
d.input(b":");
96-
d.input(password);
97-
d.result()
89+
d.update(username);
90+
d.update(b":");
91+
d.update(password);
92+
d.finalize()
9893
};
9994
let mut d = D::new();
100-
d.input(salt);
101-
d.input(&p);
102-
d.result()
95+
d.update(salt);
96+
d.update(p.as_slice());
97+
d.finalize()
10398
}
10499

105100
impl<'a, D: Digest> SrpClient<'a, D> {
@@ -123,12 +118,7 @@ impl<'a, D: Digest> SrpClient<'a, D> {
123118
v.to_bytes_be()
124119
}
125120

126-
fn calc_key(
127-
&self,
128-
b_pub: &BigUint,
129-
x: &BigUint,
130-
u: &BigUint,
131-
) -> GenericArray<u8, D::OutputSize> {
121+
fn calc_key(&self, b_pub: &BigUint, x: &BigUint, u: &BigUint) -> Output<D> {
132122
let n = &self.params.n;
133123
let k = self.params.compute_k::<D>();
134124
let interm = (k * self.params.powm(x)) % n;
@@ -151,9 +141,10 @@ impl<'a, D: Digest> SrpClient<'a, D> {
151141
) -> Result<SrpClientVerifier<D>, SrpAuthError> {
152142
let u = {
153143
let mut d = D::new();
154-
d.input(&self.a_pub.to_bytes_be());
155-
d.input(b_pub);
156-
BigUint::from_bytes_be(&d.result())
144+
d.update(&self.a_pub.to_bytes_be());
145+
d.update(b_pub);
146+
let h = d.finalize();
147+
BigUint::from_bytes_be(h.as_slice())
157148
};
158149

159150
let b_pub = BigUint::from_bytes_be(b_pub);
@@ -170,19 +161,79 @@ impl<'a, D: Digest> SrpClient<'a, D> {
170161
// M1 = H(A, B, K)
171162
let proof = {
172163
let mut d = D::new();
173-
d.input(&self.a_pub.to_bytes_be());
174-
d.input(&b_pub.to_bytes_be());
175-
d.input(&key);
176-
d.result()
164+
d.update(&self.a_pub.to_bytes_be());
165+
d.update(&b_pub.to_bytes_be());
166+
d.update(&key);
167+
d.finalize()
177168
};
178169

179170
// M2 = H(A, M1, K)
180171
let server_proof = {
181172
let mut d = D::new();
182-
d.input(&self.a_pub.to_bytes_be());
183-
d.input(&proof);
184-
d.input(&key);
185-
d.result()
173+
d.update(&self.a_pub.to_bytes_be());
174+
d.update(&proof);
175+
d.update(&key);
176+
d.finalize()
177+
};
178+
179+
Ok(SrpClientVerifier {
180+
proof,
181+
server_proof,
182+
key,
183+
})
184+
}
185+
186+
/// Process server reply to the handshake with username and salt.
187+
pub fn process_reply_with_username_and_salt(
188+
self,
189+
username: &[u8],
190+
salt: &[u8],
191+
private_key: &[u8],
192+
b_pub: &[u8],
193+
) -> Result<SrpClientVerifier<D>, SrpAuthError> {
194+
let u = {
195+
let mut d = D::new();
196+
d.update(&self.a_pub.to_bytes_be());
197+
d.update(b_pub);
198+
let h = d.finalize();
199+
BigUint::from_bytes_be(h.as_slice())
200+
};
201+
202+
let b_pub = BigUint::from_bytes_be(b_pub);
203+
204+
// Safeguard against malicious B
205+
if &b_pub % &self.params.n == BigUint::default() {
206+
return Err(SrpAuthError {
207+
description: "Malicious b_pub value",
208+
});
209+
}
210+
211+
let x = BigUint::from_bytes_be(private_key);
212+
let key = self.calc_key(&b_pub, &x, &u);
213+
// M1 = H(H(N)^H(g), H(I), salt, A, B, K)
214+
let proof = {
215+
let mut d = D::new();
216+
d.update(username);
217+
let h = d.finalize_reset();
218+
let I: &[u8] = h.as_slice();
219+
220+
d.update(self.params.compute_hash_n_xor_hash_g::<D>());
221+
d.update(I);
222+
d.update(salt);
223+
d.update(&self.a_pub.to_bytes_be());
224+
d.update(&b_pub.to_bytes_be());
225+
d.update(&key.to_vec());
226+
d.finalize()
227+
};
228+
let x = proof.to_vec().as_slice();
229+
230+
// M2 = H(A, M1, K)
231+
let server_proof = {
232+
let mut d = D::new();
233+
d.update(&self.a_pub.to_bytes_be());
234+
d.update(&proof);
235+
d.update(&key);
236+
d.finalize()
186237
};
187238

188239
Ok(SrpClientVerifier {
@@ -202,21 +253,18 @@ impl<D: Digest> SrpClientVerifier<D> {
202253
/// Get shared secret key without authenticating server, e.g. for using with
203254
/// authenticated encryption modes. DO NOT USE this method without
204255
/// some kind of secure authentication
205-
pub fn get_key(self) -> GenericArray<u8, D::OutputSize> {
256+
pub fn get_key(self) -> Output<D> {
206257
self.key
207258
}
208259

209260
/// Verification data for sending to the server.
210-
pub fn get_proof(&self) -> GenericArray<u8, D::OutputSize> {
261+
pub fn get_proof(&self) -> Output<D> {
211262
self.proof.clone()
212263
}
213264

214265
/// Verify server reply to verification data. It will return shared secret
215266
/// key in case of success.
216-
pub fn verify_server(
217-
self,
218-
reply: &[u8],
219-
) -> Result<GenericArray<u8, D::OutputSize>, SrpAuthError> {
267+
pub fn verify_server(self, reply: &[u8]) -> Result<Output<D>, SrpAuthError> {
220268
if self.server_proof.as_slice() != reply {
221269
Err(SrpAuthError {
222270
description: "Incorrect server proof",

srp/src/server.rs

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@
3636
//! encryption.
3737
use std::marker::PhantomData;
3838

39-
use digest::Digest;
40-
use generic_array::GenericArray;
39+
use digest::{Digest, Output};
4140
use num_bigint::BigUint;
4241

4342
use crate::tools::powm;
@@ -57,7 +56,7 @@ pub struct SrpServer<D: Digest> {
5756
a_pub: BigUint,
5857
b_pub: BigUint,
5958

60-
key: GenericArray<u8, D::OutputSize>,
59+
key: Output<D>,
6160

6261
d: PhantomData<D>,
6362
}
@@ -86,14 +85,14 @@ impl<D: Digest> SrpServer<D> {
8685
// H(A || B)
8786
let u = {
8887
let mut d = D::new();
89-
d.input(&a_pub.to_bytes_be());
90-
d.input(&b_pub.to_bytes_be());
91-
d.result()
88+
d.update(&a_pub.to_bytes_be());
89+
d.update(&b_pub.to_bytes_be());
90+
d.finalize()
9291
};
9392
let d = Default::default();
9493
//(Av^u) ^ b
9594
let key = {
96-
let u = BigUint::from_bytes_be(&u);
95+
let u = BigUint::from_bytes_be(u.as_slice());
9796
let t = (&a_pub * powm(&v, &u, &params.n)) % &params.n;
9897
let s = powm(&t, &b, &params.n);
9998
D::digest(&s.to_bytes_be())
@@ -119,29 +118,26 @@ impl<D: Digest> SrpServer<D> {
119118

120119
/// Get shared secret between user and the server. (do not forget to verify
121120
/// that keys are the same!)
122-
pub fn get_key(&self) -> GenericArray<u8, D::OutputSize> {
121+
pub fn get_key(&self) -> Output<D> {
123122
self.key.clone()
124123
}
125124

126125
/// Process user proof of having the same shared secret and compute
127126
/// server proof for sending to the user.
128-
pub fn verify(
129-
&self,
130-
user_proof: &[u8],
131-
) -> Result<GenericArray<u8, D::OutputSize>, SrpAuthError> {
127+
pub fn verify(&self, user_proof: &[u8]) -> Result<Output<D>, SrpAuthError> {
132128
// M = H(A, B, K)
133129
let mut d = D::new();
134-
d.input(&self.a_pub.to_bytes_be());
135-
d.input(&self.b_pub.to_bytes_be());
136-
d.input(&self.key);
130+
d.update(&self.a_pub.to_bytes_be());
131+
d.update(&self.b_pub.to_bytes_be());
132+
d.update(&self.key);
137133

138-
if user_proof == d.result().as_slice() {
134+
if user_proof == d.finalize().as_slice() {
139135
// H(A, M, K)
140136
let mut d = D::new();
141-
d.input(&self.a_pub.to_bytes_be());
142-
d.input(user_proof);
143-
d.input(&self.key);
144-
Ok(d.result())
137+
d.update(&self.a_pub.to_bytes_be());
138+
d.update(user_proof);
139+
d.update(&self.key);
140+
Ok(d.finalize())
145141
} else {
146142
Err(SrpAuthError {
147143
description: "Incorrect user proof",

srp/src/types.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,31 @@ impl SrpGroup {
4545
buf[l..].copy_from_slice(&g_bytes);
4646

4747
let mut d = D::new();
48-
d.input(&n);
49-
d.input(&buf);
50-
BigUint::from_bytes_be(&d.result())
48+
d.update(&n);
49+
d.update(&buf);
50+
BigUint::from_bytes_be(&d.finalize().as_slice())
51+
}
52+
53+
/// Compute `Hash(N) xor Hash(g)` with given hash function and return SRP parameters
54+
pub(crate) fn compute_hash_n_xor_hash_g<D: Digest>(&self) -> Vec<u8> {
55+
let n = self.n.to_bytes_be();
56+
let g_bytes = self.g.to_bytes_be();
57+
let mut buf = vec![0u8; n.len()];
58+
let l = n.len() - g_bytes.len();
59+
buf[l..].copy_from_slice(&g_bytes);
60+
61+
let mut d = D::new();
62+
d.update(&n);
63+
let h = d.finalize_reset();
64+
let h_n: &[u8] = h.as_slice();
65+
d.update(&buf);
66+
let h = d.finalize_reset();
67+
let h_g: &[u8] = h.as_slice();
68+
69+
h_n.iter()
70+
.zip(h_g.iter())
71+
.map(|(&x1, &x2)| x1 ^ x2)
72+
.collect()
5173
}
5274
}
5375

0 commit comments

Comments
 (0)