Rabbit stream cipher include (x86) (8 Jun 2014)
Posted: Sun Jun 08, 2014 12:45 pm
For the sake of improving PB's crypto capabilities, I present to you an implementation of the Rabbit stream cipher. It has a key size of 128 bits (16 bytes) and an IV size of 64 bits (8 bytes). It was developed by Cryptico A/S as a high-speed synchronous cipher and it was patented, but as of 2008 the designers released the cipher into the public domain and now it's free for any use (see here). More information about it can be found here:
http://en.wikipedia.org/wiki/Rabbit_%28cipher%29
http://cryptico.com/cryptolab.html
http://www.ecrypt.eu.org/stream/e2-rabbit.html
http://tools.ietf.org/html/rfc4503
Please have a look at the implementation code before using it in your own software just in case I overlooked something.
Rabbit.pbi
Examples below:
http://en.wikipedia.org/wiki/Rabbit_%28cipher%29
http://cryptico.com/cryptolab.html
http://www.ecrypt.eu.org/stream/e2-rabbit.html
http://tools.ietf.org/html/rfc4503
Please have a look at the implementation code before using it in your own software just in case I overlooked something.
Rabbit.pbi
Code: Select all
;/----------------------------------------------------------------------------------
;
; Include description : The Rabbit stream cipher
; Algo designers : Martin Boesgaard, Mette Vesterager, Thomas Pedersen,
; Jesper Christiansen and Ove Scavenius
; More info : http://en.wikipedia.org/wiki/Rabbit_%28cipher%29
; http://cryptico.com/cryptolab.html
; http://www.ecrypt.eu.org/stream/e2-rabbit.html
; http://tools.ietf.org/html/rfc4503
; Cryptanalysis : Rabbit claims 128-bit security against attackers whose target
; is one specific key. If, however, the attacker targets a large
; number of keys at once and does not really care which one he
; breaks, then the small IV size results in a reduced security
; level of 96 bit. This is due to generic TMD trade-off attacks.
; A small bias in the output of Rabbit exists, resulting in a
; distinguisher with 2^158 complexity but it's not a threat to
; Rabbit's security because its complexity is significantly higher
; than the brute-force of the key space (2^128).
; Impl. author : Alexandru Trutia based on the original from Cryptico A/S
; Date : 08 Jun 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. After using RABBIT_process_bytes to encrypt or decrypt data,
; RABBIT_ivsetup must be called again to set the IV before
; encrypting or decrypting data again with RABBIT_process_bytes
; 2. Cryptico had patents pending for the algorithm and for many
; years required a license fee for commercial use of the cipher
; which was waived for non-commercial uses. However, the algorithm
; was made free for any use on October 6, 2008.
;
;/----------------------------------------------------------------------------------
EnableExplicit
Structure RABBIT_state
x.l[8]
c.l[8]
carry.l
EndStructure
Structure RABBIT_ctx
master.RABBIT_state
work.RABBIT_state
EndStructure
Structure asciiarray
a.a[0]
EndStructure
Structure longarray
l.l[0]
EndStructure
;-----------------------------------------------------------------------------------
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 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
;-----------------------------------------------------------------------------------
Macro RABBIT_U32V(Value)
(Value & $FFFFFFFF)
EndMacro
Macro RABBIT_U32ST(a, b, c, isproc)
;Compares unsigned integers a and b as below:
;If (uint32)a < (uint32)b then
; (byte)c = 1
;Else
; (byte)c = 0
;Endif
CompilerIf isproc = 1
!mov ebx,dword[p.v_#a]
!cmp ebx,[p.v_#b]
!setb byte [p.v_#c]
CompilerElse
!mov ebx,dword[v_#a]
!cmp ebx,[v_#b]
!setb byte [v_#c]
CompilerEndIf
EndMacro
Macro RABBIT_g_func(x, y)
;Construct high and low argument for squaring
a = x & $FFFF
b = shr32(x, 16) & $FFFF
;Calculate high and low result of squaring
h = shr32((shr32(RABBIT_U32V(a * a), 17) + RABBIT_U32V(a * b)), 15) + b * b
l = x * x
;Return high XOr low
y = RABBIT_U32V(h ! l)
EndMacro
Procedure RABBIT_U8TO32(*in.asciiarray)
ProcedureReturn *in\a[0] + (*in\a[1] << 8) + (*in\a[2] << 16) + (*in\a[3] << 24)
EndProcedure
Procedure RABBIT_next_state(*p_instance.RABBIT_state)
;Temporary variables
Dim g.l(7)
Dim c_old.l(7)
Protected i.l, j.l, k.a, a.l, b.l, h.l, l.l
;Save old counter values
c_old(0) = *p_instance\c[0]
c_old(1) = *p_instance\c[1]
c_old(2) = *p_instance\c[2]
c_old(3) = *p_instance\c[3]
c_old(4) = *p_instance\c[4]
c_old(5) = *p_instance\c[5]
c_old(6) = *p_instance\c[6]
c_old(7) = *p_instance\c[7]
;Calculate new counter values
*p_instance\c[0] = RABBIT_U32V(*p_instance\c[0] + $4D34D34D + *p_instance\carry)
i = *p_instance\c[0] : j = c_old(0)
RABBIT_U32ST(i, j, k, 1)
*p_instance\c[1] = RABBIT_U32V(*p_instance\c[1] + $D34D34D3 + k)
i = *p_instance\c[1] : j = c_old(1)
RABBIT_U32ST(i, j, k, 1)
*p_instance\c[2] = RABBIT_U32V(*p_instance\c[2] + $34D34D34 + k)
i = *p_instance\c[2] : j = c_old(2)
RABBIT_U32ST(i, j, k, 1)
*p_instance\c[3] = RABBIT_U32V(*p_instance\c[3] + $4D34D34D + k)
i = *p_instance\c[3] : j = c_old(3)
RABBIT_U32ST(i, j, k, 1)
*p_instance\c[4] = RABBIT_U32V(*p_instance\c[4] + $D34D34D3 + k)
i = *p_instance\c[4] : j = c_old(4)
RABBIT_U32ST(i, j, k, 1)
*p_instance\c[5] = RABBIT_U32V(*p_instance\c[5] + $34D34D34 + k)
i = *p_instance\c[5] : j = c_old(5)
RABBIT_U32ST(i, j, k, 1)
*p_instance\c[6] = RABBIT_U32V(*p_instance\c[6] + $4D34D34D + k)
i = *p_instance\c[6] : j = c_old(6)
RABBIT_U32ST(i, j, k, 1)
*p_instance\c[7] = RABBIT_U32V(*p_instance\c[7] + $D34D34D3 + k)
i = *p_instance\c[7] : j = c_old(7)
RABBIT_U32ST(i, j, k, 1)
*p_instance\carry = k
;Calculate the g-values
RABBIT_g_func(RABBIT_U32V(*p_instance\x[0] + *p_instance\c[0]), g(0))
RABBIT_g_func(RABBIT_U32V(*p_instance\x[1] + *p_instance\c[1]), g(1))
RABBIT_g_func(RABBIT_U32V(*p_instance\x[2] + *p_instance\c[2]), g(2))
RABBIT_g_func(RABBIT_U32V(*p_instance\x[3] + *p_instance\c[3]), g(3))
RABBIT_g_func(RABBIT_U32V(*p_instance\x[4] + *p_instance\c[4]), g(4))
RABBIT_g_func(RABBIT_U32V(*p_instance\x[5] + *p_instance\c[5]), g(5))
RABBIT_g_func(RABBIT_U32V(*p_instance\x[6] + *p_instance\c[6]), g(6))
RABBIT_g_func(RABBIT_U32V(*p_instance\x[7] + *p_instance\c[7]), g(7))
;Calculate new state values
*p_instance\x[0] = RABBIT_U32V(g(0) + rotl32(g(7),16) + rotl32(g(6), 16))
*p_instance\x[1] = RABBIT_U32V(g(1) + rotl32(g(0), 8) + g(7))
*p_instance\x[2] = RABBIT_U32V(g(2) + rotl32(g(1),16) + rotl32(g(0), 16))
*p_instance\x[3] = RABBIT_U32V(g(3) + rotl32(g(2), 8) + g(1))
*p_instance\x[4] = RABBIT_U32V(g(4) + rotl32(g(3),16) + rotl32(g(2), 16))
*p_instance\x[5] = RABBIT_U32V(g(5) + rotl32(g(4), 8) + g(3))
*p_instance\x[6] = RABBIT_U32V(g(6) + rotl32(g(5),16) + rotl32(g(4), 16))
*p_instance\x[7] = RABBIT_U32V(g(7) + rotl32(g(6), 8) + g(5))
EndProcedure
;-----------------------------------------------------------------------------------
; Key setup. It is the user's responsibility to select the values of
; keysize and ivsize from the set of supported values specified
; above (keysize = 128 and ivsize = 64) in bits.
Procedure RABBIT_keysetup(*ctx.RABBIT_ctx, *key, keysize, ivsize)
;Temporary variables
Protected k0.l, k1.l, k2.l, k3.l
;Generate four subkeys
k0 = RABBIT_U8TO32(*key + 0)
k1 = RABBIT_U8TO32(*key + 4)
k2 = RABBIT_U8TO32(*key + 8)
k3 = RABBIT_U8TO32(*key + 12)
;Generate initial state variables
*ctx\master\x[0] = k0
*ctx\master\x[2] = k1
*ctx\master\x[4] = k2
*ctx\master\x[6] = k3
*ctx\master\x[1] = RABBIT_U32V(shl32(k3, 16)) | shr32(k2, 16)
*ctx\master\x[3] = RABBIT_U32V(shl32(k0, 16)) | shr32(k3, 16)
*ctx\master\x[5] = RABBIT_U32V(shl32(k1, 16)) | shr32(k0, 16)
*ctx\master\x[7] = RABBIT_U32V(shl32(k2, 16)) | shr32(k1, 16)
;Generate initial counter values
*ctx\master\c[0] = rotl32(k2, 16)
*ctx\master\c[2] = rotl32(k3, 16)
*ctx\master\c[4] = rotl32(k0, 16)
*ctx\master\c[6] = rotl32(k1, 16)
*ctx\master\c[1] = (k0 & $FFFF0000) | (k1 & $FFFF)
*ctx\master\c[3] = (k1 & $FFFF0000) | (k2 & $FFFF)
*ctx\master\c[5] = (k2 & $FFFF0000) | (k3 & $FFFF)
*ctx\master\c[7] = (k3 & $FFFF0000) | (k0 & $FFFF)
;Clear carry bit
*ctx\master\carry = 0
;Iterate the system four times
RABBIT_next_state(@*ctx\master)
RABBIT_next_state(@*ctx\master)
RABBIT_next_state(@*ctx\master)
RABBIT_next_state(@*ctx\master)
;Modify the counters
*ctx\master\c[0] ! *ctx\master\x[(4) & $7]
*ctx\master\c[1] ! *ctx\master\x[(5) & $7]
*ctx\master\c[2] ! *ctx\master\x[(6) & $7]
*ctx\master\c[3] ! *ctx\master\x[(7) & $7]
*ctx\master\c[4] ! *ctx\master\x[(8) & $7]
*ctx\master\c[5] ! *ctx\master\x[(9) & $7]
*ctx\master\c[6] ! *ctx\master\x[(10) & $7]
*ctx\master\c[7] ! *ctx\master\x[(11) & $7]
;Copy master instance to work instance
*ctx\work\x[0] = *ctx\master\x[0] : *ctx\work\c[0] = *ctx\master\c[0]
*ctx\work\x[1] = *ctx\master\x[1] : *ctx\work\c[1] = *ctx\master\c[1]
*ctx\work\x[2] = *ctx\master\x[2] : *ctx\work\c[2] = *ctx\master\c[2]
*ctx\work\x[3] = *ctx\master\x[3] : *ctx\work\c[3] = *ctx\master\c[3]
*ctx\work\x[4] = *ctx\master\x[4] : *ctx\work\c[4] = *ctx\master\c[4]
*ctx\work\x[5] = *ctx\master\x[5] : *ctx\work\c[5] = *ctx\master\c[5]
*ctx\work\x[6] = *ctx\master\x[6] : *ctx\work\c[6] = *ctx\master\c[6]
*ctx\work\x[7] = *ctx\master\x[7] : *ctx\work\c[7] = *ctx\master\c[7]
*ctx\work\carry = *ctx\master\carry
EndProcedure
; IV setup. After having called RABBIT_keysetup(), the user is
; allowed To call RABBIT_ivsetup() different times in order to
; encrypt/decrypt different messages with the same key but different
; IV's.
Procedure RABBIT_ivsetup(*ctx.RABBIT_ctx, *iv)
;Temporary variables
Protected i0.l, i1.l, i2.l, i3.l, i.l
;Generate four subvectors
i0 = RABBIT_U8TO32(*iv + 0)
i2 = RABBIT_U8TO32(*iv + 4)
i1 = shr32(i0, 16) | (i2 & $FFFF0000)
i3 = shl32(i2, 16) | (i0 & $0000FFFF)
;Modify counter values
*ctx\work\c[0] = *ctx\master\c[0] ! i0
*ctx\work\c[1] = *ctx\master\c[1] ! i1
*ctx\work\c[2] = *ctx\master\c[2] ! i2
*ctx\work\c[3] = *ctx\master\c[3] ! i3
*ctx\work\c[4] = *ctx\master\c[4] ! i0
*ctx\work\c[5] = *ctx\master\c[5] ! i1
*ctx\work\c[6] = *ctx\master\c[6] ! i2
*ctx\work\c[7] = *ctx\master\c[7] ! i3
;Copy state variables
i = 0
While i < 8
*ctx\work\x[i] = *ctx\master\x[i]
i + 1
Wend
*ctx\work\carry = *ctx\master\carry
;Iterate the system four times
i = 0
While i < 4
RABBIT_next_state(@*ctx\work)
i + 1
Wend
EndProcedure
; Encryption/decryption of arbitrary length messages.
; The ECRYPT_encrypt_bytes() function (declared here) encrypts byte
; strings of arbitrary length.
; The user is NOT allowed to make additional encryption calls once he
; has called ECRYPT_encrypt_bytes() (unless he starts a new message
; of course).
Procedure RABBIT_process_bytes(*ctx.RABBIT_ctx, *input.longarray, *output.longarray, msglen)
;Temporary variables
Protected i.l, *in.asciiarray, *out.asciiarray, *ks.asciiarray
Dim buffer.l(3)
;Encrypt/decrypt all full block
While msglen >= 16
;Iterate the system
RABBIT_next_state(@*ctx\work)
;Encrypt/decrypt 16 bytes of data
*output\l[0] = *input\l[0] ! *ctx\work\x[0] ! shr32(*ctx\work\x[5], 16) ! RABBIT_U32V(shl32(*ctx\work\x[3], 16))
*output\l[1] = *input\l[1] ! *ctx\work\x[2] ! shr32(*ctx\work\x[7], 16) ! RABBIT_U32V(shl32(*ctx\work\x[5], 16))
*output\l[2] = *input\l[2] ! *ctx\work\x[4] ! shr32(*ctx\work\x[1], 16) ! RABBIT_U32V(shl32(*ctx\work\x[7], 16))
*output\l[3] = *input\l[3] ! *ctx\work\x[6] ! shr32(*ctx\work\x[3], 16) ! RABBIT_U32V(shl32(*ctx\work\x[1], 16))
;Increment pointers And decrement length
*input + 16
*output + 16
msglen - 16
Wend
;Encrypt/decrypt remaining data
If msglen > 0
;Iterate the system
RABBIT_next_state(@*ctx\work)
;Generate 16 bytes of pseudo-random data
buffer(0) = *ctx\work\x[0] ! shr32(*ctx\work\x[5], 16) ! RABBIT_U32V(shl32(*ctx\work\x[3], 16))
buffer(1) = *ctx\work\x[2] ! shr32(*ctx\work\x[7], 16) ! RABBIT_U32V(shl32(*ctx\work\x[5], 16))
buffer(2) = *ctx\work\x[4] ! shr32(*ctx\work\x[1], 16) ! RABBIT_U32V(shl32(*ctx\work\x[7], 16))
buffer(3) = *ctx\work\x[6] ! shr32(*ctx\work\x[3], 16) ! RABBIT_U32V(shl32(*ctx\work\x[1], 16))
;Encrypt/decrypt the data
*in = *input
*out = *output
*ks = @buffer()
While i < msglen
*out\a[i] = *in\a[i] ! *ks\a[i]
i + 1
Wend
EndIf
EndProcedure
;-----------------------------------------------------------------------------------
DisableExplicit