Refactor challenge 36 to match SRP protocol better

This commit is contained in:
2022-10-06 17:05:46 -04:00
parent eae126f4cd
commit a1de52bfd2
4 changed files with 155 additions and 64 deletions

View File

@@ -1,13 +1,14 @@
use crate::bytes::Bytes;
use crate::rsa;
use crate::sha1;
use crate::srp;
use num_bigint::BigUint;
use num_bigint::RandBigInt;
use num_bigint::ToBigUint;
use openssl::sha::sha256;
use rand::Rng;
mod challenge33 {
pub mod challenge33 {
use num_bigint::BigUint;
use std::fs;
@@ -317,80 +318,46 @@ pub fn challenge35() {
println!("[okay] Challenge 35: implement MITM with malicious g attack on DH");
}
pub fn challenge36() {
pub fn challenge36() -> Option<()> {
let mut rng = rand::thread_rng();
// C & S
// Agree on N=[NIST Prime], g=2, k=3, I (email), P (password)
let n = challenge33::load_large_prime();
let g = 2_u8.to_biguint().unwrap();
let k = 3_u8.to_biguint().unwrap();
let _i = Bytes::from_utf8("john1337@wayne.com");
let p = Bytes::from_utf8("horse planet carpet country");
let mut server = srp::Server::default();
let email = "john1337@wayne.com";
let password = "horse planet carpet country";
let parameters = server.register(email, password)?;
// S
// Generate salt as random integer
// Generate string xH=SHA256(salt|password)
// Convert xH to integer x somehow (put 0x on hexdigest)
// Generate v=g**x % N
// Save everything but x, xH
let salt: u32 = rng.gen();
let mut salt_password = salt.to_be_bytes().to_vec();
salt_password.append(&mut p.0.clone());
let xh = sha256(&salt_password);
let x = BigUint::from_bytes_be(xh[0..4].try_into().unwrap());
let v = g.modpow(&x, &n);
// Establish session
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)?;
// C->S
// Send I, A=g**a % N (a la Diffie Hellman)
let a = rng.gen_biguint_below(&n);
let a_public = g.modpow(&a, &n);
// S->C
// Send salt, B=kv + g**b % N
let b = rng.gen_biguint_below(&n);
let b_public = k.clone() * v.clone() + g.modpow(&b, &n);
// S, C
// Compute string uH = SHA256(A|B), u = integer of uH
let mut a_b = a_public.to_bytes_be();
a_b.append(&mut b_public.to_bytes_be());
let uh = sha256(&a_b);
let u = BigUint::from_bytes_be(uh[0..4].try_into().unwrap());
// C
// Generate string xH=SHA256(salt|password)
// Convert xH to integer x somehow (put 0x on hexdigest)
// Generate S = (B - k * g**x)**(a + u * x) % N
// Generate K = SHA256(S)
let mut salt_password = salt.to_be_bytes().to_vec();
salt_password.append(&mut p.0.clone());
let xh = sha256(&salt_password);
let x = BigUint::from_bytes_be(xh[0..4].try_into().unwrap());
let s = (b_public - k * g.modpow(&x, &n)).modpow(&(a + &u * x), &n);
let k_client = sha256(&s.to_bytes_be());
// S
// Generate S = (A * v**u) ** b % N
// Generate K = SHA256(S)
let s = (a_public * v.modpow(&u, &n)).modpow(&b, &n);
let k_server = sha256(&s.to_bytes_be());
// Client
// Generate S = (B - k * g**x)**(a + u * x) % N
// Generate K = SHA256(S)
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());
// Server
let k_server = server.get_k(email)?;
assert_eq!(k_client, k_server);
// I don't have HMAC-SHA256, so I will use HMAC-SHA1 instead.
// C->S
// Send HMAC-SHA256(K, salt)
let salt = Bytes(salt.to_be_bytes().to_vec());
// 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
// 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");
println!("[okay] Challenge 36: implement secure remote password");
Some(())
}
pub fn challenge37() {