Я пытаюсь реализовать FMS атака на WEP. Я понимаю, что атака использует вероятность того, что части sbox RC4 не изменятся, чтобы создать «известные» состояния sbox для обратного инжиниринга ключа. Во многих выборках правильный октет ключа должен появляться чаще, чем шум.
Значение, которое следует добавить к счетчику частоты:
где (я думаю; нотация не определена правильно)
В моем коде я генерирую 6 миллионов пакетов данных: постоянный корневой ключ и постоянный открытый текст для имитации постоянного заголовка, а затем шифрую с 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;
}
Я получаю ключи, которые совершенно неверны. Я чувствую, что ошибка, вероятно, является разовой ошибкой или чем-то глупым, но я попросил двух людей взглянуть на это, и ни одному из них не удалось выяснить, в чем дело.
Есть что-то, что явно не так? Если нет, то что не так очевидно?
Задача ещё не решена.