Big number and RSA

This commit is contained in:
2022-10-21 13:01:14 +02:00
parent ff08afe5e0
commit 0c6dc64726
6 changed files with 179 additions and 2 deletions

View File

@@ -6,6 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
num = "0.4"
num = {version = "0.4", features = ["rand"] }
rayon = "1.5"
rand = "0.8"

13
rust/notes.md Normal file
View File

@@ -0,0 +1,13 @@
1. n at least 1024 bits
2. p and q 512 bits
3. p and q very different -> p/q !≃ 1
4. p-1 and q-1 should have a large prime factor
5. p/q should not be close to a rational number
6. do not share n
7. d is leaked change everything
8. optimal e 2^16+1
search attack about :
- factorisation
- infer from
- encryption and decryption exponent (small and partial)

35
rust/src/big.rs Normal file
View File

@@ -0,0 +1,35 @@
use num::{ BigUint, Integer};
use crypto_test::prime::miller_rabbin_test_big;
use crypto_test::utils::{ modular_inverse_big };
pub fn test(){
let p = &BigUint::parse_bytes(b"9613034531358350457419158128061542790930984559499621582258315087964794045505647063849125716018034750312098666606492420191808780667421096063354219926661209", 10).unwrap();
let q = &BigUint::parse_bytes(b"12060191957231446918276794204450896001555925054637033936061798321731482148483764659215389453209175225273226830107120695604602513887145524969000359660045617", 10).unwrap();
println!("p prime : {}", miller_rabbin_test_big(p.clone(), 40));
println!("q prime : {}", miller_rabbin_test_big(q.clone(), 40));
let n = p * q;
println!("n : {:?}",n);
let phi = &((p - 1_u16) * (q - 1_u16));
println!("phi : {:?}",phi);
let e = BigUint::parse_bytes(b"65537",10).unwrap();
println!("e : {:?}",e);
let inv = modular_inverse_big(e.clone(),phi.clone()).unwrap();
println!("inv : {:?}",inv);
let d = inv.mod_floor(phi);
println!("d : {:?}",d);
let msg = &BigUint::from_bytes_be(b"This is a $up3r test");
println!("Msg : {:?}", msg);
let c = msg.modpow(&e,&n);
println!("Encrypted msg : {:?}", c);
let decrypt = c.modpow(&d,&n);
println!("Decrypted msg : {:?}", decrypt);
}

View File

@@ -1,3 +1,21 @@
mod big;
fn main() {
println!("Hello, world!");
big::test();
//println!("{:?}",p);
/*let n = 10;
'l:for a in 1..n{
if gcd(a,n) ==1 {
for m in 1..phi(n){
if congruent(a.pow(m) as i32, 1, n as i32){
continue 'l;
}
}
println!("ok === > {a}");
}
}*/
}

View File

@@ -1,7 +1,9 @@
use num::{BigUint, One, Zero};
use crate::utils::fast_exp;
use num::integer::sqrt;
use rand::{thread_rng, Rng};
use rayon::prelude::*;
use rand::distributions::Distribution;
pub fn miller_rabbin_gen(max: u32, acr: u32) -> Vec<u32> {
let method = |n| miller_rabbin_test(n, acr);
@@ -41,6 +43,45 @@ fn find_2_k_q(mut n: u32) -> (u32, u32) {
}
(k, n)
}
pub fn miller_rabbin_test_big(n: BigUint, acr: u32) -> bool {
let two = BigUint::one() + BigUint::one();
let bits = n.bits();
if &n % &two == BigUint::zero() {
false
} else {
let n_1 = &n-BigUint::one();
let (k, q) = find_2_k_q_big(n_1.clone());
let mut random = thread_rng();
let rb = num::bigint::RandomBits::new(bits);
'l: for _ in 0..acr {
let a:BigUint = rb.sample(&mut random) ;
let mut x = a.modpow(&q,&n);
if x != BigUint::one() && x != n_1 {
for _ in num::range(BigUint::zero(), &k - BigUint::one()) {
x = x.modpow(&two,&n);
if x == n_1 {
continue 'l;
}
}
return false;
}
}
true
}
}
fn find_2_k_q_big(mut n: BigUint) -> (BigUint, BigUint) {
let mut k = BigUint::zero();
let two = BigUint::one() + BigUint::one();
while &n % &two == BigUint::zero() {
n /= &two;
k += BigUint::one();
}
(k, n)
}
fn prime_gen<F>(max: u32, method: F) -> Vec<u32>
where

View File

@@ -1,3 +1,8 @@
use num::{BigInt, BigUint, One, Zero};
use num::bigint::ToBigInt;
use num::integer::gcd;
use rand::{Rng, thread_rng};
pub fn prime_factor(mut n: u32) -> Vec<(u32, u32)> {
let mut p = 2;
let mut dec = vec![];
@@ -77,7 +82,25 @@ pub fn modular_inverse(a: u32, n: u32) -> Option<u32> {
Some(t as u32)
}
pub fn modular_inverse_big(a: BigUint, n: BigUint) -> Option<BigUint> {
let (mut t, mut new_t) = (BigInt::zero(), BigInt::one());
let (mut r, mut new_r) = (n.to_bigint().unwrap(), a.to_bigint().unwrap());
while new_r != BigInt::zero() {
let q = &r / &new_r;
(t, new_t) = (new_t.clone(), (&t - (&q * &new_t)));
(r, new_r) = (new_r.clone(), (&r - (&q * &new_r)));
}
if r > BigInt::one() {
return None;
}
if t < BigInt::zero(){
t += n.to_bigint().unwrap();
}
t.to_biguint()
}
pub fn fast_exp(mut b: u32, mut e: u32, m: u32) -> u32 {
if m == 1 {
return 0;
@@ -95,6 +118,40 @@ pub fn fast_exp(mut b: u32, mut e: u32, m: u32) -> u32 {
result
}
pub fn mini_rsa(p: u32, q: u32) -> (u32, u32) {
let mut rnd = thread_rng();
let phi = (p - 1) * (q - 1);
let mut d;
let d_inv;
loop {
d = rnd.gen_range(2..phi);
if gcd(d, phi) == 1 {
if let Some(inv) = modular_inverse(d, phi) {
d_inv = inv;
break;
}
}
}
let e = d_inv % phi;
(d, e)
}
pub fn find_all_rsa(p: u32, q: u32) -> Vec<(u32, u32)> {
let phi = (p - 1) * (q - 1);
let mut v = vec![];
for d in 2..phi {
if gcd(d, phi) == 1 {
if let Some(inv) = modular_inverse(d, phi) {
let e = inv % phi;
v.push((d, e))
}
}
}
v
}
#[cfg(test)]
mod tests {
use super::*;
@@ -147,5 +204,18 @@ mod tests {
assert_eq!(fast_exp(11, 13, 19), 11);
assert_eq!(fast_exp(1234, 754, 452), 392);
assert_eq!(fast_exp(76158, 24586, 5364), 576);
assert_eq!(fast_exp(7, 37_000_000, 11), 1)
}
#[test]
fn test_mini_rsa() {
let (p, q) = (97, 499);
let n = p * q;
let (d, e) = mini_rsa(q, p);
let m = 12345;
let c = fast_exp(m, e, n);
let m_d = fast_exp(c, d, n);
assert_eq!(m_d, m);
}
}