#IF 0
------------------
-- Greg
[email protected]
Code:
===================================================================== Skipjack Encryption Algorithm ===================================================================== Four FIPS-approved symmetric key algorithms exist for encryption: AES (Rijndael), DES, triple-DES, and Skipjack. Skipjack is free for any use public or private, commercial or non-commercial. Information about the algorithm and its implementation can be found in the following documents: [url="http://csrc.nist.gov/encryption/skipjack/skipjack.pdf"]http://csrc.nist.gov/encryption/skipjack/skipjack.pdf[/url] [url="http://csrc.nist.gov/encryption/skipjack/clarification.pdf"]http://csrc.nist.gov/encryption/skipjack/clarification.pdf[/url] Bruce Schneier's interesting overview of Skipjack's origin and design is available at: [url="http://www.counterpane.com/crypto-gram-9807.html#skip"]http://www.counterpane.com/crypto-gram-9807.html#skip[/url] The PB code appearing here is based in part on an implementation written, optimized, and placed in the public domain by Panu Rissanen, Mark Tillotson, Paulo Barreto. This PB implementation is hereby placed in the public domain. Use it as you wish. My hope is discourage reliance on home-grown encryption schemes in favor of well-examined, strong, freely available algorithms. In this posting, test-bed code appears below the SKIPJACK.BAS file contents. All code requires compiler releases 3.0/7.0 or later. <U>Implementation Notes</U> -- The algorithm operates on plaintext blocks of 8 bytes with a user key limited to 10 bytes (80 bits). Encryption of shorter blocks is possible only by padding the plaintext (often with zero bytes), which can be accomplished through several methods. The simplest of them assumes that the final byte of plaintext always identifies the number of bytes of padding added, including the final byte itself. Examples: total plaintext bytes = 30 plaintext blocks encrypted: = 4 final block = chr$(x1 to x6) + chr$(0,2) total plaintext bytes = 42 plaintext blocks encrypted: = 6 final block = chr$(x1 to x2) + chr$(0,0,0,0,0,6) -- Implementation here is handled through an #INCLUDE file. No global data is employed. -- As presented, the code does not supply a ready-to-use encryption application. It offers necessary pieces only, as well as an illustration of their use. Always keep in mind that most encryption is broken because of implementation flaws and weaknesses. -- Because of the methods of data handling required for most encryption and hashing, PowerBASIC's LONGs should be used to assure correct bit-level results (as well as additional speed). Greg Turgeon 09/2002 #ENDIF DEFLNG A-Z '%ROUNDS = 32 %BLOCKSIZE = 8 %KEYSIZE = 10 %SUBKEY_SIZE = (10*256) TYPE ENCRYPTION_CONTEXT UserKeyLength AS LONG UserKey AS BYTE PTR InBlock AS BYTE PTR OutBlock AS BYTE PTR Table AS BYTE PTR Key AS BYTE PTR '<-- pointer to encryption subkey buffer Key_Buffer AS STRING * %SUBKEY_SIZE '<-- encryption subkey buffer END TYPE '-------------------- '-- Utility macros '-------------------- MACRO zbs(xx)=string$(xx,0) '-------------------- MACRO FUNCTION shl8(xx) retval = (xx) ! shl retval, 8 END MACRO = retval '-------------------- MACRO FUNCTION byte1(xx) retval = (xx) ! mov eax, retval ! shr eax, 8 ! and eax, &hff ! mov retval, eax END MACRO = retval '-------------------- '-- Skipjack macros '-------------------- MACRO g(w,i,j,k,l) t = Ctx.@Key[(w AND &hff) of 255, i of 3] : w = w XOR shl8(t) t = Ctx.@Key[byte1(w) of 255, j of 3] : w = w XOR t t = Ctx.@Key[(w AND &hff) of 255, k of 3] : w = w XOR shl8(t) t = Ctx.@Key[byte1(w) of 255, l of 3] : w = w XOR t END MACRO '-------------------- MACRO g0(w) g(w,0,1,2,3) END MACRO '-------------------- MACRO g1(w) g(w,4,5,6,7) END MACRO '-------------------- MACRO g2(w) g(w,8,9,0,1) END MACRO '-------------------- MACRO g3(w) g(w,2,3,4,5) END MACRO '-------------------- MACRO g4(w) g(w,6,7,8,9) END MACRO '-------------------- MACRO h(w,i,j,k,l) t = Ctx.@Key[byte1(w) of 255, l of 3] : w = w XOR t t = Ctx.@Key[(w AND &hff) of 255, k of 3] : w = w XOR shl8(t) t = Ctx.@Key[byte1(w) of 255, j of 3] : w = w XOR t t = Ctx.@Key[(w AND &hff) of 255, i of 3] : w = w XOR shl8(t) END MACRO '-------------------- MACRO h0(w) h(w,0,1,2,3) END MACRO '-------------------- MACRO h1(w) h(w,4,5,6,7) END MACRO '-------------------- MACRO h2(w) h(w,8,9,0,1) END MACRO '-------------------- MACRO h3(w) h(w,2,3,4,5) END MACRO '-------------------- MACRO h4(w) h(w,6,7,8,9) END MACRO DECLARE FUNCTION SkipJack_Init&(Ctx AS ENCRYPTION_CONTEXT) DECLARE FUNCTION Set_Key&(Ctx AS ENCRYPTION_CONTEXT) DECLARE FUNCTION EncryptBlock&(Ctx AS ENCRYPTION_CONTEXT) DECLARE FUNCTION DecryptBlock&(Ctx AS ENCRYPTION_CONTEXT) '==================== FUNCTION Set_Key&(Ctx AS ENCRYPTION_CONTEXT) if Skipjack_Init(Ctx) = 0 then function = 0 : exit function end if REGISTER i&, j& LOCAL k AS BYTE PTR, uk AS BYTE PTR k = Ctx.Key : uk = Ctx.UserKey for i = 0 to 9 for j = 0 to 255 @k = Ctx.@Table[j XOR @uk] : incr k next j incr uk next i function = -1 END FUNCTION '==================== FUNCTION EncryptBlock&(Ctx AS ENCRYPTION_CONTEXT) LOCAL w1&, w2&, w3&, w4&, t&, retval& w1 = shl8(Ctx.@InBlock[0]) + Ctx.@InBlock[1] w2 = shl8(Ctx.@InBlock[2]) + Ctx.@InBlock[3] w3 = shl8(Ctx.@InBlock[4]) + Ctx.@InBlock[5] w4 = shl8(Ctx.@InBlock[6]) + Ctx.@InBlock[7] g0(w1) : w4 = w4 XOR w1 XOR 1 g1(w4) : w3 = w3 XOR w4 XOR 2 g2(w3) : w2 = w2 XOR w3 XOR 3 g3(w2) : w1 = w1 XOR w2 XOR 4 g4(w1) : w4 = w4 XOR w1 XOR 5 g0(w4) : w3 = w3 XOR w4 XOR 6 g1(w3) : w2 = w2 XOR w3 XOR 7 g2(w2) : w1 = w1 XOR w2 XOR 8 w2 = w2 XOR w1 XOR 9 : g3(w1) w1 = w1 XOR w4 XOR 10 : g4(w4) w4 = w4 XOR w3 XOR 11 : g0(w3) w3 = w3 XOR w2 XOR 12 : g1(w2) w2 = w2 XOR w1 XOR 13 : g2(w1) w1 = w1 XOR w4 XOR 14 : g3(w4) w4 = w4 XOR w3 XOR 15 : g4(w3) w3 = w3 XOR w2 XOR 16 : g0(w2) g1(w1) : w4 = w4 XOR w1 XOR 17 g2(w4) : w3 = w3 XOR w4 XOR 18 g3(w3) : w2 = w2 XOR w3 XOR 19 g4(w2) : w1 = w1 XOR w2 XOR 20 g0(w1) : w4 = w4 XOR w1 XOR 21 g1(w4) : w3 = w3 XOR w4 XOR 22 g2(w3) : w2 = w2 XOR w3 XOR 23 g3(w2) : w1 = w1 XOR w2 XOR 24 w2 = w2 XOR w1 XOR 25 : g4(w1) w1 = w1 XOR w4 XOR 26 : g0(w4) w4 = w4 XOR w3 XOR 27 : g1(w3) w3 = w3 XOR w2 XOR 28 : g2(w2) w2 = w2 XOR w1 XOR 29 : g3(w1) w1 = w1 XOR w4 XOR 30 : g4(w4) w4 = w4 XOR w3 XOR 31 : g0(w3) w3 = w3 XOR w2 XOR 32 : g1(w2) Ctx.@OutBlock[0] = byte1(w1) : Ctx.@OutBlock[1] = w1 AND &hff Ctx.@OutBlock[2] = byte1(w2) : Ctx.@OutBlock[3] = w2 AND &hff Ctx.@OutBlock[4] = byte1(w3) : Ctx.@OutBlock[5] = w3 AND &hff Ctx.@OutBlock[6] = byte1(w4) : Ctx.@OutBlock[7] = w4 AND &hff END FUNCTION '==================== FUNCTION DecryptBlock&(Ctx AS ENCRYPTION_CONTEXT) LOCAL w1&, w2&, w3&, w4&, t&, retval& w1 = shl8(Ctx.@InBlock[0]) + Ctx.@InBlock[1] w2 = shl8(Ctx.@InBlock[2]) + Ctx.@InBlock[3] w3 = shl8(Ctx.@InBlock[4]) + Ctx.@InBlock[5] w4 = shl8(Ctx.@InBlock[6]) + Ctx.@InBlock[7] h1(w2) : w3 = w3 XOR w2 XOR 32 h0(w3) : w4 = w4 XOR w3 XOR 31 h4(w4) : w1 = w1 XOR w4 XOR 30 h3(w1) : w2 = w2 XOR w1 XOR 29 h2(w2) : w3 = w3 XOR w2 XOR 28 h1(w3) : w4 = w4 XOR w3 XOR 27 h0(w4) : w1 = w1 XOR w4 XOR 26 h4(w1) : w2 = w2 XOR w1 XOR 25 w1 = w1 XOR w2 XOR 24 : h3(w2) w2 = w2 XOR w3 XOR 23 : h2(w3) w3 = w3 XOR w4 XOR 22 : h1(w4) w4 = w4 XOR w1 XOR 21 : h0(w1) w1 = w1 XOR w2 XOR 20 : h4(w2) w2 = w2 XOR w3 XOR 19 : h3(w3) w3 = w3 XOR w4 XOR 18 : h2(w4) w4 = w4 XOR w1 XOR 17 : h1(w1) h0(w2) : w3 = w3 XOR w2 XOR 16 h4(w3) : w4 = w4 XOR w3 XOR 15 h3(w4) : w1 = w1 XOR w4 XOR 14 h2(w1) : w2 = w2 XOR w1 XOR 13 h1(w2) : w3 = w3 XOR w2 XOR 12 h0(w3) : w4 = w4 XOR w3 XOR 11 h4(w4) : w1 = w1 XOR w4 XOR 10 h3(w1) : w2 = w2 XOR w1 XOR 9 w1 = w1 XOR w2 XOR 8 : h2(w2) w2 = w2 XOR w3 XOR 7 : h1(w3) w3 = w3 XOR w4 XOR 6 : h0(w4) w4 = w4 XOR w1 XOR 5 : h4(w1) w1 = w1 XOR w2 XOR 4 : h3(w2) w2 = w2 XOR w3 XOR 3 : h2(w3) w3 = w3 XOR w4 XOR 2 : h1(w4) w4 = w4 XOR w1 XOR 1 : h0(w1) Ctx.@OutBlock[0] = byte1(w1) : Ctx.@OutBlock[1] = w1 AND &hff Ctx.@OutBlock[2] = byte1(w2) : Ctx.@OutBlock[3] = w2 AND &hff Ctx.@OutBlock[4] = byte1(w3) : Ctx.@OutBlock[5] = w3 AND &hff Ctx.@OutBlock[6] = byte1(w4) : Ctx.@OutBlock[7] = w4 AND &hff END FUNCTION '==================== FUNCTION SkipJack_Init&(Ctx AS ENCRYPTION_CONTEXT) if (Ctx.UserKeylength <> %KEYSIZE) then function = 0 : exit function end if Ctx.Key_Buffer = zbs(%SUBKEY_SIZE) Ctx.Key = varptr(Ctx.Key_Buffer) Ctx.Table = codeptr(fTable) function = -1 exit function fTable: !DB &ha3,&hd7,&h09,&h83,&hf8,&h48,&hf6,&hf4,&hb3,&h21,&h15,&h78,&h99,&hb1,&haf,&hf9 !DB &he7,&h2d,&h4d,&h8a,&hce,&h4c,&hca,&h2e,&h52,&h95,&hd9,&h1e,&h4e,&h38,&h44,&h28 !DB &h0a,&hdf,&h02,&ha0,&h17,&hf1,&h60,&h68,&h12,&hb7,&h7a,&hc3,&he9,&hfa,&h3d,&h53 !DB &h96,&h84,&h6b,&hba,&hf2,&h63,&h9a,&h19,&h7c,&hae,&he5,&hf5,&hf7,&h16,&h6a,&ha2 !DB &h39,&hb6,&h7b,&h0f,&hc1,&h93,&h81,&h1b,&hee,&hb4,&h1a,&hea,&hd0,&h91,&h2f,&hb8 !DB &h55,&hb9,&hda,&h85,&h3f,&h41,&hbf,&he0,&h5a,&h58,&h80,&h5f,&h66,&h0b,&hd8,&h90 !DB &h35,&hd5,&hc0,&ha7,&h33,&h06,&h65,&h69,&h45,&h00,&h94,&h56,&h6d,&h98,&h9b,&h76 !DB &h97,&hfc,&hb2,&hc2,&hb0,&hfe,&hdb,&h20,&he1,&heb,&hd6,&he4,&hdd,&h47,&h4a,&h1d !DB &h42,&hed,&h9e,&h6e,&h49,&h3c,&hcd,&h43,&h27,&hd2,&h07,&hd4,&hde,&hc7,&h67,&h18 !DB &h89,&hcb,&h30,&h1f,&h8d,&hc6,&h8f,&haa,&hc8,&h74,&hdc,&hc9,&h5d,&h5c,&h31,&ha4 !DB &h70,&h88,&h61,&h2c,&h9f,&h0d,&h2b,&h87,&h50,&h82,&h54,&h64,&h26,&h7d,&h03,&h40 !DB &h34,&h4b,&h1c,&h73,&hd1,&hc4,&hfd,&h3b,&hcc,&hfb,&h7f,&hab,&he6,&h3e,&h5b,&ha5 !DB &had,&h04,&h23,&h9c,&h14,&h51,&h22,&hf0,&h29,&h79,&h71,&h7e,&hff,&h8c,&h0e,&he2 !DB &h0c,&hef,&hbc,&h72,&h75,&h6f,&h37,&ha1,&hec,&hd3,&h8e,&h62,&h8b,&h86,&h10,&he8 !DB &h08,&h77,&h11,&hbe,&h92,&h4f,&h24,&hc5,&h32,&h36,&h9d,&hcf,&hf3,&ha6,&hbb,&hac !DB &h5e,&h6c,&ha9,&h13,&h57,&h25,&hb5,&he3,&hbd,&ha8,&h3a,&h01,&h05,&h59,&h2a,&h46 END FUNCTION '-- end SKIPJACK.BAS '===================================================================== ' Skipjack Test Bed code ' Compiles with either PBWIN 7.0+ or PBCC 3.0+ '===================================================================== #COMPILE EXE #REGISTER NONE #DIM ALL '============ DEFLNG A-Z '-------------------- '-- Utility macros '-------------------- #IF %def(%pb_win32) MACRO eol=$CR MACRO mbox(t)=msgbox t #ELSEIF %def(%pb_cc32) MACRO eol=$CRLF MACRO mbox(t)=stdout t #ENDIF '-------------------- MACRO EnterCC #IF %def(%pb_cc32) LOCAL launched& if (cursory = 1) and (cursorx = 1) then launched = -1 #ENDIF END MACRO '-------------------- MACRO ExitCC #IF %def(%pb_cc32) if launched then input flush stdout "Press any key to end"; waitkey$ end if #ENDIF END MACRO '-------------------- 'MACRO zbs(x)=string$(x,0) 'also defined in SKIPJACK.BAS #INCLUDE "SKIPJACK.BAS" DECLARE FUNCTION Hex2Show$(Buffer$) '==================== FUNCTION PBMain&() REGISTER i& LOCAL key$, plain$, cipher$, shouldbe$, t$ LOCAL ctx AS ENCRYPTION_CONTEXT ' defined in SKIPJACK.BAS EnterCC '-- Standard test vectors key = chr$(&h00, &h99, &h88, &h77, &h66, &h55, &h44, &h33, &h22, &h11) plain = chr$(&h33, &h22, &h11, &h00, &hdd, &hcc, &hbb, &haa) cipher = zbs(len(plain)) shouldbe = chr$(&h25, &h87, &hca, &he2, &h7a, &h12, &hd3, &h00) t = t + "Key length (bits):" + str$(len(key)*8) + eol t = t + "plain: " + Hex2Show$(plain) + eol gosub DoEncrypt t = t + "cipher: " + Hex2Show$(cipher) + eol t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol '-- Be sure to reload key$ gosub DoDecrypt t = t + "plain: " + Hex2Show$(plain) + eol + eol key = chr$(&he7,&h49,&h6e,&h99,&he4,&h62,&h8b,&h7f,&h9f,&hfb) plain = chr$(&h99,&hcc,&hfe,&h2b,&h90,&hfd,&h55,&h0b) cipher = zbs(len(plain)) shouldbe = chr$(&h60,&ha7,&h3d,&h38,&h7b,&h51,&h7f,&hca) t = t + "Key length (bits):" + str$(len(key)*8) + eol t = t + "plain: " + Hex2Show$(plain) + eol gosub DoEncrypt t = t + "cipher: " + Hex2Show$(cipher) + eol t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol '-- Be sure to reload key$ key = chr$(&he7,&h49,&h6e,&h99,&he4,&h62,&h8b,&h7f,&h9f,&hfb) gosub DoDecrypt t = t + "plain: " + Hex2Show$(plain) + eol + eol key = chr$(&hf8,&hda,&h02,&h64,&h77,&h22,&hf7,&h10,&h3a,&hdf) plain = chr$(&h1d,&hdf,&h39,&hab,&hf5,&hcd,&h71,&h1e) cipher = zbs(len(plain)) shouldbe = chr$(&hc9,&h2d,&h22,&h32,&h4c,&h6b,&h31,&hae) t = t + "Key length (bits):" + str$(len(key)*8) + eol t = t + "plain: " + Hex2Show$(plain) + eol gosub DoEncrypt t = t + "cipher: " + Hex2Show$(cipher) + eol t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol '-- Be sure to reload key$ key = chr$(&hf8,&hda,&h02,&h64,&h77,&h22,&hf7,&h10,&h3a,&hdf) gosub DoDecrypt t = t + "plain: " + Hex2Show$(plain) + eol + eol key = chr$(&h5b,&h87,&h8e,&h0b,&h22,&ha7,&h05,&hac,&hf8,&hfb) plain = chr$(&h0c,&h48,&h9b,&h66,&he2,&hda,&h53,&h1b) cipher = zbs(len(plain)) shouldbe = chr$(&h6e,&h93,&h70,&ha9,&h1b,&h99,&h48,&h78) t = t + "Key length (bits):" + str$(len(key)*8) + eol t = t + "plain: " + Hex2Show$(plain) + eol gosub DoEncrypt t = t + "cipher: " + Hex2Show$(cipher) + eol t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol '-- Be sure to reload key$ key = chr$(&h5b,&h87,&h8e,&h0b,&h22,&ha7,&h05,&hac,&hf8,&hfb) gosub DoDecrypt t = t + "plain: " + Hex2Show$(plain) + eol mbox(t) ExitCC exit function '============ DoEncrypt: ctx.UserKey = strptr(key) ctx.UserKeyLength = len(key) ctx.InBlock = strptr(plain) ctx.OutBlock = strptr(cipher) if Set_Key&(ctx) then for i = 1 to (len(plain)\%BLOCKSIZE) '<-- Required: (len(plain$) mod 8) = 0 EncryptBlock ctx ctx.InBlock = ctx.InBlock + %BLOCKSIZE ctx.OutBlock = ctx.OutBlock + %BLOCKSIZE next i& else mbox("Encrypt SetKey Error") end if '-- Burn the subkey if Ctx.Key then poke$ Ctx.Key, zbs(sizeof(Ctx.Key_Buffer)) RETURN '============ DoDecrypt: ctx.UserKey = strptr(key) ctx.UserKeyLength = len(key) ctx.InBlock = strptr(cipher) ctx.OutBlock = strptr(plain) if Set_Key&(ctx) then for i = 1 to (len(plain)\%BLOCKSIZE) '<-- Required: (len(plain$) mod 8) = 0 DecryptBlock ctx ctx.InBlock = ctx.InBlock + %BLOCKSIZE ctx.OutBlock = ctx.OutBlock + %BLOCKSIZE next i else mbox("Decrypt SetKey Error") end if '-- Burn the subkey if Ctx.Key then poke$ Ctx.Key, zbs(sizeof(Ctx.Key_Buffer)) RETURN END FUNCTION '==================== FUNCTION Hex2Show$(Buffer$) LOCAL t$, i&, b AS BYTE PTR b = strptr(Buffer$) for i = 0 to len(Buffer$)-1 t = t + hex$(@b[i],2) + " " next i function = t END FUNCTION '-- end TESTBED.BAS
-- Greg
[email protected]