Code:
' RC6 algorithm, AES finalist. ' I corrected f_rnd and i_rnd macro multiply overflows and significantly optimized ' this RC6 algorithm that was ported to PB from "C" by Aleksandr Dobrev, with testbed ' code by Mike Trader. ' My laptop averages 33 ticks/byte encoding, 53 ticks/byte decoding. ' This demo will encode, decode and verify all files included on a list of files ' stored in c:\fListCrypt.txt--one file per record--and display statistics after ' each file. Individual files can be tested also. ' Discussion here: [URL="http://www.powerbasic.com/support/pbforums/showthread.php?t=35257"]http://www.powerbasic.com/support/pbforums/showthread.php?t=35257[/URL] ' John Gleason, Oct. 22, 07. ' Addendum Nov. 7, 2007. Added a big RC6 monotonic timer secure random # generator & test vector code, ' fixed bugs so test vectors match, optimized encoding further, and wrote easier to use demo code. ' I did see Aleksandr posted his similar code he'd worked on for a couple hours, but since this code I ' worked on for TWO WEEKS, and I did promise I'd post it, I figured it's time to deliver even if the thunder has died. ' ==================================================================================== ' In cryptography, RC6 is a symmetric key block cipher derived from RC5. ' It was designed by Ron Rivest, Matt Robshaw, Ray Sidney, and Yiqun Lisa Yin ' to meet the requirements of the Advanced Encryption Standard (AES) competition. ' ' The algorithm was one of the five finalists, and was also submitted to the NESSIE ' and CRYPTREC projects. It is a proprietary algorithm, patented by RSA Security. ' ' RC6 proper has a block size of 128 bits and supports key sizes of 128, 192 and 256 bits, ' but, like RC5, it can be parameterised to support a wide variety of word-lengths, ' key sizes and number of rounds. RC6 is very similar to RC5 in structure, ' using data-dependent rotations, modular addition and XOR operations; in fact, ' RC6 could be viewed as interweaving two parallel RC5 encryption processes. ' ' However, RC6 does use an extra multiplication operation not present in RC5 in ' order to make the rotation dependent on every bit in a word, and not just the ' least significant few bits. ' ' ' As RC6 has not been selected for the AES, it is not guaranteed that RC6 ' is royalty-free. As of January 2007, a web page on the official web site ' of the designers of RC6, RSA Laboratories, states the following: ' "We emphasize that if RC6 is selected for the AES, RSA Security will ' not require any licensing or royalty payments for products using the algorithm". ' The emphasis on the word "if" suggests that RSA Security Inc. may now require ' licensing and royalty payments for any products using the RC6 algorithm. ' RC6 is a patented encryption algorithm ' RC6, an encryption algorithm designed by Ron Rivest (RSA Labs) and submitted as a candidate algorithm for the ' Advanced Encryption Standard programme of the US National Institute of Standards and Technology." ' Ported to PB from "C" by Aleksandr Dobrev - Thanks to wonsky Lu for provide source on C ' Ver. 0.0.1 December 03, 2006 ' Padding and testbed Mike Trader 2007 #COMPILE EXE #DIM ALL #REGISTER NONE #INCLUDE "win32api.inc" %ROUNDS = 20 ' Utility macros MACRO zbs(xx) = STRING$(xx, 0) MACRO FUNCTION rotr(x,n) MACROTEMP s LOCAL s AS DWORD s = (x) ROTATE RIGHT s,n END MACRO = s '#define rotl(x,n) (((x) << ((INT)((n) & 0x1f))) | ((x) >> ((INT)((32 - ((n) & 0x1f)))))) MACRO FUNCTION rotl(x,n) MACROTEMP s LOCAL s AS DWORD s = (x) ROTATE LEFT s,n END MACRO = s '--------------------------------added 2 macros MACRO rotr2(x,n) MACROTEMP s LOCAL s AS DWORD s = x !mov eax, s !mov ecx, n !ror eax, cl END MACRO MACRO rotl2(x,n) !mov ecx, n !mov eax, x !rol eax, cl END MACRO '----------------------------end added 2 macros ' GET a 32 BIT WORD (v) IN machine order FROM a BYTE address IN (x) MACRO FUNCTION u4byte_in(x) MACROTEMP pdwZmacro DIM pdwZmacro AS DWORD PTR pdwZmacro = (x) END MACRO = @pdwZmacro MACRO f_rnd(i,a,b,c,d) 'changed 2 macros------------------------ MACROTEMP u,t LOCAL u, t AS LONG !mov ecx, d !lea eax, [ecx+ecx+1] !mul ecx !rol eax, 5 !mov u, eax !mov ecx, b !lea eax, [ecx+ecx+1] !mul ecx !rol eax, 5 !mov t, eax !xor eax, a !mov ecx, u !rol eax, cl !mov edx, keyPtr !mov ecx, i !add eax, [edx+ecx*4] !mov a, eax ;a = a + RC6Key(i) !mov eax, c !xor eax, u !mov ecx, t !rol eax, cl !mov ecx, i !add ecx, 1 !add eax, [edx+ecx*4] !mov c, eax ;c = c + RC6Key(i + 1) END MACRO MACRO i_rnd(i,a,b,c,d) MACROTEMP u,t,d2,b2 LOCAL u, t, d2, b2 AS DWORD !mov eax, d !mov ecx, d !add eax, eax !add eax, 1 !mul ecx !mov d2, eax rotl2(d2, 5) 'rotl2(d * (d + d + 1), 5) !mov u, eax !mov eax, b !mov ecx, b !add eax, eax !add eax, 1 !mul ecx !mov b2, eax rotl2(b2, 5) 'rotl2(b * (b + b + 1), 5) !mov t, eax rotr2(c - RC6Key(i + 1), t) !xor eax, u !mov c, eax rotr2(a - RC6Key(i), u) !xor eax, t !mov a, eax END MACRO 'end change------------------------------ 'MACRO f_rnd(i,a,b,c,d) 'this is what the above asm does... (but correctly with no undefined overflow) ' MACROTEMP u,t ' DIM u AS DWORD,t AS DWORD ' u = rotl(d * (d + d + 1), 5) ' t = rotl(b * (b + b + 1), 5) ' a = rotl(a XOR t, u) + RC6Key(i) ' c = rotl(c XOR u, t) + RC6Key(i + 1) 'END MACRO ' ' 'MACRO i_rnd(i,a,b,c,d) ' MACROTEMP u,t ' DIM u AS DWORD,t AS DWORD ' u = rotl(d * (d + d + 1), 5) ' t = rotl(b * (b + b + 1), 5) ' c = rotr(c - RC6Key(i + 1), t) XOR u ' a = rotr(a - RC6Key(i), u) XOR t 'END MACRO UNION ConvertTwoByteTYPE ' Converts a Two Byte Value str AS STRING * 02 igr AS INTEGER wrd AS WORD byt(1 TO 2) AS BYTE END UNION GLOBAL CvtTwoByte AS ConvertTwoByteTYPE '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤' SUB time_stamp_count(tick AS QUAD) ' CPU Clock count Charles E V Pegge '---------------------------' ' ' approx because it is not a serialised instruction ' ' it may execute before or after other instructions ' ' in the pipeline. ! mov ebx,tick ' var address where count is to be stored. ! db &h0f,&h31 ' RDTSC read time-stamp counter into edx:eax hi lo. ! mov [ebx],eax ' save low order 4 bytes. ! mov [ebx+4],edx ' save high order 4 bytes. '---------------------------' END SUB '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION StrToHex( sBin AS STRING ) AS STRING REGISTER i AS LONG, j AS LONG LOCAL a, b AS BYTE PTR LOCAL sHex AS STRING sHex = STRING$( LEN(sBin)*2, " " ) ' make a string the right size a = STRPTR(sHex) b = STRPTR(sBin) j = 0 FOR i = 0 TO LEN(sBin)-1 CvtTwoByte.str = HEX$(@b[i],2) ' NO String concatenation @a[j] = CvtTwoByte.byt(1) INCR j @a[j] = CvtTwoByte.byt(2) INCR j NEXT i FUNCTION = sHex ' return string END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤' ' initialise the key schedule FROM the USER supplied key SUB RC6_set_key( UserKey() AS BYTE, BYVAL key_len AS DWORD, RC6Key() AS DWORD ) LOCAL i, j, k, a, b, t AS DWORD DIM l(7) AS DWORD ' REDIM RC6Key(43) ' STATIC u4byte RC6(l_key[44]); RC6Key(0) = &Hb7e15163??? LOCAL pdwUserKey AS DWORD PTR pdwUserKey = VARPTR(UserKey(0)) k = 1 WHILE k < 44 RC6Key(k) = RC6Key(k - 1) + &H9e3779b9??? INCR k WEND IF key_len > 32 THEN key_len = 32 IF (key_len AND 3) <> 0 THEN key_len = key_len - (key_len AND 3) + 4 END IF k = 0 WHILE k < key_len \ 4 l(k) = u4byte_in(pdwUserKey + (4 * k)) INCR k WEND t = (key_len \ 4) - 1 a = 0: b = 0: i = 0: j = 0 k = 0 WHILE k < 132 a = rotl(RC6Key(i) + a + b, 3): b = b+a b = rotl(l(j) + b, b) RC6Key(i) = a : l(j) = b i = IIF(i = 43, 0, i + 1) ' i = (i + 1) % 44; j = IIF(j = t , 0, j + 1) ' j = (j + 1) % t; INCR k WEND END SUB '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤' MACRO mRC6_monotonicEncrypt(pdw_OutBlk)'RC6 encrypt a ~60 yr "monotonic" counter--won't ever repeat for 60 years. And even 'after 60 years, the odds of a 16-byte sequence repeating are > 10^18. This assumes 'your clock speed = 5GHz. If your computer is 2.5GHz, the counter won't ever repeat 'for 120 years, 1.25GHz doesn't risk repeating for 240 years and so on. What about 'Moore's law tho, if clock speeds increase to 5 PetaHz? By then the time stamp counter 'will be 128 or 256 bits AT LEAST, making the monotonic counter good for way longer '(at 5 PHz) than even the most optimistic estimate of the lifespan of the UNIVERSE. 'Be sure to make the equate %CLOCKSPEED a little larger than your actual processor 'speed to be sure there will never be any possible overlap. Realistically tho, 'even if you ignored this directive and got non-monotonic timer overlap, you'd still 'have over a billion billion to one chance of getting a duplicate round. What is 'the 60 yr. limitation workaround? Well, every 60 years or so, reset the password. 'See ya around 2068, maybe on Europa! :D MACROTEMP a,b,c,d,initComplete LOCAL a,b,c,d AS DWORD '---------------------------------------------------------------------------------- !cmp a, 0 ;this little section does the following: !ja short initComplete ;IF a, b, c, and d are not initialized--that is, all are zero--THEN !cmp b, 0 ;initialize them with initVector by direct copy. !ja short initComplete !cmp c, 0 !ja short initComplete !cmp d, 0 !ja short initComplete !lea esi, initVector !mov eax, [esi+00] !mov ebx, [esi+04] !mov ecx, [esi+08] !mov edx, [esi+12] !mov a, eax !mov b, ebx !mov c, ecx !mov d, edx '---------------------------------------------------------------------------------- initComplete: !db &h0f,&h31 ;read time stamp ctr !xor esi, esi !mov edi, keyPtr !mov ebx, ticksSinceJan1st2007 ;low dword of sys time !mov ecx, ticksSinceJan1st2007[4] ; hi " " !add eax, ebx ;add total since Jan. 1, 2007 to current day clock ticks !adc edx, ecx ;add total since Jan. 1, 2007 to current day clock ticks !xor eax, a ;previous round a !mov a, eax ;lo save to a !add eax, [edi+00] ;add key(0) !xor eax, b ;previous round b !mov b, eax ;save b !xor edx, c ;previous round c !mov c, edx ;hi save to c !add edx, [edi+04] ;key(1) !xor edx, d ;previous round d !mov d, edx ;save to d f_rnd( 2,a,b,c,d): f_rnd( 4,b,c,d,a) f_rnd( 6,c,d,a,b): f_rnd( 8,d,a,b,c) f_rnd(10,a,b,c,d): f_rnd(12,b,c,d,a) f_rnd(14,c,d,a,b): f_rnd(16,d,a,b,c) f_rnd(18,a,b,c,d): f_rnd(20,b,c,d,a) f_rnd(22,c,d,a,b): f_rnd(24,d,a,b,c) f_rnd(26,a,b,c,d): f_rnd(28,b,c,d,a) f_rnd(30,c,d,a,b): f_rnd(32,d,a,b,c) f_rnd(34,a,b,c,d): f_rnd(36,b,c,d,a) f_rnd(38,c,d,a,b): f_rnd(40,d,a,b,c) !mov esi, pdw_OutBlk !mov edi, keyPtr !mov eax, a !mov ebx, b !mov ecx, c !mov edx, d !add eax, [edi+168] !add ecx, [edi+172] !mov [esi+00], eax !mov [esi+04], ebx !mov [esi+08], ecx !mov [esi+12], edx ' END MACRO '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤' MACRO mRC6_EnCrypt(pdw_InBlk, pdw_OutBlk) ' encrypt a 16byte block OF TEXT MACROTEMP a,b,c,d LOCAL a,b,c,d AS DWORD !mov esi, pdw_InBlk !mov edi, keyPtr !mov eax, [esi+00] !mov ebx, [esi+04] !mov ecx, [esi+08] !mov edx, [esi+12] !add ebx, [edi+00] !add edx, [edi+04] !mov a, eax !mov b, ebx !mov c, ecx !mov d, edx ' above asm does this: ' a = u4byte_in(pdw_InBlk ) ' b = u4byte_in(pdw_InBlk + 4) + RC6Key(0) ' c = u4byte_in(pdw_InBlk + 8) ' d = u4byte_in(pdw_InBlk + 12) + RC6Key(1) f_rnd( 2,a,b,c,d): f_rnd( 4,b,c,d,a) f_rnd( 6,c,d,a,b): f_rnd( 8,d,a,b,c) f_rnd(10,a,b,c,d): f_rnd(12,b,c,d,a) f_rnd(14,c,d,a,b): f_rnd(16,d,a,b,c) f_rnd(18,a,b,c,d): f_rnd(20,b,c,d,a) f_rnd(22,c,d,a,b): f_rnd(24,d,a,b,c) f_rnd(26,a,b,c,d): f_rnd(28,b,c,d,a) f_rnd(30,c,d,a,b): f_rnd(32,d,a,b,c) f_rnd(34,a,b,c,d): f_rnd(36,b,c,d,a) f_rnd(38,c,d,a,b): f_rnd(40,d,a,b,c) ' below asm does this: ' u4byte_out(pdw_OutBlk, a + RC6Key(42)) ' u4byte_out(pdw_OutBlk + 4, b) ' u4byte_out(pdw_OutBlk + 8, c + RC6Key(43)) ' u4byte_out(pdw_OutBlk + 12, d) !mov esi, pdw_OutBlk !mov edi, keyPtr !mov eax, a !mov ebx, b !mov ecx, c !mov edx, d !add eax, [edi+168] !add ecx, [edi+172] !mov [esi+00], eax !mov [esi+04], ebx !mov [esi+08], ecx !mov [esi+12], edx ' END MACRO '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤' MACRO mRC6_DeCrypt(pdw_InBlk, pdw_OutBlk) ' decrypt a 16byte block OF TEXT MACROTEMP a,b,c,d LOCAL a,b,c,d AS DWORD !mov esi, pdw_InBlk !mov edi, keyPtr !mov eax, [esi+00] !mov ebx, [esi+04] !mov ecx, [esi+08] !mov edx, [esi+12] !sub ecx, [edi+172] !sub eax, [edi+168] !mov a, eax !mov b, ebx !mov c, ecx !mov d, edx 'above asm does this: 'd = u4byte_in(pdw_InBlk + 12): c = u4byte_in(pdw_InBlk + 8) - RC6Key(43) 'b = u4byte_in(pdw_InBlk + 4): a = u4byte_in(pdw_InBlk ) - RC6Key(42) i_rnd(40,d,a,b,c): i_rnd(38,c,d,a,b) i_rnd(36,b,c,d,a): i_rnd(34,a,b,c,d) i_rnd(32,d,a,b,c): i_rnd(30,c,d,a,b) i_rnd(28,b,c,d,a): i_rnd(26,a,b,c,d) i_rnd(24,d,a,b,c): i_rnd(22,c,d,a,b) i_rnd(20,b,c,d,a): i_rnd(18,a,b,c,d) i_rnd(16,d,a,b,c): i_rnd(14,c,d,a,b) i_rnd(12,b,c,d,a): i_rnd(10,a,b,c,d) i_rnd( 8,d,a,b,c): i_rnd( 6,c,d,a,b) i_rnd( 4,b,c,d,a): i_rnd( 2,a,b,c,d) 'below asm does this: 'u4byte_out(pdw_OutBlk + 12, d - RC6Key(1)) : u4byte_out(pdw_OutBlk + 8, c) 'u4byte_out(pdw_OutBlk + 4, b - RC6Key(0)) : u4byte_out(pdw_OutBlk, a) !mov esi, pdw_OutBlk !mov edi, keyPtr !mov eax, a !mov ebx, b !mov ecx, c !mov edx, d !sub ebx, [edi+00] !sub edx, [edi+04] !mov [esi+00], eax !mov [esi+04], ebx !mov [esi+08], ecx !mov [esi+12], edx END MACRO '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤' TYPE QUADTIME ftQuad AS QUAD 'fileTime as a quad END TYPE '------------------------------These two equates are for the cryptographically secure monotonic random generator %CLOCKSPEED = 2000000000 'Hz 'Enter your CPU speed. Round UP to the next nearest 10 million ticks to assure no possible 'monotonic timer overlap for the next 60 to 100+ years, depending on CPU speed. %CLOCKSPEEDADJ= %CLOCKSPEED \ 10000000 '--------------------------------------------------------------------------------------------------------------- %DOTESTVECTORS = 0 'set to 1 or other non-zero to run test vector values to see if algorithm is correct '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤' FUNCTION PBMAIN() AS LONG DIM RC6Key(43) AS STATIC DWORD DIM plaintext(5) AS STRING, UserKey2(5) AS STRING, ciphertext(5) AS STRING LOCAL KeyLen, SrcLen, encryptFiles, generateRnds, rndCount, keyPtr AS LONG LOCAL initVector AS STRING * 16 LOCAL sKey, sFile, bsFile, sCipher, t, sFileName, ciphertext1, ciphertext2 AS STRING LOCAL FileLen, i, k, hFile, PadLen, RetVal, nLoops, nBlocks, cryptFile, ii, tVect AS LONG LOCAL PerfFreq, t1, t2, ticksSinceJan1st2007 AS QUAD LOCAL cBeg, cEnd AS QUAD LOCAL Elapsed AS SINGLE LOCAL st AS SYSTEMTIME, qt AS QUADTIME LOCAL pIn, pOut AS BYTE PTR LOCAL pi2, po2, did1file, gotList AS LONG '------------Select here what you want to demo-------------------------------------- 'Set choice to non-zero encryptFiles = 0 'encrypt, decrypt and verify a file or list of files. generateRnds = 0 'cryptographically secure monotonic counter random # generator. Cycle currently > 60 years. (as of 2007) ' testVectors: Set %DOTESTVECTORS above to a non-zero value to run test vector check '-------------------End of selections----------------------------------------------- '------Enter here your secret RC6 password key for this run------------------------- ' "12345678901234567890123456789012" sKey = "use up to A 32BYTE onom .&.TmPy%" '32 bytes max--256 bits main key. ' And if you're also generating secure randoms, enter that password too... initVector = "ENTERyour16bytes" 'You choose 16 bytes max. Only used in rand generator. '-------------------End key--------------------------------------------------------- IF (encryptFiles AND generateRnds) THEN encryptFiles = 0 'can't do both at the same time IF (encryptFiles OR generateRnds) = 0 THEN generateRnds = 1 'but you've gotta do something RetVal = QueryPerformanceFrequency(PerfFreq) ' Checkhardware supports High Resolution Timer getSystemTime(st) systemTimeToFileTime(st, qt) ticksSinceJan1st2007 = (qt.ftQuad - 1.28123856e17) * %CLOCKSPEEDADJ 'Explanation of this line follows... 'Take an example: for a 2ghz machine--100 nanosec/sysTimeTick * 2 clockTicks/nanosec = 200 clockTicks/sysTimeTick 'So, %CLOCKSPEEDADJ = 200 for 2GHz. The quantity (qt.ftQuad - 1.28123856e17) is the # of 100 nanosec intervals since 'Jan. 1, 1601, MINUS 406 years of 100 nanosec intervals (1.28123856e17 intervals) which = ticks since Jan. 1, 2007. 'To customize this and make it unique to you, you can reduce (or even slightly increase) this number. Reducing it, 'however, eats into the future years it has available before repeating its cycle. 30 years may just not be enough. ;) IF generateRnds THEN OPEN "c:\monotonicRC6randoms.dat" FOR BINARY AS #1 IF encryptFiles THEN cryptFile = 1 DO IF cryptFile = 1 THEN cryptFile = 0 TRY OPEN "C:\ListCryptFiles.txt" FOR INPUT LOCK SHARED AS #1 ' <<this is a list of all the files you want to en/decrypt gotList = %TRUE ' and check for correctness of en/decryption. Does not write CATCH ' to disk, only memory. 0 min size, 85MB max size tested. END TRY END IF IF encryptFiles THEN newFile: IF gotList = %TRUE THEN LINE INPUT #1, sfileName IF EOF(1) THEN EXIT DO ELSE 'if no filelist exists, try using just a single file sFileName = "D:\ONTARIO.MPG" ' <<You can also test just a single file ** CHANGE THIS to your filename ** TRY IF did1file = 1 THEN EXIT DO OPEN sFileName FOR INPUT ACCESS READ LOCK SHARED AS #1 CLOSE #1 did1file = 1 CATCH ? "No file found to encode/decode.",,"RC6" EXIT FUNCTION END TRY END IF hFile = FREEFILE OPEN sFileName FOR BINARY LOCK SHARED AS hFile IF ERR THEN CLOSE hFile: GOTO newFile IF LOF(hFile) < 0 OR LOF(hFile) > 85000000 THEN CLOSE hFile: GOTO newFile GET$ #hFile, LOF(hFile), sFile CLOSE hFile ' END IF IF generateRnds THEN '-------cryptographically secure random generator code------------------------------------------------------------- sFile = STRING$(&h010000, 0) 'string used only for rand generator. !lea edx, initVector ;now shuffle initVector a bit !mov eax, [edx+00] !mov ecx, [edx+04] !mul ecx !lea ecx, initVector !xor [ecx+08], edx !xor [ecx+12], eax !mov eax, [ecx+06] !mov ecx, [ecx+10] !mul ecx !lea ecx, initVector !xor [ecx+00], edx !xor [ecx+04], eax '---end cryptographically secure random generator code------------------------------------------------------------- END IF #IF %DOTESTVECTORS CALL FillTestVectors(plaintext(), UserKey2(), ciphertext()) nextVect: sFile = plainText(tVect) sFileName = "Test vector" skey = userKey2(tVect) ciphertext2 = cipherText(tVect) '<< plainText and userKey should result in this cipherText INCR tVect generateRnds = 0: encryptFiles = 1 #ENDIF bsFile = sFile ' REMOVE THIS LINE if not verification testing SrcLen = LEN(sFile) KeyLen = LEN(sKey) REDIM UserKey(KeyLen) AS STATIC BYTE POKE$ VARPTR(UserKey(0)), sKey ' key to byte array RC6_set_key( UserKey(), KeyLen, RC6Key() ) ' Create password based key for crypt and decrypt IF (SrcLen AND 15) <> 0 THEN PadLen = 16 - (SrcLen AND 15) ELSE padLen = 0 IF SrcLen = 0 THEN padLen = 16 nBlocks = (SrcLen + PadLen) \ 16 sFile = sFile + zbs(PadLen) sCipher = zbs(SrcLen + PadLen) ' t = t + "Input File length :" + STR$(SrcLen) + $CRLF _ + "Key length:" + STR$(KeyLen) + " (max=32)" + $CRLF _ + "Input File: "+sFileName & $CRLF & $CRLF _ + "PadLen :" + STR$(PadLen) + $CRLF _ + "nBlocks :" + STR$(nBlocks) + $CRLF _ + "Cipher length :" + STR$(LEN(sCipher)) + $CRLF pIn = STRPTR(sFile) pOut = STRPTR(sCipher) nLoops = 1 keyPtr = VARPTR(RC6Key(0)) ' ---------------------------------------------------------- Encoding sCipher QueryPerformanceCounter t1 time_stamp_count(cBeg) ' measuring cpu clock cycles. The overhead just for making this call is about 25 clocks regenerate: FOR k = 0 TO (nBlocks-1)*16 STEP 16 po2 = pOut+k IF generateRnds THEN mRC6_monotonicEncrypt(po2) ELSE pi2 = pIn+k mRC6_EnCrypt(pi2, po2) END IF NEXT IF generateRnds THEN PUT #1, , sCipher INCR rndCount IF rndCount = 1600 THEN CLOSE: EXIT DO '~100MB file GOTO regenerate END IF time_stamp_count(cEnd) ' measuring cpu clock cycles. The overhead just for making this call is about 25 clocks sCipher = sCipher + CHR$(PadLen) ' byte array to string QueryPerformanceCounter t2 : Elapsed = (t2-t1)/PerfFreq*1000 ' m/s #IF %DOTESTVECTORS ' next lines are the test vector results you must match to be correct LOCAL answer AS STRING IF LEFT$(sCipher, SrcLen) = ciphertext2 THEN answer = "Yes it does!" ELSE answer = "No. Error in cipher!" ? "Does " & $CRLF & strToHex(LEFT$(sCipher, SrcLen)) & " =" & $CRLF & _ strToHex(ciphertext2) & " ?" & $CRLF & answer,,"RC6 Test Vector" & STR$(tVect) #ENDIF t = t + "Encrypt Clock Cycles="+STR$(cEnd-cBeg) + $CRLF _ + "Encrypted in:"+STR$(Elapsed)+" m/s" + $CRLF _ + "Encrypt Clock Cycles per Byte:"+STR$((cEnd-cBeg)\nLoops\LEN(sFile))+" c/b" + $CRLF + $CRLF _ + "Cipher length :" + STR$(LEN(sCipher)) + $CRLF ' ---------------------------------------------------------- Decoding sCipher QueryPerformanceCounter t1 PadLen = ASC(RIGHT$(sCipher, 1)) SrcLen = LEN(sCipher) - 1 nBlocks = SrcLen \ 16 sFile = zbs(SrcLen) pIn = STRPTR(sCipher) pOut = STRPTR(sFile) time_stamp_count(cBeg) ' measuring cpu clock cycles. The overhead just for making this call is about 25 clocks FOR k = 0 TO (nBlocks-1)*16 STEP 16 pi2 = pIn+k po2 = pOut+k mRC6_DeCrypt(pi2, po2) NEXT time_stamp_count(cEnd) ' measuring cpu clock cycles. The overhead just for making this call is about 25 clocks sFile = LEFT$(sFile, SrcLen-PadLen) ' convert byte array to string QueryPerformanceCounter t2 : Elapsed = (t2-t1)/PerfFreq*1000 ' m/s IF sFile <> bsFile THEN ? "Error, decryption <> original!",64,"RC6" 'REMOVE THIS if not verification testing #IF %DOTESTVECTORS RESET t IF sFile <> plainText(tVect - 1) THEN ? "Error! RC6 algorithm failed on a test vector.",64,"RC6 Test Vectors" EXIT FUNCTION END IF IF tVect <= 5 THEN GOTO nextVect ? "All vectors matched, so this RC6 algorithm correctly handled the test vectors.",,"RC6 Test Vectors" EXIT FUNCTION #ENDIF sCipher = "" ' Burn the Cipher t = t + "Recovered PadLen :" + STR$(PadLen) + $CRLF _ + "Recovered nBlocks :" + STR$(nBlocks) + $CRLF _ + "Decrypt Clock Cycles="+STR$( (cEnd-cBeg)\nLoops ) + $CRLF _ + "Decrypted File length :" + STR$(LEN(sFile)) + $CRLF _ + "Decrypt Completed in:"+STR$(Elapsed)+" m/s" + $CRLF _ + "Decrypt Clock Cycles per Byte:"+STR$((cEnd-cBeg)\nLoops\LEN(sFile))+" c/b" + $CRLF+ $CRLF ? t,64,"RC6 Encryption" RESET t': BEEP LOOP UNTIL EOF(1) ? "done",, "RC6" END FUNCTION #IF %DOTESTVECTORS SUB FillTestVectors(plaintext() AS STRING, UserKey() AS STRING, ciphertext() AS STRING) 'Official Test vectors for encryption with RC6. Thanks for the code Aleksandr Dobrev ' plaintext(0) = CHR$(&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00) userkey(0) = CHR$(&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00) ciphertext(0)= CHR$(&H8f,&Hc3,&Ha5,&H36,&H56,&Hb1,&Hf7,&H78,&Hc1,&H29,&Hdf,&H4e,&H98,&H48,&Ha4,&H1e) ' plaintext(1)= CHR$(&H02,&H13,&H24,&H35,&H46,&H57,&H68,&H79,&H8a,&H9b,&Hac,&Hbd,&Hce,&Hdf,&He0,&Hf1) userkey(1)= CHR$(&H01,&H23,&H45,&H67,&H89,&Hab,&Hcd,&Hef,&H01,&H12,&H23,&H34,&H45,&H56,&H67,&H78) ciphertext(1)= CHR$(&H52,&H4e,&H19,&H2f,&H47,&H15,&Hc6,&H23,&H1f,&H51,&Hf6,&H36,&H7e,&Ha4,&H3f,&H18) ' plaintext(2)= CHR$(&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00) userkey(2)= CHR$(&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00)+_ CHR$(&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00) ciphertext(2)= CHR$(&H6c,&Hd6,&H1b,&Hcb,&H19,&H0b,&H30,&H38,&H4e,&H8a,&H3f,&H16,&H86,&H90,&Hae,&H82) ' plaintext(3)= CHR$(&H02,&H13,&H24,&H35,&H46,&H57,&H68,&H79,&H8a,&H9b,&Hac,&Hbd,&Hce,&Hdf,&He0,&Hf1) userkey(3)= CHR$(&H01,&H23,&H45,&H67,&H89,&Hab,&Hcd,&Hef,&H01,&H12,&H23,&H34,&H45,&H56,&H67,&H78)+_ CHR$(&H89,&H9a,&Hab,&Hbc,&Hcd,&Hde,&Hef,&Hf0) ciphertext(3)= CHR$(&H68,&H83,&H29,&Hd0,&H19,&He5,&H05,&H04,&H1e,&H52,&He9,&H2a,&Hf9,&H52,&H91,&Hd4) ' plaintext(4)= CHR$(&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00) userkey(4)= CHR$(&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00)+_ CHR$(&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00) ciphertext(4)= CHR$(&H8f,&H5f,&Hbd,&H05,&H10,&Hd1,&H5f,&Ha8,&H93,&Hfa,&H3f,&Hda,&H6e,&H85,&H7e,&Hc2) ' plaintext(5)= CHR$(&H02,&H13,&H24,&H35,&H46,&H57,&H68,&H79,&H8a,&H9b,&Hac,&Hbd,&Hce,&Hdf,&He0,&Hf1) userkey(5)= CHR$(&H01,&H23,&H45,&H67,&H89,&Hab,&Hcd,&Hef,&H01,&H12,&H23,&H34,&H45,&H56,&H67,&H78)+_ CHR$(&H89,&H9a,&Hab,&Hbc,&Hcd,&Hde,&Hef,&Hf0,&H10,&H32,&H54,&H76,&H98,&Hba,&Hdc,&Hfe) ciphertext(5)= CHR$(&Hc8,&H24,&H18,&H16,&Hf0,&Hd7,&He4,&H89,&H20,&Had,&H16,&Ha1,&H67,&H4e,&H5d,&H48) END SUB #ENDIF