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