Serpent
Algorithm creator(s)
Ross Anderson, Eli Biham, Lars Knudsen
PB author(s)
Greg Turgeon
Description
A 128-bit block cipher, finalist in the AES competition losing only to Rijndael. Serpent and Rijndael are in fact somewhat similar; the main difference is that Rijndael is faster (having fewer rounds) but Serpent is more secure.
Note
Please read source header for implementation notes.
Source
https://forum.powerbasic.com/forum/user-to-user-discussions/source-code/24061-serpent-encryption-for-7-0-3-0?t=23436
See also
n/a
Source Code
Download source code file serpent.bas (Right-click -> "Save as ...")
#IF 0
=====================================================================
Serpent Encryption
=====================================================================
The authors of the Serpent encryption algorithm have placed it in the
public domain and make no restrictions on its use. The Serpent home
page is accessible at: http://www.cl.cam.ac.uk/~rja14/serpent.html
From the Serpent home page:
"Serpent is a 128-bit block cipher designed by Ross Anderson, Eli
Biham and Lars Knudsen as a candidate for the Advanced Encryption
Standard. It was a finalist in the AES competition. The winner,
Rijndael, got 86 votes at the last AES conference while Serpent got 59
votes, Twofish 31 votes, RC6 23 votes and MARS 13 votes. So NIST's
choice of Rijndael as the AES was not surprising, and we had to
content ourselves with silver in the `encryption olympics'. Serpent
and Rijndael are in fact somewhat similar; the main difference is that
Rijndael is faster (having fewer rounds) but Serpent is more secure."
The PowerBASIC implementation appearing here is based on that of Brian
Gladman, which is available at: http://fp.gladman.plus.com/cryptography_technology/
The following notice appears in Gladman's Serpent code.
--------------------------------------------------------------------
This is an independent implementation of the encryption algorithm:
Serpent by Ross Anderson, Eli Biham and Lars Knudsen
which is a candidate algorithm in the Advanced Encryption Standard
programme of the US National Institute of Standards and Technology.
Copyright in this implementation is held by Dr B R Gladman but I
hereby give permission for its free direct or derivative use subject
to acknowledgment of its origin and compliance with any conditions
that the originators of the algorithm place on its exploitation.
Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999
-------------------------------------------------------------------
The 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 SERPENT.BAS file
contents. All code requires compiler releases 3.0/7.0 or later. Implementation Notes
-- The algorithm operates on plaintext blocks of 16 bytes. Encryption
of shorter blocks is possible only by padding the plaintext (usually
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: = 2
final block = chr$(x1 to x14) + chr$(0,2)
total plaintext bytes = 40
plaintext blocks encrypted: = 3
final block = chr$(x1 to x8) + chr$(0,0,0,0,0,0,0,8)
-- Encryption key lengths can range from 1 to 32 bytes (8 to 256
bits).
-- 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.
-- Like most encryption algorithms, Serpent was designed on big-endian
systems. For this reason, little-endian systems return correct test
vector results only through considerable byte-swapping, with
efficiency suffering as a result. Because it adds nothing to the
encryption security, an efficient implementation should avoid the
byte-swapping. Here the equate %VERIFY_IMPLEMENTATION can be remmed
to avoid this byte-swapping.
-- 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 07/2002
#ENDIF
'-- Rem this equate for any use other than verification of implementation.
%VERIFY_IMPLEMENTATION = 1
%BLOCKSIZE = 16
%KEY_SIZE = 32
%SUBKEY_SIZE = 140
%MIN_KEY_SIZE = 1
%MAX_KEY_SIZE = 32
'-- Note: Strings (UserKey, etc) are processed
' as 32-bit values, so LONG PTRs required
TYPE ENCRYPTION_CONTEXT
UserKeyLength AS LONG
UserKey AS LONG PTR
InBlock AS LONG PTR
OutBlock AS LONG PTR
K AS LONG PTR '<-- pointer to subkey buffer
K_Buffer AS STRING * (%SUBKEY_SIZE*4) '<-- subkey buffer itself
END TYPE
DECLARE SUB Serpent_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)
'--------------------
' Utility macros
'--------------------
'--------------------
MACRO zbs(x) = string$(x,0)
'--------------------
MACRO FUNCTION byte_swap(x)
! mov eax, x
! bswap eax
! mov x, eax
END MACRO = x
'--------------------
MACRO FUNCTION shiftl(x,shiftval)
retval = x
! shl retval, shiftval
END MACRO = retval
'--------------------
MACRO FUNCTION rotr(x,rotval)
retval = x
! mov ecx, rotval
! ror retval, cl
END MACRO = retval
'--------------------
MACRO FUNCTION rotl(x,rotval)
retval = x
! mov ecx, rotval
! rol retval, cl
END MACRO = retval
'--------------------
MACRO FUNCTION rotl_11(x)
! mov ecx, 11
! rol lk, cl
END MACRO = x
'--------------------
MACRO make_marker(i,klen,lk)
! mov ecx, klen
! mov eax, ecx
! shr eax, 5
! mov i, eax
! and ecx, 31
! mov eax, 1
! shl eax, cl
! mov lk, eax
END MACRO
'--------------------
'Serpent macros
'--------------------
MACRO sb0(a,b,c,d,e,f,g,h)
t1 = a XOR d : t2 = a AND d : t3 = c XOR t1 : t6 = b AND t1
t4 = b XOR t3 : t10 = NOT t3 : h = t2 XOR t4 : t7 = a XOR t6
t14 = NOT t7 : t8 = c OR t7 : t11 = t3 XOR t7 : g = t4 XOR t8
t12 = h AND t11 : f = t10 XOR t12 : e = t12 XOR t14
END MACRO
'--------------------
MACRO ib0(a,b,c,d,e,f,g,h)
t1 = NOT a : t2 = a XOR b : t3 = t1 OR t2 : t4 = d XOR t3
t7 = d AND t2 : t5 = c XOR t4 : t8 = t1 XOR t7 : g = t2 XOR t5
t11 = a AND t4 : t9 = g AND t8 : t14 = t5 XOR t8 : f = t4 XOR t9
t12 = t5 OR f : h = t11 XOR t12 : e = h XOR t14
END MACRO
'--------------------
MACRO sb1(a,b,c,d,e,f,g,h)
t1 = NOT a : t2 = b XOR t1 : t3 = a OR t2 : t4 = d OR t2
t5 = c XOR t3 : g = d XOR t5 : t7 = b XOR t4 : t8 = t2 XOR g
t9 = t5 AND t7 : h = t8 XOR t9 : t11 = t5 XOR t7 : f = h XOR t11
t13 = t8 AND t11 : e = t5 XOR t13
END MACRO
'--------------------
MACRO ib1(a,b,c,d,e,f,g,h)
t1 = a XOR d : t2 = a AND b : t3 = b XOR c : t4 = a XOR t3
t5 = b OR d : t7 = c OR t1 : h = t4 XOR t5 : t8 = b XOR t7
t11 = NOT t2 : t9 = t4 AND t8 : f = t1 XOR t9 : t13 = t9 XOR t11
t12 = h AND f : g = t12 XOR t13 : t15 = a AND d : t16 = c XOR t13
e = t15 XOR t16
END MACRO
'--------------------
MACRO sb2(a,b,c,d,e,f,g,h)
t1 = NOT a : t2 = b XOR d : t3 = c AND t1 : t13 = d OR t1
e = t2 XOR t3 : t5 = c XOR t1 : t6 = c XOR e : t7 = b AND t6
t10 = e OR t5 : h = t5 XOR t7 : t9 = d OR t7 : t11 = t9 AND t10
t14 = t2 XOR h : g = a XOR t11 : t15 = g XOR t13 : f = t14 XOR t15
END MACRO
'--------------------
MACRO ib2(a,b,c,d,e,f,g,h)
t1 = b XOR d : t2 = NOT t1 : t3 = a XOR c : t4 = c XOR t1
t7 = a OR t2 : t5 = b AND t4 : t8 = d XOR t7 : t11 = NOT t4
e = t3 XOR t5 : t9 = t3 OR t8 : t14 = d AND t11 : h = t1 XOR t9
t12 = e OR h : f = t11 XOR t12 : t15 = t3 XOR t12 : g = t14 XOR t15
END MACRO
'--------------------
MACRO sb3(a,b,c,d,e,f,g,h)
t1 = a XOR c : t2 = d XOR t1 : t3 = a AND t2 : t4 = d XOR t3
t5 = b AND t4 : g = t2 XOR t5 : t7 = a OR g : t8 = b OR d
t11 = a OR d : t9 = t4 AND t7 : f = t8 XOR t9 : t12 = b XOR t11
t13 = g XOR t9 : t15 = t3 XOR t8 : h = t12 XOR t13 : t16 = c AND t15
e = t12 XOR t16
END MACRO
'--------------------
MACRO ib3(a,b,c,d,e,f,g,h)
t1 = b XOR c : t2 = b OR c : t3 = a XOR c : t7 = a XOR d
t4 = t2 XOR t3 : t5 = d OR t4 : t9 = t2 XOR t7 : e = t1 XOR t5
t8 = t1 OR t5 : t11 = a AND t4 : g = t8 XOR t9 : t12 = e OR t9
f = t11 XOR t12 : t14 = a AND g : t15 = t2 XOR t14 : t16 = e AND t15
h = t4 XOR t16
END MACRO
'--------------------
MACRO sb4(a,b,c,d,e,f,g,h)
t1 = a XOR d : t2 = d AND t1 : t3 = c XOR t2 : t4 = b OR t3
h = t1 XOR t4 : t6 = NOT b : t7 = t1 OR t6 : e = t3 XOR t7
t9 = a AND e : t10 = t1 XOR t6 : t11 = t4 AND t10 : g = t9 XOR t11
t13 = a XOR t3 : t14 = t10 AND g : f = t13 XOR t14
END MACRO
'--------------------
MACRO ib4(a,b,c,d,e,f,g,h)
t1 = c XOR d : t2 = c OR d : t3 = b XOR t2 : t4 = a AND t3
f = t1 XOR t4 : t6 = a XOR d : t7 = b OR d : t8 = t6 AND t7
h = t3 XOR t8 : t10 = NOT a : t11 = c XOR h : t12 = t10 OR t11
e = t3 XOR t12 : t14 = c OR t4 : t15 = t7 XOR t14 : t16 = h OR t10
g = t15 XOR t16
END MACRO
'--------------------
MACRO sb5(a,b,c,d,e,f,g,h)
t1 = NOT a : t2 = a XOR b : t3 = a XOR d : t4 = c XOR t1
t5 = t2 OR t3 : e = t4 XOR t5 : t7 = d AND e : t8 = t2 XOR e
t10 = t1 OR e : f = t7 XOR t8 : t11 = t2 OR t7 : t12 = t3 XOR t10
t14 = b XOR t7 : g = t11 XOR t12 : t15 = f AND t12 : h = t14 XOR t15
END MACRO
'--------------------
MACRO ib5(a,b,c,d,e,f,g,h)
t1 = NOT c : t2 = b AND t1 : t3 = d XOR t2 : t4 = a AND t3
t5 = b XOR t1 : h = t4 XOR t5 : t7 = b OR h : t8 = a AND t7
f = t3 XOR t8 : t10 = a OR d : t11 = t1 XOR t7 : e = t10 XOR t11
t13 = a XOR c : t14 = b AND t10 : t15 = t4 OR t13 : g = t14 XOR t15
END MACRO
'--------------------
MACRO sb6(a,b,c,d,e,f,g,h)
t1 = NOT a : t2 = a XOR d : t3 = b XOR t2 : t4 = t1 OR t2
t5 = c XOR t4 : f = b XOR t5 : t13 = NOT t5 : t7 = t2 OR f
t8 = d XOR t7 : t9 = t5 AND t8 : g = t3 XOR t9 : t11 = t5 XOR t8
e = g XOR t11 : t14 = t3 AND t11 : h = t13 XOR t14
END MACRO
'--------------------
MACRO ib6(a,b,c,d,e,f,g,h)
t1 = NOT a : t2 = a XOR b : t3 = c XOR t2 : t4 = c OR t1
t5 = d XOR t4 : t13 = d AND t1 : f = t3 XOR t5 : t7 = t3 AND t5
t8 = t2 XOR t7 : t9 = b OR t8 : h = t5 XOR t9 : t11 = b OR h
e = t8 XOR t11 : t14 = t3 XOR t11 : g = t13 XOR t14
END MACRO
'--------------------
MACRO sb7(a,b,c,d,e,f,g,h)
t1 = NOT c : t2 = b XOR c : t3 = b OR t1 : t4 = d XOR t3
t5 = a AND t4 : t7 = a XOR d : h = t2 XOR t5 : t8 = b XOR t5
t9 = t2 OR t8 : t11 = d AND t3 : f = t7 XOR t9 : t12 = t5 XOR f
t15 = t1 OR t4 : t13 = h AND t12 : g = t11 XOR t13 : t16 = t12 XOR g
e = t15 XOR t16
END MACRO
'--------------------
MACRO ib7(a,b,c,d,e,f,g,h)
t1 = a AND b : t2 = a OR b : t3 = c OR t1 : t4 = d AND t2
h = t3 XOR t4 : t6 = NOT d : t7 = b XOR t4 : t8 = h XOR t6
t11 = c XOR t7 : t9 = t7 OR t8 : f = a XOR t9 : t12 = d OR f
e = t11 XOR t12 : t14 = a AND h : t15 = t3 XOR f : t16 = e XOR t14
g = t15 XOR t16
END MACRO
'--------------------
MACRO k_xor(r,a,b,c,d)
a = a XOR @k[4*r+8] : b = b XOR @k[4*r+9]
c = c XOR @k[4*r+10] : d = d XOR @k[4*r+11]
END MACRO
'--------------------
MACRO k_set(r,a,b,c,d)
a = @k[4*r+8] : b = @k[4*r+9]
c = @k[4*r+10] : d = @k[4*r+11]
END MACRO
'--------------------
MACRO k_get(r,a,b,c,d)
@k[4*r+8] = a : @k[4*r+9] = b
@k[4*r+10] = c : @k[4*r+11] = d
END MACRO
'--------------------
MACRO rot(a,b,c,d)
a = rotl(a,13)
c = rotl(c,3)
d = (d XOR c) XOR shiftl(a,3)
b = b XOR a XOR c
d = rotl(d,7)
b = rotl(b,1)
a = a XOR b XOR d
c = (c XOR d) XOR shiftl(b,7)
a = rotl(a,5)
c = rotl(c,22)
END MACRO
'--------------------
MACRO irot(a,b,c,d)
c = rotr(c,22)
a = rotr(a,5)
c = (c XOR d) XOR shiftl(b,7)
a = a XOR b XOR d
d = rotr(d,7)
b = rotr(b,1)
d = (d XOR c) XOR shiftl(a,3)
b = b XOR a XOR c
c = rotr(c,3)
a = rotr(a,13)
END MACRO
'====================
SUB Serpent_Init(Ctx AS ENCRYPTION_CONTEXT)
Ctx.K_Buffer = zbs(%SUBKEY_SIZE*4)
Ctx.K = varptr(Ctx.K_BUFFER)
END SUB
'====================
FUNCTION Set_Key&(Ctx AS ENCRYPTION_CONTEXT)
'-- Returns %TRUE on success
LOCAL k AS LONG PTR, uk AS LONG PTR
LOCAL i&, j&, lk&, x&
LOCAL a&, b&, c&, d&, e&, f&, g&, h&
LOCAL t1&, t2&, t3&, t4&, t5&, t6&, t7&, t8&
LOCAL t9&, t10&, t11&, t12&, t13&, t14&, t15&, t16&
LOCAL retval& 'for macro use
'-- Verify that Serpent_Init has been called
if Ctx.K = 0 then
function = 0 : exit function
end if
x = Ctx.UserKeyLength
if(x < %MIN_KEY_SIZE) OR (x > %MAX_KEY_SIZE) then
function = 0 : exit function
end if
'-- bytes --> bits
x = (x * 8)
uk = Ctx.UserKey : k = Ctx.K 'local copies
i = 0 : lk = ((x + 31) \ 32)
do while (i < lk)
#IF %def(%VERIFY_IMPLEMENTATION)
j = @uk[lk-i-1] : @k[i] = byte_swap(j)
#ELSE
@k[i] = @uk[lk-i-1]
#ENDIF
incr i
loop
if (x < 256) then
do while (i < 8)
@k[i] = 0 : incr i
loop
make_marker(i,x,lk)
@k[i] = @k[i] AND (lk-1) OR lk
end if
for i = 0 to 131
lk = @k[i] XOR @k[i+3] XOR @k[i+5] XOR @k[i+7] XOR &h9e3779b9 XOR i
@k[i+8] = rotl_11(lk)
next i
k_set(0,a,b,c,d) : sb3(a,b,c,d,e,f,g,h) : k_get(0,e,f,g,h)
k_set(1,a,b,c,d) : sb2(a,b,c,d,e,f,g,h) : k_get(1,e,f,g,h)
k_set(2,a,b,c,d) : sb1(a,b,c,d,e,f,g,h) : k_get(2,e,f,g,h)
k_set(3,a,b,c,d) : sb0(a,b,c,d,e,f,g,h) : k_get(3,e,f,g,h)
k_set(4,a,b,c,d) : sb7(a,b,c,d,e,f,g,h) : k_get(4,e,f,g,h)
k_set(5,a,b,c,d) : sb6(a,b,c,d,e,f,g,h) : k_get(5,e,f,g,h)
k_set(6,a,b,c,d) : sb5(a,b,c,d,e,f,g,h) : k_get(6,e,f,g,h)
k_set(7,a,b,c,d) : sb4(a,b,c,d,e,f,g,h) : k_get(7,e,f,g,h)
k_set(8,a,b,c,d) : sb3(a,b,c,d,e,f,g,h) : k_get(8,e,f,g,h)
k_set(9,a,b,c,d) : sb2(a,b,c,d,e,f,g,h) : k_get(9,e,f,g,h)
k_set(10,a,b,c,d) : sb1(a,b,c,d,e,f,g,h) : k_get(10,e,f,g,h)
k_set(11,a,b,c,d) : sb0(a,b,c,d,e,f,g,h) : k_get(11,e,f,g,h)
k_set(12,a,b,c,d) : sb7(a,b,c,d,e,f,g,h) : k_get(12,e,f,g,h)
k_set(13,a,b,c,d) : sb6(a,b,c,d,e,f,g,h) : k_get(13,e,f,g,h)
k_set(14,a,b,c,d) : sb5(a,b,c,d,e,f,g,h) : k_get(14,e,f,g,h)
k_set(15,a,b,c,d) : sb4(a,b,c,d,e,f,g,h) : k_get(15,e,f,g,h)
k_set(16,a,b,c,d) : sb3(a,b,c,d,e,f,g,h) : k_get(16,e,f,g,h)
k_set(17,a,b,c,d) : sb2(a,b,c,d,e,f,g,h) : k_get(17,e,f,g,h)
k_set(18,a,b,c,d) : sb1(a,b,c,d,e,f,g,h) : k_get(18,e,f,g,h)
k_set(19,a,b,c,d) : sb0(a,b,c,d,e,f,g,h) : k_get(19,e,f,g,h)
k_set(20,a,b,c,d) : sb7(a,b,c,d,e,f,g,h) : k_get(20,e,f,g,h)
k_set(21,a,b,c,d) : sb6(a,b,c,d,e,f,g,h) : k_get(21,e,f,g,h)
k_set(22,a,b,c,d) : sb5(a,b,c,d,e,f,g,h) : k_get(22,e,f,g,h)
k_set(23,a,b,c,d) : sb4(a,b,c,d,e,f,g,h) : k_get(23,e,f,g,h)
k_set(24,a,b,c,d) : sb3(a,b,c,d,e,f,g,h) : k_get(24,e,f,g,h)
k_set(25,a,b,c,d) : sb2(a,b,c,d,e,f,g,h) : k_get(25,e,f,g,h)
k_set(26,a,b,c,d) : sb1(a,b,c,d,e,f,g,h) : k_get(26,e,f,g,h)
k_set(27,a,b,c,d) : sb0(a,b,c,d,e,f,g,h) : k_get(27,e,f,g,h)
k_set(28,a,b,c,d) : sb7(a,b,c,d,e,f,g,h) : k_get(28,e,f,g,h)
k_set(29,a,b,c,d) : sb6(a,b,c,d,e,f,g,h) : k_get(29,e,f,g,h)
k_set(30,a,b,c,d) : sb5(a,b,c,d,e,f,g,h) : k_get(30,e,f,g,h)
k_set(31,a,b,c,d) : sb4(a,b,c,d,e,f,g,h) : k_get(31,e,f,g,h)
k_set(32,a,b,c,d) : sb3(a,b,c,d,e,f,g,h) : k_get(32,e,f,g,h)
function = -1
END FUNCTION
'====================
FUNCTION EncryptBlock&(CTX AS ENCRYPTION_CONTEXT)
LOCAL a&, b&, c&, d&, e&, f&, g&, h&
LOCAL t1&, t2&, t3&, t4&, t5&, t6&, t7&, t8&
LOCAL t9&, t10&, t11&, t12&, t13&, t14&, t15&, t16&
LOCAL k AS LONG PTR
LOCAL retval& 'for macro use
#IF %def(%VERIFY_IMPLEMENTATION)
a = Ctx.@InBlock[3] : a = byte_swap(a)
b = Ctx.@InBlock[2] : b = byte_swap(b)
c = Ctx.@InBlock[1] : c = byte_swap(c)
d = Ctx.@InBlock[0] : d = byte_swap(d)
#ELSE
a = Ctx.@InBlock[3]
b = Ctx.@InBlock[2]
c = Ctx.@InBlock[1]
d = Ctx.@InBlock[0]
#ENDIF
k = Ctx.K 'local copy
k_xor(0,a,b,c,d) : sb0(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(1,e,f,g,h) : sb1(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(2,a,b,c,d) : sb2(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(3,e,f,g,h) : sb3(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(4,a,b,c,d) : sb4(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(5,e,f,g,h) : sb5(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(6,a,b,c,d) : sb6(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(7,e,f,g,h) : sb7(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(8,a,b,c,d) : sb0(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(9,e,f,g,h) : sb1(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(10,a,b,c,d) : sb2(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(11,e,f,g,h) : sb3(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(12,a,b,c,d) : sb4(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(13,e,f,g,h) : sb5(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(14,a,b,c,d) : sb6(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(15,e,f,g,h) : sb7(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(16,a,b,c,d) : sb0(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(17,e,f,g,h) : sb1(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(18,a,b,c,d) : sb2(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(19,e,f,g,h) : sb3(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(20,a,b,c,d) : sb4(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(21,e,f,g,h) : sb5(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(22,a,b,c,d) : sb6(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(23,e,f,g,h) : sb7(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(24,a,b,c,d) : sb0(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(25,e,f,g,h) : sb1(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(26,a,b,c,d) : sb2(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(27,e,f,g,h) : sb3(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(28,a,b,c,d) : sb4(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(29,e,f,g,h) : sb5(e,f,g,h,a,b,c,d) : rot(a,b,c,d)
k_xor(30,a,b,c,d) : sb6(a,b,c,d,e,f,g,h) : rot(e,f,g,h)
k_xor(31,e,f,g,h) : sb7(e,f,g,h,a,b,c,d)
k_xor(32,a,b,c,d)
#IF %def(%VERIFY_IMPLEMENTATION)
Ctx.@OutBlock[3] = byte_swap(a)
Ctx.@OutBlock[2] = byte_swap(b)
Ctx.@OutBlock[1] = byte_swap(c)
Ctx.@OutBlock[0] = byte_swap(d)
#ELSE
Ctx.@OutBlock[3] = a
Ctx.@OutBlock[2] = b
Ctx.@OutBlock[1] = c
Ctx.@OutBlock[0] = d
#ENDIF
END FUNCTION
'====================
FUNCTION DecryptBlock&(CTX AS ENCRYPTION_CONTEXT)
LOCAL a&, b&, c&, d&, e&, f&, g&, h&
LOCAL t1&, t2&, t3&, t4&, t5&, t6&, t7&, t8&
LOCAL t9&, t10&, t11&, t12&, t13&, t14&, t15&, t16&
LOCAL retval& 'for macro use
LOCAL k AS LONG PTR
#IF %def(%VERIFY_IMPLEMENTATION)
a = Ctx.@InBlock[3] : a = byte_swap(a)
b = Ctx.@InBlock[2] : b = byte_swap(b)
c = Ctx.@InBlock[1] : c = byte_swap(c)
d = Ctx.@InBlock[0] : d = byte_swap(d)
#ELSE
a = Ctx.@InBlock[3]
b = Ctx.@InBlock[2]
c = Ctx.@InBlock[1]
d = Ctx.@InBlock[0]
#ENDIF
k = Ctx.K 'local copy
k_xor(32,a,b,c,d)
ib7(a,b,c,d,e,f,g,h) : k_xor(31,e,f,g,h)
irot(e,f,g,h) : ib6(e,f,g,h,a,b,c,d) : k_xor(30,a,b,c,d)
irot(a,b,c,d) : ib5(a,b,c,d,e,f,g,h) : k_xor(29,e,f,g,h)
irot(e,f,g,h) : ib4(e,f,g,h,a,b,c,d) : k_xor(28,a,b,c,d)
irot(a,b,c,d) : ib3(a,b,c,d,e,f,g,h) : k_xor(27,e,f,g,h)
irot(e,f,g,h) : ib2(e,f,g,h,a,b,c,d) : k_xor(26,a,b,c,d)
irot(a,b,c,d) : ib1(a,b,c,d,e,f,g,h) : k_xor(25,e,f,g,h)
irot(e,f,g,h) : ib0(e,f,g,h,a,b,c,d) : k_xor(24,a,b,c,d)
irot(a,b,c,d) : ib7(a,b,c,d,e,f,g,h) : k_xor(23,e,f,g,h)
irot(e,f,g,h) : ib6(e,f,g,h,a,b,c,d) : k_xor(22,a,b,c,d)
irot(a,b,c,d) : ib5(a,b,c,d,e,f,g,h) : k_xor(21,e,f,g,h)
irot(e,f,g,h) : ib4(e,f,g,h,a,b,c,d) : k_xor(20,a,b,c,d)
irot(a,b,c,d) : ib3(a,b,c,d,e,f,g,h) : k_xor(19,e,f,g,h)
irot(e,f,g,h) : ib2(e,f,g,h,a,b,c,d) : k_xor(18,a,b,c,d)
irot(a,b,c,d) : ib1(a,b,c,d,e,f,g,h) : k_xor(17,e,f,g,h)
irot(e,f,g,h) : ib0(e,f,g,h,a,b,c,d) : k_xor(16,a,b,c,d)
irot(a,b,c,d) : ib7(a,b,c,d,e,f,g,h) : k_xor(15,e,f,g,h)
irot(e,f,g,h) : ib6(e,f,g,h,a,b,c,d) : k_xor(14,a,b,c,d)
irot(a,b,c,d) : ib5(a,b,c,d,e,f,g,h) : k_xor(13,e,f,g,h)
irot(e,f,g,h) : ib4(e,f,g,h,a,b,c,d) : k_xor(12,a,b,c,d)
irot(a,b,c,d) : ib3(a,b,c,d,e,f,g,h) : k_xor(11,e,f,g,h)
irot(e,f,g,h) : ib2(e,f,g,h,a,b,c,d) : k_xor(10,a,b,c,d)
irot(a,b,c,d) : ib1(a,b,c,d,e,f,g,h) : k_xor( 9,e,f,g,h)
irot(e,f,g,h) : ib0(e,f,g,h,a,b,c,d) : k_xor( 8,a,b,c,d)
irot(a,b,c,d) : ib7(a,b,c,d,e,f,g,h) : k_xor( 7,e,f,g,h)
irot(e,f,g,h) : ib6(e,f,g,h,a,b,c,d) : k_xor( 6,a,b,c,d)
irot(a,b,c,d) : ib5(a,b,c,d,e,f,g,h) : k_xor( 5,e,f,g,h)
irot(e,f,g,h) : ib4(e,f,g,h,a,b,c,d) : k_xor( 4,a,b,c,d)
irot(a,b,c,d) : ib3(a,b,c,d,e,f,g,h) : k_xor( 3,e,f,g,h)
irot(e,f,g,h) : ib2(e,f,g,h,a,b,c,d) : k_xor( 2,a,b,c,d)
irot(a,b,c,d) : ib1(a,b,c,d,e,f,g,h) : k_xor( 1,e,f,g,h)
irot(e,f,g,h) : ib0(e,f,g,h,a,b,c,d) : k_xor( 0,a,b,c,d)
#IF %def(%VERIFY_IMPLEMENTATION)
Ctx.@OutBlock[3] = byte_swap(a)
Ctx.@OutBlock[2] = byte_swap(b)
Ctx.@OutBlock[1] = byte_swap(c)
Ctx.@OutBlock[0] = byte_swap(d)
#ELSE
Ctx.@OutBlock[3] = a
Ctx.@OutBlock[2] = b
Ctx.@OutBlock[1] = c
Ctx.@OutBlock[0] = d
#ENDIF
END FUNCTION
'-- end SERPENT.BAS
'=====================================================================
' Serpent 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 SERPENT.BAS
#INCLUDE "SERPENT.BAS"
DECLARE FUNCTION Hex2Show$(Buffer$)
'====================
FUNCTION PBMain&()
EnterCC
LOCAL i&, key$, plain$, cipher$, shouldbe$, t$
LOCAL ctx AS ENCRYPTION_CONTEXT ' defined in SERPENT.BAS
Serpent_Init ctx
'-- Standard Serpent test vectors:
'-- 256-bit key
key = chr$(&h00,&h11,&h22,&h33,&h44,&h55,&h66,&h77,&h88,&h99,&haa,&hbb,&hcc,&hdd,&hee,&hff, _
&hff,&hee,&hdd,&hcc,&hbb,&haa,&h99,&h88,&h77,&h66,&h55,&h44,&h33,&h22,&h11,&h00)
plain = chr$(&h10,&h32,&h54,&h76,&h98,&hba,&hdc,&hfe,&hef,&hcd,&hab,&h89,&h67,&h45,&h23,&h01)
cipher = zbs(len(plain))
shouldbe = chr$(&h93,&hdf,&h9a,&h3c,&haf,&he3,&h87,&hbd,&h99,&h9e,&heb,&he3,&h93,&ha1,&h7f,&hca)
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$(&h00,&h11,&h22,&h33,&h44,&h55,&h66,&h77,&h88,&h99,&haa,&hbb,&hcc,&hdd,&hee,&hff, _
&hff,&hee,&hdd,&hcc,&hbb,&haa,&h99,&h88,&h77,&h66,&h55,&h44,&h33,&h22,&h11,&h00)
gosub DoDecrypt
t = t + "plain: " + Hex2Show$(plain) + eol + eol
'-- 192-bit key
key = chr$(&h88,&h99,&haa,&hbb,&hcc,&hdd,&hee,&hff,&hff,&hee,&hdd,&hcc,&hbb,&haa,&h99,&h88, _
&h77,&h66,&h55,&h44,&h33,&h22,&h11,&h00)
plain = chr$(&h10,&h32,&h54,&h76,&h98,&hba,&hdc,&hfe,&hef,&hcd,&hab,&h89,&h67,&h45,&h23,&h01)
cipher = zbs(len(plain))
shouldbe = chr$(&hda,&h86,&h08,&h42,&hb7,&h20,&h80,&h2b,&hf4,&h04,&ha4,&hc7,&h10,&h34,&h87,&h9a)
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$(&h88,&h99,&haa,&hbb,&hcc,&hdd,&hee,&hff,&hff,&hee,&hdd,&hcc,&hbb,&haa,&h99,&h88, _
&h77,&h66,&h55,&h44,&h33,&h22,&h11,&h00)
gosub DoDecrypt
t = t + "plain: " + Hex2Show$(plain) + eol + eol
'-- 128-bit key
key = chr$(&hff,&hee,&hdd,&hcc,&hbb,&haa,&h99,&h88,&h77,&h66,&h55,&h44,&h33,&h22,&h11,&h00)
plain = chr$(&h10,&h32,&h54,&h76,&h98,&hba,&hdc,&hfe,&hef,&hcd,&hab,&h89,&h67,&h45,&h23,&h01)
cipher = zbs(len(plain))
shouldbe = chr$(&hd5,&hba,&ha0,&h0a,&h4b,&hb9,&hd8,&ha7,&hc9,&h81,&hc8,&hdc,&h90,&hd8,&h9d,&h92)
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$(&hff,&hee,&hdd,&hcc,&hbb,&haa,&h99,&h88,&h77,&h66,&h55,&h44,&h33,&h22,&h11,&h00)
gosub DoDecrypt
t = t + "plain: " + Hex2Show$(plain) + eol + eol
mbox(t)
'============
ExitPBMain:
ExitCC
exit function
'============
DoEncrypt:
#IF %def(%VERIFY_IMPLEMENTATION) ' Set in SERPENT.BAS
'-- Because test vectors are reversed in the published documentation, the following
' action is necessary when verifying the implementation.
plain = strreverse$(plain) : key = strreverse$(key) : shouldbe = strreverse$(shouldbe)
#ENDIF
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 16) = 0
EncryptBlock ctx
ctx.InBlock = ctx.InBlock + %BLOCKSIZE
ctx.OutBlock = ctx.OutBlock + %BLOCKSIZE
next i&
else
mbox("Error")
end if
'-- Burn the subkey
poke$ Ctx.K, zbs(sizeof(Ctx.K_Buffer))
RETURN
'============
DoDecrypt:
#IF %def(%VERIFY_IMPLEMENTATION)
key = strreverse$(key)
#ENDIF
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 16) = 0
DecryptBlock ctx
ctx.InBlock = ctx.InBlock + %BLOCKSIZE
ctx.OutBlock = ctx.OutBlock + %BLOCKSIZE
next i
else
mbox("Error")
end if
#IF %def(%VERIFY_IMPLEMENTATION)
plain = strreverse$(plain)
#ENDIF
'-- Burn the subkey
poke$ Ctx.K, zbs(sizeof(Ctx.K_Buffer))
RETURN
END FUNCTION
'====================
FUNCTION Hex2Show$(Buffer$)
REGISTER i&
LOCAL t$, 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