DES.C


[View full width]

/////////////////////////////////////////////////////////////////////// // 3DES encryption example. // // Test bench for desktop (software) simulation. // // Copyright(c) 2003-2004 Impulse Accelerated Technologies, Inc. // // This implementation is based on public domain C source code by // P. Karn and is similar to the algorithm described in Part V of // Applied Cryptography by Bruce Schneier. // // When reading from a file, note that the C processes hold three copies // of the file's data in memory. #ifdef WIN32 #include <windows.h> #include <sys/types.h> #else // ! WIN32 #include <unistd.h> #endif #include <stdio.h> #include <sys/stat.h> #include "co.h" #include "co_math.h" #include "cosim_log.h" #include "des.h" #define VHDL_GEN 1 /* Generate VHDL config file for test bench */ #define DEFAULT_BLOCKS 100 /* Default number of blocks to encrypt */ extern co_architecture co_initialize(int blocks); // See des_hw.c void usage(char* ProgramName) { printf("USAGE: %s <# characters> (%d is default, 0 to read all characters in file; \ will be rounded up to nearest %i-character block)\n", ProgramName, DEFAULT_BLOCKS * DES_BLOCKSIZE, DES_BLOCKSIZE); } int parse_input_pars(int argc, char **argv) { int blocks = DEFAULT_BLOCKS; int characters; if ( argc == 2 ) { sscanf(argv[1], "%i", &characters); if ( characters >= 0 ) { blocks = characters / DES_BLOCKSIZE; if ( characters % DES_BLOCKSIZE ) { blocks++; } } else { usage(argv[0]); } } else if (argc != 1) { usage(argv[0]); } return blocks; } // Combined SP lookup table, linked in (see sp.c). // For best results, ensure that this is aligned on a 32-bit boundary; // Borland C++ 3.1 doesn't guarantee this! // extern unsigned long Spbox[SPBOX_X][SPBOX_Y]; /* Combined S and P boxes */ /* Keyschedules */ DES3_KS Ks_encrypt; DES3_KS Ks_decrypt; /* Block data for C processes */ unsigned char * PlaintextBlocks; unsigned char * EncryptedBlocks; unsigned char * DecryptedBlocks; unsigned long NumBlocks; void des_producer(co_stream config_out_encrypt, co_stream config_out_decrypt, co_stream blocks_out, co_signal encrypt_c, co_parameter blocks_param) { unsigned int blocks = (unsigned int)blocks_param; unsigned int i, k; unsigned char * key = (unsigned char *) "Gflk jqo40978J0dmm$%@878"; /* 24 bytes */ co_uint8 blockElement; cosim_logwindow log = cosim_logwindow_create("des_producer"); // Read plaintext from a file int plaintextChar,c; const char * plaintextFilename = "JohnDough.txt"; FILE * plaintextFile; struct stat plaintextFileStat; #ifdef VHDL_GEN // Generate VHDL package for test bench int cnt; FILE * fout; // test bench output file const char * testbenchFilename = "config_des.vhd"; fout = fopen(testbenchFilename, "w"); if ( fout == NULL ) { fprintf(stderr, "Error opening test bench output file %s\n", testbenchFilename); printf("\nPress the Enter key to continue.\n"); c = getc(stdin); exit(-1); } #endif plaintextFile = fopen(plaintextFilename, "r"); if ( plaintextFile == NULL ) { fprintf(stderr, "Error opening plaintext file %s\n", plaintextFilename); printf("\nPress the Enter key to continue.\n"); c = getc(stdin); exit(-1); } NumBlocks = blocks; if ( blocks == 0 ) { if ( fstat(fileno(plaintextFile), &plaintextFileStat) != 0 ) { fprintf(stderr, "Error reading size of plaintext file %s\n", plaintextFilename); printf("\nPress the Enter key to continue.\n"); c = getc(stdin); exit(-1); } NumBlocks = plaintextFileStat.st_size / DES_BLOCKSIZE; if ( plaintextFileStat.st_size % DES_BLOCKSIZE ) { NumBlocks++; } } // Allocate memory for the global arrays the C processes will use to get // at the block data. PlaintextBlocks = (unsigned char *) malloc(sizeof(unsigned char) * DES_BLOCKSIZE * NumBlocks); EncryptedBlocks = (unsigned char *) malloc(sizeof(unsigned char) * DES_BLOCKSIZE * NumBlocks); DecryptedBlocks = (unsigned char *) malloc(sizeof(unsigned char) * DES_BLOCKSIZE * NumBlocks); for ( i = 0; i < NumBlocks; i++ ) { for ( k = 0; k < DES_BLOCKSIZE; k++ ) { if ( (plaintextChar = getc(plaintextFile)) != EOF ) { blockElement = (co_uint8)plaintextChar; } else { blockElement = (co_uint8)'\0'; } PlaintextBlocks[(i * DES_BLOCKSIZE) + k] = (unsigned char)blockElement; } } // Generate the keyschedules for encryption and decryption des3key(Ks_encrypt, key, DES_ENCRYPT); des3key(Ks_decrypt, key, DES_DECRYPT); // Encrypt // We can start the C encryption process, since the block and keyschedule data has all // been written to memory. Decryption will be triggered by the encryption process when // it finishes. co_signal_post(encrypt_c, DES_ENCRYPT); #ifdef VHDL_GEN // See Tutorial #4 for information about VHDL test bench generation fprintf(fout,"-- Automatically generated file. See 3des.c for details.\n"); fprintf(fout,"-- See also tutorial #4 in the Impulse C User's Guide.\n"); fprintf(fout,"library ieee;\n"); fprintf(fout,"use ieee.std_logic_1164.all;\n"); fprintf(fout,"\npackage config is\n"); #endif // Send the keyschedule data co_stream_open(config_out_encrypt, O_WRONLY, UINT_TYPE(32)); #ifdef VHDL_GEN fprintf(fout," constant kscount : integer := 95;\n"); fprintf(fout," type ks is array (natural range <>) of std_ulogic_vector(31 downto 0);\n"); fprintf(fout," constant keyschedule : ks (0 to 95) := (\n"); cnt=0; #endif for ( k = 0; k < 2; k++ ) { for ( i = 0; i < DES_KS_DEPTH; i++ ) { #ifdef VHDL_GEN fprintf(fout," X\ "%08x\ "",Ks_encrypt[i][k]); if (cnt++ == 95) fprintf(fout,"\n"); else fprintf(fout,",\n"); #endif co_stream_write(config_out_encrypt, &Ks_encrypt[i][k], sizeof(unsigned long)); } } #ifdef VHDL_GEN fprintf(fout," );\n"); fprintf(fout," constant spcount : integer := 512;\n"); fprintf(fout," type sp is array (natural range <>) of std_ulogic_vector(31 downto 0);\n"); fprintf(fout," constant spboxes : sp (0 to 511) := (\n"); cnt=0; #endif for ( i = 0; i < SPBOX_X; i++ ) { for ( k = 0; k < SPBOX_Y; k++ ) { #ifdef VHDL_GEN fprintf(fout," X\ "%08x\ "",Spbox[i][k]); if (cnt++ == 511) fprintf(fout,"\n"); else fprintf(fout,",\n"); #endif co_stream_write(config_out_encrypt, &Spbox[i][k], sizeof(unsigned long)); } } co_stream_close(config_out_encrypt); // Decrypt // Send the keyschedule data co_stream_open(config_out_decrypt, O_WRONLY, UINT_TYPE(32)); for ( k = 0; k < 2; k++ ) { for ( i = 0; i < DES_KS_DEPTH; i++ ) { co_stream_write(config_out_decrypt, &Ks_decrypt[i][k], sizeof(unsigned long)); } } for ( i = 0; i < SPBOX_X; i++ ) { for ( k = 0; k < SPBOX_Y; k++ ) { co_stream_write(config_out_decrypt, &Spbox[i][k], sizeof(unsigned long)); } } co_stream_close(config_out_decrypt); // Send the plaintext block data to the Impulse C encryption process co_stream_open(blocks_out, O_WRONLY, UINT_TYPE(8)); #ifdef VHDL_GEN fprintf(fout," );\n"); fprintf(fout,"end package;\n"); #endif cosim_logwindow_write(log, "Sending plaintext...\n\n"); for ( i = 0; i < NumBlocks; i++ ) { for ( k = 0; k < DES_BLOCKSIZE; k++ ) { blockElement = PlaintextBlocks[(i * DES_BLOCKSIZE) + k]; co_stream_write(blocks_out, &blockElement, sizeof(blockElement)); } } cosim_logwindow_write(log, "\n\nDone sending plaintext.\n"); co_stream_close(blocks_out); } // Primitive function F. // Input is r, subkey array in keys, output is XORed into l. // Each round consumes eight 6-bit subkeys, one for // each of the 8 S-boxes, 2 longs for each round. // Each long contains four 6-bit subkeys, each taking up a byte. // The first long contains, from high to low end, the subkeys for // S-boxes 1, 3, 5 & 7; the second contains the subkeys for S-boxes // 2, 4, 6 & 8 (using the origin-1 S-box numbering in the standard, // not the origin-0 numbering used elsewhere in this code) // See comments elsewhere about the pre-rotated values of r and Spbox. // #define F(l,r,key){\ work = ((r >> 4) | (r << 28)) ^ key[0];\ l ^= Spbox[6][work & 0x3f];\ l ^= Spbox[4][(work >> 8) & 0x3f];\ l ^= Spbox[2][(work >> 16) & 0x3f];\ l ^= Spbox[0][(work >> 24) & 0x3f];\ work = r ^ key[1];\ l ^= Spbox[7][work & 0x3f];\ l ^= Spbox[5][(work >> 8) & 0x3f];\ l ^= Spbox[3][(work >> 16) & 0x3f];\ l ^= Spbox[1][(work >> 24) & 0x3f];\ } // This is the plain C 3DES process. It reads the keyschedule and block // inputs from global variables initialized in the des_producer process // and does all processing using standard C code. // // An Impulse C signal is used to notify the process of which task (encrypt or // decrypt) to start. Another signal, sent after the task is completed, notifies // the listener of which task it should start. cosim_logwindow functions are // used to display input and output for comparison with the des_ic processes. // Otherwise, this function is plain C. // void des_c(co_signal task_signal, co_signal next_task_signal) { int i; unsigned int blockCount = 0; unsigned char block[8]; unsigned long left,right,work; co_int32 task; DES3_KS * ks; unsigned char * inputBlocks; unsigned char * outputBlocks; IF_SIM( cosim_logwindow log; ) co_signal_wait(task_signal, &task); if (task == DES_ENCRYPT ) { IF_SIM ( log = cosim_logwindow_create("des_c encrypt"); ) ks = &Ks_encrypt; inputBlocks = PlaintextBlocks; outputBlocks = EncryptedBlocks; } else if ( task == DES_DECRYPT ) { IF_SIM ( log = cosim_logwindow_create("des_c decrypt"); ) ks = &Ks_decrypt; inputBlocks = EncryptedBlocks; outputBlocks = DecryptedBlocks; } else { // Don't know what to do, so just exit. return; } IF_SIM( cosim_logwindow_write(log, "3DES [C] processing blocks...\n"); ) while ( blockCount < NumBlocks ) { for ( i = 0; i < DES_BLOCKSIZE; i++ ) { block[i] = inputBlocks[(blockCount * DES_BLOCKSIZE) + i]; } // Process the block... // Read input block and place in left/right in big-endian order // left = ((unsigned long)block[0] << 24) |((unsigned long)block[1] << 16) | ((unsigned long)block[2] << 8) | (unsigned long)block[3]; right = ((unsigned long)block[4] << 24) | ((unsigned long)block[5] << 16) | ((unsigned long)block[6] << 8) | (unsigned long)block[7]; // Hoey's clever initial permutation algorithm, from Outerbridge // (see Schneier p 478) // // The convention here is the same as Outerbridge: rotate each // register left by 1 bit, i.e., so that "left" contains permuted // input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32 // (using origin-1 numbering as in the FIPS). This allows us to avoid // one of the two rotates that would otherwise be required in each of // the 16 rounds. // work = ((left >> 4) ^ right) & 0x0f0f0f0f; right ^= work; left ^= work << 4; work = ((left >> 16) ^ right) & 0xffff; right ^= work; left ^= work << 16; work = ((right >> 2) ^ left) & 0x33333333; left ^= work; right ^= (work << 2); work = ((right >> 8) ^ left) & 0xff00ff; left ^= work; right ^= (work << 8); right = (right << 1) | (right >> 31); work = (left ^ right) & 0xaaaaaaaa; left ^= work; right ^= work; left = (left << 1) | (left >> 31); /* First key */ F(left,right,(*ks)[0]); F(right,left,(*ks)[1]); F(left,right,(*ks)[2]); F(right,left,(*ks)[3]); F(left,right,(*ks)[4]); F(right,left,(*ks)[5]); F(left,right,(*ks)[6]); F(right,left,(*ks)[7]); F(left,right,(*ks)[8]); F(right,left,(*ks)[9]); F(left,right,(*ks)[10]); F(right,left,(*ks)[11]); F(left,right,(*ks)[12]); F(right,left,(*ks)[13]); F(left,right,(*ks)[14]); F(right,left,(*ks)[15]); /* Second key (must be created in opposite mode to first key) */ F(right,left,(*ks)[16]); F(left,right,(*ks)[17]); F(right,left,(*ks)[18]); F(left,right,(*ks)[19]); F(right,left,(*ks)[20]); F(left,right,(*ks)[21]); F(right,left,(*ks)[22]); F(left,right,(*ks)[23]); F(right,left,(*ks)[24]); F(left,right,(*ks)[25]); F(right,left,(*ks)[26]); F(left,right,(*ks)[27]); F(right,left,(*ks)[28]); F(left,right,(*ks)[29]); F(right,left,(*ks)[30]); F(left,right,(*ks)[31]); /* Third key */ F(left,right,(*ks)[32]); F(right,left,(*ks)[33]); F(left,right,(*ks)[34]); F(right,left,(*ks)[35]); F(left,right,(*ks)[36]); F(right,left,(*ks)[37]); F(left,right,(*ks)[38]); F(right,left,(*ks)[39]); F(left,right,(*ks)[40]); F(right,left,(*ks)[41]); F(left,right,(*ks)[42]); F(right,left,(*ks)[43]); F(left,right,(*ks)[44]); F(right,left,(*ks)[45]); F(left,right,(*ks)[46]); F(right,left,(*ks)[47]); /* Inverse permutation, also from Hoey via Outerbridge and Schneier */ right = (right << 31) | (right >> 1); work = (left ^ right) & 0xaaaaaaaa; left ^= work; right ^= work; left = (left >> 1) | (left << 31); work = ((left >> 8) ^ right) & 0xff00ff; right ^= work; left ^= work << 8; work = ((left >> 2) ^ right) & 0x33333333; right ^= work; left ^= work << 2; work = ((right >> 16) ^ left) & 0xffff; left ^= work; right ^= work << 16; work = ((right >> 4) ^ left) & 0x0f0f0f0f; left ^= work; right ^= work << 4; /* Put the block into the output stream with final swap */ block[0] = (co_int8) (right >> 24); block[1] = (co_int8) (right >> 16); block[2] = (co_int8) (right >> 8); block[3] = (co_int8) right; block[4] = (co_int8) (left >> 24); block[5] = (co_int8) (left >> 16); block[6] = (co_int8) (left >> 8); block[7] = (co_int8) left; for ( i = 0; i < DES_BLOCKSIZE; i++ ) { outputBlocks[(blockCount * DES_BLOCKSIZE) + i] = block[i]; } ++blockCount; } IF_SIM( cosim_logwindow_write(log, "3DES [C] done processing!\n"); ) if ( task == DES_ENCRYPT ) { co_signal_post(next_task_signal, DES_DECRYPT); } else { co_signal_post(next_task_signal, DES_ENCRYPT); } } void des_consumer(co_stream ic_decrypted_blocks, co_signal decrypt_finished) { uint8 icData; int i = 0; int nonMatchingBlockData = 0, nonMatchingPlaintextData = 0, failure = 0; cosim_logwindow log = cosim_logwindow_create("des_consumer"); co_signal_wait(decrypt_finished, NULL); co_stream_open(ic_decrypted_blocks, O_RDONLY, UINT_TYPE(8)); cosim_logwindow_write(log, "Consumer comparing decrypted data...\n"); while ( co_stream_read(ic_decrypted_blocks, &icData, sizeof(uint8)) == co_err_none ) { printf("%c", (unsigned char)DecryptedBlocks[i]); if ( icData != DecryptedBlocks[i] ) { nonMatchingBlockData++; } if ( icData != PlaintextBlocks[i] ) { nonMatchingPlaintextData++; } if ( DecryptedBlocks[i] != PlaintextBlocks[i] ) { nonMatchingPlaintextData++; } i++; } co_stream_close(ic_decrypted_blocks); if ( nonMatchingBlockData > 0 ) { cosim_logwindow_fwrite(log, "\nFailure! Decrypted output of Impulse C and C \ implementations doesn't match: %i differences", nonMatchingBlockData); printf("\n\nFailure! Decrypted outputs of Impulse C and C implementations do \ not match: %i differences", nonMatchingBlockData); failure = 1; } if ( nonMatchingPlaintextData > 0 ) { cosim_logwindow_fwrite(log, "\nFailure! Decrypted output doesn't match plaintext \ output: %i differences", nonMatchingPlaintextData); printf("\n\nFailure! Decrypted output doesn't match plaintext output: %i differences", nonMatchingPlaintextData); failure = 1; } if ( failure != 1 ) { cosim_logwindow_write(log, "\nSuccess! Decrypted output of Impulse C and C \ implementations is the same and matches the plaintext!"); printf("\n\nSuccess! Decrypted output of Impulse C and C implementations is the \ same and matches the plaintext (%i characters)!", i); } free(DecryptedBlocks); free(EncryptedBlocks); free(PlaintextBlocks); } int main(int argc, char *argv[]) { co_architecture my_arch; int c; int blocks = parse_input_pars(argc, argv); printf("Impulse C is Copyright 2003 Impulse Accelerated Technologies, Inc.\n"); my_arch = co_initialize(blocks); // See des_hw.c co_execute(my_arch); printf("\n\nApplication complete. Press the Enter key to continue.\n"); c = getc(stdin); return(0); }



    Practical FPGA Programming in C
    Practical FPGA Programming in C
    ISBN: 0131543180
    EAN: 2147483647
    Year: 2005
    Pages: 208

    Similar book on Amazon

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net