Pourquoi un fingerprint hardware ?

Un système de licensing basé uniquement sur une clé de licence est insuffisant : la clé peut être copiée et partagée. La solution est de lier cryptographiquement la licence à une machine précise via son empreinte matérielle.

L'empreinte hardware est un hash calculé à partir de plusieurs caractéristiques physiques de la machine. Sur la même machine, le hash doit être reproductible. Sur une machine différente, il doit être différent. Et si l'utilisateur change un composant (une RAM, une carte réseau), le système doit être tolérant à un certain degré de changement sans casser la licence.

Un bon fingerprint hardware résiste à trois attaques : la copie de la licence sur une autre machine, la virtualisation (VM), et le clonage disque.

Les 8 sources d'entropie

IronLock v2.0 combine 8 sources indépendantes. Chaque source est collectée, normalisée, puis intégrée dans un hash SHA-256 final.

SOURCE 01
UUID Carte mère
Identifiant unique gravé dans le firmware UEFI/BIOS. Persiste à travers les réinstallations OS. Quasiment immuable sauf remplacement de la carte mère.
● Stabilité très haute
SOURCE 02
BIOS Serial Number
Numéro de série du BIOS, distinct de l'UUID. Fourni par le fabricant OEM. Stable et identifiant pour les machines de marque (Dell, HP, Lenovo).
● Stabilité très haute
SOURCE 03
CPU ID
Identifiant du processeur via CPUID instruction. Inclut le stepping, le modèle et le fabricant. Stable mais identique sur machines configurées pareil.
● Stabilité haute
SOURCE 04
MAC Address
Adresse physique de la première interface réseau. Unique par carte. Peut être spoofée logiciellement — d'où l'intérêt des 7 autres sources.
● Stabilité moyenne
SOURCE 05
Disk Serial Number
Numéro de série du disque de démarrage (HDD/SSD/NVMe). Très stable, résiste aux réinstallations OS. Changer de disque = changement de source critique.
● Stabilité haute
SOURCE 06
RAM Configuration
Taille totale + nombre de slots + vitesse des barrettes. Granularité suffisante pour différencier des machines similaires. Changement RAM = source différente.
● Stabilité moyenne
SOURCE 07
OS Install GUID
Identifiant unique généré à l'installation de Windows (MachineGuid) ou Linux (machine-id). Réinitialisé à chaque réinstallation — volontaire ou clone.
● Stabilité moyenne
SOURCE 08
Hostname Hash
Hash SHA-256 du nom de machine. Faible entropie seul, mais contribue à différencier des machines identiques en parc. Configurable ou exclu selon l'usage.
● Stabilité basse

Collecte cross-platform

La collecte doit fonctionner sur Windows et Linux sans droits administrateur. IronLock utilise des APIs système disponibles en userland :

import platform, hashlib, subprocess, uuid
from typing import Optional

def _get_windows_wmic(wmic_path: str) -> Optional[str]:
    try:
        r = subprocess.run(
            ['wmic'] + wmic_path.split() + ['get', 'Value', '--format:list'],
            capture_output=True, text=True, timeout=5
        )
        lines = [l.split('=')[1].strip() for l in r.stdout.splitlines()
                 if '=' in l and l.split('=')[1].strip()]
        return lines[0] if lines else None
    except: return None

def collect_sources() -> dict:
    win = platform.system() == 'Windows'
    sources = {}

    # Source 1 : UUID carte mère
    if win:
        sources['mb_uuid'] = _get_windows_wmic('csproduct UUID')
    else:
        try:
            sources['mb_uuid'] = open('/sys/class/dmi/id/product_uuid').read().strip()
        except: sources['mb_uuid'] = None

    # Source 2 : BIOS serial
    if win:
        sources['bios_serial'] = _get_windows_wmic('bios serialnumber')
    else:
        try:
            sources['bios_serial'] = open('/sys/class/dmi/id/product_serial').read().strip()
        except: sources['bios_serial'] = None

    # Source 4 : MAC address
    sources['mac'] = ':'.join(
        ['{:02x}'.format((uuid.getnode() >> 8*i) & 0xff) for i in reversed(range(6))]
    )

    # Source 7 : OS install GUID
    if win:
        import winreg
        k = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
                           r'SOFTWARE\Microsoft\Cryptography')
        sources['os_guid'] = winreg.QueryValueEx(k, 'MachineGuid')[0]
    else:
        try:
            sources['os_guid'] = open('/etc/machine-id').read().strip()
        except: sources['os_guid'] = None

    return sources

Combinaison et hachage SHA-256

Les sources sont concaténées dans un ordre déterministe, normalisées (minuscules, espaces supprimés), puis hachées. Les sources absentes (None) sont remplacées par un placeholder constant pour ne pas perturber la longueur :

def build_fingerprint(sources: dict, salt: bytes = b'IRONLOCK_V2') -> str:
    ORDER = ['mb_uuid', 'bios_serial', 'cpu_id', 'mac',
             'disk_serial', 'ram_config', 'os_guid', 'hostname_hash']

    parts = []
    for key in ORDER:
        val = sources.get(key) or f'MISSING_{key.upper()}'
        # Normalisation : minuscules, sans espaces ni tirets
        val = val.lower().replace('-', '').replace(' ', '')
        parts.append(val)

    raw = '|'.join(parts).encode('utf-8')
    return hashlib.sha256(salt + raw).hexdigest()

# Exemple de résultat
fp = build_fingerprint(collect_sources())
# → 'a3f8c2e1d4b7f09a...64 caractères hexadécimaux'

Tolérance aux changements matériels

Un utilisateur légitime peut changer de RAM, de carte réseau ou réinstaller son OS. Le système de tolérance d'IronLock v2 fonctionne par score de concordance : chaque source vaut un certain poids, et la licence est valide tant que le score dépasse un seuil configurable :

WEIGHTS = {
    'mb_uuid':      3,  # critique
    'bios_serial':  3,  # critique
    'disk_serial':  2,  # important
    'cpu_id':       2,
    'os_guid':      1,
    'mac':          1,
    'ram_config':   1,
    'hostname_hash':1,
}
THRESHOLD = 10  # sur 14 points max — tolérance ~30%

def verify_tolerance(stored: dict, current: dict) -> bool:
    score = sum(WEIGHTS[k] for k, w in WEIGHTS.items()
                if stored.get(k) == current.get(k))
    return score >= THRESHOLD

Détection de virtualisation

Les machines virtuelles retournent des valeurs prévisibles ou absentes pour plusieurs sources. IronLock détecte les VMs en croisant plusieurs indicateurs :

  • UUID carte mère — les VMs VMware retournent des UUID commençant par 564d. VirtualBox : 080027.
  • MAC address — préfixes connus : 00:0C:29 VMware, 08:00:27 VirtualBox, 52:54:00 QEMU.
  • BIOS serial — les VMs légères retournent None ou une chaîne vide.
  • RAM config — les VMs cloud ont souvent des configurations RAM non standard (2047 MB, puissances de 2 exactes).

Implémentation dans IronLock v2

IronLock v2 automatise tout ce processus. Le fingerprint est généré en une ligne et exporté en JSON pour la gestion des licences :

# Générer le fingerprint de la machine courante
ironlock fingerprint --output fingerprint.json

# fingerprint.json (envoyé par le client pour activation)
{
  "hardware_id": "a3f8c2e1d4b7...",
  "sources": {
    "mb_uuid": "presente",
    "mac": "presente"
    // valeurs hachées, jamais en clair
  },
  "version": "2.0",
  "timestamp": "2026-02-14T10:30:00Z"
}

Conclusion

Un fingerprint hardware robuste nécessite au minimum 6 à 8 sources indépendantes, une normalisation stricte et un système de tolérance aux changements légitimes. La combinaison UUID carte mère + BIOS serial + Disk serial constitue le noyau irréductible. Les autres sources servent à la tolérance et à la détection de VM.

IronLock v2 implémente ce système complet, y compris la gestion des absences de sources, la détection de virtualisation et le scoring de concordance — sans que vous ayez à gérer ces cas un par un.

🔐
PRODUIT LIÉ
IronLock v2.0 — Fingerprint × 8 sources
← Retour au blog Article suivant →