Skip to content

Support RSA in rust #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ pub mod pkcs5;
pub mod pkey;
pub mod rand;
pub mod symm;
pub mod primarity_tests;
pub mod prime_number_generator;
pub mod rsa;
144 changes: 144 additions & 0 deletions crypto/primarity_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use num::bigint::BigUint;
use num::bigint::ToBigUint;
use num::bigint::BigInt;
use num::bigint::ToBigInt;
use num::Integer;
use rand;
use rand::Rng;

fn mod_mult(a : &mut BigUint, b : &mut BigUint, m : &BigUint) -> BigUint {
let mut res = (0u).to_biguint().unwrap();
*a = a.mod_floor(m);

let zero = (0u).to_biguint().unwrap();
while zero.lt(b) {
if b.is_odd() {
res = res.add(a);
if m.lt(&res) {
res = res.sub(m);
}
}
*a = a.shl(&1u);
if m.lt(a) {
*a = a.sub(m);
}
*b = b.shr(&1u);
}

return res;
}

pub fn mod_exp(n : &mut BigUint, e : &mut BigUint, m : &BigUint) -> BigUint {
let zero = (0u).to_biguint().unwrap();
let mut res = (1u).to_biguint().unwrap();

*n = n.mod_floor(m);
while zero.lt(e) {
if e.is_odd() {
res = mod_mult(&mut res.clone(), &mut n.clone(), m);
}
*n = mod_mult(&mut n.clone(), &mut n.clone(), m);
*e = e.shr(&1u);
}
return res;
}

fn extgcd(a: &mut BigInt, b: &mut BigInt) -> (BigInt, BigInt) {
if (*a).lt(&b.clone()) {
let c = a.clone();
*a = b.clone();
*b = c.clone();
}
let zero = (0u).to_bigint().unwrap();
let one = (1u).to_bigint().unwrap();
let minus = (-1i32).to_bigint().unwrap();

let ( mut q, mut r, mut xx, mut yy) = (zero.clone(), zero.clone(), zero.clone(), zero.clone());
let ( mut xs0, mut xs1, mut ys0, mut ys1) = (one.clone(), zero.clone(), zero.clone(), one.clone());
let mut is_plus = true;

while !zero.eq(&b.clone()) {
r = (*a).mod_floor(&b.clone());
q = (*a).div(&b.clone());
*a = b.clone();
*b = r.clone();
xx = xs1.clone();
yy = ys1.clone();
xs1 = q.mul(&xs1.clone()).add(&xs0.clone());
ys1 = q.mul(&ys1.clone()).add(&ys0.clone());
xs0 = xx.clone();
ys0 = yy.clone();
is_plus = !is_plus;
}

let (mut x, mut y) = (zero.clone(), zero.clone());
if is_plus {
x = xs0;
y = ys0.mul(&minus);
}
else {
x = xs0.mul(&minus);
y = ys0;
}
return (x.to_bigint().unwrap(), y.to_bigint().unwrap());
}

pub fn inv_mod(a: &mut BigUint, m: &BigUint) -> BigUint {
let zero = (0u).to_bigint().unwrap();
let (mut y,mut x) = extgcd(&mut a.to_bigint().unwrap(), &mut m.to_bigint().unwrap());
if x.lt(&zero.clone()) {
let mi = m.to_bigint().unwrap();
x = x.add(&mi.clone());
}
return x.to_biguint().unwrap();
}

pub fn fetmat_test(a: &mut BigUint, p: &mut BigUint) -> bool {
let one = (1u).to_biguint().unwrap();
return mod_exp(a, &mut p.sub(&one), p).eq(&one);
}

pub fn miller_rabin(n :BigUint, t:uint) -> bool {
let one = (1u).to_biguint().unwrap();
let two = (2u).to_biguint().unwrap();
if n.lt(&two) {
return false;
}
else if n.eq(&two) {
return true;
}
else if n.is_even() {
return false;
}

let phi_n = n.sub(&one);
let rng_lim = phi_n.sub(&two);
let mut q = n.sub(&one);
let mut k : i32 = 0;
while q.is_odd() {
k += 1;
q = q.shr(&1u);
}
let mut rng = rand::task_rng();
for i in range(0u,t) {
let mut a = ( rng.gen::<uint>() ).to_biguint().unwrap();
a = a.mod_floor(&rng_lim).add(&two);
let mut x = mod_exp( &mut a.clone(), &mut q.clone(), &n.clone());
if x.eq(&one) {
continue;
}
let mut found : bool = false;
for j in range(0,k) {
if x.eq(&phi_n) {
found = true;
break;
}
x = (x.mul(&x)).mod_floor(&n);
}
if found {
continue;
}
return false;
}
return true;
}
98 changes: 98 additions & 0 deletions crypto/prime_number_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use num::bigint::BigUint;
use num::bigint::ToBigUint;
use rand;
use rand::Rng;
use crypto::primarity_tests::{fetmat_test, miller_rabin};

fn generate_random_byte(primeLength: uint) -> BigUint {
let zero = (0u).to_biguint().unwrap();
let one = (1u).to_biguint().unwrap();

let mut result = (0u).to_biguint().unwrap();
let mut rng = rand::task_rng();
for bit in range(0,primeLength) {
let mut i_bit = if rng.gen::<uint>()&1 == 1 { one.clone() } else { zero.clone() };
if bit == 0 {
//To ensure generated number is odd
i_bit = one.clone();
}
else if bit >= primeLength-2 {
//To ensure gerated number is enough big
i_bit = one.clone();
}
else if bit >= primeLength-4 {
//To ensure gerated number is enough small to avoid overflow
//when use Incremental Search method to generate prime number.
i_bit = zero.clone();
}

result = result.add(&i_bit.shl(&bit));
}
return result;
}

fn get_number_test(primeLength: uint) -> uint {
/* values taken from table 4.4, HandBook of Applied Cryptography */
let num_tests: uint;
if primeLength >= 1300 {
num_tests = 2;
} else if primeLength >= 850 {
num_tests = 3;
} else if primeLength >= 650 {
num_tests = 4;
} else if primeLength >= 550 {
num_tests = 5;
} else if primeLength >= 450 {
num_tests = 6;
} else if primeLength >= 400 {
num_tests = 7;
} else if primeLength >= 350 {
num_tests = 8;
} else if primeLength >= 300 {
num_tests = 9;
} else if primeLength >= 250 {
num_tests = 12;
} else if primeLength >= 200 {
num_tests = 15;
} else if primeLength >= 150 {
num_tests = 18;
} else if primeLength >= 100 {
num_tests = 27;
} else {
num_tests = 50;
}
return num_tests;
}

pub fn generate_prime_random_choice(primeLength: uint) -> BigUint {
let num_tests = get_number_test(primeLength);
let two = (2u).to_biguint().unwrap();

loop {
let prime_candidate = generate_random_byte(primeLength);

if !fetmat_test( &mut two.clone(), &mut prime_candidate.clone() ) {
continue;
}

if miller_rabin(prime_candidate.clone(), num_tests) {
return prime_candidate;
}
}
}

pub fn generate_prime_incremental_search(primeLength: uint) -> BigUint {
let num_tests = get_number_test(primeLength);

let mut prime_candidate = generate_random_byte(primeLength);
let two = (2u).to_biguint().unwrap();
loop {
prime_candidate = prime_candidate.add(&two.clone());
if !fetmat_test( &mut two.clone(), &mut prime_candidate.clone() ) {
continue;
}
if miller_rabin(prime_candidate.clone(), num_tests) {
return prime_candidate;
}
}
}
94 changes: 94 additions & 0 deletions crypto/rsa.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use num::bigint::BigUint;
use num::bigint::ToBigUint;
use num::Integer;
use crypto::prime_number_generator::generate_prime_random_choice;
use crypto::primarity_tests::{inv_mod, mod_exp};

fn byte2biguint(number:&str) -> BigUint {
let mut res = (0i).to_biguint().unwrap();
for ch in number.chars().rev() {
res = res.shl(&8u);
let value = (ch as u8).to_biguint().unwrap();
res = res.add(&value);
}
return res;
}

fn biguint2byte(number: &mut BigUint) -> ~str {
let mut res = StrBuf::new();

let zero = (0u).to_biguint().unwrap();
let m = (256u).to_biguint().unwrap();
while zero.lt(number) {
let ch = number.mod_floor(&m);
res.push_char( (ch.to_u64().unwrap() as u8) as char );
*number = number.shr(&8u);
}
return res.into_owned();
}

pub struct RSAKey {
modulus : BigUint, /* n */
prime1 : BigUint, /* p */
prime2 : BigUint, /* q */
publicExponent : BigUint, /* e */
privateExponent : BigUint, /* d */
}

fn load_public_key(pkey: &RSAKey) -> RSAKey {
let zero = (1u).to_biguint().unwrap();
return RSAKey {
modulus : pkey.modulus.clone(),
prime1 : zero.clone(),
prime2 : zero.clone(),
publicExponent : pkey.publicExponent.clone(),
privateExponent : zero.clone()
};
}

pub fn RSA_generate_key(primeLength: uint, publicExponent: BigUint) -> RSAKey {
let one = (1u).to_biguint().unwrap();

let p = generate_prime_random_choice(primeLength);
let q = generate_prime_random_choice(primeLength);
let n = p.mul(&q);
let e = publicExponent;

// phi = (p-1)*(q-1)
let phi = p.sub(&one.clone()).mul(&q.sub(&one.clone()));
// Compute d = e**-1 mod(phi) to d*e = 1 mod(phi)
let d = inv_mod(&mut e.clone(), &mut phi.clone());

return RSAKey {
modulus : n,
prime1 : p,
prime2 : q,
publicExponent : e,
privateExponent : d
};
}

pub fn RSA_public_encrypt(ms: &str, pkey: &RSAKey) -> BigUint {
let mut m = byte2biguint(ms);
let mut e = pkey.publicExponent.clone();
let n = pkey.modulus.clone();
return mod_exp(&mut m, &mut e, &n);
}

pub fn RSA_private_decrypt(c: BigUint, pkey: &RSAKey) -> ~str {
let mut d = pkey.privateExponent.clone();
let n = pkey.modulus.clone();
let mut m = mod_exp(&mut c.clone(), &mut d, &n);
return biguint2byte(&mut m);
}

#[test]
fn test_encrypt() {
let k0 = &RSA_generate_key(128u, (65537u).to_biguint().unwrap());
let k1 = &load_public_key(k0.clone());

let msg = "RSA";
let emsg = RSA_public_encrypt(msg, k1);
let dmsg = RSA_private_decrypt(emsg, k0);
assert!(msg == dmsg)
}
2 changes: 2 additions & 0 deletions lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#![doc(html_root_url="http://sfackler.github.io/rust-openssl/doc")]

extern crate libc;
extern crate num;
extern crate rand;
#[cfg(test)]
extern crate serialize;
extern crate sync;
Expand Down