Implement challenge 37 break SRP with zero key

main
Felix Martin 2022-10-08 09:30:25 -04:00
parent a1de52bfd2
commit f0b75e6cc0
3 changed files with 89 additions and 12 deletions

View File

@ -64,4 +64,5 @@ fn main() {
}
set5::challenge36();
set5::challenge37();
set5::challenge38();
}

View File

@ -350,23 +350,84 @@ pub fn challenge36() -> Option<()> {
// I don't have HMAC-SHA256, so I will use HMAC-SHA1 instead.
// C->S Send HMAC-SHA256(K, salt)
let salt = Bytes(session_keys.salt.to_be_bytes().to_vec());
let mac_server = sha1::hmac_sha1(&Bytes(k_server.to_vec()), &salt);
// S->C Send "OK" if HMAC-SHA256(K, salt) validates
let mac_client = sha1::hmac_sha1(&Bytes(k_client.to_vec()), &salt);
assert_eq!(mac_server, mac_client, "HMAC verification failed");
let mac = sha1::hmac_sha1(&Bytes(k_client.to_vec()), &salt);
assert!(server.log_in(email, &mac)?);
println!("[okay] Challenge 36: implement secure remote password");
Some(())
}
pub fn challenge37() {
// Get your SRP working in an actual client-server setting. "Log in" with a
// valid password using the protocol.
pub fn challenge37() -> Option<()> {
let mut rng = rand::thread_rng();
// Now log in without your password by having the client send 0 as its "A"
// value. What does this to the "S" value that both sides compute?
let mut server = srp::Server::default();
let email = "john1337@wayne.com";
let password = "horse planet carpet country";
let parameters = server.register(email, password)?;
// Now log in without your password by having the client send N, N*2, &c.
println!("[xxxx] Challenge 37: TBD");
let mut log_in_with_password = || -> Option<bool> {
// Get your SRP working in an actual client-server setting. "Log in" with a
// valid password using the protocol.
let n = &parameters.n;
let g = &parameters.g;
let a = rng.gen_biguint_below(n);
let a_public = g.modpow(&a, n);
let session_keys = server.exchange(email, &a_public)?;
// Client
let u = srp::compute_u(&a_public, &session_keys.b_public)?;
let x = srp::hash_password(session_keys.salt, password)?;
let b_public = &session_keys.b_public;
let k = &parameters.k;
let s_client = (b_public - ((k * g.modpow(&x, n)) % n)).modpow(&(a + &u * x), n);
let k_client = sha256(&s_client.to_bytes_be());
let salt = Bytes(session_keys.salt.to_be_bytes().to_vec());
let mac = sha1::hmac_sha1(&Bytes(k_client.to_vec()), &salt);
server.log_in(email, &mac)
};
assert!(log_in_with_password()?);
let mut log_in_without_password_a_zero = || -> Option<bool> {
// Now log in without your password by having the client send 0 as its "A"
// value.
let a_public = 0_u8.to_biguint()?;
let session_keys = server.exchange(email, &a_public)?;
// What does this to the "S" value that both sides compute? It becomes zero.
let s_client: BigUint = 0_u8.to_biguint()?;
let k_client = sha256(&s_client.to_bytes_be());
let salt = Bytes(session_keys.salt.to_be_bytes().to_vec());
let mac = sha1::hmac_sha1(&Bytes(k_client.to_vec()), &salt);
server.log_in(email, &mac)
};
assert!(log_in_without_password_a_zero()?);
let mut log_in_without_password_multiple_n = || -> Option<bool> {
// Now log in without your password by having the client send N, N*2, &c.
let n = &parameters.n;
let a_public = n * 2_u8.to_biguint()?;
let session_keys = server.exchange(email, &a_public)?;
// If A is a multiple of N, the term $(A * v**u) ** b % N$ also becomes zero.
let s_client: BigUint = 0_u8.to_biguint()?;
let k_client = sha256(&s_client.to_bytes_be());
let salt = Bytes(session_keys.salt.to_be_bytes().to_vec());
let mac = sha1::hmac_sha1(&Bytes(k_client.to_vec()), &salt);
server.log_in(email, &mac)
};
assert!(log_in_without_password_multiple_n()?);
println!("[okay] Challenge 37: break SRP with zero key");
Some(())
}
pub fn challenge38() -> Option<()> {
println!("[xxxx] Challenge 38: TBD");
Some(())
}

View File

@ -1,4 +1,6 @@
use crate::bytes::Bytes;
use crate::set5;
use crate::sha1;
use num_bigint::BigUint;
use num_bigint::RandBigInt;
use num_bigint::ToBigUint;
@ -122,4 +124,17 @@ impl Server {
let k_server = sha256(&s_server.to_bytes_be());
Some(k_server)
}
pub fn log_in(&mut self, email: &str, mac_client: &Bytes) -> Option<bool> {
let k = self.get_k(email)?;
let password_entry = self.entries.get(email)?;
let salt = Bytes(password_entry.salt.to_be_bytes().to_vec());
// S->C Send "OK" if HMAC-SHA255(K, salt) validates
let mac_server = sha1::hmac_sha1(&Bytes(k.to_vec()), &salt);
if mac_server == *mac_client {
return Some(true);
}
Some(false)
}
}