
Een paar projecten geleden heb ik een NTP-klok gebouwd. In de code moest je hiervoor de SSID en het wachtwoord van je WiFi opgeven waardoor het script nogal kwetsbaar werd. Ik gaf toen al aan dat het mogelijk is om code te verhullen d.m.v. obfuscatie. Obfuscatie is een eerste stap naar een veilige encryptie.
In deze tutorial leg ik uit wat obfuscatie is, waarvoor het wordt toegepast en welke tools je hiervoor kunt gebruiken. Ook lever ik een basisscript om een idee te krijgen hoe je het kunt gebruiken.
Daar gaan we…
Obfuscatie in Python is het opzettelijk onleesbaar en onbegrijpelijk maken van (bron)code, zonder de werking ervan te veranderen. Het doel is het bemoeilijken van reverse-engineering (decompileren) en intellectueel eigendom of gevoelige logica af te schermen voor nieuwsgierige blikken.
Omdat Python een interpreteertaal is, wordt code vaak in platte tekst of gemakkelijk leesbare bytecode verspreid. Obfuscatie is geen waterdichte beveiliging tegen hackers, maar dient als drempel om meekijken of kopiëren te voorkomen.
Toepassingen
- Informatica en Software: Het onleesbaar maken van broncode (bijvoorbeeld door variabelen te hernoemen naar willekeurige letters) om reverse engineering, diefstal of misbruik door derden te bemoeilijken.
- Privacy en Data (Data-obfuscatie): Het verbergen of versleutelen van gevoelige gegevens in databases, zodat persoonsgegevens niet zomaar herleidbaar zijn terwijl de data nog wel bruikbaar blijft voor analyse.
Veelgebruikte technieken
- Naamverduistering (Name Mangling): Namen van variabelen, klassen en functies worden vervangen door willekeurige tekens of onbegrijpelijke combinaties (bijv. functieA wordt O0o0O0).
- Control Flow Flattening: De structuur van de code (lussen, if-statements) wordt dusdanig in de war geschopt dat logica moeilijk te volgen is.
- String Encryptie: Gevoelige tekst, zoals API-sleutels, wordt geëncrypt (bijvoorbeeld via XOR) en pas tijdens het uitvoeren in het geheugen gedecodeerd.
Tools voor Python Obfuscatie
Hoewel Python van zichzelf geen ingebouwde zware obfuscatie heeft, zijn er populaire tools en frameworks:
- PyArmor: De populairste tool voor Python. Het versleutelt de bytecode van elk codeobject en kan scripts zelfs koppelen aan specifieke machines of voorzien van een verloopdatum.
- Cython of Nuitka: Programmeurs compileren Python-code hiermee naar C of naar binaire, native uitvoerbare bestanden. Dit maakt het decompileren aanzienlijk moeilijker dan bij reguliere Python-scripts.
- Python-minifier: Verwijdert witregels, inspringingen en vervangt lange namen door korte, enkelvoudige letters (minificatie).
Belangrijke overweging
Obfuscatie verandert de code niet in onbreekbare encryptie. Het zorgt er alleen voor dat de code eruitziet als abacadabra. De allerbelangrijkste beveiligingslogica of wachtwoorden (zoals backend authenticatie) horen altijd op een eigen, veilige server te staan in plaats van in de hoofdcode.
Gratis online obfuscatie tools
Ik ben geen fan van de GRATIS online obfuscatie tools die je code omzetten. Ervaring leert dat gratis niet bestaat. Daarnaast vind ik het risico te hoog dat mijn ingevoerde (gevoelige) data, weliswaar omgezet wordt zodat ik het in mijn scripts kan gebruiken, opgeslagen wordt in de donkere krochten van het web.
Voorbeeldscript
In onderstaand script heb ik er voor gekozen om een SSID en wachtwoord in te voeren en in een apart bestand op te slaan. Je kunt natuurlijk ook meer en andere gegevens opslaan, zoals profielen van personen. De gegevens in dit bestand zijn met 3 lagen obfuscatie onleesbaar gemaakt.
Gebruikte obfuscatie (3 lagen)
- XOR-cijfer – elke byte wordt gecombineerd met een geheime sleutel (
XOR_KEY) - Base64-codering – het resultaat wordt omgezet naar leesbare ASCII
- Omdraaien – de string wordt achterstevoren gezet
Extra: een SHA-256 checksum detecteert als het bestand handmatig is aangepast.
Met het voorbeeldscript kun je:
- WiFi-gegevens opslaan / bijwerken
- Opgeslagen gegevens tonen
- Ruwe bestandsinhoud bekijken
- Sleutelinformatie tonen
Het bestand waarin de versleutelde data opgeslagen wordt heet ‘wifi_credentials.dat‘.
Sleutelbeheer
Omdat ik de encryptiesleutel niet in de het hoofdprogramma wil hebben, heb ik een keymanager gemaakt die in dezelfde map moet staan als het hoofdprogramma. De keymanager genereert de geheime sleutel secret.key. Het hoofdprogramma haalt de benodigde sleutel op en gebruikte deze voor de en-/decryptie.
Code
Kopieer onderstaande code en plak deze in je editor, sla het script op als ‘wifi_config.py‘ en start deze met python wifi_config.py.
#!/usr/bin/env python3
"""
wifi_config.py – Raspberry Pi WiFi credential manager
Slaat SSID en wachtwoord op met obfuscatie (Base64 + XOR + shuffle).
De geheime sleutel wordt geladen vanuit 'secret.key' via key_manager.py.
"""
import os
import sys
import base64
import json
import hashlib
import getpass
# Laad sleutelbeheer uit dezelfde map
try:
from key_manager import ensure_key, KEY_FILE
except ImportError:
sys.exit("✘ 'key_manager.py' niet gevonden. Zet beide bestanden in dezelfde map.")
CONFIG_FILE = "wifi_credentials.dat"
# Laad (of genereer) de XOR-sleutel bij opstarten
XOR_KEY: bytes = ensure_key()
# ── Obfuscatie helpers ────────────────────────────────────────────────────────
def _xor(data: bytes, key: bytes) -> bytes:
"""XOR elke byte van data met de sleutel (herhalend)."""
return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
def obfuscate(text: str) -> str:
"""Tekst → XOR → Base64 → omgekeerde string."""
raw = text.encode("utf-8")
xored = _xor(raw, XOR_KEY)
b64 = base64.b64encode(xored).decode("ascii")
return b64[::-1] # omdraaien als extra laag
def deobfuscate(blob: str) -> str:
"""Omgekeerde van obfuscate."""
b64 = blob[::-1] # terugdraaien
xored = base64.b64decode(b64)
raw = _xor(xored, XOR_KEY)
return raw.decode("utf-8")
def _checksum(data: dict) -> str:
"""Integriteitscontrole over de opgeslagen (obfuscated) waarden."""
combined = data["ssid"] + data["password"]
return hashlib.sha256(combined.encode()).hexdigest()[:16]
# ── Opslaan / lezen ───────────────────────────────────────────────────────────
def save_credentials(ssid: str, password: str) -> None:
"""Sla obfuscated gegevens op in CONFIG_FILE."""
payload = {
"ssid": obfuscate(ssid),
"password": obfuscate(password),
}
payload["_chk"] = _checksum(payload)
with open(CONFIG_FILE, "w") as f:
json.dump(payload, f, indent=2)
print(f"\n✔ Gegevens opgeslagen in '{CONFIG_FILE}'")
def load_credentials() -> tuple[str, str]:
"""Laad en deobfusceer de opgeslagen gegevens."""
if not os.path.exists(CONFIG_FILE):
raise FileNotFoundError(f"Bestand '{CONFIG_FILE}' niet gevonden.")
with open(CONFIG_FILE, "r") as f:
payload = json.load(f)
# Integriteitscontrole
check = {k: v for k, v in payload.items() if k != "_chk"}
if _checksum(check) != payload.get("_chk", ""):
raise ValueError("Integriteitscontrole mislukt – bestand mogelijk aangepast!")
ssid = deobfuscate(payload["ssid"])
password = deobfuscate(payload["password"])
return ssid, password
# ── Menu ──────────────────────────────────────────────────────────────────────
def menu_save() -> None:
print("\n─── WiFi-gegevens opslaan ───")
ssid = input("Voer de SSID (netwerknaam) in: ").strip()
if not ssid:
print("✘ SSID mag niet leeg zijn.")
return
password = getpass.getpass("Voer het WiFi-wachtwoord in: ")
confirm = getpass.getpass("Bevestig het wachtwoord: ")
if password != confirm:
print("✘ Wachtwoorden komen niet overeen.")
return
save_credentials(ssid, password)
def menu_show() -> None:
print("\n─── Opgeslagen gegevens tonen ───")
try:
ssid, password = load_credentials()
print(f" SSID : {ssid}")
print(f" Wachtwoord: {password}")
except (FileNotFoundError, ValueError, KeyError) as e:
print(f"✘ {e}")
def menu_raw() -> None:
"""Toon de ruwe (obfuscated) inhoud van het bestand."""
print("\n─── Ruwe bestandsinhoud ───")
if not os.path.exists(CONFIG_FILE):
print(f"✘ '{CONFIG_FILE}' bestaat nog niet.")
return
with open(CONFIG_FILE, "r") as f:
print(f.read())
def menu_key_info() -> None:
"""Toon informatie over de geladen sleutel."""
print(f"\n─── Sleutelinformatie ───")
print(f" Bestand : {KEY_FILE}")
print(f" Lengte : {len(XOR_KEY)} bytes ({len(XOR_KEY) * 8} bit)")
print(f" Preview : {XOR_KEY.hex()[:24]}…")
# ── Hoofdprogramma ────────────────────────────────────────────────────────────
def main() -> None:
print("╔══════════════════════════════════╗")
print("║ Raspberry Pi – WiFi Configuratie ║")
print("╚══════════════════════════════════╝")
print(f" Sleutel geladen uit: {KEY_FILE}")
while True:
print("\nKies een optie:")
print(" 1) WiFi-gegevens opslaan / bijwerken")
print(" 2) Opgeslagen gegevens tonen")
print(" 3) Ruwe bestandsinhoud bekijken")
print(" 4) Sleutelinformatie tonen")
print(" 5) Afsluiten")
keuze = input("\nOptie: ").strip()
if keuze == "1":
menu_save()
elif keuze == "2":
menu_show()
elif keuze == "3":
menu_raw()
elif keuze == "4":
menu_key_info()
elif keuze == "5":
print("Tot ziens!")
sys.exit(0)
else:
print("✘ Ongeldige keuze, probeer opnieuw.")
if __name__ == "__main__":
main()Note: Je zult gemerkt hebben dat bij de eerste keer opstarten er een melding verschijnt:
ℹ Geen sleutelbestand gevonden – nieuwe sleutel wordt aangemaakt …
✔ Sleutel opgeslagen in ‘secret.key’ (rechten: 600)
Tenzij het bestand secret.key niet beschikbaar is, komt de melding in principe maar een keer voor. Het hoofdprogramma zorgt ervoor dat de benodigde bestanden (secret.key via keymanager.py en wifi_credentials.dat) automatisch aangemaakt worden.
Let op! Het mag duidelijk zijn dat als het secret.key-bestand beschadigd of niet beschikbaar is, dan de data in het wifi_credentials.dat-bestand NIET bruikbaar is voor het hoofdprogramma!
Conclusie
Obfuscatie is een goede manier om gevoelige informatie te onleesbaar te maken. Zonder de key (sleutel) wordt het erg lastig de verhulde data leesbaar te maken. Het is daarom belangrijk om de key NIET in het hoofdprogramma te vermelden, maar een keymanager te gebruiken die een secret.key-bestand levert.
In dit voorbeeld geef ik het secret.key-bestand alleen de juiste permissies, in de openbare toepassing zal het meer moeten zijn dan alleen de rechten te specificeren. Daar kom ik een keer op terug. Voor nu is dit voldoende.
Encryptie
In de volgende tutorial leg ik uit hoe je encryptie (AES-128) relatief eenvoudig kunt toepassen. Daarmee nemen we afscheid van het ‘verhullen’ van data en gaan we een stevige encryptie gebruiken.
Doe er je voordeel mee en maak er iets moois van!
Have A Nice Day!

Laat een reactie achter