RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Share your advanced PureBasic knowledge/code with the community.
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by Keya »

In 1987 Ron Rivest invented RC4 (it was leaked in 1994). Last year in 2014, with twenty years of public RC4 cryptanalysis behind him + access to new massive computing power for bias-hunting simulations, Rivest and Jacob Schuldt set out to redesign it: "We thus consider the question, 'What should the original RC4 have looked like?'"

Named Spritz ("since the output comes in one drops rather than big blocks"), it is a full "drop-in replacement for RC4". See http://en.wikipedia.org/wiki/RC4#Spritz

Here is my Purebasic version, but first of all FULL CREDIT must go to Pille, Friedhelm, Rings, Lars, Andre et. al and everyone else for their work in creating the original Purebasic RC4[/url] implementation (ive left the header intact from the one i used called RC4_SpeedImproved.pb), as this is nearly all their original work, just a slight tweak by me to change from RC4 to Spritz, which was embarrassingly simple thanks to their awesome groundwork! :)

Spritz PDF - http://people.csail.mit.edu/rivest/pubs/RS14.pdf
This note reconsiders the design of the stream cipher RC4, and proposes an improved variant, which we call "Spritz" (since the output comes in one drops rather than big blocks.)
Our work leverages the considerable cryptanalytic work done on the original RC4 and its proposed variants. It also uses simulations extensively to search for biases and to guide the selection of intermediate expressions. We estimate that Spritz can produce output with about 24 cycles/byte of computation. Furthermore, our statistical tests suggest that about 281 bytes of output are needed before one can reasonably distinguish Spritz output from random output; this is a marked improvement over RC4.
Our proposal Spritz not only provides a "drop-in replacement" for RC4, with much improved security properties, but also provides a suite of new cryptographic functionalities based on its new "sponge-like" construction and interface.


Ive only just finished it and it's based on pseudocode from Wiki and Bruce Schneier, but it looks right and is based on the same code and variables as RC4 (i, j, S() etc).

Bruce on Spritz - "I have always really liked RC4, and am happy to see a 21st-century redesign. I don't know what kind of use it'll get with its 8-bit word size, but surely there's a niche for it somewhere."
And I really like RC4 too, because it's such a simple algorithm and so small and easy to implement, and variable keysize means you can use keys <=56bit for no export hassles, but because RC4 is considered broken i like to look at the newer variants

Here's the pseudocode comparison taken from Bruce Schneier's page (https://www.schneier.com/blog/archives/ ... ew_rc.html):

Code: Select all

RC4:
    1: i = i + 1
    2: j = j + S[i]
    3: SWAP(S[i];S[j])
    4: z = S[S[i] + S[j]]
    5: Return z

Spritz:
    1: i = i + w
    2: j = k + S[j + S[i]]
    2a: k = i + k + S[j]
    3: SWAP(S[i];S[j])
    4: z = S[j + S[i + S[z + k]]]
    5: Return z

And last but not least here's my implementation (again thanks to all who provided the original code that laid the groundwork). IT COULD BE FLAWED, i dont know! But it seems to decrypt and encrypt ok and as the code is so simple it seems right. It looks correct anyway, but maybe somebody here will find a flaw :D
There are only a few test vectors in the PDF and they didn't mention which password was used, or which constant value for 'w' was used.
Anyway hopefully it will encourage others to look at the other https://en.wikipedia.org/wiki/RC4#RC4_variants (although it seems Spritz is the best of the variant proposals)

Code: Select all

;RC4-SPRITZ.PB
;-------------
; RC4-Spritz variant by Keya, but the majority of code is by others (see original header next)
; English forum: http://www.purebasic.fr/english/viewtopic.php?f=12&t=62455
;
;---Begin original 'RC4Mem' header:---
;  German forum: http://www.purebasic.fr/german/archive/viewtopic.php?t=1708
;   ^url 404s... instead today see http://purearea.net/pb/CodeArchiv/Encode+Decode/RC4_SpeedImproved.pb
;  Author: Friedhelm (updated for PB3.92+ by Lars, updated for PB 4.00 by Andre)
;  Date: 25. July 2003
;  OS: Windows
;  Demo: No
;
;  RC4Mem for PB by Pille, 15.07.2003.  Special Thanks to Rings
;
;  RC4 is a stream cipher designed by Rivest for RSA Data Security (now RSA Security).
;  It is a variable key-size stream cipher with byte-oriented operations. The algorithm is 
;  based on the use of a random permutation. Analysis shows that the period of the cipher is
;  overwhelmingly likely To be greater than 10^100. Eight To sixteen machine operations are 
;  required per output byte, And the cipher can be expected to run very quickly in software.
;  Independent analysts have scrutinized the algorithm and it is considered secure.
;---End Original RC4Mem header:---


Procedure.l RC4SpritzMem(Mem.l, memLen.l, key.s)
  Dim S.l(255)
  Dim K.l(255)
  
  i.l=0: j.l=0: t.l=0: x.l=0
  temp.l=0: y.l=0  
  j = 1
  l.l           = Len(key)
  *Sp.LONG      = @S()
  *keyP.BYTE    = @key
  For i = 0 To 255
    *Sp\l = i
    *Sp + 4
    If *keyP\b = 0
      *keyP = @key
    EndIf
    K(i) = *keyP\b
    *keyP+1
  Next i
  
  j = 0
  For i = 0 To 255
    j = (j + S(i) + K(i)) & 255
    temp = S(i)
    S(i) = S(j)
    S(j) = temp
  Next i

  
  i = 0
  j = 0
  z = 0
  w = 1    ;Schneier on 'w': "The parameter w is basically a constant. It's always 1 in RC4 but
           ;can be any odd number in Spritz (odd because that means it's always relatively prime to 256)."  
  *Memm.BYTE = Mem
  For x = 0 To memLen-1
    i = (i+w) & 255                         ;i := (i + w) mod 256
    
    j = (k + S((j + S(i)) & 255)) & 255     ;j := (k + S[(j + S[i]) mod 256]) mod 256
    
    k = (k + i + S(j)) & 255                ;k := (k + i + S[j]) mod 256
    
    temp = S(i)                         
    S(i) = S(j)                             ;swap values of S[i] and S[j]
    S(j) = temp
    
    z = S((j + S((i + S((z + k) & 255)) & 255)) & 255)    ;output z := S[(j + S[(i + S[(z + k) mod 256]) mod 256]) mod 256]
       
    *Memm\b ! z
    *Memm + 1
  Next
  ProcedureReturn Mem
EndProcedure


;------------------------------------------------------------------------------------------
;PARAMETERS
sTxt.s ="1234567890 The quick brown fox jumped over the lazy dog."      ;String to encrypt
key.s = "s3cr3t k3y"                                                    ;Private cipher key

CompilerIf #PB_Compiler_Unicode
  OrigLen.l =  Len(sTxt) * 2
CompilerElse
  OrigLen.l =  Len(sTxt)
CompilerEndIf


;TEST ENCRYPT & DECRYPT
RC4SpritzMem(@sTxt,OrigLen,key)
MessageRequester("RC4-Spritz", "Encrypted=" + sTxt)

RC4SpritzMem(@sTxt,OrigLen,key)
MessageRequester("RC4-Spritz", "Decrypted=" + sTxt)

Speed-wise these two sister implementations are very close, I did five timing runs on each (well, six but discarded each first, and debugger disabled of course!), with 5,000,000 iterations with the above parameters.
Spritz is only ~6% slower on my i7, not bad considering the apparently much greater security margin.
;RC4: 14505, 14437, 14556, 14416, 14470 (avg 14477ms)
;Spritz: 15400, 15366, 15339, 15338, 15434 (avg 15375ms)

There is of course still much room for improvement - "We estimate that Spritz can produce output with about 24 cycles/byte of computation." I'm not sure if that would make it faster or not than RC4 (probably not as Wiki's page mentions RC4 is "7 cycles per byte on original Pentium"), but any way you look at it the performance is pretty good.

Again, thankyou to anyone who has ever made Purebasic RC4 contributions
Last edited by Keya on Fri Jun 19, 2015 5:39 am, edited 7 times in total.
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by Keya »

i just found this MASM implementation (369 bytes compiled x86) http://masm32.com/board/index.php?topic=4012.0
im guessing its faster than mine above but im too new to Purebasic to try to port it! but it has the full suite of "sponge functions" that allow you to use Spritz for a lot of other crypto things too such as hashes, MAC generation etc

This C implementation looks good https://github.com/jedisct1/spritz
Last edited by Keya on Sat Jun 20, 2015 8:03 am, edited 1 time in total.
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by Kukulkan »

Nice work and clean implementation. Thanks!

Sadly, I do not believe that RC4Spritz is getting a chance. If you have to take a decision for a symmetric encryption algorithm you may have 10 arguments for RC4Spitz but it still is RC4. Trust me, you do not want to have the discussions about the security. Especially with customers. Everybody heard about the RC4 weakness and if they hear your decision to chose RC4 they will say "hah, but you know that RC4 is not secure anymore?". You can tell them that your RC4 is not affected but these discussions will block every sales process. :(

Nevertheless, nice work.

Kind regards,

Kukulkan
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by wilbert »

Kukulkan wrote:Sadly, I do not believe that RC4Spritz is getting a chance.
eSTREAM mentions a few alternatives https://en.wikipedia.org/wiki/ESTREAM
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by Keya »

Kukulkan, RC4 has some very nice properties, i think you'll agree :). While it's considered broken in that its a cakewalk for the NSA, breaking it is still non-trivial for 99.9999% of the rest of ppl on the planet, so it's not an overnight failure and depending on your individual needs it might still be perfectly fine. Bruce Schneier - "When I talk about what sorts of secret cryptographic advances the NSA might have, a practical RC4 attack is one of the possibilities." Perhaps security against the NSA isn't one of your tasks requirements.

And when you take the same author of RC4 - Ron Rivest... give him 25 years more experience, give him 20 years public cryptanalysis of his cipher, give him massive computing power for simulations... you get another cipher with the same very nice properties retained (and more added!), and apparently much better security. RC4 proved itself very strong for a very long time... I think Spritz deserves a bit more of a chance to be proven on its own merits :) (it's not RC4! and simply being "based on RC4" doesn't necessarily mean it suffers the same weaknesses - Rivest afterall set out to address known weaknesses in this redesign). But perhaps you just want to use some 'underlying encryption' in your program and its not related to sales/advertising, it doesnt really matter so much.

I totally agree with you from a sales perspective in that you probably wouldn't want to advertise "RC4-based" or anything like that! :) If using it commercially i'd just call it "Spritz" (if naming it at all) and never mention RC4, lol. If making a commercial application though surely you'd just get export clearance and use the latest and greatest, but another nice property of RC4 and Spritz is that because of its variable keysize you can use it with a 56bit key to avoid legal export-related hassles. Unless im mistaken you can't even for example use Tiny Encryption Algorithm for export without clearance as it has fixed 64bit keys.

Of course if you want maximum security from a stream cipher then neither RC4 or Spritz are for you - we know there are stronger stream ciphers, and this is a replacement redesign by Rivest - a 'fixed, improved' version... not a brand new cipher. Like Bruce Schneier said at the start of his Spritz page where he reminds us that its design is still very similar: "It retains all of the problems that RC4 had. It's built on a 256-element array of bytes, making it less than ideal for modern 32-bit and 64-bit CPUs. It's not very fast. (It's 50% slower than RC4, which was already much slower than algorithms like AES and Threefish.) It has a long key setup. But it's a very clever design."

Dan Bernstein's Salsa20/ChaCha look really nice to me at the moment! again different properties though, like everything better suited to some tasks not others. Anyone care to do a Purebasic implementation? will be in time for xmas :D

It all depends on what properties best suit your task ... ROT13 gets the job done against certain adversaries, it just depends who you're protecting against and how far you want/need to go, right!?? "the right tool for the job" or something like that ... Spritz clearly isn't that right tool for most jobs, but like Bruce said surely it'll have a niche :D
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by wilbert »

Keya wrote:Dan Bernstein's Salsa20/ChaCha look really nice to me at the moment!
Salsa20 seems not that complicated and could benefit from using SSE2 instructions from what I've read (the same is true for ChaCha20).
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by Keya »

Salsa has fixed 256bit keysize though so it cant be used without export clearance, whereas RC4/Spritz is variable 40-2048bit so it can be used without those legal hassles if it fits your security bill. Properties :D
Ive got some private basic code for ChaCha a friend ported from C which passes all test vectors, but i havent ported it over to Purebasic yet, im still very new to PB so it would take a while and im very busy with uni :( there's not too much code to it though, very efficient algorithm

Youtube: Ron Rivest discusses Spritz
Here's an interesting 2015 talk by Ron Rivest "On the growth of Cryptography", it's a historical discussion 1hr:37m long but halfway in he introduces Spritz after discussing RC4
https://www.youtube.com/watch?feature=p ... N_4#t=3137 (RC4 @ 52:20)
https://www.youtube.com/watch?feature=p ... N_4#t=3339 (Spritz @ 55:50, for three and a half minutes)
xakep
User
User
Posts: 40
Joined: Fri Mar 25, 2016 2:02 pm
Location: Europe

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by xakep »

@Keya
Simply perfect, you saved my day!

Could you tell me if these declarations are right: (i allways like to use EnableExplicit)

Code: Select all

Procedure.l RC4SpritzMem(Mem.l, memLen.l, key.s)
  Dim S.l(255)
  Dim K.l(255)
  Define i.l, j.l, t.l, x.l, temp.l, y.l, l.l, *Sp.LONG, *keyP.BYTE, z.l, w, *Memm.BYTE, k.l
....
Not sure about w

Thanks for your time.
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by walbus »

I self think, RC4 .. has no future, sorry.
Last edited by walbus on Mon Apr 04, 2016 8:26 am, edited 4 times in total.
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by Keya »

dont forget we still need to check test vectors! which were sadly lacking in availability at the time i posted lol
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: RC4 cipher Spritz variant by Ron Rivest & Jacob Schuldt

Post by Keya »

hello I have uploaded a Public Domain C implementation of Spritz (https://github.com/jedisct1/spritz)
Libs for Windows, Linux, OSX, 32+64, and all four GCC optimization levels 0-3, are at http://www.mediafire.com/download/fkh2g ... tz-lib.zip (48kb)
It wants a SecureZeroMemory function which doesnt exist on Windows XP but it has alternative code for that so I recompiled, Windows 32+64 libs only: http://www.mediafire.com/download/3a9x5 ... itz-xp.zip
I got some courage to try compiling it after finding it easy to compile a similar RC4 lib hehee, and yes this was just as easy, whew! :)

The function are:

Code: Select all

int spritz_stream(unsigned char *out, size_t outlen,
                  const unsigned char *key, size_t keylen);
int spritz_encrypt(unsigned char *out, const unsigned char *msg, size_t msglen,
                   const unsigned char *nonce, size_t noncelen,
                   const unsigned char *key, size_t keylen);
int spritz_decrypt(unsigned char *out, const unsigned char *c, size_t clen,
                   const unsigned char *nonce, size_t noncelen,
                   const unsigned char *key, size_t keylen);
int spritz_auth(unsigned char *out, size_t outlen,
                const unsigned char *msg, size_t msglen,
                const unsigned char *key, size_t keylen);
Here is my demo:

Code: Select all

CompilerIf #PB_Compiler_Unicode
  CompilerError "Ascii compile for this demo"
CompilerEndIf

#SpritzOPT$ = "3"  ;0-3
CompilerIf (#PB_Compiler_OS = #PB_OS_Linux) Or (#PB_Compiler_OS = #PB_OS_Windows And #PB_Compiler_Processor = #PB_Processor_x64)
  #APIPrefix = ""
CompilerElse
  #APIPrefix = "_"
CompilerEndIf
CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Windows: #SpritzOS$ = "Windows"
  CompilerCase #PB_OS_MacOS: #SpritzOS$ = "OSX"
  CompilerCase #PB_OS_Linux: #SpritzOS$ = "Linux"
CompilerEndSelect
CompilerSelect #PB_Compiler_Processor
  CompilerCase #PB_Processor_x64: #SpritzCPU$ = "64"
  CompilerCase #PB_Processor_x86: #SpritzCPU$ = "32"
CompilerEndSelect
#SpritzLIB$ = #SpritzOS$+"/spritz-"+#SpritzCPU$+".O"+#SpritzOPT$+".o"

ImportC #SpritzLIB$    ;"Windows/spritz-32.O3.o" 
  spritz_stream(*out, outlen.l, *key, keylen.l) As #APIPrefix+"spritz_stream"
  spritz_encrypt(*out, *msg, msglen.l, *nonce, noncelen.l, *key, keylen.l) As #APIPrefix+"spritz_encrypt"
  spritz_decrypt(*out, *c, clen.l, *nonce, noncelen.l, *key, keylen.l) As #APIPrefix+"spritz_decrypt"
  spritz_auth(*out, outlen.l, *msg, msglen.l, *key, keylen.l) As #APIPrefix+"spritz_auth"
EndImport


msg.s = "My secret message"
key.s = "My key"
nonce.s = "My nonce" ;nonce = number used ONLY ONCE http://en.wikipedia.org/wiki/Cryptographic_nonce

datlen.i = Len(msg)

*enc = AllocateMemory(512)
spritz_encrypt(*enc, @msg, Len(msg), @nonce, Len(nonce), @key, Len(key))
ShowMemoryViewer(*enc, datlen)
MessageRequester("Spritz", "Encrypted")


*dec = AllocateMemory(512)
spritz_decrypt(*dec, *enc, datlen, @nonce, Len(nonce), @key, Len(key))
ShowMemoryViewer(*dec, datlen)
MessageRequester("Spritz", "Decrypted")
There was also a "spritz_hash" function but i removed that, because it just felt like the right thing to do lol.
I'm not sure quite what spritz_auth() does, but at least the code shows it doesnt use spritz_hash().
spritz_stream() im guessing isnt needed unless you want to use it to xor the stream yourself as opposed to using the built-in spritz_encrypt()/decrypt().
Post Reply