Serpent cipher include (x86) (24 May 2014)
Posted: Sat May 24, 2014 2:43 pm
Here is another secure cipher for use in your programs along the default encryption that PureBasic offers. Serpent was an AES finalist and while it lost to Rijndael, it actually is considered to be more secure. It is a block cipher with a block size of 128 bit (16 bytes), and keys of 128, 192 and 256 bits. You can find more information about it here: http://en.wikipedia.org/wiki/Serpent_%28cipher%29.
Regarding the implementation, you might want to read the notes about the endianness. Also, you will need the 3 files called
.
That's about it, hope it will be useful.
Serpent.pbi
Examples below:
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