Implementing RC4 on Racket

196 views Asked by At

I'm trying to translate a C# implementation of the RC4 cipher I wrote to the Racket language.

However, they are producing different keystreams. I have already eliminated the possiblity of miswriting the key-scheduling phase; that must be correct as they result in the same array S. Thus I'm focusing on finding differences in the keystream generation phase.

C#:

public int Dencode (int c)
{
    I = (I + 1) % 256;
    J = (J + S [I]) % 256;
    int tmp = S [I];
    S [I] = S [J];
    S [J] = tmp;
    return S [(S[I] + S[J]) % 256] ^ c;
}

Racket:

(define (toret c)
    (set! i (unsafe-fxmodulo (add1 i) 256))
    (set! j (unsafe-fxmodulo (add1 (Sr i)) 256))
    (swap! (box (Sr i)) (box (Sr j)))
    (bitwise-xor (Sr (unsafe-fxmodulo (+ (Sr i) (Sr j)) 256)) c))

with swap defined as

(define (swap! ba bb)
  (define temp (unbox ba))
  (set-box! ba (unbox bb))
  (set-box! bb temp))

and Sr defined as (define (Sr x) (unsafe-bytes-ref S x)).

What is the difference? Why are these functions producing different output? In both cases i and j are initialized to 0, and S is an identical 256-byte array.

2

There are 2 answers

0
ithisa On BEST ANSWER

There was a very stupid error. (set! j (unsafe-fxmodulo (add1 (Sr i)) 256)) is not equivalent to J = (J + S [I]) % 256;! Adding debug printf lines after each statement helped a lot.

3
C. K. Young On

The line

(swap! (box (Sr i)) (box (Sr j)))

won't do what you expect. It doesn't magically make (Sr i) and (Sr j) mutable references. The swap! procedure swaps the contents of the boxes---but the boxes contain (Sr i) and (Sr j) by value, not by reference.

What you need to do is to amend your swap! procedure to use unsafe-bytes-set! instead.


Here's some code to demonstrate my point:

#lang racket
(require racket/unsafe/ops)

(define (box-swap! x y)
  (define tmp (unbox x))
  (set-box! x (unbox y))
  (set-box! y tmp))

(define (wrong-swap! bs x y)
  (box-swap! (box (unsafe-bytes-ref bs x))
             (box (unsafe-bytes-ref bs y))))

(define (right-swap! bs x y)
  (define tmp (unsafe-bytes-ref bs x))
  (unsafe-bytes-set! bs x (unsafe-bytes-ref bs y))
  (unsafe-bytes-set! bs y tmp))

Example:

> (define bs (bytes 1 2 3 4 5 6))
> bs
#"\1\2\3\4\5\6"
> (wrong-swap! bs 0 5)
> bs
#"\1\2\3\4\5\6"
> (right-swap! bs 0 5)
> bs
#"\6\2\3\4\5\1"