A new cipher and hash function was published in October last year called Spritz which is based on RC4, the most popular cryptography cipher ever used. I've been trying to implement it but not getting the same results as test vectors provided. Attached is some C code and the assembler version I'm stuck with. Would be nice to have extra set of eyes on code to see what exactly I'm doing wrong. Any advice appreciated.
Published document with specification/design : http://people.csail.mit.edu/rivest/pubs/RS14.pdf
; Spritz - a spongy RC4-like stream cipher and hash function
; Designed by Ron Rivest and Jacob Schuldt
;
.686
.model flat, stdcall
.nolist
.nocref
WIN32_LEAN_AND_MEAN equ 1
include windows.inc
include stdio.inc
includelib kernel32.lib
includelib msvcrt.lib
.list
.cref
option epilogue:none
option prologue:none
N equ 256
STATE struct
a byte ?
i byte ?
j byte ?
k byte ?
z byte ?
w byte ?
s byte N dup (?)
STATE ends
.code
InitializeState proc fastcall state:dword
pushad
mov edi, state
xor eax, eax
stosb ; a = 0
stosb ; i = 0
stosb ; j = 0
stosb ; k = 0
stosb ; z = 0
inc eax
stosb ; w = 1
dec eax
; for v = 0 to N - 1
; s[v] = v
init_sbox: ; fixed for 256 bytes
stosb
inc al
jnz init_sbox
popad
ret
InitializeState endp
InitializeStateLen equ $ - InitializeState
Absorb proc fastcall state:dword, M:dword, len:dword
pushad
; for v = 0 to I.length - 1
xor ebx, ebx
mov esi, M
absorb_loop:
; AbsorbByte(I[v])
movzx edx, byte ptr[esi+ebx] ; I[v]
call AbsorbByte
inc ebx
cmp ebx, [esp+32+4] ; v < len
jnz absorb_loop
popad
retn 4
Absorb endp
AbsorbLen equ $ - Absorb
AbsorbByte proc fastcall state:dword, b:dword
pushad
mov ebx, b
; AbsorbNibble (LOW (b))
and edx, 15
call AbsorbNibble
; AbsorbNibble (HIGH (b))
mov edx, ebx
shr edx, 4
call AbsorbNibble
popad
ret
AbsorbByte endp
AbsorbByteLen equ $ - AbsorbByte
AbsorbNibble proc fastcall state:dword, x:dword
pushad
; if a == [N/2]
; Shuffle()
.if [state][STATE.a] == N/2
call Shuffle
.endif
; Swap(S[a], S[[N/2] + x])
add dl, N/2
mov al, [state][STATE.s][edx]
xchg al, [state][STATE.a]
mov [state][STATE.s][edx], al
; a = a + 1
inc [state][STATE.a]
popad
ret
AbsorbNibble endp
AbsorbNibbleLen equ $ - AbsorbNibble
AbsorbStop proc fastcall state:dword
pushad
; if a == [N/2]
; Shuffle()
.if [state][STATE.a] == N/2
call Shuffle
.endif
; a = a + 1
inc [state][STATE.a]
popad
ret
AbsorbStop endp
AbsorbStopLen equ $ - AbsorbStop
Shuffle proc fastcall state:dword
call Whip
call Crush
call Whip
call Crush
call Whip
; a = 0
and [state][STATE.a], 0
ret
Shuffle endp
ShuffleLen equ $ - Shuffle
Whip proc fastcall state:dword
pushad
; for v = 0 to r - 1
; Update()
xor ebx, ebx
whip_loop:
call Update
inc ebx
cmp ebx, 2*N ; 2N
jnz whip_loop
; w = w + 1
add [state][STATE.w], 2 ; when N is power of 2
popad
ret
Whip endp
WhipLen equ $ - Whip
Crush proc fastcall state:dword
pushad
; for v = 0 to [N/2] - 1
xor esi, esi
crush_loop:
; if S[v] > S[N - 1 - v]
mov edx, esi
neg edx
add edx, N-1
mov al, [state][STATE.s][esi] ; s[v]
mov bl, [state][STATE.s][edx] ; s[N - 1 - v]
.if al > bl
; Swap (S[v], S[N - 1 - v])
mov [state][STATE.s][edx], al
mov [state][STATE.s][esi], bl
.endif
inc esi
cmp esi, N/2
jnz crush_loop
popad
ret
Crush endp
CrushLen equ $ - Crush
Squeeze proc fastcall state:dword, p:dword, r:dword
pushad
; if a > 0
; Shuffle ()
.if [state][STATE.a] > 0
call Shuffle
.endif
; for v = 0 to r - 1
mov ebx, [esp+32+4] ; r
mov edi, edx ; p
squeeze_loop:
call Drip
; p[v] = Drip()
stosb
dec ebx
jnz squeeze_loop
; return P
popad
retn 4
Squeeze endp
SqueezeLen equ $ - Squeeze
Drip proc fastcall state:dword
; if a > 0
; Shuffle()
.if [state][STATE.a] > 0
call Shuffle
.endif
; Update()
call Update
; return Output()
call Output
ret
Drip endp
DripLen equ $ - Drip
Update proc fastcall state:dword
pushad
movzx eax, byte ptr[state][STATE.i]
movzx ebx, byte ptr[state][STATE.j]
mov dh, [state][STATE.k]
; i = i + w
add al, [state][STATE.w]
; j = k + S[j + S[i]]
mov dl, [state][STATE.s][eax]
add bl, dl
mov bl, [state][STATE.s][ebx]
add bl, dh
; Swap(S[i], S[j])
xchg dl, [state][STATE.s][ebx]
mov [state][STATE.s][eax], dl
; k = i + k + S[j]
add dl, al
add dl, dh
mov [state][STATE.i], al
mov [state][STATE.j], bl
mov [state][STATE.k], dl
popad
ret
Update endp
UpdateLen equ $ - Update
; z = S[j + S[i + S[z + k]]]
; return z;
Output proc fastcall state:dword
pushad
movzx eax, byte ptr[state][STATE.i]
movzx ebx, byte ptr[state][STATE.j]
movzx edx, byte ptr[state][STATE.z]
; z + k
add dl, [state][STATE.k]
; i + s[z + k]
add al, [state][STATE.s][edx]
; j + s[i + s[z + k]]
add bl, [state][STATE.s][eax]
; z = s[j]
mov al, [state][STATE.s][ebx]
mov [state][STATE.z], al
; return z
mov [esp+1ch], eax
popad
ret
Output endp
OutputLen equ $ - Output
public _Stream
_Stream:
Stream proc fastcall p:dword, r:dword, key:dword, len:dword
pushad
mov edi, p ; edi = p
mov esi, r ; esi = r
mov ebp, esp
sub esp, sizeof STATE
mov ecx, esp
call InitializeState
push [ebp+32+8] ; len
mov edx, [ebp+32+4] ; key
call Absorb
push esi ; r
mov edx, edi ; edx = p
call Squeeze
mov esp, ebp
popad
ret
Stream endp
StreamLen equ $ - Stream
; Produces an r-byte hash of the input message (byte sequence) M
Hash proc fastcall h:dword, M:dword, r:dword
pushad
mov esi, [esp+32+4] ; esi = r
mov ebp, esp
sub esp, sizeof STATE
mov edi, ecx ; edi = h
; InitializeState()
mov ecx, esp ; ecx = &state
call InitializeState
; Absorb(M); AbsorbStop()
push esi ; r, edx = M
call Absorb
call AbsorbStop
; Absorb(r)
push sizeof byte
mov edx, esi
call Absorb
; return Squeeze(r)
push esi ; r
mov edx, edi ; edx = h
call Squeeze
mov esp, ebp
popad
ret
Hash endp
HashLen equ $ - Hash
TotalLen equ InitializeStateLen + \
AbsorbLen + \
AbsorbByteLen + \
AbsorbNibbleLen + \
AbsorbStopLen + \
ShuffleLen + \
WhipLen + \
CrushLen + \
SqueezeLen + \
DripLen + \
UpdateLen + \
OutputLen + \
HashLen + \
StreamLen
%echo ======================
%echo Total Size : @CatStr(%TotalLen) Bytes
%echo ======================
.data
fmt db "%02x ", 0
newline db 13, 10, 0
plaintext db "arcfour"
plaintext_len equ $-plaintext
ciphertext db 32 dup (?)
.code
spritzx:
mov ecx, offset ciphertext
mov edx, 32
push plaintext_len
push offset plaintext
call Stream
xor ebx, ebx
print_bytes:
movzx eax, byte ptr[ciphertext+ebx]
invoke printf, addr fmt, eax
inc ebx
cmp ebx, 32
jnz print_bytes
invoke ExitProcess, 0
end spritzx
Using C code, the 32-byte result for stream is
ff 8c f2 68 09 4c 87 b9 5f 74 ce 6f ee 9d 30 03 a5 f9 fe 69 44 65 3c d5 0e 66 bf 18 9c 63 f6 99
But with asm code, it's
29 b2 10 fe 7f 2a 6a f4 a4 45 a0 1d a0 d7 bd 50 f2 49 b3 88 a0 a8 b7 40 6b 4a 84 9f 95 88 eb 6d
I used stdcall for functions instead and changed code to make it easier to read but still get wrong values.
; Spritz - a spongy RC4-like stream cipher and hash function
; Designed by Ron Rivest and Jacob Schuldt
;
.686
.model flat, stdcall
.nolist
.nocref
WIN32_LEAN_AND_MEAN equ 1
include windows.inc
include stdio.inc
includelib kernel32.lib
includelib msvcrt.lib
.list
.cref
N equ 256
STATE struct
a byte ?
i byte ?
j byte ?
k byte ?
z byte ?
w byte ?
s byte N dup (?)
STATE ends
.code
InitializeState proc state:dword
pushad
mov edi, [state]
xor eax, eax
mov [edi][STATE.a], al
mov [edi][STATE.i], al
mov [edi][STATE.j], al
mov [edi][STATE.k], al
mov [edi][STATE.z], al
mov [edi][STATE.w], 1
; for v = 0 to N - 1
; s[v] = v
init_sbox:
mov [edi][STATE.s][eax], al
inc eax
cmp eax, N
jnz init_sbox
popad
ret
InitializeState endp
InitializeStateLen equ $ - InitializeState
Absorb proc state:dword, M:dword, len:dword
pushad
; for v = 0 to I.length - 1
xor ebx, ebx
mov esi, [M]
absorb_loop:
; AbsorbByte(I[v])
movzx edx, byte ptr[esi+ebx] ; I[v]
push edx
push [state]
call AbsorbByte
inc ebx
cmp ebx, [len] ; v < len
jnz absorb_loop
popad
ret
Absorb endp
AbsorbLen equ $ - Absorb
AbsorbByte proc state:dword, b:dword
pushad
mov esi, [state]
mov edi, [b]
; AbsorbNibble (LOW (b))
mov ebx, edi
and ebx, 15
push ebx
push esi
call AbsorbNibble
; AbsorbNibble (HIGH (b))
shr edi, 4
push edi
push esi
call AbsorbNibble
popad
ret
AbsorbByte endp
AbsorbByteLen equ $ - AbsorbByte
AbsorbNibble proc state:dword, x:dword
pushad
mov esi, [state]
; if a == [N/2]
; Shuffle()
.if [esi][STATE.a] == N/2
push esi
call Shuffle
.endif
; Swap(S[a], S[[N/2] + x])
mov edx, [x]
add dl, N/2
mov al, [esi][STATE.s][edx]
xchg al, [esi][STATE.a]
mov [esi][STATE.s][edx], al
; a = a + 1
mov al, byte ptr[esi][STATE.a]
add al, 1
mov [esi][STATE.a], al
popad
ret
AbsorbNibble endp
AbsorbNibbleLen equ $ - AbsorbNibble
AbsorbStop proc state:dword
pushad
mov esi, [state]
; if a == [N/2]
; Shuffle()
.if [esi][STATE.a] == N/2
push esi
call Shuffle
.endif
; a = a + 1
mov al, byte ptr[esi][STATE.a]
add al, 1
mov [esi][STATE.a], al
popad
ret
AbsorbStop endp
AbsorbStopLen equ $ - AbsorbStop
Shuffle proc state:dword
pushad
mov ebx, [state]
push ebx
call Whip
push ebx
call Crush
push ebx
call Whip
push ebx
call Crush
push ebx
call Whip
; a = 0
and [ebx][STATE.a], 0
popad
ret
Shuffle endp
ShuffleLen equ $ - Shuffle
Whip proc state:dword
pushad
; for v = 0 to r - 1
; Update()
mov esi, [state]
xor ebx, ebx
whip_loop:
push esi
call Update
inc ebx
cmp ebx, 2*N ; 2N
jnz whip_loop
; w = w + 1
mov al, byte ptr[esi][STATE.w]
add al, 2
mov [esi][STATE.w], al
popad
ret
Whip endp
WhipLen equ $ - Whip
Crush proc state:dword
pushad
; for v = 0 to [N/2] - 1
xor esi, esi
mov edi, [state]
crush_loop:
; if S[v] > S[N - 1 - v]
mov edx, esi
neg edx
add edx, N-1
mov al, [edi][STATE.s][esi] ; s[v]
mov bl, [edi][STATE.s][edx] ; s[N - 1 - v]
.if al > bl
; Swap (S[v], S[N - 1 - v])
mov [edi][STATE.s][edx], al
mov [edi][STATE.s][esi], bl
.endif
inc esi
cmp esi, N/2
jnz crush_loop
popad
ret
Crush endp
CrushLen equ $ - Crush
Squeeze proc state:dword, p:dword, r:dword
pushad
mov esi, [state]
; if a > 0
; Shuffle ()
.if [esi][STATE.a] > 0
push esi
call Shuffle
.endif
; for v = 0 to r - 1
mov ebx, [r] ; r
mov edi, [p] ; p
squeeze_loop:
push esi
call Drip
; p[v] = Drip()
stosb
dec ebx
jnz squeeze_loop
; return P
popad
ret
Squeeze endp
SqueezeLen equ $ - Squeeze
Drip proc uses esi state:dword
mov esi, [state]
; if a > 0
; Shuffle()
.if [esi][STATE.a] > 0
push esi
call Shuffle
.endif
; Update()
push esi
call Update
; return Output()
push esi
call Output
ret
Drip endp
DripLen equ $ - Drip
Update proc state:dword
pushad
mov esi, [state]
xor eax, eax
xor ebx, ebx
; i = i + w
mov al, byte ptr[esi][STATE.i]
add al, byte ptr[esi][STATE.w]
mov byte ptr[esi][STATE.i], al
; j = k + S[j + S[i]]
mov al, byte ptr[esi][STATE.i]
mov bl, byte ptr[esi][STATE.j]
add bl, byte ptr[esi][STATE.s][eax]
mov bl, byte ptr[esi][STATE.s][ebx]
add bl, byte ptr[esi][STATE.k]
mov byte ptr[esi][STATE.j], bl
; k = i + k + S[j]
mov bl, byte ptr[esi][STATE.j]
mov bl, byte ptr[esi][STATE.s][ebx]
add bl, byte ptr[esi][STATE.k]
add bl, byte ptr[esi][STATE.i]
mov byte ptr[esi][STATE.k], bl
; Swap (S[i], S[j])
mov al, byte ptr[esi][STATE.i]
mov cl, byte ptr[esi][STATE.s][eax]
mov bl, byte ptr[esi][STATE.j]
mov dl, byte ptr[esi][STATE.s][ebx]
mov byte ptr[esi][STATE.s][eax], dl
mov byte ptr[esi][STATE.s][ebx], cl
popad
ret
Update endp
UpdateLen equ $ - Update
; z = S[j + S[i + S[z + k]]]
; return z;
Output proc uses esi state:dword
mov esi, [state]
xor eax, eax
mov al, byte ptr[esi][STATE.k]
add al, byte ptr[esi][STATE.z]
mov al, byte ptr[esi][STATE.s][eax]
add al, byte ptr[esi][STATE.i]
mov al, byte ptr[esi][STATE.s][eax]
add al, byte ptr[esi][STATE.j]
mov al, byte ptr[esi][STATE.s][eax]
mov byte ptr[esi][STATE.z], al
ret
Output endp
OutputLen equ $ - Output
public _Stream
_Stream:
Stream proc p:dword, r:dword, key:dword, len:dword
local state:STATE
pushad
lea esi, [state]
push esi
call InitializeState
push [len]
push [key]
push esi
call Absorb
push [r]
push [p]
push esi
call Squeeze
popad
ret
Stream endp
StreamLen equ $ - Stream
; Produces an r-byte hash of the input message (byte sequence) M
Hash proc h:dword, M:dword, r:dword
pushad
mov esi, [esp+32+4] ; esi = r
mov ebp, esp
sub esp, sizeof STATE
mov edi, ecx ; edi = h
; InitializeState()
mov ecx, esp ; ecx = &state
call InitializeState
; Absorb(M); AbsorbStop()
push esi ; r, edx = M
call Absorb
call AbsorbStop
; Absorb(r)
push sizeof byte
mov edx, esi
call Absorb
; return Squeeze(r)
push esi ; r
call Squeeze
mov esp, ebp
popad
ret
Hash endp
HashLen equ $ - Hash
TotalLen equ InitializeStateLen + \
AbsorbLen + \
AbsorbByteLen + \
AbsorbNibbleLen + \
AbsorbStopLen + \
ShuffleLen + \
WhipLen + \
CrushLen + \
SqueezeLen + \
DripLen + \
UpdateLen + \
OutputLen + \
HashLen + \
StreamLen
%echo ======================
%echo Total Size : @CatStr(%TotalLen) Bytes
%echo ======================
.data
fmt db "%02x ", 0
newline db 13, 10, 0
plaintext db "arcfour"
plaintext_len equ $-plaintext
ciphertext db 32 dup (?)
.code
spritzy:
push plaintext_len
push offset plaintext
push 32
push offset ciphertext
call Stream
xor ebx, ebx
print_bytes:
movzx eax, byte ptr[ciphertext+ebx]
invoke printf, addr fmt, eax
inc ebx
cmp ebx, 32
jnz print_bytes
invoke ExitProcess, 0
end spritzy
Had a nice walk and spotted problem in AbsorbNibble. Should have been using S[a] and not a itself..
AbsorbNibble proc state:dword, x:dword
pushad
mov esi, [state]
; if a == [N/2]
; Shuffle()
.if [esi][STATE.a] == N/2
push esi
call Shuffle
.endif
; Swap(S[a], S[[N/2] + x])
mov edx, [x]
xor eax, eax
add dl, N/2
mov al, [esi][STATE.s][edx]
mov bl, [esi][STATE.a] ; ebx = a
xchg al, [esi][STATE.s][ebx]
mov [esi][STATE.s][edx], al
; a = a + 1
inc [esi][STATE.a]
popad
ret
AbsorbNibble endp
I rebuilt your stdcall version with modifyed AbsorbNibble proc .
NOW OUTPUT IS:
Quote1a fa 8b 5e e3 37 db c7 22 59 7f 0f dc 3a 42 c7 75 4b f1 03 6f 54 fb 4a eb 03 35 d4 a4 e9 a3 6e
BEFORE IT WAS :
Quote29 b2 10 fe 7f 2a 6a f4 a4 45 a0 1d a0 d7 bd 50 f2 49 b3 88 a0 a8 b7 40 6b 4a 84 9f 95 88 eb 6d
Yep, initially posted wrong bytes too..
Spritz Hash = ff 8c f2 68 09 4c 87 b9 5f 74 ce 6f ee 9d 30 03 a5 f9 fe 69 44 65 3c d5 0e 66 bf 18 9c 63 f6 99
Spritz Stream = 1a fa 8b 5e e3 37 db c7 22 59 7f 0f dc 3a 42 c7 75 4b f1 03 6f 54 fb 4a eb 03 35 d4 a4 e9 a3 6e
This is hash function using stdcall
Hash proc h:dword, len:dword, M:dword, r:dword
local state:STATE
pushad
; InitializeState()
lea esi, [state]
push esi
call InitializeState
; Absorb(M); AbsorbStop()
push dword ptr[r]
push dword ptr[M]
push esi ; r, edx = M
call Absorb
push esi
call AbsorbStop
; Absorb(r)
push sizeof byte
lea eax, [len]
push eax
push esi
call Absorb
; return Squeeze(r)
push dword ptr[len]
push dword ptr[h]
push esi ; r
call Squeeze
popad
ret
Hash endp
Overall, the comments/code needs cleaning up.
Won't wait :
Spritz Hash = ff 8c f2 68 09 4c 87 b9 5f 74 ce 6f ee 9d 30 03 a5 f9 fe 69 44 65 3c d5 0e 66 bf 18 9c 63 f6 99
Spritz Stream = 1a fa 8b 5e e3 37 db c7 22 59 7f 0f dc 3a 42 c7 75 4b f1 03 6f 54 fb 4a eb 03 35 d4 a4 e9 a3 6e
- because for such work is need to pay :badgrin:
But comments is free : Lorenzo with RSA have made really great work, and my opinion that is really best for beginner - from such to begin, stayed catch bugs as sub esp/add esp - not disturb ebp, and so on. But that's for security reasons is need to do for myself, as it save critical code for cipher programs :eusa_boohoo: Also, I could remark, that RSA developers, noticed needs for such type of algos, in programs passwords - that is in nonce parameter, as key is user password - or opposite :eusa_dance:
True, I haven't finished this completely yet. Below is last bit I wrote with some test code in C.
It's not work, I just wanted to implement it. :icon_cool:
; *********************************************************
; Spritz - a spongy RC4-like stream cipher and hash function
; Designed by Ron Rivest and Jacob Schuldt
; *********************************************************
;
; 369 bytes
.686
.model flat
option epilogue:none
option prologue:none
N equ 256
STATE struct
a byte ?
i byte ?
j byte ?
k byte ?
z byte ?
w byte ?
s byte N dup (?)
STATE ends
.code
; *********************************************************
public _spritz_init
_spritz_init:
spritz_init proc fastcall state:dword
pushad
mov edi, state
xor eax, eax
stosb ; a = 0
stosb ; i = 0
stosb ; j = 0
stosb ; k = 0
stosb ; z = 0
inc eax
stosb ; w = 1
dec eax
; for v = 0 to N - 1
; s[v] = v
init_sbox: ; fixed for 256 bytes
stosb
inc al
jnz init_sbox
popad
ret
spritz_init endp
spritz_initLen equ $ - spritz_init
; *********************************************************
public _spritz_update
_spritz_update:
spritz_update proc fastcall state:dword
pushad
movzx eax, byte ptr[state][STATE.i]
movzx ebx, byte ptr[state][STATE.j]
mov dh, [state][STATE.k]
; i = i + w
add al, [state][STATE.w]
; j = k + S[j + S[i]]
mov dl, [state][STATE.s][eax]
add bl, dl
mov bl, [state][STATE.s][ebx]
add bl, dh
; Swap(S[i], S[j])
xchg dl, [state][STATE.s][ebx]
mov [state][STATE.s][eax], dl
; k = i + k + S[j]
add dl, al
add dl, dh
mov [state][STATE.i], al
mov [state][STATE.j], bl
mov [state][STATE.k], dl
popad
ret
spritz_update endp
spritz_updateLen equ $ - spritz_update
; *********************************************************
public _spritz_whip
_spritz_whip:
spritz_whip proc fastcall state:dword
pushad
; for v = 0 to r - 1
; spritz_update()
xor ebx, ebx
whip_loop:
call spritz_update
inc ebx
cmp ebx, 2*N ; 2N
jnz whip_loop
; w = w + 1
add [state][STATE.w], 2 ; when N is power of 2
popad
ret
spritz_whip endp
spritz_whipLen equ $ - spritz_whip
; *********************************************************
public _spritz_crush
_spritz_crush:
spritz_crush proc fastcall state:dword
pushad
; for v = 0 to [N/2] - 1
xor esi, esi
crush_loop:
; if S[v] > S[N - 1 - v]
mov edx, N - 1
sub edx, esi
mov al, [state][STATE.s][esi] ; s[v]
mov bl, [state][STATE.s][edx] ; s[N - 1 - v]
.if al > bl
; Swap (S[v], S[N - 1 - v])
mov [state][STATE.s][edx], al
mov [state][STATE.s][esi], bl
.endif
inc esi
cmp esi, N/2
jnz crush_loop
popad
ret
spritz_crush endp
spritz_crushLen equ $ - spritz_crush
; *********************************************************
public _spritz_shuffle
_spritz_shuffle:
spritz_shuffle proc fastcall state:dword
call spritz_whip
call spritz_crush
call spritz_whip
call spritz_crush
call spritz_whip
; a = 0
and [state][STATE.a], 0
ret
spritz_shuffle endp
spritz_shuffleLen equ $ - spritz_shuffle
; *********************************************************
public _spritz_shuffle_absorb
_spritz_shuffle_absorb:
spritz_shuffle_absorb proc fastcall state:dword
.if [state][STATE.a] == N/2
call spritz_shuffle
.endif
ret
spritz_shuffle_absorb endp
spritz_shuffle_absorbLen equ $ - spritz_shuffle_absorb
; *********************************************************
spritz_absorb_nibble proc fastcall state:dword, x:dword
pushad
call spritz_shuffle_absorb
; Swap(S[a], S[[N/2] + x])
xor eax, eax
add dl, N/2
mov al, [state][STATE.s][edx]
mov bl, [state][STATE.a] ; ebx = a
xchg al, [state][STATE.s][ebx]
mov [state][STATE.s][edx], al
; a = a + 1
inc [state][STATE.a]
popad
ret
spritz_absorb_nibble endp
spritz_absorb_nibbleLen equ $ - spritz_absorb_nibble
; *********************************************************
public _spritz_absorb_byte
_spritz_absorb_byte:
spritz_absorb_byte proc fastcall state:dword, b:dword
pushad
mov ebx, b
; spritz_absorb_nibble (LOW (b))
and edx, 15
call spritz_absorb_nibble
; spritz_absorb_nibble (HIGH (b))
mov edx, ebx
shr edx, 4
call spritz_absorb_nibble
popad
ret
spritz_absorb_byte endp
spritz_absorb_byteLen equ $ - spritz_absorb_byte
; *********************************************************
public _spritz_absorb
_spritz_absorb:
spritz_absorb proc fastcall state:dword, I:dword, I_len:dword
pushad
; for v = 0 to I.length - 1
xor ebx, ebx
mov esi, I
absorb_loop:
; spritz_absorb_byte(I[v])
movzx edx, byte ptr[esi+ebx] ; I[v]
call spritz_absorb_byte
inc ebx
cmp ebx, [esp+32+4] ; v < I_len
jnz absorb_loop
popad
retn 4
spritz_absorb endp
spritz_absorbLen equ $ - spritz_absorb
; *********************************************************
public _spritz_absorb_stop
_spritz_absorb_stop:
spritz_absorb_stop proc fastcall state:dword
call spritz_shuffle_absorb
; a = a + 1
inc [state][STATE.a]
ret
spritz_absorb_stop endp
spritz_absorb_stopLen equ $ - spritz_absorb_stop
; *********************************************************
public _spritz_absorb_and_stop
_spritz_absorb_and_stop:
spritz_absorb_and_stop proc fastcall state:dword, I:dword, I_len:dword
push [esp+4]
call spritz_absorb
call spritz_absorb_stop
ret
spritz_absorb_and_stop endp
spritz_absorb_and_stopLen equ $ - spritz_absorb_and_stop
; *********************************************************
public _spritz_shuffle_squeeze
_spritz_shuffle_squeeze:
spritz_shuffle_squeeze proc fastcall state:dword
.if [state][STATE.a] > 0
call spritz_shuffle
.endif
ret
spritz_shuffle_squeeze endp
spritz_shuffle_squeezeLen equ $ - spritz_shuffle_squeeze
; *********************************************************
; z = S[j + S[i + S[z + k]]]
; return z;
public _spritz_output
_spritz_output:
spritz_output proc fastcall state:dword
pushad
movzx eax, byte ptr[state][STATE.i]
movzx ebx, byte ptr[state][STATE.j]
movzx edx, byte ptr[state][STATE.z]
; z + k
add dl, [state][STATE.k]
; i + s[z + k]
add al, [state][STATE.s][edx]
; j + s[i + s[z + k]]
add bl, [state][STATE.s][eax]
; z = s[j]
mov al, [state][STATE.s][ebx]
mov [state][STATE.z], al
; return z
mov [esp+1ch], eax
popad
ret
spritz_output endp
spritz_outputLen equ $ - spritz_output
; *********************************************************
public _spritz_drip_nosqueeze
_spritz_drip_nosqueeze:
spritz_drip_nosqueeze proc fastcall state:dword
call spritz_update
call spritz_output
ret
spritz_drip_nosqueeze endp
spritz_drip_nosqueezeLen equ $ - spritz_drip_nosqueeze
; *********************************************************
public _spritz_squeeze
_spritz_squeeze:
spritz_squeeze proc fastcall state:dword, P:dword, P_len:dword
pushad
call spritz_shuffle_squeeze
; for v = 0 to r - 1
mov ebx, [esp+32+4] ; r
mov edi, edx ; p
squeeze_loop:
call spritz_drip_nosqueeze
; P[v] = spritz_drip_nosqueeze()
stosb
dec ebx
jnz squeeze_loop
; return P
popad
retn 4
spritz_squeeze endp
spritz_squeezeLen equ $ - spritz_squeeze
; *********************************************************
public _spritz_drip
_spritz_drip:
spritz_drip proc fastcall state:dword
call spritz_shuffle_squeeze
call spritz_drip_nosqueeze
ret
spritz_drip endp
spritz_dripLen equ $ - spritz_drip
end
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <windows.h>
char *keys[] = { "ABC", "spam", "arcfour" };
void dump_bytes (uint8_t b[], size_t len)
{
for (size_t i=0; i<len; i++)
{
printf ("%02x ", b[i]);
}
putchar ('\n');
}
enum {
spritz_N = 256
};
typedef struct
{
uint8_t a, i, j, k, z, w;
uint8_t S[spritz_N];
} spritz_state;
/*******************************************************************************/
/* the spritz primitives */
extern "C" void __fastcall spritz_init (spritz_state *s);
extern "C" void __fastcall spritz_shuffle_squeeze (spritz_state *s);
extern "C" void __fastcall spritz_update (spritz_state *s);
extern "C" void __fastcall spritz_whip (spritz_state *s, uint_fast16_t r);
extern "C" void __fastcall spritz_crush (spritz_state *s);
extern "C" void __fastcall spritz_shuffle (spritz_state *s);
extern "C" void __fastcall spritz_absorb (spritz_state *s, const void *I, size_t I_len);
extern "C" void __fastcall spritz_absorb_byte (spritz_state *s, uint32_t b);
extern "C" void __fastcall spritz_absorb_stop (spritz_state *s);
extern "C" void __fastcall spritz_absorb_and_stop (spritz_state *s, const void *I, size_t I_len); /* commonly used helper function */
extern "C" uint8_t __fastcall spritz_output (spritz_state *s);
extern "C" void __fastcall spritz_squeeze (spritz_state *s, void *P, size_t P_len);
extern "C" uint8_t __fastcall spritz_drip (spritz_state *s);
extern "C" uint8_t __fastcall spritz_drip_nosqueeze (spritz_state *s);
/* the spritz hash inline functions */
static void
spritz_hash_init (spritz_state *s)
{
spritz_init (s);
}
static void
spritz_hash_add (spritz_state *s, const void *M, size_t M_len)
{
spritz_absorb (s, M, M_len);
}
void
spritz_hash_finish (spritz_state *s, void *H, size_t H_len)
{
spritz_absorb_stop (s);
spritz_absorb_byte (s, H_len);
spritz_squeeze (s, H, H_len);
}
void
spritz_cipher_init (spritz_state *s, const void *K, size_t K_len, const void *IV, size_t IV_len)
{
spritz_init (s);
spritz_absorb (s, K, K_len);
if (IV)
{
spritz_absorb_stop (s);
spritz_absorb (s, IV, IV_len);
}
spritz_shuffle_squeeze (s);
}
void
spritz_cipher_encrypt (spritz_state *s, const void *I, void *O, size_t len)
{
const uint8_t *i = (const uint8_t *)I;
uint8_t *o = ( uint8_t *)O;
while (len--)
*o++ = *i++ + spritz_drip_nosqueeze (s);
}
void
spritz_cipher_decrypt (spritz_state *s, const void *I, void *O, size_t len)
{
const uint8_t *i = (const uint8_t *)I;
uint8_t *o = ( uint8_t *)O;
while (len--)
*o++ = *i++ - spritz_drip_nosqueeze (s);
}
/*****************************************************************************/
void
spritz_cipher_xor_crypt (spritz_state *s, const void *I, void *O, size_t len)
{
const uint8_t *i = (const uint8_t *)I;
uint8_t *o = ( uint8_t *)O;
while (len--)
*o++ = *i++ ^ spritz_drip_nosqueeze (s);
}
void dump_hash (void)
{
uint8_t out[32];
spritz_state s;
for (int i=0; i<sizeof(keys) / sizeof(char*); i++)
{
memset (out, 0, sizeof (out));
spritz_hash_init (&s);
spritz_hash_add (&s, keys[i], strlen(keys[i]));
spritz_hash_finish (&s, out, sizeof (out));
dump_bytes (out, sizeof (out));
}
}
int main (int argc, char *argv[])
{
spritz_state s;
uint8_t ct[128]={0};
uint8_t ptx[128]={0};
char pt[]="The Spritz's recipe is shrouded in mystery";
const char key[]="secret password";
size_t keylen = strlen (key);
size_t ptlen = strlen (pt);
dump_bytes ((uint8_t*)pt, ptlen);
spritz_cipher_init (&s, key, keylen, 0, 0);
spritz_cipher_encrypt (&s, pt, ct, ptlen);
dump_bytes (ct, ptlen);
spritz_cipher_init (&s, key, keylen, 0, 0);
spritz_cipher_decrypt (&s, ct, ptx, ptlen);
dump_bytes (ptx, ptlen);
return 0;
}
That's good deal, but I can say only - that I can't understand this code with comments, so won't help you to implement it - but idea is great, I agree :icon_eek: