Finish challenge 39 without invmod
This commit is contained in:
@@ -62,8 +62,9 @@ fn main() {
|
|||||||
set5::challenge34();
|
set5::challenge34();
|
||||||
set5::challenge35();
|
set5::challenge35();
|
||||||
set5::challenge36();
|
set5::challenge36();
|
||||||
|
set5::challenge37().unwrap_or_else(|| println!("[FAIL] challenge 37"));
|
||||||
}
|
}
|
||||||
set5::challenge37();
|
set5::challenge38().unwrap_or_else(|| println!("[FAIL] challenge 38"));
|
||||||
set5::challenge38();
|
set5::challenge39().unwrap_or_else(|| println!("[FAIL] challenge 39"));
|
||||||
set5::challenge39();
|
set5::challenge40().unwrap_or_else(|| println!("[FAIL] challenge 40"));
|
||||||
}
|
}
|
||||||
|
|||||||
94
src/rsa.rs
94
src/rsa.rs
@@ -1,5 +1,8 @@
|
|||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use num_bigint::RandBigInt;
|
use num_bigint::RandBigInt;
|
||||||
|
use openssl::bn::BigNum;
|
||||||
|
use openssl::bn::BigNumContext;
|
||||||
|
use openssl::error::ErrorStack;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PublicKey(pub BigUint);
|
pub struct PublicKey(pub BigUint);
|
||||||
@@ -24,3 +27,94 @@ impl Keypair {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RsaPublicKey {
|
||||||
|
e: BigNum,
|
||||||
|
n: BigNum,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RsaPrivateKey {
|
||||||
|
d: BigNum,
|
||||||
|
n: BigNum,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rsa_gen_keys() -> Result<(RsaPublicKey, RsaPrivateKey), ErrorStack> {
|
||||||
|
let mut ctx = BigNumContext::new()?;
|
||||||
|
|
||||||
|
// Generate 2 random primes. We'll use small numbers to start, so you can just pick them out of a prime table. Call them "p" and "q".
|
||||||
|
let mut p = BigNum::new()?;
|
||||||
|
let mut q = BigNum::new()?;
|
||||||
|
p.generate_prime(256, true, None, None)?;
|
||||||
|
q.generate_prime(256, true, None, None)?;
|
||||||
|
|
||||||
|
// Let n be p * q. Your RSA math is modulo n.
|
||||||
|
let mut n = BigNum::new()?;
|
||||||
|
n.checked_mul(&p, &q, &mut ctx)?;
|
||||||
|
// This is stupid but I couldn't figure out how to clone a bignum so we do this.
|
||||||
|
let mut n2 = BigNum::new()?;
|
||||||
|
n2.checked_mul(&p, &q, &mut ctx)?;
|
||||||
|
|
||||||
|
// Let et be (p-1)*(q-1) (the "totient"). You need this value only for keygen.
|
||||||
|
let mut et = BigNum::new()?;
|
||||||
|
q.sub_word(1)?;
|
||||||
|
p.sub_word(1)?;
|
||||||
|
et.checked_mul(&p, &q, &mut ctx)?;
|
||||||
|
|
||||||
|
// Let e be 3.
|
||||||
|
// Compute d = invmod(e, et). invmod(17, 3120) is 2753.
|
||||||
|
let e = BigNum::from_u32(3)?;
|
||||||
|
let d = invmod(&e, &et)?;
|
||||||
|
|
||||||
|
// Your public key is [e, n]. Your private key is [d, n].
|
||||||
|
Ok((RsaPublicKey { e, n }, RsaPrivateKey { d, n: n2 }))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invmod(a: &BigNum, n: &BigNum) -> Result<BigNum, ErrorStack> {
|
||||||
|
//let zero = BigNum::from_u32(0)?;
|
||||||
|
|
||||||
|
//let gcd_extended = |a: &mut BigNum, b: &mut BigNum| -> (BigNum, BigNum, BigNum) {
|
||||||
|
// if *a == zero {
|
||||||
|
// return (
|
||||||
|
// BigNum::from_u32(0).unwrap(),
|
||||||
|
// BigNum::from_u32(1).unwrap(),
|
||||||
|
// b);
|
||||||
|
// }
|
||||||
|
// (
|
||||||
|
// BigNum::from_u32(0).unwrap(),
|
||||||
|
// BigNum::from_u32(1).unwrap(),
|
||||||
|
// b)
|
||||||
|
//}
|
||||||
|
|
||||||
|
let mut ctx = BigNumContext::new()?;
|
||||||
|
let mut r = BigNum::new()?;
|
||||||
|
r.mod_inverse(&a, &n, &mut ctx)?;
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rsa_encrypt(m: &BigNum, p: &RsaPublicKey) -> Result<BigNum, ErrorStack> {
|
||||||
|
let mut ctx = BigNumContext::new()?;
|
||||||
|
let mut c = BigNum::new()?;
|
||||||
|
// To encrypt: c = m**e%n.
|
||||||
|
c.mod_exp(&m, &p.e, &p.n, &mut ctx)?;
|
||||||
|
Ok(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rsa_decrypt(c: &BigNum, p: &RsaPrivateKey) -> Result<BigNum, ErrorStack> {
|
||||||
|
let mut ctx = BigNumContext::new()?;
|
||||||
|
let mut m = BigNum::new()?;
|
||||||
|
// To decrypt: m = c**d%n.
|
||||||
|
m.mod_exp(&c, &p.d, &p.n, &mut ctx)?;
|
||||||
|
Ok(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rsa_encrypt_str(m: &str, p: &RsaPublicKey) -> Result<BigNum, ErrorStack> {
|
||||||
|
// Finally, to encrypt a string, do something cheesy.
|
||||||
|
let m = BigNum::from_slice(&m.as_bytes())?;
|
||||||
|
assert!(m < p.n);
|
||||||
|
rsa_encrypt(&m, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rsa_decrypt_str(c: &BigNum, p: &RsaPrivateKey) -> Result<String, ErrorStack> {
|
||||||
|
let m = rsa_decrypt(c, p)?;
|
||||||
|
Ok(String::from(std::str::from_utf8(&m.to_vec()).unwrap()))
|
||||||
|
}
|
||||||
|
|||||||
32
src/set5.rs
32
src/set5.rs
@@ -5,6 +5,7 @@ use crate::srp;
|
|||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use num_bigint::RandBigInt;
|
use num_bigint::RandBigInt;
|
||||||
use num_bigint::ToBigUint;
|
use num_bigint::ToBigUint;
|
||||||
|
use openssl::bn::BigNum;
|
||||||
use openssl::sha::sha256;
|
use openssl::sha::sha256;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
@@ -509,6 +510,33 @@ pub fn challenge38() -> Option<()> {
|
|||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn challenge39() {
|
pub fn challenge39() -> Option<()> {
|
||||||
println!("[xxxx] Challenge 39: Implement RSA");
|
// I recommend you not bother with primegen,
|
||||||
|
// but do take the time to get your own EGCD and
|
||||||
|
// invmod algorithm working.
|
||||||
|
let a = BigNum::from_u32(17).ok()?;
|
||||||
|
let n = BigNum::from_u32(3120).ok()?;
|
||||||
|
let r = BigNum::from_u32(2753).ok()?;
|
||||||
|
assert_eq!(rsa::invmod(&a, &n).ok()?, r, "invmod does not work");
|
||||||
|
|
||||||
|
let (public_key, private_key) = rsa::rsa_gen_keys().ok()?;
|
||||||
|
|
||||||
|
// Test this out with a number, like "42".
|
||||||
|
let i = BigNum::from_u32(1337).ok()?;
|
||||||
|
let c = rsa::rsa_encrypt(&i, &public_key).ok()?;
|
||||||
|
let m = rsa::rsa_decrypt(&c, &private_key).ok()?;
|
||||||
|
assert_eq!(i, m, "rsa is broken");
|
||||||
|
|
||||||
|
let i = "Party, party, party, all night long. Yuah!";
|
||||||
|
let c = rsa::rsa_encrypt_str(&i, &public_key).ok()?;
|
||||||
|
let m = rsa::rsa_decrypt_str(&c, &private_key).ok()?;
|
||||||
|
assert_eq!(i, &m, "string rsa is broken");
|
||||||
|
|
||||||
|
println!("[okay] Challenge 39: implement RSA");
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn challenge40() -> Option<()> {
|
||||||
|
// println!("[xxxx] Challenge 40: implement an E=3 RSA Broadcast attack");
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user