Newer
Older
from hashlib import sha256
from scapy.layers.dhcp import DHCP
BYTE_ORDER = "big"
# Special, well-known MAC addresses
special_macs = [
"00:00:00:00:00:00", # Default
"ff:ff:ff:ff:ff:ff" # Broadcast
]
def get_ig_bit(mac: str) -> int:
"""
Get the I/G bit of a given MAC address.
Args:
mac (str): MAC address to get the I/G bit from
Returns:
int: 8-bit integer with the I/G bit set to its corresponding value,
and all other bits set to 0
"""
first_byte = int(mac.split(":")[0], BASE_HEX)
ig_mask = 0b00000001
return first_byte & ig_mask
def get_ul_bit(mac: str) -> int:
"""
Get the U/L bit of a given MAC address.
Args:
mac (str): MAC address to get the U/L bit from
Returns:
int: 8-bit integer with the U/L bit set to its corresponding value,
and all other bits set to 0
"""
first_byte = int(mac.split(":")[0], BASE_HEX)
ul_mask = 0b00000010
return first_byte & ul_mask
def anonymize_mac(mac: str) -> str:
"""
Anonymize a given MAC address.
Args:
mac (str): MAC address to anonymize
Returns:
str: anonymized MAC address
"""
# Special MAC address
if mac in special_macs:
return mac
## Classic MAC address
mac_split = mac.split(":")
## I/G bit: first byte, least-significant bit
# I/G bit = 0 ==> Unicast address
# I/G bit = 1 ==> Multicast address
is_multicast = bool(ig_bit) # True ==> Multicast, False ==> Unicast
# Multicast address:
# do not anonymize
if is_multicast:
return mac
## U/L bit: first byte, second least-significant bit
# U/L bit = 0 ==> Universally administered address (UAA)
# U/L bit = 1 ==> Locally administered address (LAA)
is_local = bool(ul_bit) # True ==> LAA, False ==> UAA
## Locally administered address
# Compute SHA-256 hash of the MAC address
mac_sha256 = sha256()
for byte in mac_split:
mac_sha256.update(int(byte, BASE_HEX).to_bytes(1, BYTE_ORDER))
digest = mac_sha256.digest()
first_byte = (digest[0] & 0b11111100) | bit_mask # Keep I/G and U/L bits
return f"{first_byte:02x}:" + ':'.join(f"{digest[i]:02x}" for i in range(1, 6))
## Universally administered address
# Compute SHA-256 hash based on the three least-significant bytes
mac_sha256 = sha256()
for byte in mac_split[3:]:
mac_sha256.update(int(byte, BASE_HEX).to_bytes(1, BYTE_ORDER))
digest = mac_sha256.digest()
# Keep OUI and anonymize the rest
':'.join(mac_split[:3]) + # Keep OUI
':'.join(f"{digest[i]:02x}" for i in range(0, 3)) # Hashed last 3 bytes
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
)
def anonymize_ether(ether: Ether) -> Ether:
"""
Anonymize a packet's Ether layer.
Args:
ether (scapy.Ether): Ether layer to anonymize
Returns:
scapy.Ether: anonymized Ether layer
"""
ether.setfieldval("src", anonymize_mac(ether.getfieldval("src")))
ether.setfieldval("dst", anonymize_mac(ether.getfieldval("dst")))
return ether
def anonymize_arp(arp: ARP) -> ARP:
"""
Anonymize a packet's ARP layer.
Args:
packet (scapy.ARP): ARP layer to anonymize
Returns:
scapy.ARP: anonymized ARP layer
"""
arp.setfieldval("hwsrc", anonymize_mac(arp.getfieldval("hwsrc")))
arp.setfieldval("hwdst", anonymize_mac(arp.getfieldval("hwdst")))
return arp
def anonymize_dhcp(dhcp: DHCP) -> DHCP:
"""
Anonymize a packet's DHCP layer.
Args:
dhcp (scapy.DHCP): DHCP layer to anonymize
Returns:
scapy.DHCP: anonymized DHCP layer
"""
# Anonymize client MAC address
dhcp.setfieldval("chaddr", anonymize_mac(dhcp.getfieldval("chaddr")))
return dhcp