AES-256-GCM · ChaCha20 · Argon2id · ECDSA P-384 · GUI PyQt6 — Python 3.12+

IronLock v2.0

Système de protection logicielle et licensing machine-bound v2. AES-256-GCM + ChaCha20-Poly1305, Argon2id 64 Mo, ECDSA P-384, fingerprint 12 sources, 12 checks anti-debug Ring0, 15 checks VM, GUI PyQt6, rétro-compatibilité v1 complète.

AES-256-GCM + ChaCha20 Argon2id 64 Mo ECDSA P-384 Fingerprint 12 sources Anti-Debug 12 checks VM Detector 15 checks GUI PyQt6 Cython C Natif
GCM
AES-256
64Mo
Argon2id
P-384
ECDSA
12
Fingerprint
12
AntiDebug
15
VM Checks
GUI
PyQt6
v1
Rétro-compat
01

À propos de IronLock v2.0

IronLock v2.0 est la version majeure développée par Tristan Ruard. Elle introduit une cryptographie de niveau militaire (AES-256-GCM, ChaCha20-Poly1305, Argon2id, ECDSA P-384), un anti-debug Ring0 avec 12 checks en ordre aléatoire, un détecteur VM 15 checks incluant CPUID hardware, une interface graphique PyQt6 complète, et une rétro-compatibilité totale avec les licences et payloads v1.

🔐 AES-256-GCM

Chiffrement AEAD natif — tag authentification intégré 16B par chunk, nonce 96-bit unique, pas de padding oracle, pas de HMAC séparé. Fallback ChaCha20-Poly1305 si pas d'AES-NI.

⚗ Argon2id

KDF memory-hard 64 Mo. PHC winner 2015. Résistant GPU/ASIC — ×62 plus difficile que PBKDF2. La clé maître n'est jamais persistée, effacée après HKDF.

🔑 ECDSA P-384

192-bit security. Clé publique 97B (vs 294B RSA). Vérification <0.5ms. Rétro-compat signatures RSA v1 via IRONLOCK_PUBLIC_KEY_RSA_V1.

🖼 GUI PyQt6

Dashboard licences, packager drag&drop AES-GCM, licence manager ECDSA, paramètres. 3 thèmes : Dark / Light / High Contrast WCAG AA.

IronLock v2.0 est entièrement rétro-compatible v1. Les payloads .ironenc v1 (AES-CBC) sont déchiffrés automatiquement. Les licences RSA v1 sont acceptées via IRONLOCK_PUBLIC_KEY_RSA_V1. Aucune intervention client requise.
02

Nouveautés v2.0 vs v1

Composantv2.0v2.0Gain
ChiffrementAES-256-GCM + HMACAES-256-GCM + ChaCha20AEAD intégré, timing-safe, fallback ARM
KDFPBKDF2 100K iterArgon2id m=64 Mo×62 résistance GPU, memory-hard
Dérivation sessionAucuneHKDF-SHA256Clés éphémères, jamais directes
LicencesECDSA P-384ECDSA P-384192-bit, 10× compact, 5× rapide
Fingerprint8 sources12 sources+chassis, volume, CPU features, screen
Anti-debug5 checks fixes12 checks aléatoiresRing0 NtQuery, PEB, RDTSC, stack walk
VM detector7 checks15 checksCPUID bit, Docker/WSL, temp, uptime
GUICLI uniquementPyQt6 3 thèmesDashboard, packager, licences
ObfuscationPyArmor bytecodePyArmor + Cython CExtension .pyd/.so native
Séquence boot10 étapes12 étapes+serveur online, +pré-check tamper
Rétro-compatN/Av1 payload + licencesMagic IRONLK1 → CBC legacy branch
03

Installation

Prérequis

pip install -r requirements.txt

Dépendances

PackageVersionRôleRequis
cryptography≥41.0.0AES-GCM, ChaCha20, ECDSA P-384, HKDF, HMAC✅ Obligatoire
argon2-cffi≥21.3.0Argon2id memory-hard (fallback PBKDF2 300K si absent)⚡ Fortement recommandé
PyQt6≥6.6.0Interface graphique — dashboard, packager, licences🖼 GUI seulement
pyarmor≥9.0.0Obfuscation bytecode Python🏗 Build
Cython≥3.0.0Compilation C natif → .pyd/.so (v2 recommandé)🏗 Build C natif
pyinstaller≥6.0.0Compilation EXE/ELF/Mach-O onefile🏗 Build
psutil≥5.9.0check_ram_signature VM detector🔍 Optionnel

Vérification

python core/crypto_engine.py # Self-test AES-GCM + ChaCha20 + Argon2id python core/fingerprint.py # 12 sources → machine_fingerprint.json python core/vm_detector.py # 15 checks + rapport python core/anti_debug.py # 12 checks ordre aléatoire python gui/app.py # Lance la GUI PyQt6
04

Workflow complet en 6 étapes

Étape 1 — Clés ECC P-384 (une fois)

python tools/license_generator.py # → [?] Key type : 1 (ECC P-384 recommandé) # → private_key.pem ← HORS LIGNE UNIQUEMENT # → public_key.pem ← Copier dans loader.py
IRONLOCK_PUBLIC_KEY_PEM = """-----BEGIN PUBLIC KEY----- <coller public_key.pem> -----END PUBLIC KEY-----"""

Étape 2 — Packager le programme

# Fichier unique python tools/packager.py monapp.exe -n "MonApp v2.0" # Répertoire complet python tools/packager.py ./projet/ -n "MonApp" -o dist/ # → payload.ironenc (AES-256-GCM)

Étape 3 — Obfusquer + compiler

# Standard PyArmor python tools/obfuscate_build.py --source-dir core/ --exe-name MonApp # Cython C natif (v2 recommandé) python tools/obfuscate_build.py --source-dir core/ --exe-name MonApp --cython

Étapes 4–6 — Licence + distribution

# Côté client — sur SA machine python core/fingerprint.py # → machine_fingerprint.json → envoyer au dev # Côté dev — générer licence python tools/license_generator.py # → licence_Client_XXXXXXXX.lic → renommer licence.lic
Package client : MonApp.exe + payload.ironenc + licence.lic dans le même dossier. Lancer MonApp.exe. Sans Python requis si compilé avec PyInstaller.
05

Séquence de sécurité — 12 étapes

À chaque lancement, le loader exécute 12 vérifications séquentielles. Toute défaillance → arrêt sécurisé avec délai aléatoire (100–800ms) pour compliquer l'analyse de timing.

01
Anti-debug v2 (12 checks, ordre aléatoire) STOP 12 checks
IsDebuggerPresent, CheckRemoteDebugger, TracerPid, timing, NtQueryInformationProcess (ProcessDebugPort/Flags), PEB.NtGlobalFlag, RDTSC delta, exception handler, CloseHandle(NULL), stack walk, env vars debug, scan processus. Ordre random.shuffle() à chaque lancement.
02
Pré-check anti-tamper v2
Calcul de référence initiale pour comparaison ultérieure à l'étape 11 (après chargement de la licence et déchiffrement).
03
VM/sandbox detection v2 (15 checks) STOP 15 checks
Score ≥ 3 + confiance > VM_CONFIDENCE_THRESHOLD (0.3). Nouveau : CPUID hypervisor bit, vendor string, Docker/WSL, température CPU, RAM signature, artefacts sandbox, uptime court. Configurable : ALLOW_VM = True désactive.
04
Chargement licence .lic OK
Lecture + parsing JSON du fichier licence.lic. Format v2 (IRONLOCK-ECDSA-P384-SHA256-v2) ou v1 (IRONLOCK-RSA-PSS-SHA256-v1) acceptés.
05
Vérification signature ECDSA P-384 / RSA v1 STOP
Tentative ECDSA P-384 d'abord. Si format v1 détecté → fallback RSA-PSS via IRONLOCK_PUBLIC_KEY_RSA_V1. Un seul bit modifié → InvalidSignature.
06
Vérification expiration STOP
expires_at = null → perpétuelle. Sinon : datetime.utcnow() < datetime.strptime(expires_at). Message d'erreur avec la date exacte.
07
Vérification serveur online (optionnel) STOP v2
Si LICENCE_SERVER_URL configuré : POST /api/v2/heartbeat. Si révoquée → arrêt. Si inaccessible → grace period (SERVER_GRACE_PERIOD_H = 72h). Token JWT mis en cache chiffré localement.
08
Collecte fingerprint v2 (12 sources) OK
Collecte en temps réel des 12 sources hardware. Pré-calcul fait à l'étape 7 (avant la vérification serveur pour inclure le fingerprint dans le heartbeat).
09
Matching fingerprint (8/12 par défaut) STOP
Correspondance exacte d'abord. Sinon : matching partiel composant par composant. Si score < FINGERPRINT_TOLERANCE (8) → arrêt avec le score affiché (ex: "7/12 concordants, minimum 8").
10
Déchiffrement AES-GCM/ChaCha20 en mémoire OK
Chaîne : SHA256(fp:secret) → Argon2id(salt) → HKDF(enc+hmac). Déchiffrement chunk par chunk avec vérification tag AEAD individuel. Aucun fichier temporaire. Master secret effacé après HKDF. Rétro-compat v1 si magic IRONLK1.
11
Anti-tamper loader (hash SHA-256) STOP
Si loader_hash non-vide dans la licence : SHA-256 du loader actuel vs valeur stockée. Si différent → effacement du payload de la mémoire + arrêt. Un EXE patché invalide ici.
12
Exécution + Watchdog daemon (5s) OK
Watchdog thread daemon démarré. Payload exécuté en mémoire (Python exec, binaire temp, ZIP __main__). Payload effacé après exécution. Watchdog arrêté proprement.
06

Crypto Engine v2 v2.0

Le moteur v2 supporte deux algorithmes AEAD — sélection automatique selon la présence d'AES-NI dans le CPU — et utilise Argon2id comme KDF memory-hard pour résister aux attaques GPU/ASIC.

Chaîne de dérivation des clés

fingerprint + licence_secret ↓ SHA-256 master_secret (32B) # effacé après usage ↓ Argon2id (m=64Mo, t=3, p=4, salt=32B) master_key (32B) # jamais utilisée directement ├── HKDF(info="encryption") → enc_key (32B) └── HKDF(info="hmac") → hmac_key (32B)

Sélection algo auto (AES-NI)

# Détection au démarrage _HAS_AES_NI = _detect_aes_ni() # Linux : "aes" dans /proc/cpuinfo # macOS : sysctl machdep.cpu.features # Windows : True par défaut (CPU ≥ 2010) # Sélection automatique engine = CryptoEngine(secret) # AES-NI présent → AESGCM (0x01) # AES-NI absent → ChaCha20 (0x02) # Forcer ChaCha20 engine = CryptoEngine(secret, prefer_chacha=True)

AES-256-GCM vs v1 AES-256-GCM

Aspectv1 — AES-256-GCMv2 — AES-256-GCM
AuthentificationHMAC-SHA256 séparé 32B/chunkTag AEAD intégré 16B/chunk
Padding oraclePossibleImpossible (aucun padding)
IV/NonceIV 16B par chunkNonce 12B 96-bit par chunk
KDFPBKDF2 100K iterArgon2id 64 Mo
Overhead par chunkIV(16) + HMAC(32) = 48BNonce(12) + Tag(16) = 28B
Timing-safeNonOui (GCM + ChaCha20)
L'overhead par chunk passe de 48B (v1) à 28B (v2) — soit 20B de moins par chunk 64Ko, i.e. un payload v2 est légèrement plus compact que v1 à contenu égal.
07

Format .ironenc v2

┌──────────────────────────────────────────────────────────┐ │ IronLock .ironenc v2 — Structure binaire │ ├──────────────────────┬──────────────────────────────────┤ │ MAGIC 7B │ "IRONLK2" (v1 = "IRONLK1") │ │ VERSION 1B │ uint8 = 2 │ │ ALGO 1B │ 0x01=AES-GCM / 0x02=ChaCha20 │ │ SALT 32B │ Argon2id salt (aléatoire/fichier)│ │ META_LEN 4B │ big-endian uint32 │ │ META_NONCE 12B │ nonce 96-bit metadata │ │ META_CT var │ JSON chiffré AEAD │ │ META_TAG 16B │ tag authentification metadata │ │ HEADER_HMAC 32B │ HMAC-SHA256 de tout ce précède │ │ CHUNK_COUNT 4B │ big-endian uint32 │ ├──────────────────────┴──────────────────────────────────┤ │ CHUNK × N │ │ ├── NONCE 12B nonce unique 96-bit par chunk │ │ ├── LEN 4B taille ciphertext │ │ ├── ENC_DATA var ciphertext AEAD │ │ └── TAG 16B tag AEAD — authentif individuelle │ └──────────────────────────────────────────────────────────┘
Rétro-compat : si le magic IRONLK1 est détecté, le moteur bascule automatiquement sur _decrypt_v1_legacy() — AES-256-GCM + HMAC-SHA256. Aucune configuration requise, transparent pour l'utilisateur.
08

Fingerprint — 12 sources v2.0

L'empreinte v2 collecte 12 sources hardware indépendantes. Chaque source est hashée en SHA-256 tronqué 16 chars pour le matching partiel, puis toutes sont combinées en un SHA-256 final 64 chars.

#SourceWindowsLinuxmacOSv2
1cpu_idwmic ProcessorId/proc/cpuinfo Serialsysctl brand MD5
2mac_addressuuid.getnode() — vérifie non-random (bit multicast)
3disk_serialwmic SerialNumberlsblk /dev/sdasystem_profiler
4motherboard_uuidwmic csproduct UUID/sys/class/dmi/product_uuidioreg IOPlatformUUID
5bios_serialwmic bios SerialNumber/sys/class/dmi/product_serialsystem_profiler
6hostnameplatform.node()
7platform_sigMD5(machine + processor + system)
8cpu_timingVariance 10 × 10K iter, bucketisée ±20%
9chassis_serialwmic systemenclosure/sys/class/dmi/chassis_serialioreg Hardware UUID🆕 v2
10volume_serialvol C: / wmic logicaldiskfindmnt -o UUID /diskutil info /🆕 v2
11cpu_featuresMD5(wmic Caption)MD5(/proc/cpuinfo flags)MD5(sysctl features)🆕 v2
12screen_resGetSystemMetricsxrandr --currentsystem_profiler SPDisplays🆕 v2
✅ Transparent (≤4 changements)

RAM, GPU, carte réseau, hostname, clavier, souris → 8 autres sources concordantes → licence valide. Aucune intervention.

⚠ Renouvellement (>4 changements)

Carte mère + disque + chassis + volume en même temps → score < 8/12 → renouvellement requis. Client envoie nouveau fingerprint.json.

🔒 Sécurité renforcée

4 nouvelles sources v2 détectent mieux les VMs : cpu_features (AES-NI absent sur VM), screen_res (800×600 sandbox), chassis/volume (inconnus sur VM légère).

09

Anti-Debug — 12 checks v2.0

Les 12 checks sont exécutés dans un ordre aléatoire à chaque lancement via random.shuffle(). Un attaquant qui bypasse les checks séquentiellement doit recommencer à chaque tentative.

01
IsDebuggerPresent() Windows
API Win32 native. Vérifie le flag PEB.BeingDebugged. Le plus basique mais toujours présent comme couche initiale.
02
CheckRemoteDebuggerPresent() Windows
Détecte les debuggers distants attachés via OpenProcess. Retourne True même si le debugger est sur une machine différente via réseau.
03
TracerPid /proc/self/status Linux
Lit TracerPid: dans le fichier status du process. Si non-nul, un debugger ptrace est attaché.
04
Timing anomaly Tous
Boucle XOR 1 million d'itérations. Sous debugger avec breakpoints actifs : souvent > 2000ms. Normal : < 500ms.
05
Scan processus connus Tous
tasklist (Win) / ps aux (Linux) pour : ollydbg, x64dbg, x32dbg, windbg, ida, idaq, processhacker, wireshark, dnspy, gdb, strace, ltrace, radare2…
06
NtQueryInformationProcess Windows 🆕 v2 CRITIQUE
Appels NT directs : ProcessDebugPort (7) → non-nul = debugger. ProcessDebugFlags (31) → 0 = debugger. Plus difficile à patcher que l'API Win32 car utilise ntdll directement.
07
PEB.NtGlobalFlag + HeapForceFlags Windows 🆕 v2 CRITIQUE
NtGlobalFlag & 0x70 = 0x70 quand créé via debugger (FLG_HEAP_ENABLE_TAIL_CHECK etc.). HeapForceFlags modifié. Impossible à falsifier sans patcher le kernel ou le PEB directement.
08
RDTSC delta Tous 🆕 v2
20 mesures de perf_counter_ns() autour d'un os.getpid(). Moyenne > 500µs par syscall = suspecte. Sous debugger avec hooks actifs, la latence augmente massivement.
09
Exception handler timing Tous 🆕 v2
ZeroDivisionError intentionnelle chronométrée. Sans debugger : < 1ms. Avec debugger interceptant toutes exceptions : souvent > 100ms. Vérifie aussi que l'exception a bien été catchée (catchée = non-suspect).
10
CloseHandle(NULL) Windows 🆕 v2
CloseHandle(0) sans debugger → STATUS_INVALID_HANDLE, retour 0. Avec debugger configuré pour intercepter les exceptions → retour non-nul. Technique documentée dans le SDK Windows.
11
Stack walk Tous 🆕 v2
inspect.stack() pour détecter des frames de modules debugger : pydevd, _pydevd, pdb, debugpy, bdb, trace. Détecte PyCharm, VS Code, pdb, pudb...
12
Variables d'environnement debug Tous 🆕 v2
PYCHARM_DEBUG, VSCODE_DEBUG, PYDEVD_USE_FRAME_EVAL, PYTHONDEBUG, COR_ENABLE_PROFILING, VS_DEBUGGER_ATTACHED.
10

VM Detector — 15 checks v2.0

Score pondéré — score ≥ 3 = VM détectée. Confiance = min(1.0, score / 15.0). Seuil configurable via VM_CONFIDENCE_THRESHOLD.

Registre Windows — poids 3

VMware Tools, VirtualBox Guest Additions, Hyper-V vmbus, QEMU, /.HARDWARE/ACPI/DSDT/VBOX__, Microsoft Virtual Machine Guest.

Processus VM — poids 2

vmtoolsd, vmwaretray, vboxservice, vboxtray, xenservice, qemu-ga, vmicsvc, prl_tools, vmusrvc.

Drivers/modules — poids 3

vmbus, vmhgfs, vboxguest, vboxsf, xenbus, xennet, vmw_vmci, vmwgfx, vmxnet (driverquery / /proc/modules).

CPUID model — poids 3

wmic model : virtualbox/vmware/kvm/hyper-v. systemd-detect-virt. /proc/cpuinfo : hypervisor flag.

Timing side-channel — poids 1

50 mesures os.getpid(). Coefficient de variation > 2.0 → VM probable. VMs ont une variance syscall plus élevée.

Préfixes MAC — poids 2

00:0C:29 VMware, 08:00:27 VBox, 52:54:00 QEMU/KVM, 00:15:5D Hyper-V, 00:1C:42 Parallels, 00:16:3E Xen.

Fichiers VM — poids 2

C:\Program Files\VMware, drivers\vmhgfs.sys, VBoxGuest.sys. /proc/xen, /dev/vboxguest, /usr/bin/vmware-toolbox-cmd.

CPUID hypervisor bit — poids 4 🆕

Bit 31 de ECX lors de CPUID(EAX=1) — flag hardware. Impossible à falsifier sans modifier le CPU émulé. Poids le plus élevé : 4.

CPUID vendor string — poids 3 🆕

CPUID(0x40000000) → "VMwareVMware", "VBoxVBoxVBox", "KVMKVMKVM", "Microsoft Hv". Via wmic Manufacturer/Model ou dmidecode.

Température CPU — poids 2 🆕

WMI MSAcpi_ThermalZoneTemperature. Valeur 0 ou fixe non-réaliste (< 1°C ou > 120°C) → VM sans capteur réel. Très fiable Windows.

RAM signature — poids 1 🆕

RAM ronde exacte (2048, 4096, 8192 MB ±2 MB). Machine physique : généralement quelques MB de moins (BIOS reservations).

Docker / WSL / LXC — poids 3 🆕

/.dockerenv, /run/.containerenv (Podman), /proc/version "microsoft" (WSL), cgroup "docker" (/proc/1/cgroup), container=lxc.

Artefacts sandbox — poids 2 🆕

Hostname contenant : cuckoo, sandbox, malware, anyrun, joesandbox, threatgrid. Variables CUCKOO, SANDBOX, INETSIM, FAKENET.

CPU cores ≤ 1 — poids 1 🆕

os.cpu_count() ≤ 1 = sandbox souvent mono-core. Utilisé en corrélation avec d'autres checks — poids faible isolément.

Uptime court — poids 2 🆕

Windows : GetTickCount64(). Linux : /proc/uptime. Uptime < 300s (5 min) → sandbox analytique démarré récemment pour l'analyse.

11

Watchdog daemon

🔴 Surveillance continue

Thread daemon=True — s'arrête automatiquement à la fin du programme. Vérifie toutes les check_interval secondes (défaut 5s). Checks légers à chaque tick : IsDebuggerPresent, TracerPid, NtQuery, PEB, RDTSC. Scan processus (lourd) toutes les 5 ticks. Stack walk toutes les 3 ticks.

🔀 Ordre aléatoire v2

La liste des checks légers est mélangée (random.shuffle()) au démarrage du watchdog. Un attaquant ne peut pas prédire quel check sera exécuté en premier ni la séquence entre ticks.

# Handler par défaut v2 — délai aléatoire avant exit def _default_handler(self, threat_type: str): time.sleep(random.uniform(0.05, 0.3)) print(f"[IronLock] Security threat: {threat_type}", file=sys.stderr) os._exit(1) # Contourne atexit et finally # Handler personnalisé avec alerte API def custom_handler(threat_type: str): urllib.request.urlopen("https://api.app.com/threat", ...) os._exit(1) watchdog = WatchdogThread(check_interval=3.0, on_threat=custom_handler) watchdog.start()
12

Licences ECDSA P-384 v2.0

Aspectv1 — ECDSA P-384v2 — ECDSA P-384
Niveau de sécurité112 bits192 bits
Taille clé privée1 740 bytes48 bytes (×36 plus compact)
Taille clé publique294 bytes97 bytes (×3 plus compact)
Vitesse signature~2 ms< 0.5 ms (×4 plus rapide)
Vitesse vérification~0.1 ms< 0.5 ms
Rétro-compat loader v2Via IRONLOCK_PUBLIC_KEY_RSA_V1Natif — format principal
Format signatureIRONLOCK-RSA-PSS-SHA256-v1IRONLOCK-ECDSA-P384-SHA256-v2
CLI INTERACTIF
python tools/license_generator.py [?] Key type : 1 (ECC P-384 recommandé) [?] Customer name : Tristan Ruard [?] Customer email : t@exemple.com [?] Product name : MonApp v2.0 [?] machine_fingerprint.json : fp.json [+] FP version : 2.0 [+] Components : 12 sources [?] Perpetual? (y/N) : N [?] Duration [365] : 365 [?] Max machines [1] : 1 [?] Loader hash : (vide) [?] Server URL : (vide) ✅ Signature valid [+] Licence saved : licence_Tristan_Ruard_a3f7c8d1.lic
API PYTHON
from tools.license_generator import * import json priv = load_private_key("private_key.pem") fp = json.loads(open("fp.json").read()) lic = create_licence( customer_name = "Tristan Ruard", product = "MonApp v2.0", fingerprint = fp["fingerprint"], components = fp["components"], duration_days = 365, grace_period_h = 72, ) sig = sign_licence(lic, priv) pkg = package_licence(lic, sig, priv) save_licence(pkg, "licence.lic")
13

Format .lic v2

{ "data": { "id": "4c8d7f23-a1b9-4e32-c7d6-8f3b2a1e9c04", "version": "2.0", ← nouveau v2 "customer_name": "Tristan Ruard", "customer_email": "tristan@exemple.com", "product": "MonApp v2.0", "fingerprint": "sha256-64-chars", "components": { ← 12 sources v2 "cpu_id": "3a7f1b2c...", "chassis_serial": "b2c9e8f4...", "volume_serial": "f4a9b1c7...", "cpu_features": "c8d2f5b3..." }, "max_activations": 1, "activations": 0, "issued_at": "2025-05-16", "expires_at": "2026-05-16", ← null = perpétuelle "features": ["standard"], "licence_secret": "hex-64-chars", "loader_hash": "sha256-loader", "server_url": "", ← nouveau v2 "grace_period_h": 72 ← nouveau v2 }, "signature": "base64-ECDSA-P384-DER...", "format": "IRONLOCK-ECDSA-P384-SHA256-v2" }
🔴
Modifier un seul bit dans data invalide la signature ECDSA. Il est cryptographiquement impossible (192-bit security) de fabriquer une signature valide sans la clé privée P-384.
14

Rétro-compatibilité v1 → v2

✅ Payloads .ironenc v1

Détection automatique du magic IRONLK1. Le moteur bascule sur _decrypt_v1_legacy() — AES-256-GCM + HMAC-SHA256. Aucune configuration requise.

engine = CryptoEngine(secret) data = engine.decrypt_to_memory( "old_payload_v1.ironenc" ) # Fonctionne automatiquement
↔ Licences RSA v1

Ajouter dans loader.py :

IRONLOCK_PUBLIC_KEY_RSA_V1 = """ -----BEGIN PUBLIC KEY----- <ancienne clé RSA-2048> -----END PUBLIC KEY-----""" # Loader v2 tente ECDSA P-384 d'abord, # puis RSA v1 en fallback automatique
🧬 Fingerprints v1 (8 sources)

Compatibles. Le matching partiel ne teste que les sources présentes dans la licence. Une licence v1 avec 8 composants est validée sur ces 8 uniquement.

Recommandation : régénérer progressivement les licences en v2 (12 sources) lors des renouvellements.

15

GUI PyQt6 — Vue d'ensemble v2.0

Lancement : python gui/app.py · python gui/app.py --theme light · python gui/app.py --theme high_contrast

📊 Dashboard
  • Cartes stats en temps réel
  • Tableau licences rechargeable
  • Alertes expiration
  • Export CSV
📦 Packager
  • Sélection source / dossier
  • Chiffrement AES-GCM live
  • Progress bar worker thread
  • Log détaillé
📄 Licences
  • Formulaire ECDSA P-384
  • Chargement fingerprint JSON
  • Génération asynchrone
  • Résultat formaté
⚙ Paramètres
  • Génération clés ECC P-384
  • Tolérance fingerprint
  • Thèmes (3)
  • Serveur REST + grace
Le packager GUI utilise un worker thread (QThread) pour le chiffrement — l'interface reste réactive pendant tout le processus. La progress bar affiche la progression chunk par chunk avec l'algorithme utilisé (AES-GCM ou ChaCha20).
16

Dashboard licences

📊 Cartes stats

4 cartes en haut : Licences actives (orange), Expirent ce mois (jaune warning), Tentatives suspectes (rouge), Payloads protégés (teal). Mise à jour au clic "Rafraîchir" ou au lancement.

📋 Tableau licences

Colonnes : Client, Produit, Date expiration, Statut coloré (✅ Active / ⚠ Expire bientôt / ❌ Expirée), Score HW (ex: 12/12). Tri par clic d'en-tête. Export CSV via bouton dédié.

Le dashboard lit automatiquement tous les fichiers .lic du répertoire licences/. Créer ce répertoire et y placer les licences générées pour les voir apparaître.

17

Packager visuel

🎯 Sélection source

Bouton "Parcourir" ouvre d'abord un sélecteur de dossier. Cliquer "Annuler" → sélecteur de fichier. Supporte EXE, binaires Linux, scripts .py, et répertoires (ZIP auto).

📊 Progress live

La barre de progression se met à jour chunk par chunk (10% prép → 40% chiffrement → 80% manifest → 100%). Le log affiche l'algo utilisé (AES-256-GCM ou ChaCha20-Poly1305).

✅ Résultat

À la fin : taille originale vs chiffrée, nombre de chunks, hash SHA-256 original. Un MessageBox confirme le succès avec le nom du fichier généré.

18

Licence Manager ECDSA P-384

Le formulaire Licences couvre tous les paramètres de create_licence() :

  • Chemin clé privée ECC P-384 (ou RSA v1)
  • Fichier machine_fingerprint.json du client
  • Nom, email, nom du produit
  • Case "Perpétuelle" (désactive le spinner durée)
  • Durée en jours (défaut 365)
  • Nombre de machines maximum
  • URL serveur REST (optionnel — Phase C)
  • Dossier de sortie des fichiers .lic
⚡ Worker thread

La génération tourne dans un QThread séparé. L'UI reste réactive. Le résultat est affiché avec :

  • Chemin complet du fichier .lic généré
  • ID unique de la licence (UUID)
  • Format : IRONLOCK-ECDSA-P384-SHA256-v2

Un MessageBox rappelle de renommer le fichier en licence.lic avant envoi au client.

19

Thèmes GUI

🌑 Dark IronLock

Fond #06080d, accents orange #ff6b35 + teal #00ffcc + violet #a855f7. Police Orbitron + Share Tech Mono + Exo 2. Optimisé pour longues sessions de développement. Réduit la fatigue oculaire.

☀ Light Professionnel

Fond blanc cassé #f5f7fa, accents orange sombre #e05a23. Adapté aux présentations clients, environnements à forte luminosité ambiante.

⬛ High Contrast

Fond noir pur, texte blanc pur, bordures blanches épaisses. Aucun gradient. Accessibilité maximale — conforme WCAG AA. Compatible lecteurs d'écran.

python gui/app.py --theme dark # Défaut python gui/app.py --theme light # Light professionnel python gui/app.py --theme high_contrast # WCAG AA # Changer en live depuis le menu Vue ou onglet Paramètres
20

Packager universel (outil CLI)

# Fichier unique EXE/ELF/Python python tools/packager.py monapp.exe \ -n "MonApp v2.0" -o dist/ # Répertoire → ZIP → AES-256-GCM python tools/packager.py ./mon_projet/ \ -n "MonApp" -o dist/ -v "2.1.0"
== IronLock v2.0 — Packaging: MonApp v2.0 == [1/4] Preparing payload... Type : file | 15,234,816 bytes [2/4] Encrypting AES-256-GCM ... payload.ironenc — 15,308,240 bytes Algo : AES-256-GCM | Chunks: 233 [3/4] Copying IronLock v2 core files... ✓ loader.py ✓ fingerprint.py ✓ vm_detector.py ✓ anti_debug.py ✓ crypto_engine.py [4/4] Generating manifest ... ✓ == PACKAGE COMPLETE ==
21

Pipeline obfuscation & build

# Standard : PyArmor obf-code 2 + PyInstaller python tools/obfuscate_build.py --source-dir core/ --exe-name MonApp # C natif Cython + PyInstaller (v2 recommandé) python tools/obfuscate_build.py --source-dir core/ --exe-name MonApp --cython # Obfuscation seule python tools/obfuscate_build.py --source-dir core/ --skip-pyinstaller # Avec icône + onedir python tools/obfuscate_build.py --source-dir core/ --exe-name MonApp --icon app.ico --onedir
ModeProtectionDécompilable ?Requis
PyArmor TrialBytecode chiffré obf-code 1Difficile (déobfuscation possible)pyarmor gratuit
PyArmor Basicobf-code 2, mix-strTrès difficile~60$/an
PyArmor Pro BCCCompile en C natif LLVMPratiquement impossible~200$/an
Cython v2 --cython.pyd/.so extension nativePratiquement impossibleCython gratuit ≥3.0
22

Loader — API Python

# Invocation standard from core.loader import run_loader run_loader() # Chemins personnalisés run_loader( licence_path = "./licences/client_A.lic", payload_path = "./payloads/app_v2.ironenc", extra_args = ["--mode", "production"], )
# Mode debug (dev uniquement — jamais en prod) run_loader( debug_mode = True, # Désactive anti-debug + watchdog allow_vm = True, # Autorise les VMs ) # VM autorisée (hébergement cloud) run_loader( allow_vm = True, licence_path = "licence.lic", payload_path = "payload.ironenc", )
🔴
Ne jamais activer debug_mode=True en production. Ce mode désactive l'anti-debug, le watchdog et les checks VM — 0 protection. Réservé aux tests internes.
23

Paramètres configurables

# ── core/loader.py — modifier AVANT obfuscation et build ── # Clé publique ECC P-384 (obligatoire) IRONLOCK_PUBLIC_KEY_PEM = """-----BEGIN PUBLIC KEY----- REPLACE_WITH_YOUR_ECC_P384_PUBLIC_KEY -----END PUBLIC KEY-----""" # Rétro-compat licences RSA v1 (optionnel) IRONLOCK_PUBLIC_KEY_RSA_V1 = "" # Fingerprint — tolérance sur 12 sources FINGERPRINT_TOLERANCE = 8 # 4 changements tolérés FINGERPRINT_TOTAL = 12 # VM ALLOW_VM = False # True = autoriser les VMs VM_CONFIDENCE_THRESHOLD = 0.3 # 0.0–1.0 # Serveur REST (Phase C — optionnel) LICENCE_SERVER_URL = "" # Ex: "https://lic.votreapp.com" SERVER_VERIFY_INTERVAL_H = 24 # Heartbeat toutes les N heures SERVER_GRACE_PERIOD_H = 72 # Grace period sans réseau
ParamètreDéfautImpact
FINGERPRINT_TOLERANCE8Tolérance matérielle : 8/12 = 4 composants changés acceptés
ALLOW_VMFalseTrue = désactive complètement le VM Detector (CI/CD)
VM_CONFIDENCE_THRESHOLD0.3Hausser → moins sensible aux faux positifs
SERVER_GRACE_PERIOD_H72h0 = online-only ; très grand = offline-only
WatchdogThread check_interval5.0sRéduire → plus réactif mais plus de CPU
24

Couches de protection v2

Couchev1v2Gain sécurité
ChiffrementAES-256-GCM + HMACAES-256-GCM + ChaCha20AEAD intégré, timing-safe
KDFPBKDF2 100KArgon2id 64 Mo×62 résistance GPU
Session keysNonHKDF-SHA256Clés éphémères
LicencesECDSA P-384ECDSA P-384192-bit, 10× compact
Fingerprint8 sources12 sources+4 sources anti-VM
Anti-debug5 checks fixes12 checks aléatoiresRing0, NT API, stack walk
VM detector7 checks15 checksCPUID, Docker, uptime
ObfuscationPyArmor bytecodePyArmor + Cython CExtension native
Séquence boot10 étapes12 étapes+server check, +pré-tamper
Erreurs fatalesDélai fixeDélai 100–800ms aléatoireTiming analysis
Effacement mémoirePayload après execPayload + clés + master_secretSurface d'attaque minimale
25

Compatibilité

FonctionnalitéWindows 10/11Linux Ubuntu 22+macOS 12+
Loader v2 (12 étapes)
AES-256-GCM + ChaCha20
Argon2id
ECDSA P-384 licences
Retro-compat v1 payload + licences
Anti-debug NtQuery / PEB
Anti-debug TracerPid
Anti-debug timing + stack walk
VM Detector registre Windows
VM Detector Docker/WSL⚠ WSL
VM Detector CPUID✅ wmic✅ systemd
Fingerprint 12 sources complètes⚠ partiel⚠ partiel
GUI PyQt6 (3 thèmes)
Cython C natif✅ .pyd✅ .so✅ .so
Python 3.12+✅ Cible✅ Cible✅ Cible
26

FAQ

La clé AES est-elle stockée quelque part en v2 ?

Non. La chaîne complète : SHA256(fp:secret)Argon2id(salt)HKDF(enc/hmac). Chaque maillon est effacé avec bytes(len(key)) immédiatement après usage. La clé de chiffrement n'existe que le temps du déchiffrement chunk par chunk — quelques millisecondes.

Que se passe-t-il si argon2-cffi n'est pas installé ?

IronLock détecte l'absence à l'import (_ARGON2_AVAILABLE = False) et bascule sur PBKDF2-SHA256 avec 300 000 itérations. Un avertissement est affiché lors du self-test. La protection reste correcte mais environ ×5 moins résistante aux attaques GPU spécialisées.

Le format v2 est-il plus volumineux que v1 ?

Non — légèrement plus compact. Nonce GCM 12B remplace IV CBC 16B (−4B). Tag AEAD 16B remplace HMAC 32B (−16B). Soit −20B par chunk 64 Ko, i.e. <0.03% de gain sur un gros fichier. En pratique imperceptible mais dans le bon sens.

Peut-on utiliser une licence v1 RSA avec le loader v2 ?

Oui, via IRONLOCK_PUBLIC_KEY_RSA_V1 dans le loader. Tentative ECDSA P-384 d'abord, puis RSA en fallback. Aucune intervention côté client. Recommandation : migrer progressivement vers ECDSA P-384 lors des renouvellements.

La GUI est-elle incluse dans le package client ?

Non. La GUI (gui/) est un outil développeur. Le package client contient uniquement le loader compilé (MonApp.exe), payload.ironenc, et licence.lic.

ChaCha20 est-il aussi sécurisé qu'AES-256-GCM ?

Oui — sécurité équivalente 256-bit. ChaCha20-Poly1305 est préféré sur hardware sans AES-NI car constant-time natif, évitant les timing attacks sur les implémentations logicielles d'AES. RFC 8439.

Comment configurer le serveur de licences online (Phase C) ?

Définir LICENCE_SERVER_URL = "https://lic.votreapp.com" dans le loader avant build. Le loader enverra un heartbeat à chaque démarrage. Sans réseau : grace period de SERVER_GRACE_PERIOD_H heures (défaut 72h) avant blocage. Laisser vide pour mode offline pur.

Le Watchdog peut-il être bypassé en attachant un debugger après le démarrage ?

Le Watchdog vérifie toutes les 5 secondes. Un debugger attaché après le démarrage sera détecté dans l'intervalle suivant (max 5s). Les checks incluent NtQueryInformationProcess (difficile à patcher depuis userland sans RING0) et la stack walk des frames Python.

27

Changelog

v2.0.0 — 2025 Q2

v2.0.0 — 2025 Q1