#include #include #include #include #include #include #include #include "nmglobal.h" #include "randnum.h" /******************** ** IDEA Encryption ** ********************* ** IDEA - International Data Encryption Algorithm. ** Based on code presented in Applied Cryptography by Bruce Schneier. ** Which was based on code developed by Xuejia Lai and James L. Massey. ** Other modifications made by Colin Plumb. ** */ /* ** DEFINES */ #define IDEAKEYSIZE 16 #define IDEABLOCKSIZE 8 #define ROUNDS 8 #define KEYLEN (6*ROUNDS+4) /* ** MACROS */ #define low16(x) ((x) & 0x0FFFF) #define MUL(x,y) (x=mul(low16(x),y)) typedef uint16_t IDEAkey[KEYLEN]; /* ** PROTOTYPES */ static clock_t DoIDEAIteration(unsigned char *plain1, unsigned char *crypt1, unsigned char *plain2, unsigned long arraysize, unsigned long nloops, IDEAkey Z, IDEAkey DK); static uint16_t mul(register uint16_t a, register uint16_t b); static uint16_t inv(uint16_t x); static void en_key_idea(uint16_t userkey[8], IDEAkey Z); static void de_key_idea(IDEAkey Z, IDEAkey DK); static void cipher_idea(uint16_t in[4], uint16_t out[4], IDEAkey Z); /*********** ** DoIDEA ** ************ ** Perform IDEA encryption. Note that we time encryption & decryption ** time as being a single loop. */ void DoIDEA(void) { const char *context = "CPU:IDEA"; IDEAStruct *locideastruct=&global_ideastruct; /* Loc pointer to global structure */ clock_t total_time = 0; int iterations = 0; unsigned char *plain1 = NULL; /* First plaintext buffer */ unsigned char *crypt1 = NULL; /* Encryption buffer */ unsigned char *plain2 = NULL; /* Second plaintext buffer */ IDEAkey Z,DK; uint16_t userkey[8]; int i; /* ** Re-init random-number generator. */ randnum(3); /* ** Build an encryption/decryption key */ for ( i = 0; i < 8; i++) { userkey[i] = (uint16_t)(abs_randwc((int32_t)60000) & 0xFFFF); } for(i = 0; i < KEYLEN ; i++) { Z[i] = 0; } /* ** Compute encryption/decryption subkeys */ en_key_idea(userkey,Z); de_key_idea(Z,DK); /* ** Allocate memory for buffers. We'll make 3, called plain1, ** crypt1, and plain2. It works like this: ** plain1 >>encrypt>> crypt1 >>decrypt>> plain2. ** So, plain1 and plain2 should match. ** Also, fill up plain1 with sample text. */ plain1 = malloc(locideastruct->arraysize); if (!plain1) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); exit(1); } crypt1 = malloc(locideastruct->arraysize); if (!crypt1) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); free(plain1); exit(1); } plain2 = malloc(locideastruct->arraysize); if (!plain2) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); free(plain1); free(plain2); exit(1); } /* ** Note that we build the "plaintext" by simply loading ** the array up with random numbers. */ for (i = 0;i < locideastruct->arraysize; i++) { plain1[i] = (unsigned char)(abs_randwc(255) & 0xFF); } /* ** See if we need to perform self adjustment loop. */ if (locideastruct->adjust == FALSE) { locideastruct->adjust = TRUE; /* ** Do self-adjustment. This involves initializing the ** # of loops and increasing the loop count until we ** get a number of loops that we can use. */ for (locideastruct->loops = 100; locideastruct->loops < MAXIDEALOOPS; locideastruct->loops += 10) { if (DoIDEAIteration(plain1, crypt1, plain2, locideastruct->arraysize, locideastruct->loops, Z, DK) > global_min_ticks) { break; } } } /* ** All's well if we get here. Do the test. */ do { total_time += DoIDEAIteration(plain1, crypt1, plain2, locideastruct->arraysize, locideastruct->loops, Z, DK); iterations += locideastruct->loops; } while (total_time < locideastruct->request_secs * CLOCKS_PER_SEC); free(plain1); free(crypt1); free(plain2); locideastruct->iterspersec = (double)(iterations * CLOCKS_PER_SEC) / (double)total_time; } /******************** ** DoIDEAIteration ** ********************* ** Execute a single iteration of the IDEA encryption algorithm. ** Actually, a single iteration is one encryption and one ** decryption. */ static clock_t DoIDEAIteration(unsigned char *plain1, unsigned char *crypt1, unsigned char *plain2, unsigned long arraysize, unsigned long nloops, IDEAkey Z, IDEAkey DK) { clock_t start, stop; register unsigned long i; register unsigned long j; start = clock(); for (i = 0; i < nloops; i++) { for (j = 0; j < arraysize; j += sizeof(uint16_t) * 4) { cipher_idea((uint16_t *)(plain1 + j), (uint16_t *)(crypt1 + j), Z); /* Encrypt */ } } for (j = 0; j < arraysize; j += sizeof(uint16_t) * 4) { cipher_idea((uint16_t *)(crypt1 + j), (uint16_t *)(plain2 + j), DK); /* Decrypt */ } stop = clock(); return stop - start; } /******** ** mul ** ********* ** Performs multiplication, modulo (2**16)+1. This code is structured ** on the assumption that untaken branches are cheaper than taken ** branches, and that the compiler doesn't schedule branches. */ static uint16_t mul(register uint16_t a, register uint16_t b) { register uint32_t p; if(a) { if(b) { p=(uint32_t)(a*b); b=low16(p); a=(uint16_t)(p>>16); return(b-a+(b> 7); Z+=i&8; i&=7; } return; } /**************** ** de_key_idea ** ***************** ** Compute IDEA decryption subkeys DK from encryption ** subkeys Z. */ static void de_key_idea(IDEAkey Z, IDEAkey DK) { IDEAkey TT; int j; uint16_t t1, t2, t3; uint16_t *p; p=(uint16_t *)(TT+KEYLEN); t1=inv(*Z++); t2=-*Z++; t3=-*Z++; *--p=inv(*Z++); *--p=t3; *--p=t2; *--p=t1; for(j=1;j