## RSA Cryptography

### November 16, 2010

The key generator takes the number of bits *k* and the encryption key *e* and returns the modulus *n* and the decryption key *d*. Large primes *v* are generated as a random integer on the range 2^{k/2−1} ≤ *v* < 2^{k/2}; if *v* is not prime, or not co-prime to *e*, or not congruent to 3 mod 4 (which avoids some nasty theoretical weaknesses), then it is incremented and the tests are applied again. This process can take a while for large values of *k*, because the arithmetic on large integers is slow and because it can take hundreds or thousands of trial *v* before a suitable one is found:

`(define (keygen k e)`

(define (gen k)

(let loop ((v (randint (expt 2 (- k 1)) (expt 2 k))))

(if (or (< 1 (gcd e (- v 1)))

(not (= (modulo v 4) 3))

(not (prime? v)))

(loop (+ v 1))

v)))

(let* ((k2 (quotient k 2)) (p (gen k2)) (q (gen k2))

(d (inverse e (* (- p 1) (- q 1)))))

(values (* p q) d)))

Encryption and decryption can be done by a single function; as long as you feed it the right key, it will make the right calculation:

`(define (crypt text modulus key)`

(expm text key modulus))

Here’s a 32-bit example, using the message 42:

`> (keygen 32 65537)`

1893932189

1461164273

> (crypt 42 1893932189 65537)

1118138102

> (crypt 1118138102 1893932189 1461164273)

42

We don’t know the random numbers *p* and *q* used by the key generator, but we can factor *n* to find them; of course, if *n* was larger, factoring would be more difficult, which is the basis for the security of the algorithm. We use Fermat’s method to do the factoring, since *p* and *q* must be close, so Fermat’s method is better than trial division:

`> (factors 1893932189)`

(51551 36739)

We steal much code from other sources. `Digits`

, `expm`

, `isqrt`

, and `randint`

come from the Standard Prelude. `Euclid`

, `inverse`

and `jacobi`

come from the exercise on modular arithmetic. `Square?`

comes from the exercise on powering predicates. `Prime?`

is the Baillie-Wagstaff algorithm, and `factors`

is the Fermat method. You can run the program at http://programmingpraxis.codepad.org/rRxeR2C9.

My Haskell solution (see http://bonsaicode.wordpress.com/2010/11/16/programming-praxis-rsa-cryptography/ for a version with comments):

Racket (with shameless use of libraries):

#! /bin/sh

#| Hey Emacs, this is -*-scheme-*- code!

exec racket -l errortrace –require “$0″ –main — ${1+”$@”}

|#

;; https://programmingpraxis.com/2010/11/16/rsa-cryptography/ but of

;; course also http://en.wikipedia.org/wiki/Rsa

#lang racket

(require rackunit rackunit/text-ui

(planet soegaard/math/math)

srfi/27)

(define *bit-length* (make-parameter 10))

(define (random-prime)

(let* ([min (expt 2 (sub1 (*bit-length*)))]

[r (+ min (big-random min))])

(next-prime r)))

(provide make-keys)

(define (make-keys [defaults? #f])

(let* (

[p (if defaults? 61 (random-prime))]

[q (if defaults? 53 (random-prime))]

[n (* p q)]

[φ (* (sub1 p) (sub1 q))]

[e (if defaults? 17 65537)]

[d (inverse e φ)]

)

(values (cons n e) ;public

(cons d (cons n e)) ;private

)))

(provide encrypt-integer)

(define (encrypt-integer m pubkey)

(match-define (cons n e) pubkey)

(with-modulus n (^ m e)))

(provide decrypt-integer)

(define (decrypt-integer c privkey)

(match-define (cons d (cons n e)) privkey)

(with-modulus n (^ c d)))

(define-test-suite praxis-tests

(let ()

;; example from Programming Praxis

(define-values (pub priv) (make-keys #t))

(check-equal? (encrypt-integer 65 pub) 2790)))

(define-test-suite random-tests

(for ([_ (in-range 5)])

(define-values (pub priv) (make-keys))

(define plaintext (big-random (car pub)))

(check-equal? (decrypt-integer (encrypt-integer plaintext pub) priv) plaintext)

(printf “W00t~%”)))

(define-test-suite all-tests

random-tests

praxis-tests)

(provide main)

(define (main . args)

;; This indirectly affects big-random. Feh.

(random-source-randomize! default-random-source)

(exit (run-tests all-tests ‘verbose)))

Once again, my submission is entirely too large to fit here nicely.

The problem: I needed to either import some number-theoretic functions (Extended Euclidean Algorithm, primality

test), or define them myself if the incredible gmpy library is unavailable for the Python installation being used.

Though I’m certainly biased, I’m a huge fan of the mathematical exercises here! Sorry it took so long for me to get to

this.

Works for any N = 18, the integers get too big.

import java.math.BigInteger;

import java.security.SecureRandom;

/**

* Cryptography.

*

* Generates public and private keys used in encryption and

* decryption

*

* Author: Jamie

* Version: Dec 27, 2011

*/

public class RSA

{

private final static BigInteger one = new BigInteger(“1”);

private final static SecureRandom random = new SecureRandom();

// prime numbers

private BigInteger p;

private BigInteger q;

// modulus

private BigInteger n;

// totient

private BigInteger t;

// public key

private BigInteger e;

// private key

private BigInteger d;

private String cipherText;

/**

* Constructor for objects of class RSA

*/

public RSA(int N)

{

p = BigInteger.probablePrime(N/2, random);

q = BigInteger.probablePrime(N/2, random);

// initialising modulus

n = p.multiply(q);

// initialising t by euler’s totient function (p-1)(q-1)

t = (p.subtract(one)).multiply(q.subtract(one));

// initialising public key ~ 65537 is common public key

e = new BigInteger(“65537”);

}

public int generatePrivateKey()

{

d = e.modInverse(t);

return d.intValue();

}

public String encrypt(String plainText)

{

String encrypted = “”;

for(int i = 0; i < plainText.length(); i++){

char m = plainText.charAt(i);

BigInteger bi1 = BigInteger.valueOf(m);

BigInteger bi2 = bi1.modPow(e, n);

m = (char) bi2.intValue();

encrypted += m;

}

cipherText = encrypted;

return encrypted;

}

public String decrypt()

{

String decrypted = "";

for(int i = 0; i < cipherText.length(); i++){

char c = cipherText.charAt(i);

BigInteger bi1 = BigInteger.valueOf(c);

BigInteger bi2 = bi1.modPow(d, n);

c = (char) bi2.intValue();

decrypted += c;

}

return decrypted;

}

}

I solved it in Clojure- my solution is available here: https://github.com/topher200/rsa-cryptography

I also made a small blog post about it here: http://blog.tophernet.com/2011/04/rsa-cryptography-in-clojure.html