Clean up and consider BigUint as alternative to BigNum for RSA implementation
This commit is contained in:
93
src/dh.rs
Normal file
93
src/dh.rs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// Implementations of Diffie–Hellman key exchange
|
||||||
|
use num_bigint::BigUint;
|
||||||
|
use num_bigint::RandBigInt;
|
||||||
|
use rand::Rng;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PublicKey(pub BigUint);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PrivateKey(pub BigUint);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Keypair {
|
||||||
|
pub private: PrivateKey,
|
||||||
|
pub public: PublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keypair {
|
||||||
|
pub fn make(p: &BigUint, g: &BigUint) -> Self {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let private = rng.gen_biguint_below(p);
|
||||||
|
let public = g.modpow(&private, p);
|
||||||
|
Self {
|
||||||
|
private: PrivateKey(private),
|
||||||
|
public: PublicKey(public),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expmod(base: u32, exp: u32, m: u32) -> u32 {
|
||||||
|
if exp == 0 {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp % 2 == 0 {
|
||||||
|
let s = expmod(base, exp / 2, m);
|
||||||
|
(s * s) % m
|
||||||
|
} else {
|
||||||
|
(expmod(base, exp - 1, m) * base) % m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_large_prime() -> BigUint {
|
||||||
|
let s = fs::read_to_string("data/33.txt").expect("run from git root dir");
|
||||||
|
let b: Vec<u8> = s
|
||||||
|
.chars()
|
||||||
|
.filter(|c| *c != '\n')
|
||||||
|
.map(|c| c.to_digit(16).unwrap().try_into().unwrap())
|
||||||
|
.collect();
|
||||||
|
BigUint::from_radix_be(&b, 16).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn simple() {
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
// Set a variable "p" to 37 and "g" to 5.
|
||||||
|
let p: u32 = 37;
|
||||||
|
let g: u32 = 5;
|
||||||
|
|
||||||
|
// Generate "a", a random number mod 37. Now generate "A", which is "g" raised to the "a"
|
||||||
|
// power mode 37 --- A = (g**a) % p.
|
||||||
|
let a: u32 = rng.gen::<u32>() % p;
|
||||||
|
let A = expmod(g, a, p);
|
||||||
|
|
||||||
|
// Do the same for "b" and "B".
|
||||||
|
let b: u32 = rng.gen::<u32>() % p;
|
||||||
|
let B = expmod(g, b, p);
|
||||||
|
|
||||||
|
// "A" and "B" are public keys. Generate a session key with them; set "s" to "B" raised to
|
||||||
|
// the "a" power mod 37 --- s = (B**a) % p.
|
||||||
|
let s = expmod(B, a, p);
|
||||||
|
|
||||||
|
// Do the same with A**b, check that you come up with the same "s".
|
||||||
|
let s_ = expmod(A, b, p);
|
||||||
|
|
||||||
|
assert_eq!(s, s_, "crypto is broken");
|
||||||
|
// To turn "s" into a key, you can just hash it to create 128 bits of key material (or
|
||||||
|
// SHA256 it to create a key for encrypting and a key for a MAC).
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serious() {
|
||||||
|
let p = load_large_prime();
|
||||||
|
let g = 2_u8.into();
|
||||||
|
|
||||||
|
let a = Keypair::make(&p, &g);
|
||||||
|
let b = Keypair::make(&p, &g);
|
||||||
|
|
||||||
|
let s = b.public.0.modpow(&a.private.0, &p);
|
||||||
|
let s_ = a.public.0.modpow(&b.private.0, &p);
|
||||||
|
assert_eq!(s, s_, "crypto is broken");
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ mod bytes;
|
|||||||
mod bytes_base64;
|
mod bytes_base64;
|
||||||
mod cbc;
|
mod cbc;
|
||||||
mod ctr;
|
mod ctr;
|
||||||
|
mod dh;
|
||||||
mod dsa;
|
mod dsa;
|
||||||
mod ecb;
|
mod ecb;
|
||||||
mod md4;
|
mod md4;
|
||||||
@@ -27,7 +28,7 @@ mod srp;
|
|||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
const RUN_ALL: bool = true;
|
const RUN_ALL: bool = false;
|
||||||
if RUN_ALL {
|
if RUN_ALL {
|
||||||
set1::challenge1();
|
set1::challenge1();
|
||||||
set1::challenge2();
|
set1::challenge2();
|
||||||
@@ -61,6 +62,7 @@ fn main() {
|
|||||||
set4::challenge30();
|
set4::challenge30();
|
||||||
set4::challenge31();
|
set4::challenge31();
|
||||||
set4::challenge32();
|
set4::challenge32();
|
||||||
|
}
|
||||||
set5::challenge33();
|
set5::challenge33();
|
||||||
set5::challenge34();
|
set5::challenge34();
|
||||||
set5::challenge35();
|
set5::challenge35();
|
||||||
@@ -71,7 +73,6 @@ fn main() {
|
|||||||
set5::challenge40().unwrap_or_else(|| println!("[fail] challenge 40"));
|
set5::challenge40().unwrap_or_else(|| println!("[fail] challenge 40"));
|
||||||
set6::challenge41().unwrap_or_else(|_| println!("[fail] challenge 41"));
|
set6::challenge41().unwrap_or_else(|_| println!("[fail] challenge 41"));
|
||||||
set6::challenge42().unwrap_or_else(|_| println!("[fail] challenge 42"));
|
set6::challenge42().unwrap_or_else(|_| println!("[fail] challenge 42"));
|
||||||
}
|
|
||||||
set6::challenge43().unwrap_or_else(|| println!("[fail] challenge 43"));
|
set6::challenge43().unwrap_or_else(|| println!("[fail] challenge 43"));
|
||||||
set6::challenge44().unwrap_or_else(|| println!("[fail] challenge 44"));
|
set6::challenge44().unwrap_or_else(|| println!("[fail] challenge 44"));
|
||||||
set6::challenge45().unwrap_or_else(|| println!("[fail] challenge 45"));
|
set6::challenge45().unwrap_or_else(|| println!("[fail] challenge 45"));
|
||||||
|
|||||||
69
src/rsa.rs
69
src/rsa.rs
@@ -1,36 +1,13 @@
|
|||||||
use crate::utils::bnclone;
|
use crate::utils::bnclone;
|
||||||
|
use num_bigint::BigInt;
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use num_bigint::RandBigInt;
|
use num_bigint::ToBigInt;
|
||||||
use openssl::bn::BigNum;
|
use openssl::bn::BigNum;
|
||||||
use openssl::bn::BigNumContext;
|
use openssl::bn::BigNumContext;
|
||||||
use openssl::bn::MsbOption;
|
use openssl::bn::MsbOption;
|
||||||
use openssl::error::ErrorStack;
|
use openssl::error::ErrorStack;
|
||||||
use openssl::sha::sha256;
|
use openssl::sha::sha256;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PublicKey(pub BigUint);
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PrivateKey(pub BigUint);
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Keypair {
|
|
||||||
pub private: PrivateKey,
|
|
||||||
pub public: PublicKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Keypair {
|
|
||||||
pub fn make(p: &BigUint, g: &BigUint) -> Self {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let private = rng.gen_biguint_below(p);
|
|
||||||
let public = g.modpow(&private, p);
|
|
||||||
Self {
|
|
||||||
private: PrivateKey(private),
|
|
||||||
public: PublicKey(public),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RsaPublicKey {
|
pub struct RsaPublicKey {
|
||||||
pub e: BigNum,
|
pub e: BigNum,
|
||||||
pub n: BigNum,
|
pub n: BigNum,
|
||||||
@@ -51,7 +28,10 @@ fn generate_random_prime(bits: i32) -> Result<BigNum, ErrorStack> {
|
|||||||
Ok(p)
|
Ok(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rsa_gen_keys_with_size(p_bits: i32, q_bits: i32) -> Result<(RsaPublicKey, RsaPrivateKey), ErrorStack> {
|
pub fn rsa_gen_keys_with_size(
|
||||||
|
p_bits: i32,
|
||||||
|
q_bits: i32,
|
||||||
|
) -> Result<(RsaPublicKey, RsaPrivateKey), ErrorStack> {
|
||||||
let mut ctx = BigNumContext::new()?;
|
let mut ctx = BigNumContext::new()?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -87,6 +67,43 @@ pub fn rsa_gen_keys() -> Result<(RsaPublicKey, RsaPrivateKey), ErrorStack> {
|
|||||||
rsa_gen_keys_with_size(512, 512)
|
rsa_gen_keys_with_size(512, 512)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extended_gcd(a: &BigUint, b: &BigUint) -> (BigInt, BigInt, BigInt) {
|
||||||
|
// https://brilliant.org/wiki/extended-euclidean-algorithm/
|
||||||
|
assert!(a < b, "a has to be smaller than b for extended GCD");
|
||||||
|
let mut a: BigInt = a.clone().into();
|
||||||
|
let mut b: BigInt = b.clone().into();
|
||||||
|
|
||||||
|
let mut x: BigInt = 0_i32.into();
|
||||||
|
let mut y: BigInt = 1_i32.into();
|
||||||
|
let mut u: BigInt = 1_i32.into();
|
||||||
|
let mut v: BigInt = 0_i32.into();
|
||||||
|
|
||||||
|
while a != 0_u32.into() {
|
||||||
|
let (q, r) = (&b / &a, &b % &a);
|
||||||
|
let m = &x - &u * &q;
|
||||||
|
let n = &y - &v * &q;
|
||||||
|
b = a;
|
||||||
|
a = r;
|
||||||
|
x = u;
|
||||||
|
y = v;
|
||||||
|
u = m;
|
||||||
|
v = n;
|
||||||
|
}
|
||||||
|
(b, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invmod_biguint(a: &BigUint, n: &BigUint) -> Option<BigUint> {
|
||||||
|
let r = extended_gcd(a, n);
|
||||||
|
match r {
|
||||||
|
(_, _, v1) if v1 == 0_i32.into() => None,
|
||||||
|
(_, u1, _) => {
|
||||||
|
let n = n.clone().to_bigint()?;
|
||||||
|
let r = ((&u1 % &n) + &n) % &n;
|
||||||
|
r.to_biguint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn invmod(a: &BigNum, n: &BigNum) -> Result<BigNum, ErrorStack> {
|
pub fn invmod(a: &BigNum, n: &BigNum) -> Result<BigNum, ErrorStack> {
|
||||||
fn extended_gcd(a: BigNum, b: BigNum) -> Result<(BigNum, BigNum, BigNum), ErrorStack> {
|
fn extended_gcd(a: BigNum, b: BigNum) -> Result<(BigNum, BigNum, BigNum), ErrorStack> {
|
||||||
// credit: https://www.dcode.fr/extended-gcd
|
// credit: https://www.dcode.fr/extended-gcd
|
||||||
|
|||||||
124
src/set5.rs
124
src/set5.rs
@@ -1,4 +1,5 @@
|
|||||||
use crate::bytes::Bytes;
|
use crate::bytes::Bytes;
|
||||||
|
use crate::dh;
|
||||||
use crate::rsa;
|
use crate::rsa;
|
||||||
use crate::sha1;
|
use crate::sha1;
|
||||||
use crate::srp;
|
use crate::srp;
|
||||||
@@ -9,98 +10,29 @@ use openssl::bn::BigNum;
|
|||||||
use openssl::sha::sha256;
|
use openssl::sha::sha256;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
pub mod challenge33 {
|
|
||||||
use num_bigint::BigUint;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
pub fn load_large_prime() -> BigUint {
|
|
||||||
let s = fs::read_to_string("data/33.txt").expect("run from git root dir");
|
|
||||||
let b: Vec<u8> = s
|
|
||||||
.chars()
|
|
||||||
.filter(|c| *c != '\n')
|
|
||||||
.map(|c| c.to_digit(16).unwrap().try_into().unwrap())
|
|
||||||
.collect();
|
|
||||||
BigUint::from_radix_be(&b, 16).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn challenge33() {
|
pub fn challenge33() {
|
||||||
fn expmod(base: u32, exp: u32, m: u32) -> u32 {
|
dh::simple();
|
||||||
if exp == 0 {
|
dh::serious();
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if exp % 2 == 0 {
|
|
||||||
let s = expmod(base, exp / 2, m);
|
|
||||||
(s * s) % m
|
|
||||||
} else {
|
|
||||||
(expmod(base, exp - 1, m) * base) % m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simple_diffie_hellman() {
|
|
||||||
#![allow(non_snake_case)]
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
// Set a variable "p" to 37 and "g" to 5.
|
|
||||||
let p: u32 = 37;
|
|
||||||
let g: u32 = 5;
|
|
||||||
|
|
||||||
// Generate "a", a random number mod 37. Now generate "A", which is "g" raised to the "a"
|
|
||||||
// power mode 37 --- A = (g**a) % p.
|
|
||||||
let a: u32 = rng.gen::<u32>() % p;
|
|
||||||
let A = expmod(g, a, p);
|
|
||||||
|
|
||||||
// Do the same for "b" and "B".
|
|
||||||
let b: u32 = rng.gen::<u32>() % p;
|
|
||||||
let B = expmod(g, b, p);
|
|
||||||
|
|
||||||
// "A" and "B" are public keys. Generate a session key with them; set "s" to "B" raised to
|
|
||||||
// the "a" power mod 37 --- s = (B**a) % p.
|
|
||||||
let s = expmod(B, a, p);
|
|
||||||
|
|
||||||
// Do the same with A**b, check that you come up with the same "s".
|
|
||||||
let s_ = expmod(A, b, p);
|
|
||||||
|
|
||||||
assert_eq!(s, s_, "crypto is broken");
|
|
||||||
// To turn "s" into a key, you can just hash it to create 128 bits of key material (or
|
|
||||||
// SHA256 it to create a key for encrypting and a key for a MAC).
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serious_diffie_hellman() {
|
|
||||||
let p = challenge33::load_large_prime();
|
|
||||||
let g = 2_u8.to_biguint().unwrap();
|
|
||||||
|
|
||||||
let a = rsa::Keypair::make(&p, &g);
|
|
||||||
let b = rsa::Keypair::make(&p, &g);
|
|
||||||
|
|
||||||
let s = b.public.0.modpow(&a.private.0, &p);
|
|
||||||
let s_ = a.public.0.modpow(&b.private.0, &p);
|
|
||||||
assert_eq!(s, s_, "crypto is broken");
|
|
||||||
}
|
|
||||||
|
|
||||||
simple_diffie_hellman();
|
|
||||||
serious_diffie_hellman();
|
|
||||||
println!("[okay] Challenge 33: implemented Diffie-Hellman");
|
println!("[okay] Challenge 33: implemented Diffie-Hellman");
|
||||||
}
|
}
|
||||||
|
|
||||||
mod challenge34 {
|
mod challenge34 {
|
||||||
use crate::bytes::Bytes;
|
use crate::bytes::Bytes;
|
||||||
use crate::cbc;
|
use crate::cbc;
|
||||||
use crate::rsa;
|
use crate::dh;
|
||||||
use crate::sha1::Sha1;
|
use crate::sha1::Sha1;
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
|
|
||||||
pub struct Bot {
|
pub struct Bot {
|
||||||
p: BigUint,
|
p: BigUint,
|
||||||
keypair: rsa::Keypair,
|
keypair: dh::Keypair,
|
||||||
pub s: Option<BigUint>,
|
pub s: Option<BigUint>,
|
||||||
pub key: Option<Bytes>,
|
pub key: Option<Bytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bot {
|
impl Bot {
|
||||||
pub fn new(p: BigUint, g: &BigUint) -> Self {
|
pub fn new(p: BigUint, g: &BigUint) -> Self {
|
||||||
let keypair = rsa::Keypair::make(&p, g);
|
let keypair = dh::Keypair::make(&p, g);
|
||||||
Bot {
|
Bot {
|
||||||
p,
|
p,
|
||||||
keypair,
|
keypair,
|
||||||
@@ -109,11 +41,11 @@ mod challenge34 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_public_key(&self) -> rsa::PublicKey {
|
pub fn get_public_key(&self) -> dh::PublicKey {
|
||||||
self.keypair.public.clone()
|
self.keypair.public.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exchange_keys(&mut self, public: &rsa::PublicKey) -> rsa::PublicKey {
|
pub fn exchange_keys(&mut self, public: &dh::PublicKey) -> dh::PublicKey {
|
||||||
let s = public.0.modpow(&self.keypair.private.0, &self.p);
|
let s = public.0.modpow(&self.keypair.private.0, &self.p);
|
||||||
self.s = Some(s);
|
self.s = Some(s);
|
||||||
self.make_encryption_key();
|
self.make_encryption_key();
|
||||||
@@ -176,8 +108,8 @@ mod challenge34 {
|
|||||||
|
|
||||||
pub fn challenge34() {
|
pub fn challenge34() {
|
||||||
fn echo() {
|
fn echo() {
|
||||||
let p = challenge33::load_large_prime();
|
let p = dh::load_large_prime();
|
||||||
let g = 2_u8.to_biguint().unwrap();
|
let g: BigUint = 2_u8.into();
|
||||||
|
|
||||||
let mut a = challenge34::Bot::new(p.clone(), &g);
|
let mut a = challenge34::Bot::new(p.clone(), &g);
|
||||||
|
|
||||||
@@ -200,9 +132,9 @@ pub fn challenge34() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn echo_mitm() {
|
fn echo_mitm() {
|
||||||
let p = challenge33::load_large_prime();
|
let p = dh::load_large_prime();
|
||||||
let g = 2_u8.to_biguint().unwrap();
|
let g = 2_u8.into();
|
||||||
let p_public = rsa::PublicKey(p.clone());
|
let p_public = dh::PublicKey(p.clone());
|
||||||
|
|
||||||
// A->M Send "p", "g", "A"
|
// A->M Send "p", "g", "A"
|
||||||
let mut a = challenge34::Bot::new(p.clone(), &g);
|
let mut a = challenge34::Bot::new(p.clone(), &g);
|
||||||
@@ -239,7 +171,7 @@ pub fn challenge34() {
|
|||||||
fn attack(cipher: &Bytes) -> Bytes {
|
fn attack(cipher: &Bytes) -> Bytes {
|
||||||
// Do the DH math on this quickly to see what that does to the predictability of the key.
|
// Do the DH math on this quickly to see what that does to the predictability of the key.
|
||||||
// With p = A; s = (A ** b) % p becomes (p ** b) % p = 0 => s = 0
|
// With p = A; s = (A ** b) % p becomes (p ** b) % p = 0 => s = 0
|
||||||
let s = 0_u8.to_biguint().unwrap();
|
let s = 0_u8.into();
|
||||||
challenge34::decrypt_with_s(cipher, &s)
|
challenge34::decrypt_with_s(cipher, &s)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,22 +198,22 @@ pub fn challenge35() {
|
|||||||
fn attack_g1(cipher: &Bytes) -> Bytes {
|
fn attack_g1(cipher: &Bytes) -> Bytes {
|
||||||
// A = (g ** a) % p, g = 1 -> A = 1
|
// A = (g ** a) % p, g = 1 -> A = 1
|
||||||
// s = (A ** b) % p, A = 1 -> s = 1
|
// s = (A ** b) % p, A = 1 -> s = 1
|
||||||
let s = 1_u8.to_biguint().unwrap();
|
let s = 1_u8.into();
|
||||||
challenge34::decrypt_with_s(cipher, &s)
|
challenge34::decrypt_with_s(cipher, &s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attack_g_is_p(cipher: &Bytes) -> Bytes {
|
fn attack_g_is_p(cipher: &Bytes) -> Bytes {
|
||||||
// A = (g ** a) % p, g = p -> A = 0
|
// A = (g ** a) % p, g = p -> A = 0
|
||||||
// s = (A ** b) % p, A = 0 -> s = 0
|
// s = (A ** b) % p, A = 0 -> s = 0
|
||||||
let s = 0_u8.to_biguint().unwrap();
|
let s = 0_u8.into();
|
||||||
challenge34::decrypt_with_s(cipher, &s)
|
challenge34::decrypt_with_s(cipher, &s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attack_g_is_p_minus_one(cipher: &Bytes, p: &BigUint) -> Bytes {
|
fn attack_g_is_p_minus_one(cipher: &Bytes, p: &BigUint) -> Bytes {
|
||||||
// A = (g ** a) % p, g = p - 1 -> A = 1 | (p - 1)
|
// A = (g ** a) % p, g = p - 1 -> A = 1 | (p - 1)
|
||||||
// s = (A ** b) % p, A = 1 | (p - 1) -> s = 1 | (p - 1)
|
// s = (A ** b) % p, A = 1 | (p - 1) -> s = 1 | (p - 1)
|
||||||
let s1 = 1_u8.to_biguint().unwrap();
|
let s1: BigUint = 1_u8.into();
|
||||||
let s2 = p - 1_u8.to_biguint().unwrap();
|
let s2: BigUint = p - &s1;
|
||||||
let m1 = challenge34::decrypt_with_s(cipher, &s1);
|
let m1 = challenge34::decrypt_with_s(cipher, &s1);
|
||||||
let m2 = challenge34::decrypt_with_s(cipher, &s2);
|
let m2 = challenge34::decrypt_with_s(cipher, &s2);
|
||||||
|
|
||||||
@@ -294,7 +226,7 @@ pub fn challenge35() {
|
|||||||
|
|
||||||
// Do the MITM attack again, but play with "g". Write attacks for each.
|
// Do the MITM attack again, but play with "g". Write attacks for each.
|
||||||
let m = Bytes::from_utf8("Quick to the point, to the point, no faking");
|
let m = Bytes::from_utf8("Quick to the point, to the point, no faking");
|
||||||
let p = challenge33::load_large_prime();
|
let p = dh::load_large_prime();
|
||||||
let g = 2_u8.to_biguint().unwrap();
|
let g = 2_u8.to_biguint().unwrap();
|
||||||
echo(&m, &g, &p);
|
echo(&m, &g, &p);
|
||||||
|
|
||||||
@@ -432,8 +364,8 @@ pub fn challenge38() -> Option<()> {
|
|||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
// Client and Server
|
// Client and Server
|
||||||
let n = challenge33::load_large_prime();
|
let n = dh::load_large_prime();
|
||||||
let g = 2_u8.to_biguint()?;
|
let g: BigUint = 2_u8.into();
|
||||||
let password = "bar";
|
let password = "bar";
|
||||||
|
|
||||||
// Server: x = SHA256(salt|password); v = g**x % n;
|
// Server: x = SHA256(salt|password); v = g**x % n;
|
||||||
@@ -480,9 +412,9 @@ pub fn challenge38() -> Option<()> {
|
|||||||
// Now, run the protocol as a MITM attacker: pose as the server and use arbitrary values
|
// Now, run the protocol as a MITM attacker: pose as the server and use arbitrary values
|
||||||
// for b, B, u, and salt. Crack the password from A's HMAC-SHA256(K, salt).
|
// for b, B, u, and salt. Crack the password from A's HMAC-SHA256(K, salt).
|
||||||
let dict = ["foo", "bar", "lol"];
|
let dict = ["foo", "bar", "lol"];
|
||||||
let g = 2_u8.to_biguint()?;
|
let g: BigUint = 2_u8.into();
|
||||||
let n = challenge33::load_large_prime();
|
let n = dh::load_large_prime();
|
||||||
let b = 11_u8.to_biguint()?;
|
let b: BigUint = 11_u8.into();
|
||||||
let salt_bytes = Bytes(salt.to_be_bytes().to_vec());
|
let salt_bytes = Bytes(salt.to_be_bytes().to_vec());
|
||||||
|
|
||||||
for password in dict {
|
for password in dict {
|
||||||
@@ -511,8 +443,12 @@ pub fn challenge38() -> Option<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn challenge39() -> Option<()> {
|
pub fn challenge39() -> Option<()> {
|
||||||
// I recommend you not bother with primegen,
|
let a: BigUint = 17_u32.into();
|
||||||
// but do take the time to get your own EGCD and
|
let n: BigUint = 3120_u32.into();
|
||||||
|
let r: BigUint = 2753_u32.into();
|
||||||
|
assert_eq!(rsa::invmod_biguint(&a, &n)?, r, "invmod does not work");
|
||||||
|
|
||||||
|
// I recommend you not bother with primegen, but do take the time to get your own EGCD and
|
||||||
// invmod algorithm working.
|
// invmod algorithm working.
|
||||||
let a = BigNum::from_u32(17).ok()?;
|
let a = BigNum::from_u32(17).ok()?;
|
||||||
let n = BigNum::from_u32(3120).ok()?;
|
let n = BigNum::from_u32(3120).ok()?;
|
||||||
|
|||||||
13
src/set6.rs
13
src/set6.rs
@@ -364,7 +364,6 @@ pub fn challenge46() -> Result<(), ErrorStack> {
|
|||||||
let c_b = rsa::rsa_encrypt_unpadded(&BigNum::from_u32(98)?, &public_key)?;
|
let c_b = rsa::rsa_encrypt_unpadded(&BigNum::from_u32(98)?, &public_key)?;
|
||||||
assert!(parity_oracle(&c_b), "parity oracle even doesn't work");
|
assert!(parity_oracle(&c_b), "parity oracle even doesn't work");
|
||||||
|
|
||||||
|
|
||||||
// Double by multiplying with (2**e) % n
|
// Double by multiplying with (2**e) % n
|
||||||
let mut ctx = BigNumContext::new()?;
|
let mut ctx = BigNumContext::new()?;
|
||||||
let two = BigNum::from_u32(2)?;
|
let two = BigNum::from_u32(2)?;
|
||||||
@@ -374,7 +373,6 @@ pub fn challenge46() -> Result<(), ErrorStack> {
|
|||||||
return &(&c * &multiplier) % &private_key.n;
|
return &(&c * &multiplier) % &private_key.n;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let solve = |mut cipher: BigNum, n: BigNum| -> Result<BigNum, ErrorStack> {
|
let solve = |mut cipher: BigNum, n: BigNum| -> Result<BigNum, ErrorStack> {
|
||||||
// - You can repeatedly apply this heuristic, once per bit of the message, checking your oracle
|
// - You can repeatedly apply this heuristic, once per bit of the message, checking your oracle
|
||||||
// function each time.
|
// function each time.
|
||||||
@@ -410,7 +408,6 @@ pub fn challenge46() -> Result<(), ErrorStack> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn challenge47() -> Result<(), ErrorStack> {
|
pub fn challenge47() -> Result<(), ErrorStack> {
|
||||||
|
|
||||||
// Generate a 256 bit keypair (that is, p and q will each be 128 bit primes), [n, e, d].
|
// Generate a 256 bit keypair (that is, p and q will each be 128 bit primes), [n, e, d].
|
||||||
let (public_key, private_key) = rsa::rsa_gen_keys_with_size(128, 128)?;
|
let (public_key, private_key) = rsa::rsa_gen_keys_with_size(128, 128)?;
|
||||||
|
|
||||||
@@ -432,8 +429,14 @@ pub fn challenge47() -> Result<(), ErrorStack> {
|
|||||||
let c_unpadded = rsa::rsa_encrypt_unpadded(&m, &public_key)?;
|
let c_unpadded = rsa::rsa_encrypt_unpadded(&m, &public_key)?;
|
||||||
let c = rsa::rsa_encrypt(&m, &public_key)?;
|
let c = rsa::rsa_encrypt(&m, &public_key)?;
|
||||||
|
|
||||||
assert!(!oracle(&c_unpadded), "oracle wrongly thinks unpadded message is padded");
|
assert!(
|
||||||
assert!(oracle(&c), "oracle wrongly thinks padded message is not padded");
|
!oracle(&c_unpadded),
|
||||||
|
"oracle wrongly thinks unpadded message is padded"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
oracle(&c),
|
||||||
|
"oracle wrongly thinks padded message is not padded"
|
||||||
|
);
|
||||||
|
|
||||||
println!("[xxxx] Challenge 47: Bleichenbacher's PKCS 1.5 Padding Oracle (Simple Case)");
|
println!("[xxxx] Challenge 47: Bleichenbacher's PKCS 1.5 Padding Oracle (Simple Case)");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::bytes::Bytes;
|
use crate::bytes::Bytes;
|
||||||
use crate::set5;
|
use crate::dh;
|
||||||
use crate::sha1;
|
use crate::sha1;
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use num_bigint::RandBigInt;
|
use num_bigint::RandBigInt;
|
||||||
@@ -61,7 +61,7 @@ impl Server {
|
|||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
// Agree on N=[NIST Prime], g=2, k=3
|
// Agree on N=[NIST Prime], g=2, k=3
|
||||||
let n = set5::challenge33::load_large_prime();
|
let n = dh::load_large_prime();
|
||||||
let g = 2_u8.to_biguint()?;
|
let g = 2_u8.to_biguint()?;
|
||||||
let k = 3_u8.to_biguint()?;
|
let k = 3_u8.to_biguint()?;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::{bytes::Bytes, bytes_base64::BytesBase64};
|
use crate::{bytes::Bytes, bytes_base64::BytesBase64};
|
||||||
|
use openssl::bn::BigNum;
|
||||||
use std::{
|
use std::{
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
use openssl::bn::BigNum;
|
|
||||||
|
|
||||||
pub fn unix_timestamp() -> u32 {
|
pub fn unix_timestamp() -> u32 {
|
||||||
let start = SystemTime::now();
|
let start = SystemTime::now();
|
||||||
|
|||||||
Reference in New Issue
Block a user