我正在尝试对 WEP实施FMS 攻击。我知道攻击利用 RC4 sbox 的部分不改变的可能性来创建“已知”的 sbox 状态来对密钥进行逆向工程。对于许多样本,正确的密钥八位字节应该比噪声更频繁地出现。
应该添加到频率计数的值是:
哪里(我认为;符号定义不正确)
- B 从 0 开始
- P.out 是输出的密钥流字节
- S 是 Sbox
- j 是 RC4 密钥调度算法中使用的“指针”
在我的代码中,我生成了 600 万个数据包:一个常量根密钥和常量明文来模拟常量头,然后用 加密RC4(IV + root_key).encrypt(plaintext)
,而不丢弃前 256 个八位字节)。这些(IV, encrypted_data)
对通过get_key
函数运行:
uint8_t RC4_ksa(const std::string & k, std::array <uint8_t, 256> & s, const uint16_t octets = 256){
for(uint16_t i = 0; i < 256; i++){
s[i] = i;
}
uint8_t j = 0;
for(uint16_t i = 0; i < octets; i++){
j = (j + s[i] + k[i % k.size()]);
std::swap(s[i], s[j]);
}
return j;
}
std::string get_key(const uint8_t keylen, const std::vector <std::pair <std::string, std::string> > & captured){
std::string rkey = ""; // root key to build
const std::string & pt = header; // "plaintext" with constant header
// recreate root key one octet at a time
for(uint8_t i = 3; i < keylen; i++){
// vote counter for current octet
std::array <unsigned int, 256> votes;
votes.fill(0);
uint8_t most = 0; // most probable index/octet value
// get vote from each "captured" ciphertext
for(std::pair <std::string, std::string> const & c : captured){
const std::string & IV = c.first;
// IV should be of form (i = root key index + 3, 255, some value)
if ((static_cast<uint8_t> (IV[0]) != i) ||
(static_cast<uint8_t> (IV[1]) != 0xff)){
continue; // skip this data
}
const std::string & ct = c.second;
const std::string key = IV + rkey;
// find current packet's vote
std::array <uint8_t, 256> sbox; // SBox after simulating; fill with RC4_ksa
uint8_t j = RC4_ksa(key, sbox, i); // simulate using key in KSA, up to known octets only
uint8_t keybytestream = pt[i - 3] ^ ct[i - 3];
// S^-1[keybytestream]
uint16_t sinv;
for(sinv = 0; sinv < 256; sinv++){
if (sbox[sinv] == keybytestream){
break;
}
}
// get mapping
uint8_t ki = sinv - j - sbox[i];
// add to tally and keep track of which tally is highest
votes[ki]++;
if (votes[ki] > votes[most]){
most = ki;
}
}
// select highest voted value as next key octet
rkey += std::string(1, most);
}
return rkey;
}
我得到的密钥完全不正确。我觉得这个错误可能是一次性错误或类似的愚蠢的东西,但我已经让两个人看这个,没有一个人设法弄清楚什么是错误的。
有什么明显的错误吗?如果不是,那么什么是不那么明显的错误?