Diffie-Hellman key exchange algorithm – deeper and better

In my last post on D-H algorithm (http://daveti.blog.com/2011/04/21/diffiehellman-key-exchange-dh-algorithm-in-c/), we talked about 2 implementation using C. However, I’ve been thinking about one thing here these days – if there is any potential integer overflow risk in both functions (though for unsigned value, there is ‘over’ but no ‘flow’ indeed). Clearly, it would be perfect if a complete mathematic induction and deduction with formulas could be provided for D-H algorithm to find out the max value. But that is not the point here – we are going thru all the possible inputs given the certain ranges and rewrite a new dh4 function with better performance and integer overflow detection. We may need another post to talk about integer overflow with details. Anyway, check it out:)

/*
* dh4.c
* Example source file for D-H algorithm in key exchange
* Deeper into potential integer overflow detection
* Example fields: IPsec, MG<->MGC authentication
* Example usage: ./dh
* dhKey = g^a mod(p)
*      g – unsigned long, like 2-4294967295(0xffffffff)
*      a – unsigned int, like 2-65535(0xffff)
*      p – unsigned int, prime number, like 2-65535
* Destination: we will going thru all the possible values
* for g, a and p and try to figure out if there is potential
* integer overflow using dh2 implementation.
* Build cmd: gcc -o dh -lm dh.c
* 2011/04/28
* dave.tian@alcatel-lucent.com
*
http://daveti.blog.com
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/times.h>
#include <unistd.h>

unsigned long dh1( unsigned long, unsigned int, unsigned int);
unsigned long dh4( unsigned long, unsigned int, unsigned int);

int main( int argc, char **argv)
{
        // g: 2~0xffffffff
        // a: 2~0xffff
        // p: 2~0xffff
        // D-H algorithm: g^a mod(p);
        unsigned long gIdx = 0;
        unsigned int aIdx = 0;
        unsigned int pIdx = 0;
        unsigned int pRoot = 0;
        unsigned int pRootIdx = 0;
        unsigned long dhKey = 0;
        int isPrime = 0;

        // To accelerate the speed of the computation, it is good to
        // find out all the possible prime numbers and store them in
        // a array. Please note when the range of prime need to search
        // is very large (much larger than 0~0xffff in our case). Stack
        // size may not support this. Think about 2 ways here – either
        // static data area or link structure with malloc allocation.
        // daveti on 2011/04/28
        unsigned int primeArray[ 0xffff] = {0};
        unsigned int primeTotal = 0;
        unsigned int arrayIdx = 0;

        struct tms time_buf_head, time_buf_end;
        clock_t time_head, time_end;
        long tck = sysconf (_SC_CLK_TCK);
        time_head = times( &time_buf_head );
        // Find the prime numbers first and store them
        // Here we do not think 1 is a prime number!
        for ( pIdx = 2; pIdx <= 0xffff; pIdx++)
        {
                isPrime = 1;
                pRoot = (unsigned int)sqrt( pIdx);
                for ( pRootIdx = 2; pRootIdx <= pRoot; pRootIdx++)
                {
                        if ( pIdx%pRootIdx == 0)
                        {
                                // This is not a prime number!
                                isPrime = 0;
                                break;
                        }
                }
                if ( (isPrime == 1) && (arrayIdx < 0xffff))
                {
                        // This is a prime number. Store it!
                        primeArray[ arrayIdx] = pIdx;
                        primeTotal++;
                        arrayIdx++;
                }
        }
        time_end = times( &time_buf_end );
        printf("Prime searching: user time: %f, sys time: %f, child user time: %f, child sys time: %fn",
                ((time_buf_end.tms_utime – time_buf_head.tms_utime) / (double)tck),
                ((time_buf_end.tms_stime – time_buf_head.tms_stime) / (double)tck),
                ((time_buf_end.tms_cutime – time_buf_head.tms_cutime) / (double)tck),
                ((time_buf_end.tms_cstime – time_buf_head.tms_cstime) / (double)tck) );
        printf("Dump the first 10 prime numbers: ");
        for ( arrayIdx = 0; arrayIdx < 10; arrayIdx++)
        {
                printf("%u, ", primeArray[ arrayIdx]);
        }
        printf("nPrime found in total: %un", primeTotal);

        time_head = times( &time_buf_head );
        for ( gIdx = 2; gIdx <= 0xffffffff; gIdx++)
        {
                for ( aIdx = 2; aIdx <= 0xffff; aIdx++)
                {
                        for ( pIdx = 0; pIdx < primeTotal; pIdx++)
                        {
                                dhKey = dh4( gIdx, aIdx, primeArray[ pIdx]);
                        }
                }
        }
        time_end = times( &time_buf_end );

        printf("Loop: user time: %f, sys time: %f, child user time: %f, child sys time: %fn",
                ((time_buf_end.tms_utime – time_buf_head.tms_utime) / (double)tck),
                ((time_buf_end.tms_stime – time_buf_head.tms_stime) / (double)tck),
                ((time_buf_end.tms_cutime – time_buf_head.tms_cutime) / (double)tck),
                ((time_buf_end.tms_cstime – time_buf_head.tms_cstime) / (double)tck) );

        return 0;
}

unsigned long dh1( unsigned long g, unsigned int a, unsigned int p)
{
        // This is a recurssion version of D-H algorithm
        // implemented by daveti on 2011/04/20
        // Is there a way using C code to detect the potential
        // integer overflow here? I do not think so. Assembly
        // code may help here. Even if it does, the code is NOT
        // portable anymore – CPU architecture specified.
        // daveti on 2011/04/26

        if ( a == 0)
        {
                printf("Errorn");
                return 0;
        }

        if ( a == 1)
        {
                return g%p;
        }

        // (a*b)%c == ((a%c)*(b%c))%c
        return ((g%p)*(dh1( g, a-1, p)))%p;
}

unsigned long dh4( unsigned long g, unsigned int a, unsigned int p)
{
        // This is non-recurssion version of D-H algorithm
        // implemented by daveti on 2011/04/21
        // g^4%p = (g%p*((g%p*((g%p*(g%p))%p))%p))%p
        // let z = g%p
        // g^4%p = (z*((z*((z*z)%p))%p))%p
        //       = (((((z*z)%p)*z)%p)*z)%p
        // What about this function – any way to detect potential
        // integer overflow here? I think so:) Generally, we are
        // going back to the old question – how do we detect potential
        // integer overflow for ‘a+b’ and/or ‘a*b’…
        // daveti on 2011/04/26

        if ( a == 0)
        {
                printf("Errorn");
                return 0;
        }

        unsigned long z = g%p;
        // Check for possible zero value to fast the output
        // and to avoid floating exception during devision
        // computation in the overflow detection.
        // daveti on 2011/04/27
        if ( (a == 1) || (z == 0))
        {
                return z;
        }

        unsigned int idx = 0;
        unsigned long tmp = z;
        unsigned long overflow = 0;
        for ( idx = 2; idx <= a; idx++)
        {
                // tmp = (tmp*z)%p;
                // Add potential overflow detection for each loop
                // Isn’t this method clever:)
                overflow = tmp*z;
                if ( overflow/tmp != z)
                {
                        printf("Error: Integer overflow on ‘tmp*z’"
                                " – tmp=%lu, z=%lun", tmp, z);
                        return 0;
                }
                tmp = overflow%p;
        }

        return tmp;
}

About daveti

Interested in kernel hacking, compilers, machine learning and guitars.
This entry was posted in Programming and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s