Diffie-Hellman key exchange and RSA public-key encryption both rely on functions like this:
( ( (g^a)%p )^b )%p
(^ denotes raising to a power, and % denotes modulus, the remainder after dividing).
The Diffie-Hellman key-exchange algorithm allows two people, Alice and Bob, to agree upon a number (to use as a key for encryption) without Eve knowing what it is, even though she sees everything that passes between Alice and Bob. It relies on the fact that:
(g^a)^b = (g^b)^a (which also = g^ab = g^ba)
The first equation above has the same property. Here's how the key exchange works:
Alice picks random(ish) numbers g, a, and p. p should be prime (in fact, (p-1)/2 should also be prime), and a should be large. 2 and 5 are the most commonly used values for g. She sends g, p, and the resulting value of (g^a)%p to Bob, but not a by itself.
Bob picks b (which should also be large), and sends (g^b)%p back to Alice. Eve, watching each exchange, now has g, p, (g^b)%p and (g^a)%p, but she can't get a or b from these. We hope. It would require that Eve know how to efficiently compute discrete logarithms, and the security of this algorithm (as well as that of RSA and most other public key algorithms) depends on nobody figuring out how to do that.
Bob takes the (g^a)%p that Alice sent him and raises it to b, then takes mod p, giving him ( ( (g^a)%p )^b )%p. Alice does the same thing and ends up with ( ( (g^b)%p )^a )%p - which is the same number. Alice and Bob can now use this number as a password for encrypting future communications.
Since g, a, b and p are usually very large numbers (hundreds of digits long), we need a fast way to compute (g^a)%p. That's where Modular Exponentiation comes in.
Incidentally, you can use dc to compute g^a%p to check your work:
% dc 2 8 255 |p 1
Means 2^8%255 (which equals 1). `man dc` for more information on dc, the UNIX desktop calculator.
The term modular exponentiation refers to the function:
(g^a)%p
We need to compute this function efficiently to use public key cryptography of the Diffie-Hellman or RSA variety.
If we calculate g^a as:
g^a = g*g*g*g.... (a times)
we'll spend a lot of time multiplying if a is large (which it usually is; often it's greater than the number of particles in the universe!). Here's how to get there faster.
Since we're dealing with computers here, let's assume we have a binary representation of a. If a = 42, we'd write it as
42 = 101010b (the b here means binary) = 1*2^5 + 0*2^4 + 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0
That means that:
if a=42, g^a = g^(2^5 + 2^3 + 2^1) = g^(32) * g^(8) * g^(2)
Now we just need g^32, g^8 and g^2. But check this out:
g^2 * g^2 = g^4 and g^4 * g^4 = g^8 and g^8 * g^8 = g^16 and g^16 * g^16 = g^32 and so on.
So by progressively multiplying the products by themselves, we can get g^(2^n) with just n-1 multiplications. Since there are only about log2(a) bits in a, we can find g^a with at most log2(a)-1 + log2(a) multiplication operations. (The second log2(a) comes from where we multiplied g^32 * g^8 * g^2 above).
So how does the modulus play into all of this? Well, it turns out that you can distribute the operation into the multiplication without changing the result, leaving you with smaller numbers to multiply, like this:
[g^32 % p * g^8 % p * g^2 % p] % p = (g^a)%p
You can do the same thing when computing g^(2^n). Why does it work? Look at it this way:
(3*4*5)%7 =? ( ( (3*4)%7 )*5 )%7 (12*5)%7 ( (7+5)*5 )%7 split the product into a multiple of the modulus (7*5 + 5*5)%7 and the remainder. The multiple divides out ( 5*5)%7 evenly, and you're left with what you'd have ( (12)%7 )*5 )%7 had if you had done the % after the first *.
In this lab you will use Diffie-Hellman key exchange to establish a secret key to use for communication with a server. Specifically:
p: [your P value here] g^s%p: [your public value here]
where p and g^s%p are expressed in decimal. Note that the labels p: and g^s%p: are 2 of the lines, and the numbers are one (long) line each.
Debug Mode makes it easier to tell if your program is working properly.
In passoff mode, an eavesdropper won't be able to determine the shared secret, and the secret message will be readable only to you.
We will use an autograder to pass off your lab.
Submit a file with your source code to Learning Suite
If you want to write your client in Perl, you'll probably find the Math::BigInt library quite useful. There are also bindings for OpenSSL available.
If you are coding in Java then you will find the BigInteger object very useful. Python ints magically grow into bigints as needed with no user intervention.
OpenSSL includes a great bignum library. Some of this code might be helpful for using it: (includes example of how to generate a prime using OpenSSL). Note that you must link in the openssl libraries using “-lcrypto” when compiling. For example to compile your c program named dh.c with openssl, type “gcc -o dh dh.c -lcrypto”.
OpenSSL can be difficult to install on Windows machines for VC++. Here are some helpful hints on installing the OpenSSL library on your home computer.