Skipjack
Algorithm creator(s)
NSA
PB author(s)
Greg Turgeon
Description
Skipjack, well known for its use in the Clipper program, is an unbalanced Feistel network, a product of military cryptography. It is a 64-bit symmetric block cipher with an 80-bit key, and is about twice as fast as DES on 32-bit microprocessors.
Note
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 by padding the plaintext (often with zero bytes), which can be accomplished through several methods.
Source
https://forum.powerbasic.com/forum/user-to-user-discussions/source-code/24146-skipjack-encryption-for-3-0-7-0?t=23509
See also
n/a
Source Code
Download source code file skipjack.bas (Right-click -> "Save as ...")
#IF 0
=====================================================================
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:
http://csrc.nist.gov/encryption/skipjack/skipjack.pdf
http://csrc.nist.gov/encryption/skipjack/clarification.pdf
Bruce Schneier's interesting overview of Skipjack's origin and design is
available at: http://www.counterpane.com/crypto-gram-9807.html#skip
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. Implementation Notes
-- 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
'SKIPJACK.BAS
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
'-- TESTBED.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
gturgeon@compuserve.com