1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Add WPA2Decrypter callback interface

This commit is contained in:
Matias Fontanini
2016-02-28 08:01:04 -08:00
parent 3e84b07a01
commit 1681981fe8
6 changed files with 200 additions and 2 deletions

View File

@@ -131,6 +131,12 @@ ELSE()
MESSAGE(STATUS "Disabling ACK tracking support")
ENDIF()
OPTION(LIBTINS_ENABLE_WPA2_CALLBACKS "Enable WPA2 callback interface" ON)
IF(LIBTINS_ENABLE_WPA2_CALLBACKS AND TINS_HAVE_WPA2_DECRYPTION AND TINS_HAVE_CXX11)
SET(STATUS "Enabling WPA2 callback interface")
SET(TINS_HAVE_WPA2_CALLBACKS ON)
ENDIF()
# Use pcap_sendpacket to send l2 packets rather than raw sockets
IF(WIN32)
SET(USE_PCAP_SENDPACKET_DEFAULT ON)

View File

@@ -19,7 +19,7 @@ before_build:
- mkdir build
- cd build
- if "%platform%"=="x64" ( set GENERATOR="Visual Studio 12 Win64" ) else ( set GENERATOR="Visual Studio 12" )
- cmake .. -G %GENERATOR% -DPCAP_ROOT_DIR=c:\WpdPack -DLIBTINS_BUILD_SHARED=0
- cmake .. -G %GENERATOR% -DPCAP_ROOT_DIR=c:\WpdPack -DLIBTINS_BUILD_SHARED=0 -DLIBTINS_ENABLE_WPA2=0
build:
project: C:/projects/libtins/build/libtins.sln
verbosity: minimal

View File

@@ -19,4 +19,7 @@
/* Have GCC builtin swap */
#cmakedefine TINS_HAVE_GCC_BUILTIN_SWAP
/* Have WPA2Decrypter callbacks */
#cmakedefine TINS_HAVE_WPA2_CALLBACKS
#endif // TINS_CONFIG_H

View File

@@ -36,6 +36,9 @@
#include <string>
#include <algorithm>
#include <vector>
#ifdef TINS_HAVE_WPA2_CALLBACKS
#include <functional>
#endif // TINS_HAVE_WPA2_CALLBACKS
#include "utils.h"
#include "snap.h"
#include "rawpdu.h"
@@ -160,8 +163,15 @@ public:
* \return The generated PMK.
*/
const pmk_type& pmk() const;
/**
* \brief Getter for the SSID
* \return The access point's SSID
*/
const std::string& ssid() const;
private:
pmk_type pmk_;
std::string ssid_;
};
} // WPA2
@@ -275,6 +285,32 @@ public:
*/
typedef std::map<addr_pair, WPA2::SessionKeys> keys_map;
#ifdef TINS_HAVE_WPA2_CALLBACKS
/**
* \brief The type used to store the callback type used when a new access
* point is found.
*
* The first argument to the function will be the access point's SSID and
* the second one its BSSID.
*/
typedef std::function<void(const std::string&,
const address_type&)> ap_found_callback_type;
/**
* The type used to store the callback type used when a new handshake
* is captured.
*
* The first argument to the function will be the access point's SSID and
* the second one its BSSID. The third argument will be the client's hardware
* address.
*/
typedef std::function<void(const std::string&,
const address_type&,
const address_type&)> handshake_captured_callback_type;
#endif // TINS_HAVE_WPA2_CALLBACKS
/**
* \brief Adds an access points's information.
*
@@ -353,6 +389,30 @@ public:
*/
bool decrypt(PDU& pdu);
#ifdef TINS_HAVE_WPA2_CALLBACKS
/**
* \brief Sets the handshake captured callback
*
* This callback will be executed every time a new handshake is captured.
*
* \sa handshake_captured_callback_type
* \param callback The new callback to be set
*/
void handshake_captured_callback(const handshake_captured_callback_type& callback);
/**
* \brief Sets the access point found callback
*
* This callback will be executed every time a new access point is found, that's
* advertising an SSID added when calling add_ap_data.
*
* \sa ap_found_callback_type
* \param callback The new callback to be set
*/
void ap_found_callback(const ap_found_callback_type& callback);
#endif // TINS_HAVE_WPA2_CALLBACKS
/**
* \brief Getter for the keys on this decrypter
*
@@ -381,6 +441,10 @@ private:
pmks_map pmks_;
bssids_map aps_;
keys_map keys_;
#ifdef TINS_HAVE_WPA2_CALLBACKS
handshake_captured_callback_type handshake_captured_callback_;
ap_found_callback_type ap_found_callback_;
#endif // TINS_HAVE_WPA2_CALLBACKS
};
#endif // TINS_HAVE_WPA2_DECRYPTION

View File

@@ -491,7 +491,7 @@ bool SessionKeys::uses_ccmp() const {
// supplicant_data
SupplicantData::SupplicantData(const string& psk, const string& ssid)
: pmk_(SessionKeys::PMK_SIZE) {
: pmk_(SessionKeys::PMK_SIZE), ssid_(ssid) {
PKCS5_PBKDF2_HMAC_SHA1(
psk.c_str(),
psk.size(),
@@ -506,6 +506,11 @@ SupplicantData::SupplicantData(const string& psk, const string& ssid)
const SupplicantData::pmk_type& SupplicantData::pmk() const {
return pmk_;
}
const string& SupplicantData::ssid() const {
return ssid_;
}
} // namespace WPA2
void WPA2Decrypter::add_ap_data(const string& psk, const string& ssid) {
@@ -525,6 +530,12 @@ void WPA2Decrypter::add_access_point(const string& ssid, const address_type& add
throw runtime_error("Supplicant data not registered");
}
aps_.insert(make_pair(addr, it->second));
#ifdef TINS_HAVE_WPA2_CALLBACKS
if (ap_found_callback_) {
ap_found_callback_(ssid, addr);
}
#endif // TINS_HAVE_WPA2_CALLBACKS
}
void WPA2Decrypter::add_decryption_keys(const addr_pair& addresses,
@@ -540,6 +551,12 @@ void WPA2Decrypter::try_add_keys(const Dot11Data& dot11, const RSNHandshake& hs)
try {
SessionKeys session(hs, it->second.pmk());
keys_[addr_p] = session;
#ifdef TINS_HAVE_WPA2_CALLBACKS
if (handshake_captured_callback_) {
handshake_captured_callback_(it->second.ssid(), addr_p.first,
addr_p.second);
}
#endif // TINS_HAVE_WPA2_CALLBACKS
}
catch(WPA2::invalid_handshake&) {
@@ -629,6 +646,18 @@ bool WPA2Decrypter::decrypt(PDU& pdu) {
return false;
}
#ifdef TINS_HAVE_WPA2_CALLBACKS
void WPA2Decrypter::handshake_captured_callback(const handshake_captured_callback_type& callback) {
handshake_captured_callback_ = callback;
}
void WPA2Decrypter::ap_found_callback(const ap_found_callback_type& callback) {
ap_found_callback_ = callback;
}
#endif // TINS_HAVE_WPA2_CALLBACKS
#endif // TINS_HAVE_WPA2_DECRYPTION
} // namespace Crypto

View File

@@ -8,22 +8,59 @@
#include <stdint.h>
#include "crypto.h"
#include "radiotap.h"
#include "dot11/dot11_data.h"
#include "udp.h"
#include "tcp.h"
using namespace Tins;
using std::string;
using std::vector;
class WPA2DecryptTest : public testing::Test {
public:
typedef HWAddress<6> address_type;
static const uint8_t ccmp_packets[7][652];
static const uint8_t tkip_packets[7][211];
static const size_t ccmp_packets_size[], tkip_packets_size[];
struct handshake {
handshake(const string& ssid, const address_type& bssid, const address_type& client_hw)
: ssid(ssid), bssid(bssid), client_hw(client_hw) {
}
string ssid;
address_type bssid;
address_type client_hw;
};
struct ap_data {
ap_data(const string& ssid, const address_type& bssid)
: ssid(ssid), bssid(bssid) {
}
string ssid;
address_type bssid;
};
void check_ccmp_packet5(const PDU& pdu);
void check_ccmp_packet6(const PDU& pdu);
void check_tkip_packet5(const PDU& pdu);
void check_tkip_packet6(const PDU& pdu);
void handshake_captured(const string& ssid, const address_type& bssid, const address_type& client_hw) {
handshakes_.push_back(handshake(ssid, bssid, client_hw));
}
void ap_found(const string& ssid, const address_type& bssid) {
access_points_.push_back(ap_data(ssid, bssid));
}
vector<handshake> handshakes_;
vector<ap_data> access_points_;
};
// packet taken from aircrack's site.
@@ -283,4 +320,63 @@ TEST_F(WPA2DecryptTest, DecryptCCMPAndTKIPWithoutUsingBeacon) {
}
}
#ifdef TINS_HAVE_WPA2_CALLBACKS
TEST_F(WPA2DecryptTest, HandshakeCapturedCallback) {
using namespace std::placeholders;
Crypto::WPA2Decrypter decrypter;
decrypter.add_ap_data("libtinstest", "NODO", "00:1b:11:d2:1b:eb");
decrypter.add_ap_data("Induction", "Coherer", "00:0c:41:82:b2:55");
decrypter.handshake_captured_callback(std::bind(&WPA2DecryptTest::handshake_captured,
this, _1, _2, _3));
for(size_t i = 1; i < 7; ++i) {
RadioTap radio(ccmp_packets[i], ccmp_packets_size[i]);
decrypter.decrypt(radio);
}
for(size_t i = 1; i < 7; ++i) {
RadioTap radio(tkip_packets[i], tkip_packets_size[i]);
decrypter.decrypt(radio);
}
ASSERT_EQ(2, handshakes_.size());
handshake hs = handshakes_[0];
EXPECT_EQ(hs.ssid, "Coherer");
EXPECT_EQ(address_type("00:0d:93:82:36:3a"), hs.client_hw);
EXPECT_EQ(address_type("00:0c:41:82:b2:55"), hs.bssid);
hs = handshakes_[1];
EXPECT_EQ(hs.ssid, "NODO");
EXPECT_EQ(address_type("94:0c:6d:8f:93:88"), hs.client_hw);
EXPECT_EQ(address_type("00:1b:11:d2:1b:eb"), hs.bssid);
}
TEST_F(WPA2DecryptTest, AccessPointFoundCallback) {
using namespace std::placeholders;
Crypto::WPA2Decrypter decrypter;
decrypter.add_ap_data("libtinstest", "NODO");
decrypter.add_ap_data("Induction", "Coherer");
decrypter.ap_found_callback(std::bind(&WPA2DecryptTest::ap_found, this, _1, _2));
for(size_t i = 0; i < 7; ++i) {
RadioTap radio(ccmp_packets[i], ccmp_packets_size[i]);
decrypter.decrypt(radio);
}
for(size_t i = 0; i < 7; ++i) {
RadioTap radio(tkip_packets[i], tkip_packets_size[i]);
decrypter.decrypt(radio);
}
ASSERT_EQ(2, access_points_.size());
ap_data data = access_points_[0];
EXPECT_EQ("Coherer", data.ssid);
EXPECT_EQ(address_type("00:0c:41:82:b2:55"), data.bssid);
data = access_points_[1];
EXPECT_EQ("NODO", data.ssid);
EXPECT_EQ(address_type("00:1b:11:d2:1b:eb"), data.bssid);
}
#endif // TINS_HAVE_WPA2_CALLBACKS
#endif // defined(TINS_HAVE_DOT11) && defined(TINS_HAVE_WPA2_DECRYPTION)