mirror of
https://github.com/mfontanini/libtins
synced 2026-01-27 12:14:26 +01:00
Added WPA2Decrypter class.
This commit is contained in:
@@ -100,4 +100,5 @@ libtins_include_HEADERS = include/internals.h \
|
||||
include/utils.h \
|
||||
include/cxxstd.h \
|
||||
include/stp.h \
|
||||
include/exceptions.h
|
||||
include/exceptions.h \
|
||||
include/config.h
|
||||
|
||||
@@ -384,7 +384,8 @@ libtins_include_HEADERS = include/internals.h \
|
||||
include/utils.h \
|
||||
include/cxxstd.h \
|
||||
include/stp.h \
|
||||
include/exceptions.h
|
||||
include/exceptions.h \
|
||||
include/config.h
|
||||
|
||||
all: all-am
|
||||
|
||||
|
||||
84
configure
vendored
84
configure
vendored
@@ -775,6 +775,7 @@ enable_maintainer_mode
|
||||
with_pcap_include_path
|
||||
with_pcap_lib_path
|
||||
enable_c__11
|
||||
enable_wpa2
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
host_alias
|
||||
@@ -1418,6 +1419,7 @@ Optional Features:
|
||||
--disable-maintainer-mode disable make rules and dependencies not useful
|
||||
(and sometimes confusing) to the casual installer
|
||||
--enable-c++11 enable C++11 features
|
||||
--disable-wpa2 disable WPA2 decryption features
|
||||
|
||||
Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
@@ -15199,6 +15201,8 @@ CPPFLAGS=$old_cppflags
|
||||
|
||||
# Options
|
||||
|
||||
wpa2_msg="WPA2 decryption(which requires openssl) can be disabled using the --disable-wpa2 flag."
|
||||
|
||||
# Check whether --enable-c++11 was given.
|
||||
if test "${enable_c__11+set}" = set; then :
|
||||
enableval=$enable_c__11; ax_cxx_compile_cxx11_required=truednl
|
||||
@@ -15324,6 +15328,86 @@ $as_echo "#define HAVE_CXX11 1" >>confdefs.h
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-wpa2 was given.
|
||||
if test "${enable_wpa2+set}" = set; then :
|
||||
enableval=$enable_wpa2;
|
||||
else
|
||||
|
||||
for ac_header in openssl/evp.h openssl/hmac.h openssl/aes.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
as_fn_error $? "openssl headers are missing! $wpa2_msg " "$LINENO" 5
|
||||
|
||||
$as_echo "#define HAVE_WPA2_DECRYPTION 0" >>confdefs.h
|
||||
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PKCS5_PBKDF2_HMAC_SHA1 in -lcrypto" >&5
|
||||
$as_echo_n "checking for PKCS5_PBKDF2_HMAC_SHA1 in -lcrypto... " >&6; }
|
||||
if ${ac_cv_lib_crypto_PKCS5_PBKDF2_HMAC_SHA1+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lcrypto $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char PKCS5_PBKDF2_HMAC_SHA1 ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return PKCS5_PBKDF2_HMAC_SHA1 ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_link "$LINENO"; then :
|
||||
ac_cv_lib_crypto_PKCS5_PBKDF2_HMAC_SHA1=yes
|
||||
else
|
||||
ac_cv_lib_crypto_PKCS5_PBKDF2_HMAC_SHA1=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_PKCS5_PBKDF2_HMAC_SHA1" >&5
|
||||
$as_echo "$ac_cv_lib_crypto_PKCS5_PBKDF2_HMAC_SHA1" >&6; }
|
||||
if test "x$ac_cv_lib_crypto_PKCS5_PBKDF2_HMAC_SHA1" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_LIBCRYPTO 1
|
||||
_ACEOF
|
||||
|
||||
LIBS="-lcrypto $LIBS"
|
||||
|
||||
else
|
||||
as_fn_error $? "openssl library is missing! $wpa2_msg " "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
|
||||
$as_echo "#define HAVE_WPA2_DECRYPTION 1" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
23
configure.ac
23
configure.ac
@@ -36,12 +36,35 @@ CPPFLAGS=$old_cppflags
|
||||
|
||||
# Options
|
||||
|
||||
wpa2_msg="WPA2 decryption(which requires openssl) can be disabled using the --disable-wpa2 flag."
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
c++11,
|
||||
[ --enable-c++11 enable C++11 features],
|
||||
[AX_CXX_COMPILE_STDCXX_11(noext)]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
wpa2,
|
||||
[ --disable-wpa2 disable WPA2 decryption features],
|
||||
[],
|
||||
[
|
||||
AC_CHECK_HEADERS(
|
||||
[openssl/evp.h openssl/hmac.h openssl/aes.h],
|
||||
[],
|
||||
[AC_MSG_ERROR([openssl headers are missing! $wpa2_msg ])]
|
||||
AC_DEFINE([HAVE_WPA2_DECRYPTION], 0, Have WPA2 decryption library)
|
||||
)
|
||||
AC_CHECK_LIB(
|
||||
crypto,
|
||||
PKCS5_PBKDF2_HMAC_SHA1,
|
||||
[],
|
||||
[AC_MSG_ERROR([openssl library is missing! $wpa2_msg ])]
|
||||
)
|
||||
AC_DEFINE([HAVE_WPA2_DECRYPTION], 1, Have WPA2 decryption library)
|
||||
]
|
||||
)
|
||||
|
||||
# Substitute options
|
||||
|
||||
AC_SUBST(CXXFLAGS)
|
||||
|
||||
@@ -9,12 +9,24 @@
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
#undef HAVE_LIBCRYPTO
|
||||
|
||||
/* Define to 1 if you have the `pcap' library (-lpcap). */
|
||||
#undef HAVE_LIBPCAP
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
||||
#undef HAVE_OPENSSL_AES_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/evp.h> header file. */
|
||||
#undef HAVE_OPENSSL_EVP_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/hmac.h> header file. */
|
||||
#undef HAVE_OPENSSL_HMAC_H
|
||||
|
||||
/* Define to 1 if you have the <pcap.h> header file. */
|
||||
#undef HAVE_PCAP_H
|
||||
|
||||
@@ -39,6 +51,9 @@
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Have WPA2 decryption library */
|
||||
#undef HAVE_WPA2_DECRYPTION
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
148
include/crypto.h
148
include/crypto.h
@@ -34,15 +34,57 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "dot11.h"
|
||||
#include "utils.h"
|
||||
#include "snap.h"
|
||||
#include "rawpdu.h"
|
||||
#include "handshake_capturer.h"
|
||||
#include "config.h"
|
||||
|
||||
namespace Tins {
|
||||
class PDU;
|
||||
class Dot11;
|
||||
class Dot11Data;
|
||||
|
||||
namespace Crypto {
|
||||
/**
|
||||
* \cond
|
||||
*/
|
||||
#ifdef HAVE_WPA2_DECRYPTION
|
||||
namespace WPA2 {
|
||||
class invalid_handshake : public std::exception {
|
||||
public:
|
||||
const char *what() const throw() {
|
||||
return "invalid handshake";
|
||||
}
|
||||
};
|
||||
class CCMPSessionKeys {
|
||||
public:
|
||||
typedef Internals::byte_array<80> ptk_type;
|
||||
typedef Internals::byte_array<32> pmk_type;
|
||||
|
||||
CCMPSessionKeys(const RSNHandshake &hs, const pmk_type &pmk);
|
||||
SNAP *decrypt_unicast(const Dot11Data &dot11, const RawPDU &raw) const;
|
||||
private:
|
||||
ptk_type ptk;
|
||||
};
|
||||
|
||||
class SupplicantData {
|
||||
public:
|
||||
typedef HWAddress<6> address_type;
|
||||
typedef CCMPSessionKeys::pmk_type pmk_type;
|
||||
|
||||
SupplicantData(const std::string &psk, const std::string &ssid);
|
||||
|
||||
const pmk_type &pmk() const;
|
||||
private:
|
||||
pmk_type pmk_;
|
||||
};
|
||||
}
|
||||
#endif // HAVE_WPA2_DECRYPTION
|
||||
/**
|
||||
* \endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief RC4 Key abstraction.
|
||||
*/
|
||||
@@ -65,11 +107,11 @@ namespace Crypto {
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* \brief Decrypts WEP-encrypted traffic.
|
||||
*/
|
||||
class WEPDecrypter {
|
||||
public:
|
||||
typedef Dot11::address_type address_type;
|
||||
typedef HWAddress<6> address_type;
|
||||
|
||||
/**
|
||||
* \brief Constructs a WEPDecrypter object.
|
||||
@@ -93,19 +135,18 @@ namespace Crypto {
|
||||
void remove_password(const address_type &addr);
|
||||
|
||||
/**
|
||||
* \brief Decrypts the provided PDU and forwards the decrypted
|
||||
* PDU to the functor held by this object.
|
||||
* \brief Decrypts the provided PDU.
|
||||
*
|
||||
* A Dot11Data PDU is looked up inside the provided PDU chain.
|
||||
* If no such PDU exists or there is no password associated
|
||||
* with the Dot11 packet's BSSID, then the PDU is left intact.
|
||||
*
|
||||
* Otherwise, the packet is decrypted using the given password.
|
||||
* If the CRC found after decrypting it is invalid,
|
||||
* then false is returned.
|
||||
* If the CRC found after decrypting is invalid, false is
|
||||
* returned.
|
||||
*
|
||||
* \return false if decryption failed due to invalid CRC, true
|
||||
* otherwise.
|
||||
* \return false if no decryption was performed or decryption
|
||||
* failed, true otherwise.
|
||||
*/
|
||||
bool decrypt(PDU &pdu);
|
||||
private:
|
||||
@@ -117,6 +158,95 @@ namespace Crypto {
|
||||
std::vector<uint8_t> key_buffer;
|
||||
};
|
||||
|
||||
#ifdef HAVE_WPA2_DECRYPTION
|
||||
/**
|
||||
* \brief Decrypts WPA2-encrypted traffic.
|
||||
*
|
||||
* This class takes valid PSK and SSID tuples, captures client handshakes,
|
||||
* and decrypts their traffic afterwards.
|
||||
*/
|
||||
class WPA2Decrypter {
|
||||
public:
|
||||
/*
|
||||
* \brief The type used to store Dot11 addresses.
|
||||
*/
|
||||
typedef HWAddress<6> address_type;
|
||||
|
||||
/**
|
||||
* \brief Adds a supplicant's information.
|
||||
*
|
||||
* 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
|
||||
* that contain the given SSID.
|
||||
*
|
||||
* Note that using this overload, the decryption of data frames and
|
||||
* 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.
|
||||
*
|
||||
* \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);
|
||||
|
||||
/**
|
||||
* \brief Adds a supplicant's information, including the BSSID.
|
||||
*
|
||||
* This overload can be used if the BSSID associated with this SSID is
|
||||
* known beforehand. The addr parameter indicates which specific BSSID
|
||||
* is associated to the SSID.
|
||||
*
|
||||
* Note that if any other access point broadcasts the provided SSID,
|
||||
* it will be taken into account as well.
|
||||
*
|
||||
* \param psk The PSK associated with this SSID.
|
||||
* \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);
|
||||
|
||||
/**
|
||||
* \brief Decrypts the provided PDU.
|
||||
*
|
||||
* A Dot11Data PDU is looked up inside the provided PDU chain.
|
||||
* If no such PDU exists or no PSK was associated with the SSID
|
||||
* broadcasted by the Dot11 packet's BSSID, or no EAPOL handshake
|
||||
* was captured for the client involved in the communication,
|
||||
* then the PDU is left intact.
|
||||
*
|
||||
* Otherwise, the packet is decrypted using the generated PTK.
|
||||
* If the resulting MIC is invalid, then the packet is left intact.
|
||||
*
|
||||
* \return false if no decryption was performed, or the decryption
|
||||
* failed, true otherwise.
|
||||
*/
|
||||
bool decrypt(PDU &pdu);
|
||||
private:
|
||||
typedef std::map<std::string, WPA2::SupplicantData> pmks_map;
|
||||
typedef std::map<address_type, WPA2::SupplicantData> bssids_map;
|
||||
typedef std::pair<address_type, address_type> addr_pair;
|
||||
typedef std::map<addr_pair, WPA2::CCMPSessionKeys> keys_map;
|
||||
|
||||
void try_add_keys(const Dot11Data &dot11, const RSNHandshake &hs);
|
||||
addr_pair make_addr_pair(const address_type &addr1, const address_type &addr2) {
|
||||
return (addr1 < addr2) ?
|
||||
std::make_pair(addr1, addr2) :
|
||||
std::make_pair(addr2, addr1);
|
||||
}
|
||||
addr_pair extract_addr_pair(const Dot11Data &dot11);
|
||||
bssids_map::const_iterator find_ap(const Dot11Data &dot11);
|
||||
void add_access_point(const std::string &ssid, const address_type &addr);
|
||||
|
||||
RSNHandshakeCapturer capturer;
|
||||
pmks_map pmks;
|
||||
bssids_map aps;
|
||||
keys_map keys;
|
||||
};
|
||||
#endif // HAVE_WPA2_DECRYPTION
|
||||
|
||||
/**
|
||||
* \brief Pluggable decrypter object which can be used to decrypt
|
||||
* data on sniffing sessions.
|
||||
|
||||
@@ -41,27 +41,70 @@
|
||||
*/
|
||||
namespace Tins {
|
||||
namespace Internals {
|
||||
void skip_line(std::istream &input);
|
||||
bool from_hex(const std::string &str, uint32_t &result);
|
||||
template<size_t n>
|
||||
class byte_array {
|
||||
public:
|
||||
typedef uint8_t* iterator;
|
||||
typedef const uint8_t* const_iterator;
|
||||
|
||||
template<bool, typename>
|
||||
struct enable_if {
|
||||
|
||||
};
|
||||
byte_array() {
|
||||
std::fill(begin(), end(), 0);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
byte_array(InputIterator start, InputIterator last) {
|
||||
std::copy(start, end, data);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
byte_array(InputIterator start) {
|
||||
std::copy(start, n, data);
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return data;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return data + n;
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return data + n;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return n;
|
||||
}
|
||||
private:
|
||||
uint8_t data[n];
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct enable_if<true, T> {
|
||||
typedef T type;
|
||||
};
|
||||
void skip_line(std::istream &input);
|
||||
bool from_hex(const std::string &str, uint32_t &result);
|
||||
|
||||
template<bool, typename>
|
||||
struct enable_if {
|
||||
|
||||
PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match = true);
|
||||
|
||||
PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size);
|
||||
|
||||
Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct enable_if<true, T> {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match = true);
|
||||
|
||||
PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size);
|
||||
|
||||
Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);
|
||||
} // namespace Internals
|
||||
} // namespace Tins
|
||||
/**
|
||||
* \endcond
|
||||
*/
|
||||
|
||||
226
src/crypto.cpp
226
src/crypto.cpp
@@ -27,7 +27,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/aes.h>
|
||||
#include "crypto.h"
|
||||
#include "dot11.h"
|
||||
|
||||
namespace Tins {
|
||||
namespace Crypto {
|
||||
@@ -98,5 +102,227 @@ PDU *WEPDecrypter::decrypt(RawPDU &raw, const std::string &password) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_WPA2_DECRYPTION
|
||||
// WPA2Decrypter
|
||||
|
||||
const HWAddress<6> &min(const HWAddress<6>& lhs, const HWAddress<6>& rhs) {
|
||||
return lhs < rhs ? lhs : rhs;
|
||||
}
|
||||
|
||||
const HWAddress<6> &max(const HWAddress<6>& lhs, const HWAddress<6>& rhs) {
|
||||
return lhs < rhs ? rhs : lhs;
|
||||
}
|
||||
|
||||
template<typename InputIterator1, typename InputIterator2, typename OutputIterator>
|
||||
void xor_range(InputIterator1 src1, InputIterator2 src2, OutputIterator dst, size_t sz) {
|
||||
for(size_t i = 0; i < sz; ++i) {
|
||||
*dst++ = *src1++ ^ *src2++;
|
||||
}
|
||||
}
|
||||
|
||||
namespace WPA2 {
|
||||
CCMPSessionKeys::CCMPSessionKeys(const RSNHandshake &hs, const pmk_type &pmk) {
|
||||
uint8_t PKE[100] = "Pairwise key expansion";
|
||||
uint8_t MIC[16];
|
||||
min(hs.client_address(), hs.supplicant_address()).copy(PKE + 23);
|
||||
max(hs.client_address(), hs.supplicant_address()).copy(PKE + 29);
|
||||
const uint8_t *nonce1 = hs.handshake()[1].nonce(),
|
||||
*nonce2 = hs.handshake()[2].nonce();
|
||||
if(std::lexicographical_compare(nonce1, nonce1 + 32, nonce2, nonce2 + 32)) {
|
||||
std::copy(nonce1, nonce1 + 32, PKE + 35);
|
||||
std::copy(nonce2, nonce2 + 32, PKE + 67);
|
||||
}
|
||||
else {
|
||||
std::copy(nonce2, nonce2 + 32, PKE + 35);
|
||||
std::copy(nonce1, nonce1 + 32, PKE + 67);
|
||||
}
|
||||
for(int i(0); i < 4; ++i) {
|
||||
PKE[99] = i;
|
||||
HMAC(EVP_sha1(), pmk.begin(), pmk.size(), PKE, 100, ptk.begin() + i * 20, 0);
|
||||
}
|
||||
PDU::serialization_type buffer = const_cast<RSNEAPOL&>(hs.handshake()[3]).serialize();
|
||||
std::fill(buffer.begin() + 81, buffer.begin() + 81 + 16, 0);
|
||||
if(hs.handshake()[3].key_descriptor() == 2)
|
||||
HMAC(EVP_sha1(), ptk.begin(), 16, &buffer[0], buffer.size(), MIC, 0);
|
||||
else
|
||||
HMAC(EVP_md5(), ptk.begin(), 16, &buffer[0], buffer.size(), MIC, 0);
|
||||
|
||||
if(!std::equal(MIC, MIC + sizeof(MIC), hs.handshake()[3].mic()))
|
||||
throw invalid_handshake();
|
||||
}
|
||||
|
||||
SNAP *CCMPSessionKeys::decrypt_unicast(const Dot11Data &dot11, const RawPDU &raw) const {
|
||||
const RawPDU::payload_type &pload = raw.payload();
|
||||
uint8_t MIC[16] = {0};
|
||||
uint8_t PN[6] = {
|
||||
pload[7],
|
||||
pload[6],
|
||||
pload[5],
|
||||
pload[4],
|
||||
pload[1],
|
||||
pload[0]
|
||||
};
|
||||
|
||||
uint8_t AAD[32] = {0};
|
||||
AAD[0] = 0;
|
||||
AAD[1] = 22 + 6 * int(dot11.from_ds() && dot11.to_ds());
|
||||
if(dot11.subtype() == Dot11::QOS_DATA_DATA)
|
||||
AAD[1] += 2;
|
||||
AAD[2] = dot11.protocol() | (dot11.type() << 2) | ((dot11.subtype() << 4) & 0x80);
|
||||
AAD[3] = 0x40 | dot11.to_ds() | (dot11.from_ds() << 1) |
|
||||
(dot11.more_frag() << 2) | (dot11.order() << 7);
|
||||
dot11.addr1().copy(AAD + 4);
|
||||
dot11.addr2().copy(AAD + 10);
|
||||
dot11.addr3().copy(AAD + 16);
|
||||
|
||||
AAD[22] = dot11.frag_num();
|
||||
AAD[23] = 0;
|
||||
|
||||
if(dot11.from_ds() && dot11.to_ds())
|
||||
dot11.addr4().copy(AAD + 24);
|
||||
|
||||
AES_KEY ctx;
|
||||
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<uint8_t> output(total_sz);
|
||||
|
||||
uint8_t counter[16];
|
||||
counter[0] = 0x59;
|
||||
counter[1] = 0;
|
||||
dot11.addr2().copy(counter + 2);
|
||||
std::copy(PN, PN + 6, counter + 8);
|
||||
counter[14] = (total_sz >> 8) & 0xff;
|
||||
counter[15] = total_sz & 0xff;
|
||||
|
||||
AES_encrypt(counter, MIC, &ctx);
|
||||
xor_range(MIC, AAD, MIC, 16);
|
||||
AES_encrypt(MIC, MIC, &ctx);
|
||||
xor_range(MIC, AAD + 16, MIC, 16);
|
||||
AES_encrypt(MIC, MIC, &ctx);
|
||||
|
||||
counter[0] = 1;
|
||||
counter[14] = counter[15] = 0;
|
||||
AES_encrypt(counter, crypted_block, &ctx);
|
||||
uint8_t nice_MIC[8];
|
||||
std::copy(pload.begin() + pload.size() - 8, pload.end(), nice_MIC);
|
||||
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;
|
||||
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(MIC, &output[(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()) :
|
||||
0;
|
||||
}
|
||||
|
||||
// supplicant_data
|
||||
|
||||
SupplicantData::SupplicantData(const std::string &psk, const std::string &ssid) {
|
||||
PKCS5_PBKDF2_HMAC_SHA1(
|
||||
psk.c_str(),
|
||||
psk.size(),
|
||||
(unsigned char *)ssid.c_str(),
|
||||
ssid.size(),
|
||||
4096,
|
||||
pmk_.size(),
|
||||
pmk_.begin()
|
||||
);
|
||||
}
|
||||
|
||||
const SupplicantData::pmk_type &SupplicantData::pmk() const {
|
||||
return pmk_;
|
||||
}
|
||||
} // namespace WPA2
|
||||
|
||||
void WPA2Decrypter::add_supplicant_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,
|
||||
const address_type &addr)
|
||||
{
|
||||
// ADD CODE PLX
|
||||
add_supplicant_data(psk, ssid);
|
||||
}
|
||||
|
||||
void WPA2Decrypter::add_access_point(const std::string &ssid, const address_type &addr) {
|
||||
pmks_map::const_iterator it = pmks.find(ssid);
|
||||
if(it == pmks.end())
|
||||
throw std::runtime_error("supplicant data not registered");
|
||||
aps.insert(std::make_pair(addr, it->second));
|
||||
}
|
||||
|
||||
void WPA2Decrypter::try_add_keys(const Dot11Data &dot11, const RSNHandshake &hs) {
|
||||
bssids_map::const_iterator it = find_ap(dot11);
|
||||
if(it != aps.end()) {
|
||||
addr_pair addr_p = extract_addr_pair(dot11);
|
||||
try {
|
||||
keys.insert(std::make_pair(addr_p, WPA2::CCMPSessionKeys(hs, it->second.pmk())));
|
||||
}
|
||||
catch(WPA2::invalid_handshake&) { }
|
||||
}
|
||||
}
|
||||
|
||||
WPA2Decrypter::addr_pair WPA2Decrypter::extract_addr_pair(const Dot11Data &dot11) {
|
||||
if(dot11.from_ds() && !dot11.to_ds())
|
||||
return make_addr_pair(dot11.addr2(), dot11.addr3());
|
||||
else if(!dot11.from_ds() && dot11.to_ds())
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr2());
|
||||
else
|
||||
return make_addr_pair(dot11.addr2(), dot11.addr3());
|
||||
}
|
||||
|
||||
WPA2Decrypter::bssids_map::const_iterator WPA2Decrypter::find_ap(const Dot11Data &dot11) {
|
||||
if(dot11.from_ds() && !dot11.to_ds())
|
||||
return aps.find(dot11.addr2());
|
||||
else if(!dot11.from_ds() && dot11.to_ds())
|
||||
return aps.find(dot11.addr1());
|
||||
else
|
||||
return aps.find(dot11.addr3());
|
||||
}
|
||||
|
||||
bool WPA2Decrypter::decrypt(PDU &pdu) {
|
||||
if(capturer.process_packet(pdu)) {
|
||||
try_add_keys(pdu.rfind_pdu<Dot11Data>(), capturer.handshakes().front());
|
||||
capturer.clear_handshakes();
|
||||
}
|
||||
else if(const Dot11Beacon *beacon = pdu.find_pdu<Dot11Beacon>()) {
|
||||
if(aps.count(beacon->addr3()) == 0) {
|
||||
try {
|
||||
std::string ssid = beacon->ssid();
|
||||
if(pmks.count(ssid)) {
|
||||
add_access_point(ssid, beacon->addr3());
|
||||
}
|
||||
}
|
||||
catch(option_not_found&) { }
|
||||
}
|
||||
}
|
||||
else {
|
||||
Dot11Data *data = pdu.find_pdu<Dot11Data>();
|
||||
RawPDU *raw = pdu.find_pdu<RawPDU>();
|
||||
if(data && raw && data->wep()) {
|
||||
keys_map::const_iterator it = keys.find(extract_addr_pair(*data));
|
||||
if(it != keys.end()) {
|
||||
SNAP *snap = it->second.decrypt_unicast(*data, *raw);
|
||||
if(snap) {
|
||||
data->inner_pdu(snap);
|
||||
data->wep(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} // namespace WPA2
|
||||
#endif // HAVE_WPA2_DECRYPTION
|
||||
} // namespace Crypto
|
||||
} // namespace Tins
|
||||
|
||||
Reference in New Issue
Block a user