【问题标题】:CipherSaber bugCipherSaber 漏洞
【发布时间】:2013-05-17 07:18:56
【问题描述】:

所以我实现了ciphersaber-1。它几乎可以工作,我可以解密cstest1.cs1。但我无法让 cstest2.cs1 工作。

输出是:

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óÅ

所以我在初始化状态时一定有一个错误。奇怪的是,我可以毫无问题地加密和解密长文本,所以这个 bug 是对称的。

我将 rc4 密码实现为可重入单字节算法,正如您在 rc4.c 中看到的那样。

状态存储在 rc4_state 结构体中:

typedef unsigned char rc4_byte;

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

状态用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;
}

实际的加密/解密是在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];
}

为了完整性,交换:

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

我已经为此烦恼了两天多...状态,至少对于“asdfg”键是正确的。任何帮助都会很好。

整个内容可以在我的 github 仓库中找到:https://github.com/rioki/ciphersaber/

【问题讨论】:

  • 如果将!= 255 替换为!= 0 会发生什么情况。您似乎跳过了初始化的最后一步。

标签: c encryption rc4-cipher


【解决方案1】:

我在网上搜索时偶然发现了您的问题,但由于您尚未更新your code at GitHub,我想您可能仍然想知道问题所在。

就在这段代码中:

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

在此循环迭代 255 次后,i 的值为 255,循环将终止。结果,状态缓冲区的最后一个字节未初始化。

这很容易解决。只需将while (i != 255); 更改为while (i);

【讨论】:

  • 天哪!你喜欢我的问题。一旦你这样看,它似乎很明显。
【解决方案2】:

很抱歉您没有收到反馈,我今天终于在 Python 3 中完成了这个,但对 C 的了解不够,无法调试您的代码。

ciphersaber 主页面上的某些链接已损坏(指向“.com”而不是“.org”),因此您可能没有找到常见问题解答:

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

它包括以下调试提示:

  • 确保您没有以文本文件的形式读取或写入加密文件。文件 I/O 必须使用二进制模式。
  • 如果您使用 C 语言编写,请务必将字节存储为无符号字符。
  • 注意经典的索引问题。您选择的编程语言中的数组是以 0 开头还是 1 开头?
  • 确保在加密时写入随机的 10 字节 IV,并在解密时从文件开头读取 IV。
  • 如果您的程序仍然无法运行,请在关键设置步骤之后输入一些语句以打印出 S 数组。然后运行你的程序 使用 asdfg 作为密钥解密文件 cstest1.cs1。这是S的方法 数组应该看起来:

文件:cstest1.cs1

键: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

我还发现“令人难忘的测试用例”在这里很有帮助: http://www.cypherspace.org/adam/csvec/

包括: key="Al"+ct="Al Dakota 购买"(iv="Al Dakota"): pt =“蜂蜜酒”

尽管令人难忘的测试用例需要 cs2,但从 cs1 升级到 cs2 相当简单,即使没有完全调试程序的其余部分,您也可以自信地将程序从 cs1 转换为 cs2。

另请注意,常见问题解答声称网站上曾经有一个文件无法解码,请确保您的目标文件不以“0e e3 f9 b2 40 11 fc 3e ...”开头 (虽然我认为这是一个较小的测试文件,而不是证书。)

哦,而且还知道该网站并没有真正了解 RC4 及其衍生产品的最新研究。除非一切都失败,否则将其保留为玩具程序。

【讨论】:

  • 感谢您迟到的评论。我会考虑你的建议。这是一个周日下午的有趣项目,所以不用担心。我通常使用 GPG 和 TrueCrypt。让我恼火的是我没有找到我的错误。
  • 是的,这是一个简短的程序,只有一两个循环,但我有几个小时无法确定的错误,感觉很糟糕。对于大多数算法来说,很难调试通过难以辨认的黑匣子的东西,这无济于事。
【解决方案3】:

Python

这是我用 Python 写的一个问题,后来被删除了。它将文件作为流处理,因此内存使用量适中。

用法

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)

【讨论】:

  • 谢谢你,我会尝试作为参考来找到我的差异。
猜你喜欢
  • 1970-01-01
  • 2021-06-05
  • 2017-06-08
  • 2012-10-13
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 2022-01-12
  • 2012-08-16
相关资源
最近更新 更多