From 5d315c5b6d4eabb474000836df9ed67322651b59 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sun, 2 Jun 2013 16:14:21 -0300 Subject: [PATCH] Fixed a CCMP padding bug. --- include/crypto.h | 31 +++++++-- include/eapol.h | 15 ++-- src/crypto.cpp | 138 ++++++++++++++++++++----------------- tests/src/wpa2_decrypt.cpp | 16 ++--- 4 files changed, 113 insertions(+), 87 deletions(-) diff --git a/include/crypto.h b/include/crypto.h index 2247946..3b08b2f 100644 --- a/include/crypto.h +++ b/include/crypto.h @@ -63,6 +63,7 @@ namespace Crypto { typedef Internals::byte_array<80> ptk_type; typedef Internals::byte_array<32> pmk_type; + SessionKeys(); SessionKeys(const RSNHandshake &hs, const pmk_type &pmk); SNAP *decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const; private: @@ -179,9 +180,9 @@ namespace Crypto { typedef HWAddress<6> address_type; /** - * \brief Adds a supplicant's information. + * \brief Adds an access points's information. * - * This associates an SSID with a PSK., and allows the decryption of + * This associates an SSID with a PSK, and allows the decryption of * any BSSIDs that broadcast the same SSID. * * The decrypter will inspect beacon frames, looking for SSID tags @@ -191,15 +192,15 @@ namespace Crypto { * handshake capturing will be disabled until any access point * broadcasts the provided SSID(this shouldn't take long at all). * If this is not the desired behaviour, then you should check out - * the ovther add_supplicant_data overload. + * the ovther add_ap_data overload. * * \param psk The PSK associated with the SSID. * \param ssid The network's SSID. */ - void add_supplicant_data(const std::string &psk, const std::string &ssid); + void add_ap_data(const std::string &psk, const std::string &ssid); /** - * \brief Adds a supplicant's information, including the BSSID. + * \brief Adds a access points's information, including its BSSID. * * This overload can be used if the BSSID associated with this SSID is * known beforehand. The addr parameter indicates which specific BSSID @@ -212,7 +213,7 @@ namespace Crypto { * \param ssid The network's SSID. * \param addr The access point's BSSID. */ - void add_supplicant_data(const std::string &psk, const std::string &ssid, const address_type &addr); + void add_ap_data(const std::string &psk, const std::string &ssid, const address_type &addr); /** * \brief Decrypts the provided PDU. @@ -320,7 +321,7 @@ namespace Crypto { void rc4(ForwardIterator start, ForwardIterator end, RC4Key &key, OutputIterator output); /** - * \brief Wrapper function to create DecrypterProxyes using a + * \brief Wrapper function to create a DecrypterProxy using a * WEPDecrypter as the Decrypter template parameter. * * \param functor The functor to be forwarded to the DecrypterProxy @@ -328,6 +329,16 @@ namespace Crypto { */ template DecrypterProxy make_wep_decrypter_proxy(const Functor &functor); + + /** + * \brief Wrapper function to create a DecrypterProxy using a + * WPA2Decrypter as the Decrypter template parameter. + * + * \param functor The functor to be forwarded to the DecrypterProxy + * constructor. + */ + template + DecrypterProxy make_wpa2_decrypter_proxy(const Functor &functor); // Implementation section @@ -366,6 +377,12 @@ namespace Crypto { { return DecrypterProxy(functor); } + + template + DecrypterProxy make_wpa2_decrypter_proxy(const Functor &functor) + { + return DecrypterProxy(functor); + } // RC4 stuff diff --git a/include/eapol.h b/include/eapol.h index 5cbf50f..d68daad 100644 --- a/include/eapol.h +++ b/include/eapol.h @@ -473,8 +473,8 @@ namespace Tins { const key_type &key() const { return _key; } /** - * \brief Getter for the key_mic field. - * \return The key_mic field. + * \brief Getter for the key mic field. + * \return 1 if this EAPOL PDU contains a valid MIC, 0 otherwise. */ small_uint<1> key_mic() const { return _header.key_mic; }; @@ -500,17 +500,18 @@ namespace Tins { * \brief Getter for the encrypted field. * \return The encrypted field. */ - small_uint<1 > encrypted() const { return _header.encrypted; }; + small_uint<1> encrypted() const { return _header.encrypted; }; /** - * \brief Getter for the key_descriptor field. - * \return The key_descriptor field. + * \brief Getter for the key descriptor field. + * \return The key descriptor field. */ small_uint<3> key_descriptor() const { return _header.key_descriptor; }; /** - * \brief Getter for the key_t field. - * \return The key_t field. + * \brief Getter for the key type field. + * + * \return 1 if this is a pairwise key, 0 otherwise. */ small_uint<1> key_t() const { return _header.key_t; }; diff --git a/src/crypto.cpp b/src/crypto.cpp index 5164eae..5745b61 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -225,6 +225,10 @@ HWAddress<6> get_bssid(const Dot11Data &dot11) { namespace WPA2 { +SessionKeys::SessionKeys() { + +} + SessionKeys::SessionKeys(const RSNHandshake &hs, const pmk_type &pmk) { uint8_t PKE[100] = "Pairwise key expansion"; uint8_t MIC[16]; @@ -257,7 +261,7 @@ SessionKeys::SessionKeys(const RSNHandshake &hs, const pmk_type &pmk) { } SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const { - const RawPDU::payload_type &pload = raw.payload(); + RawPDU::payload_type &pload = raw.payload(); uint8_t MIC[16] = {0}; uint8_t PN[6] = { pload[7], @@ -290,7 +294,6 @@ SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) con AES_set_encrypt_key(ptk.begin() + 32, 128, &ctx); uint8_t crypted_block[16]; size_t total_sz = raw.payload_size() - 16, offset = 8, blocks = (total_sz + 15) / 16; - std::vector output(total_sz); uint8_t counter[16]; counter[0] = 0x59; @@ -314,17 +317,20 @@ SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) con xor_range(crypted_block, nice_MIC, nice_MIC, 8); for(size_t i = 1; i <= blocks; ++i) { size_t block_sz = (i == blocks) ? (total_sz % 16) : 16; + if(block_sz == 0) + block_sz = 16; counter[14] = (i >> 8) & 0xff; counter[15] = i & 0xff; AES_encrypt(counter, crypted_block, &ctx ); - xor_range(crypted_block, &pload[offset], &output[(i - 1) * 16], block_sz); + + xor_range(crypted_block, &pload[offset], &pload[(i - 1) * 16], block_sz); - xor_range(MIC, &output[(i - 1) * 16], MIC, block_sz); + xor_range(MIC, &pload[(i - 1) * 16], MIC, block_sz); AES_encrypt(MIC, MIC, &ctx); offset += block_sz; } return (std::equal(nice_MIC, nice_MIC + sizeof(nice_MIC), MIC)) ? - new SNAP(&output[0], output.size()) : + new SNAP(&pload[0], total_sz) : 0; } @@ -334,67 +340,68 @@ RC4Key SessionKeys::generate_rc4_key(const Dot11Data &dot11, const RawPDU &raw) Internals::byte_array<16> rc4_key; uint16_t ppk[6]; const Dot11::address_type addr = get_bssid(dot11); - if(pload.size() >= 7) { - // Phase 1 - ppk[0] = join_bytes(pload[4], pload[5]); - ppk[1] = join_bytes(pload[6], pload[7]); - ppk[2] = join_bytes(addr[1], addr[0]); - ppk[3] = join_bytes(addr[3], addr[2]); - ppk[4] = join_bytes(addr[5], addr[4]); - - for(size_t i = 0; i < 4; ++i) { - ppk[0] += sbox(ppk[4] ^ join_bytes(tk[1], tk[0])); - ppk[1] += sbox(ppk[0] ^ join_bytes(tk[5], tk[4])); - ppk[2] += sbox(ppk[1] ^ join_bytes(tk[9], tk[8])); - ppk[3] += sbox(ppk[2] ^ join_bytes(tk[13], tk[12])); - ppk[4] += sbox(ppk[3] ^ join_bytes(tk[1], tk[0])) + 2*i; - ppk[0] += sbox(ppk[4] ^ join_bytes(tk[3], tk[2])); - ppk[1] += sbox(ppk[0] ^ join_bytes(tk[7], tk[6])); - ppk[2] += sbox(ppk[1] ^ join_bytes(tk[11], tk[10])); - ppk[3] += sbox(ppk[2] ^ join_bytes(tk[15], tk[14])); - ppk[4] += sbox(ppk[3] ^ join_bytes(tk[3], tk[2])) + 2*i + 1; - } - - // Phase 2, step 1 - ppk[5] = ppk[4] + join_bytes(pload[0], pload[2]); - - // Phase 2, step 2 - ppk[0] += sbox(ppk[5] ^ join_bytes(tk[1], tk[0])); - ppk[1] += sbox(ppk[0] ^ join_bytes(tk[3], tk[2])); - ppk[2] += sbox(ppk[1] ^ join_bytes(tk[5], tk[4])); - ppk[3] += sbox(ppk[2] ^ join_bytes(tk[7], tk[6])); - ppk[4] += sbox(ppk[3] ^ join_bytes(tk[9], tk[8])); - ppk[5] += sbox(ppk[4] ^ join_bytes(tk[11], tk[10])); - - ppk[0] += rotate(ppk[5] ^ join_bytes(tk[13], tk[12])); - ppk[1] += rotate(ppk[0] ^ join_bytes(tk[15], tk[14])); - ppk[2] += rotate(ppk[1]); - ppk[3] += rotate(ppk[2]); - ppk[4] += rotate(ppk[3]); - ppk[5] += rotate(ppk[4]); - - // Phase 2, step 3 - rc4_key[0] = upper_byte(join_bytes(pload[0], pload[2])); - rc4_key[1] = (rc4_key[0] | 0x20) & 0x7f; - rc4_key[2] = lower_byte(join_bytes(pload[0], pload[2])); - rc4_key[3] = lower_byte((ppk[5] ^ join_bytes(tk[1], tk[0])) >> 1); - rc4_key[4] = lower_byte(ppk[0]); - rc4_key[5] = upper_byte(ppk[0]); - rc4_key[6] = lower_byte(ppk[1]); - rc4_key[7] = upper_byte(ppk[1]); - rc4_key[8] = lower_byte(ppk[2]); - rc4_key[9] = upper_byte(ppk[2]); - rc4_key[10] = lower_byte(ppk[3]); - rc4_key[11] = upper_byte(ppk[3]); - rc4_key[12] = lower_byte(ppk[4]); - rc4_key[13] = upper_byte(ppk[4]); - rc4_key[14] = lower_byte(ppk[5]); - rc4_key[15] = upper_byte(ppk[5]); + // Phase 1 + ppk[0] = join_bytes(pload[4], pload[5]); + ppk[1] = join_bytes(pload[6], pload[7]); + ppk[2] = join_bytes(addr[1], addr[0]); + ppk[3] = join_bytes(addr[3], addr[2]); + ppk[4] = join_bytes(addr[5], addr[4]); + + for(size_t i = 0; i < 4; ++i) { + ppk[0] += sbox(ppk[4] ^ join_bytes(tk[1], tk[0])); + ppk[1] += sbox(ppk[0] ^ join_bytes(tk[5], tk[4])); + ppk[2] += sbox(ppk[1] ^ join_bytes(tk[9], tk[8])); + ppk[3] += sbox(ppk[2] ^ join_bytes(tk[13], tk[12])); + ppk[4] += sbox(ppk[3] ^ join_bytes(tk[1], tk[0])) + 2*i; + ppk[0] += sbox(ppk[4] ^ join_bytes(tk[3], tk[2])); + ppk[1] += sbox(ppk[0] ^ join_bytes(tk[7], tk[6])); + ppk[2] += sbox(ppk[1] ^ join_bytes(tk[11], tk[10])); + ppk[3] += sbox(ppk[2] ^ join_bytes(tk[15], tk[14])); + ppk[4] += sbox(ppk[3] ^ join_bytes(tk[3], tk[2])) + 2*i + 1; } + + // Phase 2, step 1 + ppk[5] = ppk[4] + join_bytes(pload[0], pload[2]); + + // Phase 2, step 2 + ppk[0] += sbox(ppk[5] ^ join_bytes(tk[1], tk[0])); + ppk[1] += sbox(ppk[0] ^ join_bytes(tk[3], tk[2])); + ppk[2] += sbox(ppk[1] ^ join_bytes(tk[5], tk[4])); + ppk[3] += sbox(ppk[2] ^ join_bytes(tk[7], tk[6])); + ppk[4] += sbox(ppk[3] ^ join_bytes(tk[9], tk[8])); + ppk[5] += sbox(ppk[4] ^ join_bytes(tk[11], tk[10])); + + ppk[0] += rotate(ppk[5] ^ join_bytes(tk[13], tk[12])); + ppk[1] += rotate(ppk[0] ^ join_bytes(tk[15], tk[14])); + ppk[2] += rotate(ppk[1]); + ppk[3] += rotate(ppk[2]); + ppk[4] += rotate(ppk[3]); + ppk[5] += rotate(ppk[4]); + + // Phase 2, step 3 + rc4_key[0] = upper_byte(join_bytes(pload[0], pload[2])); + rc4_key[1] = (rc4_key[0] | 0x20) & 0x7f; + rc4_key[2] = lower_byte(join_bytes(pload[0], pload[2])); + rc4_key[3] = lower_byte((ppk[5] ^ join_bytes(tk[1], tk[0])) >> 1); + rc4_key[4] = lower_byte(ppk[0]); + rc4_key[5] = upper_byte(ppk[0]); + rc4_key[6] = lower_byte(ppk[1]); + rc4_key[7] = upper_byte(ppk[1]); + rc4_key[8] = lower_byte(ppk[2]); + rc4_key[9] = upper_byte(ppk[2]); + rc4_key[10] = lower_byte(ppk[3]); + rc4_key[11] = upper_byte(ppk[3]); + rc4_key[12] = lower_byte(ppk[4]); + rc4_key[13] = upper_byte(ppk[4]); + rc4_key[14] = lower_byte(ppk[5]); + rc4_key[15] = upper_byte(ppk[5]); return RC4Key(rc4_key.begin(), rc4_key.end()); } SNAP *SessionKeys::tkip_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const { + // at least 20 bytes for IV + crc + stuff + if(raw.payload_size() <= 20) + return 0; Crypto::RC4Key key = generate_rc4_key(dot11, raw); RawPDU::payload_type &pload = raw.payload(); rc4(pload.begin() + 8, pload.end(), key, pload.begin()); @@ -434,14 +441,14 @@ const SupplicantData::pmk_type &SupplicantData::pmk() const { } } // namespace WPA2 -void WPA2Decrypter::add_supplicant_data(const std::string &psk, const std::string &ssid) { +void WPA2Decrypter::add_ap_data(const std::string &psk, const std::string &ssid) { pmks.insert(std::make_pair(ssid, WPA2::SupplicantData(psk, ssid))); } -void WPA2Decrypter::add_supplicant_data(const std::string &psk, const std::string &ssid, +void WPA2Decrypter::add_ap_data(const std::string &psk, const std::string &ssid, const address_type &addr) { - add_supplicant_data(psk, ssid); + add_ap_data(psk, ssid); add_access_point(ssid, addr); } @@ -457,7 +464,8 @@ void WPA2Decrypter::try_add_keys(const Dot11Data &dot11, const RSNHandshake &hs) if(it != aps.end()) { addr_pair addr_p = extract_addr_pair(dot11); try { - keys.insert(std::make_pair(addr_p, WPA2::SessionKeys(hs, it->second.pmk()))); + WPA2::SessionKeys session(hs, it->second.pmk()); + keys[addr_p] = session; } catch(WPA2::invalid_handshake&) { } } diff --git a/tests/src/wpa2_decrypt.cpp b/tests/src/wpa2_decrypt.cpp index e8e81c8..1ba1a56 100644 --- a/tests/src/wpa2_decrypt.cpp +++ b/tests/src/wpa2_decrypt.cpp @@ -91,7 +91,7 @@ void WPA2DecryptTest::check_tkip_packet6(const PDU &pdu) { TEST_F(WPA2DecryptTest, DecryptCCMPUsingBeacon) { Crypto::WPA2Decrypter decrypter; - decrypter.add_supplicant_data("Induction", "Coherer"); + decrypter.add_ap_data("Induction", "Coherer"); for(size_t i = 0; i < 7; ++i) { RadioTap radio(ccmp_packets[i], ccmp_packets_size[i]); if(i > 4) { @@ -108,7 +108,7 @@ TEST_F(WPA2DecryptTest, DecryptCCMPUsingBeacon) { TEST_F(WPA2DecryptTest, DecryptCCMPWithoutUsingBeacon) { Crypto::WPA2Decrypter decrypter; - decrypter.add_supplicant_data("Induction", "Coherer", "00:0c:41:82:b2:55"); + decrypter.add_ap_data("Induction", "Coherer", "00:0c:41:82:b2:55"); for(size_t i = 1; i < 7; ++i) { RadioTap radio(ccmp_packets[i], ccmp_packets_size[i]); if(i > 4) { @@ -125,7 +125,7 @@ TEST_F(WPA2DecryptTest, DecryptCCMPWithoutUsingBeacon) { TEST_F(WPA2DecryptTest, DecryptTKIPUsingBeacon) { Crypto::WPA2Decrypter decrypter; - decrypter.add_supplicant_data("libtinstest", "NODO"); + decrypter.add_ap_data("libtinstest", "NODO"); for(size_t i = 0; i < 7; ++i) { RadioTap radio(tkip_packets[i], tkip_packets_size[i]); if(i > 4) { @@ -142,7 +142,7 @@ TEST_F(WPA2DecryptTest, DecryptTKIPUsingBeacon) { TEST_F(WPA2DecryptTest, DecryptTKIPWithoutUsingBeacon) { Crypto::WPA2Decrypter decrypter; - decrypter.add_supplicant_data("libtinstest", "NODO", "00:1b:11:d2:1b:eb"); + decrypter.add_ap_data("libtinstest", "NODO", "00:1b:11:d2:1b:eb"); for(size_t i = 1; i < 7; ++i) { RadioTap radio(tkip_packets[i], tkip_packets_size[i]); if(i > 4) { @@ -159,8 +159,8 @@ TEST_F(WPA2DecryptTest, DecryptTKIPWithoutUsingBeacon) { TEST_F(WPA2DecryptTest, DecryptCCMPAndTKIPUsingBeacon) { Crypto::WPA2Decrypter decrypter; - decrypter.add_supplicant_data("libtinstest", "NODO"); - decrypter.add_supplicant_data("Induction", "Coherer"); + decrypter.add_ap_data("libtinstest", "NODO"); + decrypter.add_ap_data("Induction", "Coherer"); for(size_t i = 0; i < 7; ++i) { RadioTap radio(ccmp_packets[i], ccmp_packets_size[i]); if(i > 4) { @@ -189,8 +189,8 @@ TEST_F(WPA2DecryptTest, DecryptCCMPAndTKIPUsingBeacon) { TEST_F(WPA2DecryptTest, DecryptCCMPAndTKIPWithoutUsingBeacon) { Crypto::WPA2Decrypter decrypter; - decrypter.add_supplicant_data("libtinstest", "NODO", "00:1b:11:d2:1b:eb"); - decrypter.add_supplicant_data("Induction", "Coherer", "00:0c:41:82:b2:55"); + decrypter.add_ap_data("libtinstest", "NODO", "00:1b:11:d2:1b:eb"); + decrypter.add_ap_data("Induction", "Coherer", "00:0c:41:82:b2:55"); for(size_t i = 1; i < 7; ++i) { RadioTap radio(ccmp_packets[i], ccmp_packets_size[i]); if(i > 4) {