Regarding the implementation, you might want to read the notes about the endianness. Also, you will need the 3 files called
that are available here: http://www.cs.technion.ac.il/~biham/Reports/Serpent/ to test it. You should copy them to the same dir where "Serpent_VectorTest.pb" resides. One more thing: this code is pretty slow, but maybe someone will find a solution to speed it up a bitSerpent-128-128.verified.test-vectors
Serpent-192-128.verified.test-vectors
Serpent-256-128.verified.test-vectors

That's about it, hope it will be useful.
Serpent.pbi
Code: Select all
;/----------------------------------------------------------------------------------
;
; Include description : The Serpent cipher in ECB and CBC modes
; Algo designers : Ross Anderson, Eli Biham and Lars Knudsen
; More info : http://en.wikipedia.org/wiki/Serpent_%28cipher%29
; Cryptanalysis : All known attacks are computationally infeasible. A 2011 attack
; breaks 11 round Serpent (all key sizes) with 2^116 known plaintexts,
; 2^107.5 time and 2^104 memory.
; Impl. author : Alexandru Trutia
; Date : 24 may 2014
; Version : 1.0
; Target Compiler : PureBasic 5.22+
; Target OS : Windows x86 (not tested on any other operating systems)
; License : Free, unrestricted, no warranty whatsoever
; Use at your own risk
; Additional notes : 1. The key can have a minimum of 128 bits (16 bytes) to a
; maximum of 256 bits (32 bytes). 192 bit encryption is also
; possible.
; 2. serpent_encoder / serpent_decoder need minimum 16 bytes buffers
; 3. This implementation can work in LE or BE modes by setting the
; #SERPENT_BO constant as shown below.
; 4. The output buffer will be exactly as big as the input one
; because this code uses Residual block termination padding.
; (http://www.technology-base.org/wiki/index.php?n=Main.IRBT)
;
;/----------------------------------------------------------------------------------
;
;Original header:
;
;/* 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 */
;
;/----------------------------------------------------------------------------------
EnableExplicit
#SERPENT_BLOCK_SIZE = 16
;/----------------------------------------------------------------------------------
;These values have no effect on the security. Like some other ciphers out there, Serpent
;was designed on big endian machines. This implementation was created for Intel x86
;processors that use the little endian format. The problem is that some test vectors for
;Serpent are in little endian and some in big endian format, so make sure to switch to the
;needed mode with these values. For production code you might want to use
;#SERPENT_ENDIAN_AS_IS since it's a bit faster.
Enumeration
#SERPENT_ENDIAN_AS_IS ;This will leave data as-is.
#SERPENT_ENDIAN_BSWAP ;This will convert the key, input and output data to little endian, adds overhead.
EndEnumeration
Enumeration
#SERPENT_CBC ;Recommended, uses a 128 bit IV (16 bytes)
#SERPENT_ECB
EndEnumeration
#SERPENT_BO = #SERPENT_ENDIAN_AS_IS
;/----------------------------------------------------------------------------------
Structure serpent_ctx
l_key.l[140]
EndStructure
Structure asciiarray
a.a[0]
EndStructure
Structure longarray
l.l[0]
EndStructure
;-----------------------------------------------------------------------------------
Procedure.l rotl32(value.l, count.l = 1)
;by mk-soft
;found here: http://forums.purebasic.com/english/viewtopic.php?p=272695&sid=0269f75f2190bc2765a21c29c86e8ae5#p272695
!mov eax, dword [p.v_value]
!mov ecx, dword [p.v_count]
!rol eax, cl
ProcedureReturn
EndProcedure
Procedure.l rotr32(value.l, count.l = 1)
;by mk-soft
;found here: http://forums.purebasic.com/english/viewtopic.php?p=272695&sid=0269f75f2190bc2765a21c29c86e8ae5#p272695
!mov eax, dword [p.v_value]
!mov ecx, dword [p.v_count]
!ror eax, cl
ProcedureReturn
EndProcedure
Procedure.l shl32(value.l, count.l = 1)
;by mk-soft
;found here: http://forums.purebasic.com/english/viewtopic.php?p=272695&sid=0269f75f2190bc2765a21c29c86e8ae5#p272695
!mov eax, dword [p.v_value]
!mov ecx, dword [p.v_count]
!shl eax, cl
ProcedureReturn
EndProcedure
Procedure.l shr32(value.l, count.l = 1)
;by mk-soft
;found here: http://forums.purebasic.com/english/viewtopic.php?p=272695&sid=0269f75f2190bc2765a21c29c86e8ae5#p272695
!mov eax, dword [p.v_value]
!mov ecx, dword [p.v_count]
!shr eax, cl
ProcedureReturn
EndProcedure
Procedure.l bswap32(val.l)
!mov eax,dword[p.v_val]
!bswap eax
ProcedureReturn
EndProcedure
Procedure xorbuffer(*buff1.asciiarray, *buff2.asciiarray, bufflen)
;Note: Result returned in *buff1
;Vars
Protected i
;Begin
While i < bufflen
*buff1\a[i] ! *buff2\a[i]
i + 1
Wend
EndProcedure
;-----------------------------------------------------------------------------------
Macro sb0(a,b,c,d,e,f,g,h)
t1 = a ! d
t2 = a & d
t3 = c ! t1
t6 = b & t1
t4 = b ! t3
t10 = ~t3
h = t2 ! t4
t7 = a ! t6
t14 = ~t7
t8 = c | t7
t11 = t3 ! t7
g = t4 ! t8
t12 = h & t11
f = t10 ! t12
e = t12 ! t14
EndMacro
Macro ib0(a,b,c,d,e,f,g,h)
t1 = ~a
t2 = a ! b
t3 = t1 | t2
t4 = d ! t3
t7 = d & t2
t5 = c ! t4
t8 = t1 ! t7
g = t2 ! t5
t11 = a & t4
t9 = g & t8
t14 = t5 ! t8
f = t4 ! t9
t12 = t5 | f
h = t11 ! t12
e = h ! t14
EndMacro
Macro sb1(a,b,c,d,e,f,g,h)
t1 = ~a
t2 = b ! t1
t3 = a | t2
t4 = d | t2
t5 = c ! t3
g = d ! t5
t7 = b ! t4
t8 = t2 ! g
t9 = t5 & t7
h = t8 ! t9
t11 = t5 ! t7
f = h ! t11
t13 = t8 & t11
e = t5 ! t13
EndMacro
Macro ib1(a,b,c,d,e,f,g,h)
t1 = a ! d
t2 = a & b
t3 = b ! c
t4 = a ! t3
t5 = b | d
t7 = c | t1
h = t4 ! t5
t8 = b ! t7
t11 = ~t2
t9 = t4 & t8
f = t1 ! t9
t13 = t9 ! t11
t12 = h & f
g = t12 ! t13
t15 = a & d
t16 = c ! t13
e = t15 ! t16
EndMacro
Macro sb2(a,b,c,d,e,f,g,h)
t1 = ~a
t2 = b ! d
t3 = c & t1
t13 = d | t1
e = t2 ! t3
t5 = c ! t1
t6 = c ! e
t7 = b & t6
t10 = e | t5
h = t5 ! t7
t9 = d | t7
t11 = t9 & t10
t14 = t2 ! h
g = a ! t11
t15 = g ! t13
f = t14 ! t15
EndMacro
Macro ib2(a,b,c,d,e,f,g,h)
t1 = b ! d
t2 = ~t1
t3 = a ! c
t4 = c ! t1
t7 = a | t2
t5 = b & t4
t8 = d ! t7
t11 = ~t4
e = t3 ! t5
t9 = t3 | t8
t14 = d & t11
h = t1 ! t9
t12 = e | h
f = t11 ! t12
t15 = t3 ! t12
g = t14 ! t15
EndMacro
Macro sb3(a,b,c,d,e,f,g,h)
t1 = a ! c
t2 = d ! t1
t3 = a & t2
t4 = d ! t3
t5 = b & t4
g = t2 ! t5
t7 = a | g
t8 = b | d
t11 = a | d
t9 = t4 & t7
f = t8 ! t9
t12 = b ! t11
t13 = g ! t9
t15 = t3 ! t8
h = t12 ! t13
t16 = c & t15
e = t12 ! t16
EndMacro
Macro ib3(a,b,c,d,e,f,g,h)
t1 = b ! c
t2 = b | c
t3 = a ! c
t7 = a ! d
t4 = t2 ! t3
t5 = d | t4
t9 = t2 ! t7
e = t1 ! t5
t8 = t1 | t5
t11 = a & t4
g = t8 ! t9
t12 = e | t9
f = t11 ! t12
t14 = a & g
t15 = t2 ! t14
t16 = e & t15
h = t4 ! t16
EndMacro
Macro sb4(a,b,c,d,e,f,g,h)
t1 = a ! d
t2 = d & t1
t3 = c ! t2
t4 = b | t3
h = t1 ! t4
t6 = ~b
t7 = t1 | t6
e = t3 ! t7
t9 = a & e
t10 = t1 ! t6
t11 = t4 & t10
g = t9 ! t11
t13 = a ! t3
t14 = t10 & g
f = t13 ! t14
EndMacro
Macro ib4(a,b,c,d,e,f,g,h)
t1 = c ! d
t2 = c | d
t3 = b ! t2
t4 = a & t3
f = t1 ! t4
t6 = a ! d
t7 = b | d
t8 = t6 & t7
h = t3 ! t8
t10 = ~a
t11 = c ! h
t12 = t10 | t11
e = t3 ! t12
t14 = c | t4
t15 = t7 ! t14
t16 = h | t10
g = t15 ! t16
EndMacro
Macro sb5(a,b,c,d,e,f,g,h)
t1 = ~a
t2 = a ! b
t3 = a ! d
t4 = c ! t1
t5 = t2 | t3
e = t4 ! t5
t7 = d & e
t8 = t2 ! e
t10 = t1 | e
f = t7 ! t8
t11 = t2 | t7
t12 = t3 ! t10
t14 = b ! t7
g = t11 ! t12
t15 = f & t12
h = t14 ! t15
EndMacro
Macro ib5(a,b,c,d,e,f,g,h)
t1 = ~c
t2 = b & t1
t3 = d ! t2
t4 = a & t3
t5 = b ! t1
h = t4 ! t5
t7 = b | h
t8 = a & t7
f = t3 ! t8
t10 = a | d
t11 = t1 ! t7
e = t10 ! t11
t13 = a ! c
t14 = b & t10
t15 = t4 | t13
g = t14 ! t15
EndMacro
Macro sb6(a,b,c,d,e,f,g,h)
t1 = ~a
t2 = a ! d
t3 = b ! t2
t4 = t1 | t2
t5 = c ! t4
f = b ! t5
t13 = ~t5
t7 = t2 | f
t8 = d ! t7
t9 = t5 & t8
g = t3 ! t9
t11 = t5 ! t8
e = g ! t11
t14 = t3 & t11
h = t13 ! t14
EndMacro
Macro ib6(a,b,c,d,e,f,g,h)
t1 = ~a
t2 = a ! b
t3 = c ! t2
t4 = c | t1
t5 = d ! t4
t13 = d & t1
f = t3 ! t5
t7 = t3 & t5
t8 = t2 ! t7
t9 = b | t8
h = t5 ! t9
t11 = b | h
e = t8 ! t11
t14 = t3 ! t11
g = t13 ! t14
EndMacro
Macro sb7(a,b,c,d,e,f,g,h)
t1 = ~c
t2 = b ! c
t3 = b | t1
t4 = d ! t3
t5 = a & t4
t7 = a ! d
h = t2 ! t5
t8 = b ! t5
t9 = t2 | t8
t11 = d & t3
f = t7 ! t9
t12 = t5 ! f
t15 = t1 | t4
t13 = h & t12
g = t11 ! t13
t16 = t12 ! g
e = t15 ! t16
EndMacro
Macro ib7(a,b,c,d,e,f,g,h)
t1 = a & b
t2 = a | b
t3 = c | t1
t4 = d & t2
h = t3 ! t4
t6 = ~d
t7 = b ! t4
t8 = h ! t6
t11 = c ! t7
t9 = t7 | t8
f = a ! t9
t12 = d | f
e = t11 ! t12
t14 = a & h
t15 = t3 ! f
t16 = e ! t14
g = t15 ! t16
EndMacro
Macro k_xor(r,a,b,c,d)
a ! *ctx\l_key[4 * r + 8]
b ! *ctx\l_key[4 * r + 9]
c ! *ctx\l_key[4 * r + 10]
d ! *ctx\l_key[4 * r + 11]
EndMacro
Macro k_set(r,a,b,c,d)
a = *ctx\l_key[4 * r + 8]
b = *ctx\l_key[4 * r + 9]
c = *ctx\l_key[4 * r + 10]
d = *ctx\l_key[4 * r + 11]
EndMacro
Macro k_get(r,a,b,c,d)
*ctx\l_key[4 * r + 8] = a
*ctx\l_key[4 * r + 9] = b
*ctx\l_key[4 * r + 10] = c
*ctx\l_key[4 * r + 11] = d
EndMacro
Macro rot(a,b,c,d)
a = rotl32(a, 13)
c = rotl32(c, 3)
d ! c ! (a << 3)
b ! a ! c
d = rotl32(d, 7)
b = rotl32(b, 1)
a ! b ! d
c ! d ! (b << 7)
a = rotl32(a, 5)
c = rotl32(c, 22)
EndMacro
Macro irot(a,b,c,d)
c = rotr32(c, 22)
a = rotr32(a, 5)
c ! d ! shl32(b, 7)
a ! b ! d
d = rotr32(d, 7)
b = rotr32(b, 1)
d ! c ! shl32(a, 3)
b ! a ! c
c = rotr32(c, 3)
a = rotr32(a, 13)
EndMacro
;-----------------------------------------------------------------------------------
Procedure serpent_encrypt(*ctx.serpent_ctx, *in_blk.longarray, *out_blk.longarray)
Protected.l a, b, c, d, e, f, g, h, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16
CompilerIf #SERPENT_BO = #SERPENT_ENDIAN_AS_IS
a = *in_blk\l[0]
b = *in_blk\l[1]
c = *in_blk\l[2]
d = *in_blk\l[3]
CompilerElseIf #SERPENT_BO = #SERPENT_ENDIAN_BSWAP
a = bswap32(*in_blk\l[3])
b = bswap32(*in_blk\l[2])
c = bswap32(*in_blk\l[1])
d = bswap32(*in_blk\l[0])
CompilerEndIf
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)
CompilerIf #SERPENT_BO = #SERPENT_ENDIAN_AS_IS
*out_blk\l[0] = a
*out_blk\l[1] = b
*out_blk\l[2] = c
*out_blk\l[3] = d
CompilerElseIf #SERPENT_BO = #SERPENT_ENDIAN_BSWAP
*out_blk\l[3] = bswap32(a)
*out_blk\l[2] = bswap32(b)
*out_blk\l[1] = bswap32(c)
*out_blk\l[0] = bswap32(d)
CompilerEndIf
EndProcedure
Procedure serpent_decrypt(*ctx.serpent_ctx, *in_blk.longarray, *out_blk.longarray)
Protected.l a, b, c, d, e, f, g, h, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16
CompilerIf #SERPENT_BO = #SERPENT_ENDIAN_AS_IS
a = *in_blk\l[0]
b = *in_blk\l[1]
c = *in_blk\l[2]
d = *in_blk\l[3]
CompilerElseIf #SERPENT_BO = #SERPENT_ENDIAN_BSWAP
a = bswap32(*in_blk\l[3])
b = bswap32(*in_blk\l[2])
c = bswap32(*in_blk\l[1])
d = bswap32(*in_blk\l[0])
CompilerEndIf
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)
CompilerIf #SERPENT_BO = #SERPENT_ENDIAN_AS_IS
*out_blk\l[0] = a
*out_blk\l[1] = b
*out_blk\l[2] = c
*out_blk\l[3] = d
CompilerElseIf #SERPENT_BO = #SERPENT_ENDIAN_BSWAP
*out_blk\l[3] = bswap32(a)
*out_blk\l[2] = bswap32(b)
*out_blk\l[1] = bswap32(c)
*out_blk\l[0] = bswap32(d)
CompilerEndIf
EndProcedure
;-----------------------------------------------------------------------------------
;*ctx(in) = A context buffer allocated with sizeof(serpent_ctx) bytes
;*in_key(in) = The key (password) buffer. Never pass a *in_key buffer smaller than 128 or bigger than 256 bytes!
;key_len(in) = The length of the key in bits (e.g. 128, 192 or 256)
Procedure serpent_keysetup(*ctx.serpent_ctx, *in_key.longarray, key_len)
Protected.l i, lk, a, b, c, d, e, f, g, h, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16
If key_len > 256 Or key_len < 0
ProcedureReturn 0
EndIf
i = 0
lk = (key_len + 31) / 32
While i < lk
CompilerIf #SERPENT_BO = #SERPENT_ENDIAN_AS_IS
*ctx\l_key[i] = *in_key\l[i]
CompilerElseIf #SERPENT_BO = #SERPENT_ENDIAN_BSWAP
*ctx\l_key[i] = bswap32(*in_key\l[lk - i - 1])
CompilerEndIf
i + 1
Wend
If key_len < 256
While i < 8
*ctx\l_key[i + 1] = 0
i + 1
Wend
i = key_len / 32
lk = shl32(1 , key_len) % 32
*ctx\l_key[i] = *ctx\l_key[i] & (lk - 1) | lk
EndIf
i = 0
While i < 132
lk = *ctx\l_key[i] ! *ctx\l_key[i + 3] ! *ctx\l_key[i + 5] ! *ctx\l_key[i + 7] ! $9E3779B9 ! i
*ctx\l_key[i + 8] = shl32(lk , 11) | shr32(lk , 21)
i + 1
Wend
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)
ProcedureReturn 1
EndProcedure
;*ctx(in) = A context buffer initialized with serpent_keysetup above
;*in(in) = Input buffer, must be bigger than 16 bytes
;*out(out) = Output buffer, 16 bytes minimum. Must be different from *in, same size as *in
;size(in) = Input (and output) buffer size in bytes
;mode(in) = Encryption mode. Can be either #SERPENT_CBC (recommended) or #SERPENT_ECB (to be avoided)
;*iv(in) = Initialization vector, 16 bytes of random data. Needed only in CBC mode
;*cb(in) = Optional callback procedure address for monitoring progress. Takes 2 integer parameters.
Procedure serpent_encoder(*ctx.serpent_ctx, *in, *out, size, *iv, mode = #SERPENT_CBC, *cb=0)
;Vars
Protected totalrounds, remainingbytes, *temp, encrypt, currentblock, result, *remaining, *remainingout
;Begin
If *in <> 0 And *out <> 0 And size >= #SERPENT_BLOCK_SIZE
If mode = #SERPENT_CBC
If *iv = 0 ;Check IV
Debug "[!] Serpent in CBC mode needs an initialization vector!"
CallDebugger
EndIf
EndIf
;See how many rounds to make and how many bytes remain
totalrounds = size / #SERPENT_BLOCK_SIZE
remainingbytes = size % #SERPENT_BLOCK_SIZE
*temp = AllocateMemory(#SERPENT_BLOCK_SIZE)
If *temp <> 0
;Encrypt the full rounds
While encrypt < totalrounds
;Copy the block in the temp buffer
CopyMemory(*in + currentblock, *temp, #SERPENT_BLOCK_SIZE)
If mode = #SERPENT_CBC
If encrypt = 0 ;For the first block, XOR with the IV
xorbuffer(*temp, *iv, #SERPENT_BLOCK_SIZE)
Else ;For the subsequent blocks, XOR with the previous block
xorbuffer(*temp, *out + currentblock - #SERPENT_BLOCK_SIZE, #SERPENT_BLOCK_SIZE)
EndIf
EndIf
;Encrypt the block
serpent_encrypt(*ctx, *temp, *out + currentblock)
;Call the callback
If *cb <> 0 And (encrypt % 64) = 1 ;called every 64 encrypted blocks
CallFunctionFast(*cb, encrypt, totalrounds)
EndIf
;Increment vars
currentblock + #SERPENT_BLOCK_SIZE
encrypt + 1
Wend
;The remaining bytes will be padded in RBT-mode then encrypted
If remainingbytes > 0
;Allocate memory for the operations
*remaining = AllocateMemory(remainingbytes)
*remainingout = AllocateMemory(#SERPENT_BLOCK_SIZE)
If *remaining <> 0 And *remainingout <> 0
;Copy the remaining bytes in a temporary buffer
CopyMemory(*in + size - remainingbytes, *remaining, remainingbytes)
;Re-encrypt the last block
serpent_encrypt(*ctx, *out + currentblock - #SERPENT_BLOCK_SIZE, *remainingout)
;Use the leftmost bytes of this re-encrypted block as a key for XOR-ing the remaining data
xorbuffer(*remaining, *remainingout, remainingbytes)
;Finally, copy the XORed remaining data to the output buffer
CopyMemory(*remaining, *out + currentblock, remainingbytes)
;Clean up
FreeMemory(*remaining)
FreeMemory(*remainingout)
result = 1
EndIf
Else
result = 1
EndIf
;Call the callback
If *cb <> 0
CallFunctionFast(*cb, totalrounds, totalrounds)
EndIf
;Clean up
FreeMemory(*temp)
EndIf
EndIf
;Return
ProcedureReturn result
EndProcedure
;*ctx(in) = A context buffer initialized with serpent_keysetup above
;*in(in) = Input buffer, must be bigger than 16 bytes
;*out(out) = Output buffer, 16 bytes minimum. Must be different from *in, same size as *in
;size(in) = Input (and output) buffer size in bytes
;mode(in) = Decryption mode. Can be either #SERPENT_CBC or #SERPENT_ECB
;*iv(in) = Initialization vector that was used for encryption. Needed only in CBC mode
;*cb(in) = Optional callback procedure address for monitoring progress. Takes 2 integer parameters.
Procedure serpent_decoder(*ctx.serpent_ctx, *in, *out, size, *iv, mode = #SERPENT_CBC, *cb=0)
;Vars
Protected totalrounds, remainingbytes, *temp, decrypt, currentblock, result, *remaining, *remainingout
;Begin
If *in <> 0 And *out <> 0 And size >= #SERPENT_BLOCK_SIZE
If mode = #SERPENT_CBC
If *iv = 0 ;Check IV
Debug "[!] Serpent in CBC mode needs an initialization vector!"
CallDebugger
EndIf
EndIf
;See how many rounds to make and how many bytes remain
totalrounds = size / #SERPENT_BLOCK_SIZE
remainingbytes = size % #SERPENT_BLOCK_SIZE
*temp = AllocateMemory(#SERPENT_BLOCK_SIZE)
If *temp <> 0
;Decrypt the full rounds
While decrypt < totalrounds
;Copy the block in the temp buffer
CopyMemory(*in + currentblock, *temp, #SERPENT_BLOCK_SIZE)
;Decrypt the block
serpent_decrypt(*ctx, *temp, *out + currentblock)
If mode = #SERPENT_CBC
If decrypt = 0 ;For the first block, XOR with the IV
xorbuffer(*out + currentblock, *iv, #SERPENT_BLOCK_SIZE)
Else ;For the subsequent blocks, XOR with the previous input block
xorbuffer(*out + currentblock, *in + currentblock - #SERPENT_BLOCK_SIZE, #SERPENT_BLOCK_SIZE)
EndIf
EndIf
;Call the callback
If *cb <> 0 And (decrypt % 64) = 1 ;called every 64 encrypted blocks
CallFunctionFast(*cb, decrypt, totalrounds)
EndIf
;Increment vars
currentblock + #SERPENT_BLOCK_SIZE
decrypt + 1
Wend
;For RBT mode, we need to decrypt the remaining bytes
If remainingbytes > 0
;Allocate memory for the operations
*remaining = AllocateMemory(remainingbytes)
If *remaining <> 0
;Copy the remaining bytes in a temporary buffer
CopyMemory(*in + size - remainingbytes, *remaining, remainingbytes)
;Re-encrypt the last block
serpent_encrypt(*ctx, *in + currentblock - #SERPENT_BLOCK_SIZE, *temp)
;Use the leftmost bytes of this re-encrypted block as a key for XOR-ing the remaining data
xorbuffer(*remaining, *temp, remainingbytes)
;Copy the XORed remaining data to the output buffer
CopyMemory(*remaining, *out + currentblock, remainingbytes)
;Clean up
FreeMemory(*remaining)
result = 1
EndIf
Else
result = 1
EndIf
;Call the callback
If *cb <> 0
CallFunctionFast(*cb, totalrounds, totalrounds)
EndIf
;Clean up
FreeMemory(*temp)
EndIf
EndIf
;Return
ProcedureReturn result
EndProcedure
;-----------------------------------------------------------------------------------
DisableExplicit