diff --git a/research/libwifi/__init__.py b/research/libwifi/__init__.py index 3bc67f98c..448987a2b 100644 --- a/research/libwifi/__init__.py +++ b/research/libwifi/__init__.py @@ -1,4 +1,3 @@ from .wifi import * -from .dragonfly import * from .crypto import * from .injectiontest import * diff --git a/research/libwifi/dragonfly.py b/research/libwifi/dragonfly.py deleted file mode 100644 index e8f679b07..000000000 --- a/research/libwifi/dragonfly.py +++ /dev/null @@ -1,334 +0,0 @@ -# TODO: For now only include the code we actually used for EAP-pwd -# TODO: Program unit tests so we can easily keep our EAP-pwd code correct -#!/usr/bin/env python3 -from scapy.all import * -from .wifi import * -import sys, struct, math, random, select, time, binascii - -from Crypto.Hash import HMAC, SHA256 -from Crypto.PublicKey import ECC -from Crypto.Math.Numbers import Integer - -# Alternative is https://eli.thegreenplace.net/2009/03/07/computing-modular-square-roots-in-python -from sympy.ntheory.residue_ntheory import sqrt_mod_iter - -# ----------------------- Utility --------------------------------- - -def int_to_data(num): - return binascii.unhexlify("%064x" % num) - -def zeropoint_to_data(): - return int_to_data(0) + int_to_data(0) - -#TODO: Not sure if this actually works under python2... -def str2bytes(password): - if not isinstance(password, str): return password - if sys.version_info < (3, 0): - return bytes(password) - else: - return bytes(password, 'utf8') - -def getord(value): - if isinstance(value, int): - return value - else: - return ord(value) - -def HMAC256(pw, data): - h = HMAC.new(pw, digestmod=SHA256) - h.update(data) - return h.digest() - - -# ----------------------- Elliptic Curve Operations --------------------------------- - -# This is group 19. Support of it is required by WPA3. -secp256r1_p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff -secp256r1_r = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 - -def legendre_symbol(a, p): - """Compute the Legendre symbol.""" - if a % p == 0: return 0 - - ls = pow(a, (p - 1)//2, p) - return -1 if ls == p - 1 else ls - -def point_on_curve(x, y, curve="p256"): - try: - point = ECC.EccPoint(x, y) - except ValueError: - return False - return True - -def point_to_data(p): - if p is None: - return zeropoint_to_data() - return int_to_data(p.x) + int_to_data(p.y) - - -# ----------------------- WPA3 --------------------------------- - -def is_sae(p): - if not Dot11Auth in p: - return False - return p[Dot11Auth].algo == 3 - -def is_sae_commit(p): - return is_sae(p) and p[Dot11Auth].seqnum == 1 - -def is_sae_confirm(p): - return is_sae(p) and p[Dot11Auth].seqnum == 2 - -def KDF_Length(data, label, context, length): - iterations = int(math.ceil(length / 256.0)) - result = b"" - for i in range(1, iterations + 1): - hash_data = struct.pack(" addr2 else addr2 + addr1 - - for counter in range(1, 100): - hash_data = str2bytes(password) + struct.pack("= curve.p: - continue - x = Integer(pwd_value) - - y_sqr = (x**3 - x * 3 + curve.b) % curve.p - if legendre_symbol(y_sqr, curve.p) != 1: - continue - - y = y_sqr.sqrt(curve.p) - y_bit = getord(pwd_seed[-1]) & 1 - if y & 1 == y_bit: - return ECC.EccPoint(x, y, curve_name) - else: - return ECC.EccPoint(x, curve.p - y, curve_name) - - -# TODO: Use this somewhere??? -def calc_k_kck_pmk(pwe, peer_element, peer_scalar, my_rand, my_scalar): - k = ((pwe * peer_scalar + peer_element) * my_rand).x - - keyseed = HMAC256(b"\x00" * 32, int_to_data(k)) - kck_and_pmk = KDF_Length(keyseed, "SAE KCK and PMK", - int_to_data((my_scalar + peer_scalar) % secp256r1_r), 512) - kck = kck_and_pmk[0:32] - pmk = kck_and_pmk[32:] - - return k, kck, pmk - - -def calculate_confirm_hash(kck, send_confirm, scalar, element, peer_scalar, peer_element): - return HMAC256(kck, struct.pack(" 1 - - # COMMIT-ELEMENT = inverse(mask * PWE) - temp = self.pwe * mask - self.element = ECC.EccPoint(temp.x, Integer(secp256r1_p) - temp.y) - - auth = build_sae_commit(self.srcaddr, self.dstaddr, self.scalar, self.element) - sendp(RadioTap()/auth) - - def process_commit(self, p): - payload = str(p[Dot11Auth].payload) - - group_id = struct.unpack(" 1 else b"" - hash_data += struct.pack(">H", i) + str2bytes(label) + struct.pack(">H", length) - digest = HMAC256(data, hash_data) - result += digest - - result = result[:num_bytes] - if length % 8 != 0: - num_clear = 8 - (length % 8) - trailbyte = result[-1] >> num_clear << num_clear - result = result[:-1] + struct.pack(">B", trailbyte) - return result - - -def derive_pwe_ecc_eappwd(password, peer_id, server_id, token, curve_name="p256", info=None): - curve = ECC._curves[curve_name] - bits = curve.modulus_bits - - hash_pw = struct.pack(">I", token) + str2bytes(peer_id + server_id + password) - for counter in range(1, 100): - hash_data = hash_pw + struct.pack("> (8 - (521 % 8)) - - if pwd_value >= curve.p: - continue - x = Integer(pwd_value) - - log(DEBUG, "X-candidate: %x" % x) - y_sqr = (x**3 - x * 3 + curve.b) % curve.p - if legendre_symbol(y_sqr, curve.p) != 1: - continue - - y = y_sqr.sqrt(curve.p) - y_bit = getord(pwd_seed[-1]) & 1 - if y & 1 == y_bit: - if not info is None: info["counter"] = counter - return ECC.EccPoint(x, y, curve_name) - else: - if not info is None: info["counter"] = counter - return ECC.EccPoint(x, curve.p - y, curve_name) - - -def calculate_confirm_eappwd(k, element1, scalar1, element2, scalar2, group_num=19, rand_func=1, prf=1): - hash_data = int_to_data(k) - hash_data += point_to_data(element1) - hash_data += int_to_data(scalar1) - hash_data += point_to_data(element2) - hash_data += int_to_data(scalar2) - hash_data += struct.pack(">HBB", group_num, rand_func, prf) - confirm = HMAC256(b"\x00" * 32, hash_data) - return confirm - -# ----------------------- Fuzzing/Testing --------------------------------- - -def inject_sae_auth(srcaddr, bssid): - p = Dot11(addr1=bssid, addr2=srcaddr, addr3=bssid) - p = p/Dot11Auth(algo=3, seqnum=1, status=0) - - group_id = 19 - scalar = 0 - element_x = 0 - element_y = 0 - p = p/Raw(struct.pack("