Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

srp: alternate implementation, based on @brndnmtthws changes #81

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 42 additions & 84 deletions srp/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,17 @@
use std::marker::PhantomData;

use digest::{Digest, Output};
use num_bigint::BigUint;
use generic_array::GenericArray;
use num_bigint::{BigInt, Sign};

use crate::types::{SrpAuthError, SrpGroup};

/// SRP client state before handshake with the server.
pub struct SrpClient<'a, D: Digest> {
params: &'a SrpGroup,

a: BigUint,
a_pub: BigUint,
a: BigInt,
a_pub: BigInt,

d: PhantomData<D>,
}
Expand Down Expand Up @@ -100,7 +101,7 @@ pub fn srp_private_key<D: Digest>(username: &[u8], password: &[u8], salt: &[u8])
impl<'a, D: Digest> SrpClient<'a, D> {
/// Create new SRP client instance.
pub fn new(a: &[u8], params: &'a SrpGroup) -> Self {
let a = BigUint::from_bytes_be(a);
let a = BigInt::from_bytes_be(Sign::Plus, a);
let a_pub = params.modpow(&a);

Self {
Expand All @@ -113,79 +114,23 @@ impl<'a, D: Digest> SrpClient<'a, D> {

/// Get password verfier for user registration on the server
pub fn get_password_verifier(&self, private_key: &[u8]) -> Vec<u8> {
let x = BigUint::from_bytes_be(private_key);
let x = BigInt::from_bytes_be(Sign::Plus, private_key);
let v = self.params.modpow(&x);
v.to_bytes_be()
v.to_bytes_be().1
}

fn calc_key(&self, b_pub: &BigUint, x: &BigUint, u: &BigUint) -> Output<D> {
fn calc_key(&self, b_pub: &BigInt, x: &BigInt, u: &BigInt) -> GenericArray<u8, D::OutputSize> {
let n = &self.params.n;
let k = self.params.compute_k::<D>();
let interm = (k * self.params.modpow(x)) % n;
// Because we do operation in modulo N we can get: (kv + g^b) < kv
let v = if *b_pub > interm {
(b_pub - &interm) % n
} else {
(n + b_pub - &interm) % n
};
let interm = k * self.params.modpow(x);
let v = b_pub - &interm;
// S = |B - kg^x| ^ (a + ux)
let s = v.modpow(&(&self.a + (u * x) % n), n);
D::digest(&s.to_bytes_be())
let s = v.modpow(&(&self.a + (u * x)), n);
D::digest(&s.to_bytes_be().1)
}

/// Process server reply to the handshake.
pub fn process_reply(
self,
private_key: &[u8],
b_pub: &[u8],
) -> Result<SrpClientVerifier<D>, SrpAuthError> {
let u = {
let mut d = D::new();
d.update(&self.a_pub.to_bytes_be());
d.update(b_pub);
let h = d.finalize();
BigUint::from_bytes_be(h.as_slice())
};

let b_pub = BigUint::from_bytes_be(b_pub);

// Safeguard against malicious B
if &b_pub % &self.params.n == BigUint::default() {
return Err(SrpAuthError {
description: "Malicious b_pub value",
});
}

let x = BigUint::from_bytes_be(private_key);
let key = self.calc_key(&b_pub, &x, &u);
// M1 = H(A, B, K)
let proof = {
let mut d = D::new();
d.update(&self.a_pub.to_bytes_be());
d.update(&b_pub.to_bytes_be());
d.update(&key);
d.finalize()
};

// M2 = H(A, M1, K)
let server_proof = {
let mut d = D::new();
d.update(&self.a_pub.to_bytes_be());
d.update(&proof);
d.update(&key);
d.finalize()
};

Ok(SrpClientVerifier {
proof,
server_proof,
key,
})
}

/// Process server reply to the handshake with username and salt.
#[allow(non_snake_case)]
pub fn process_reply_with_username_and_salt(
self,
username: &[u8],
salt: &[u8],
Expand All @@ -194,43 +139,56 @@ impl<'a, D: Digest> SrpClient<'a, D> {
) -> Result<SrpClientVerifier<D>, SrpAuthError> {
let u = {
let mut d = D::new();
d.update(&self.a_pub.to_bytes_be());
d.update(&self.a_pub.to_bytes_be().1);
d.update(b_pub);
let h = d.finalize();
BigUint::from_bytes_be(h.as_slice())
BigInt::from_bytes_be(Sign::Plus, h.as_slice())
};

let b_pub = BigUint::from_bytes_be(b_pub);
let b_pub = BigInt::from_bytes_be(Sign::Plus, b_pub);

// Safeguard against malicious B
if &b_pub % &self.params.n == BigUint::default() {
if &b_pub % &self.params.n == BigInt::default() {
return Err(SrpAuthError {
description: "Malicious b_pub value",
});
}

let x = BigUint::from_bytes_be(private_key);
let x = BigInt::from_bytes_be(Sign::Plus, private_key);
let key = self.calc_key(&b_pub, &x, &u);
// M1 = H(H(N)^H(g), H(I), salt, A, B, K)
// M = H(H(N) XOR H(g) | H(U) | s | A | B | K)
let proof = {
let hn = {
let n = &self.params.n;
let mut d = D::new();
d.update(n.to_bytes_be().1);
BigInt::from_bytes_be(Sign::Plus, &d.finalize())
};
let hg = {
let g = &self.params.g;
let mut d = D::new();
d.update(g.to_bytes_be().1);
BigInt::from_bytes_be(Sign::Plus, &d.finalize())
};
let hu = {
let mut d = D::new();
d.update(username);
d.finalize()
};
let mut d = D::new();
d.update(username);
let h = d.finalize_reset();
let I: &[u8] = h.as_slice();

d.update(self.params.compute_hash_n_xor_hash_g::<D>());
d.update(I);
d.update((hn ^ hg).to_bytes_be().1);
d.update(hu);
d.update(salt);
d.update(&self.a_pub.to_bytes_be());
d.update(&b_pub.to_bytes_be());
d.update(&key.to_vec());
d.update(&self.a_pub.to_bytes_be().1);
d.update(&b_pub.to_bytes_be().1);
d.update(&key);
d.finalize()
};

// M2 = H(A, M1, K)
let server_proof = {
let mut d = D::new();
d.update(&self.a_pub.to_bytes_be());
d.update(&self.a_pub.to_bytes_be().1);
d.update(&proof);
d.update(&key);
d.finalize()
Expand All @@ -245,7 +203,7 @@ impl<'a, D: Digest> SrpClient<'a, D> {

/// Get public ephemeral value for handshaking with the server.
pub fn get_a_pub(&self) -> Vec<u8> {
self.a_pub.to_bytes_be()
self.a_pub.to_bytes_be().1
}
}

Expand Down
33 changes: 17 additions & 16 deletions srp/src/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,56 @@
//! It is strongly recommended to use them instead of custom generated
//! groups. Additionally it is not recommended to use `G_1024` and `G_1536`,
//! they are provided only for compatibility with the legacy software.
use crate::types::SrpGroup;
use lazy_static::lazy_static;
use num_bigint::BigUint;
use num_bigint::{BigInt, Sign};

use crate::types::SrpGroup;

lazy_static! {
pub static ref G_1024: SrpGroup = SrpGroup {
n: BigUint::from_bytes_be(include_bytes!("groups/1024.bin")),
g: BigUint::from_bytes_be(&[2]),
n: BigInt::from_bytes_be(Sign::Plus, include_bytes!("groups/1024.bin")),
g: BigInt::from_bytes_be(Sign::Plus, &[2]),
};
}

lazy_static! {
pub static ref G_1536: SrpGroup = SrpGroup {
n: BigUint::from_bytes_be(include_bytes!("groups/1536.bin")),
g: BigUint::from_bytes_be(&[2]),
n: BigInt::from_bytes_be(Sign::Plus, include_bytes!("groups/1536.bin")),
g: BigInt::from_bytes_be(Sign::Plus, &[2]),
};
}

lazy_static! {
pub static ref G_2048: SrpGroup = SrpGroup {
n: BigUint::from_bytes_be(include_bytes!("groups/2048.bin")),
g: BigUint::from_bytes_be(&[2]),
n: BigInt::from_bytes_be(Sign::Plus, include_bytes!("groups/2048.bin")),
g: BigInt::from_bytes_be(Sign::Plus, &[2]),
};
}

lazy_static! {
pub static ref G_3072: SrpGroup = SrpGroup {
n: BigUint::from_bytes_be(include_bytes!("groups/3072.bin")),
g: BigUint::from_bytes_be(&[5]),
n: BigInt::from_bytes_be(Sign::Plus, include_bytes!("groups/3072.bin")),
g: BigInt::from_bytes_be(Sign::Plus, &[5]),
};
}

lazy_static! {
pub static ref G_4096: SrpGroup = SrpGroup {
n: BigUint::from_bytes_be(include_bytes!("groups/4096.bin")),
g: BigUint::from_bytes_be(&[5]),
n: BigInt::from_bytes_be(Sign::Plus, include_bytes!("groups/4096.bin")),
g: BigInt::from_bytes_be(Sign::Plus, &[5]),
};
}

lazy_static! {
pub static ref G_6144: SrpGroup = SrpGroup {
n: BigUint::from_bytes_be(include_bytes!("groups/6144.bin")),
g: BigUint::from_bytes_be(&[5]),
n: BigInt::from_bytes_be(Sign::Plus, include_bytes!("groups/6144.bin")),
g: BigInt::from_bytes_be(Sign::Plus, &[5]),
};
}

lazy_static! {
pub static ref G_8192: SrpGroup = SrpGroup {
n: BigUint::from_bytes_be(include_bytes!("groups/8192.bin")),
g: BigUint::from_bytes_be(&[19]),
n: BigInt::from_bytes_be(Sign::Plus, include_bytes!("groups/8192.bin")),
g: BigInt::from_bytes_be(Sign::Plus, &[19]),
};
}
1 change: 0 additions & 1 deletion srp/src/k_sha1_1024.bin

This file was deleted.

1 change: 0 additions & 1 deletion srp/src/prime.bin

This file was deleted.

Loading