1

So I implemented ciphersaber-1. It almost works, I can decrypt the cstest1.cs1. But i have trouble getting cstest2.cs1 to work.

The output is:

The Fourth Amendment to the Constitution of the Unite ▀Stat→s of America

"The right o☻ the people to be secure in their persons, houses, papers, and
effects, against unreasonab→e searches an╚A)┤Xx¹▼☻dcðþÈ_#­0Uc.?n~J¿|,lómsó£k░7╠▄
íuVRÊ ╣├xð"↕(Gû┤.>!{³♫╚Tƒ}Àõ+»~C;ÔÙ²÷g.qÏø←1ß█yÎßsÈ÷g┐ÅJÔÞ┘Îö║AÝf╔ìêâß╗È;okn│CÚê
õ&æÄ[5&Þ½╔s╦Nå1En♂☻♫ôzÓ9»Á╝ÐÅ├ðzÝÎòeØ%W¶]¤▲´Oá╗e_Ú)╣ó0↑ï^☻P>ù♂­¥¯▄‗♦£mUzMצվ~8å
ì½³░Ùã♠,H-tßJ!³*²RóÅ

So I must have a bug in initializing the state. The odd thing is that I can encrypt and decrypt long texts without problems, so the bug is symmetric.

I implemented the rc4 cipher as a reentrent single byte algorithm as you can see in rc4.c.

The state is stored in the rc4_state struct:

typedef unsigned char rc4_byte;

struct rc4_state_
{
    rc4_byte i;
    rc4_byte j;
    rc4_byte state[256];
};
typedef struct rc4_state_ rc4_state;

The state is initialized with rc4_init:

void rc4_init(rc4_state* state, rc4_byte* key, size_t keylen)
{
    rc4_byte i, j, n;

    i = 0;
    do
    {
        state->state[i] = i;
        i++;
    }    
    while (i != 255);

    j = 0;
    i = 0;
    do
    {
        n = i % keylen;
        j += state->state[i] + key[n];
        swap(&state->state[i], &state->state[j]);
        i++;
    }    
    while (i != 255);

    state->i = 0;
    state->j = 0;
}

The actual encryption / decryption is done in rc4:

rc4_byte rc4(rc4_state* state, rc4_byte in)
{
    rc4_byte n;

    state->i++;
    state->j += state->state[state->i];
    swap(&state->state[state->i], &state->state[state->j]);
    n = state->state[state->i] + state->state[state->j];

    return in ^ state->state[n];
}

For completeness, swap:

void swap(rc4_byte* a, rc4_byte* b)
{
    rc4_byte t = *a;
    *a = *b;
    *b = t;
}

I have been breaking my head on this for more than two days... The state, at least for the "asdfg" key is correct. Any help would be nice.

The whole thing can be found in my github reopsitory: https://github.com/rioki/ciphersaber/

rioki
  • 5,988
  • 5
  • 32
  • 55

3 Answers3

3

I stumbled across your question while searching online, but since you haven't updated your code at GitHub yet, I figured you might still like to know what the problem was.

It's in this bit of code:

i = 0;
do
{
    state->state[i] = i;
    i++;
}    
while (i != 255);

After this loop has iterated 255 times, i will have a value of 255 and the loop will terminate. As a result, the last byte of your state buffer is being left uninitialised.

This is easily fixed. Just change while (i != 255); to while (i);.

r3mainer
  • 23,981
  • 3
  • 51
  • 88
1

Sorry you haven't gotten feedback, I finally pulled this off in Python 3 today, but don't know enough about C to debug your code.

Some of the links on the main ciphersaber page are broken (pointing to ".com" instead of ".org"), so you might not have found the FAQ:

http://ciphersaber.gurus.org/faq.html

It includes the following debugging tips:

  • Make sure you are not reading or writing encrypted files as text files. You must use binary mode for file I/O.
  • If you are writing in the C language, be sure to store bytes as unsigned char.
  • Watch out for classic indexing problems. Do arrays in you chosen programming language start with 0 or 1?
  • Make sure you are writing out a random 10 byte IV when you encrypt and are reading the IV from the start of the file when you decrypt.
  • If your program still does not work, put in some statements to print out the S array after the key setup step. Then run your program to decrypt the file cstest1.cs1 using asdfg as the key. Here is how the S array should look:

file: cstest1.cs1

key: asdfg

176 32 49 160 15 112 58 8 186 19 50 161 60 17 82 153 37 141 131 127 59 2 165 103 98 53 9 57 41 150 174 64 36 62 191 154 44 136 149 158 226 113 230 227 247 155 221 34 125 20 163 95 128 219 1 181 201 146 88 204 213 80 143 164 145 234 134 248 100 77 188 235 76 217 194 35 75 99 126 92 243 177 52 180 83 140 198 42 151 18 91 33 16 192 101 48 97 220 114 110 124 72 139 218 142 118 81 84 31 29 195 68 209 172 200 214 93 240 61 22 206 123 152 7 203 10 119 171 79 250 109 137 199 167 11 104 211 129 208 216 178 207 242 162 30 120 65 115 87 170 47 69 244 212 45 85 73 222 225 185 63 0 179 210 108 245 202 46 96 148 51 173 24 182 89 116 3 67 205 94 231 23 21 13 169 215 190 241 228 132 252 4 233 56 105 26 12 135 223 166 238 229 246 138 239 54 5 130 159 236 66 175 189 147 193 237 43 40 117 157 86 249 74 27 156 14 133 251 196 187 197 102 106 39 232 255 121 122 253 111 90 38 55 70 184 78 224 25 6 107 168 254 144 28 183 71

I also found the "memorable test cases" helpful here: http://www.cypherspace.org/adam/csvec/

Including: key="Al"+ct="Al Dakota buys"(iv="Al Dakota "): pt = "mead"

Even though the memorable test cases require cs2, upgrading to cs2 from cs1 is fairly trivial, you may be able to confidently convert your program to cs2 from cs1 even without fully debugging the rest of it.

Also note that the FAQ claims there used to be a file on the site that wouldn't decode, make sure your target file doesn't begin with "0e e3 f9 b2 40 11 fc 3e ..." (Though I think that was a smaller test file, not the certificate.)

Oh, and also know that the site's not really up to date on the latest research into RC4 and derivatives. Just reserve this as a toy program unless all else fails.

Brownbat
  • 266
  • 1
  • 8
  • Thank you for the late comment. I will look into your advice. It was a Sunday afternoon fun project, so no worries there. I normally use GPG and TrueCrypt. What annoyed me to hell is that I did not find my bug. – rioki Aug 21 '13 at 15:59
  • Yeah, it's a short program with just like one or two loops, but I had some bug that I couldn't nail down for hours, it felt horrible. It doesn't help that it's really hard to debug something that passes through an indecipherable black box for most of the algorithm. – Brownbat Aug 24 '13 at 15:17
1

Python

Here's one I wrote in Python for a question that later got deleted. It processes the file as a stream so memory usage is modest.

Usage

python encrypt.py <key> <rounds> < <infile> > <outfile>
python decrypt.py <key> <rounds> < <infile> > <outfile>

rc4.py

#!/usr/bin/env python
# coding: utf-8
import psyco
from sys import stdin,stdout,argv
def rc4(K):
    R=range(256)
    S=R[:]
    T=bytearray(K*256)[:256]
    j=0
    for i in R*int(argv[2]):
        j=j+S[i]+T[i]&255
        S[i],S[j]=S[j],S[i]
    i=j=0
    while True:
        B=stdin.read(4096)
        if not B: break
        for c in B:
            i+=1&255
            j=j+S[i]&255
            S[i],S[j]=S[j],S[i]
            stdout.write(chr(ord(c)^S[S[i]+S[j]&255]))
psyco.bind(rc4)

encrypt.py

from rc4 import *
import os
V=os.urandom(10)
stdout.write(V)
rc4(argv[1]+V)

decrypt.py

from rc4 import *
V=stdin.read(10)
rc4(argv[1]+V)
John La Rooy
  • 295,403
  • 53
  • 369
  • 502