Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
KNX et L'IA
#9
Hello, voici le script python pour virer le mdp du projet
Code :
#!/usr/bin/env python3
"""
Retire la protection par mot de passe d'un fichier .knxproj (ETS 5.7 / 6).

Usage :
    python knxproj_unprotect.py projet.knxproj
    python knxproj_unprotect.py projet.knxproj -p "MotDePasse" -o projet_clair.knxproj

Si -p est omis, le mot de passe est demandé de façon masquée.
Dépendance : pip install pyzipper
"""

import argparse
import base64
import getpass
import hashlib
import io
import re
import sys
import zipfile
from pathlib import Path

try:
    import pyzipper
except ImportError:
    sys.exit("Module manquant : installe-le avec  pip install pyzipper")

# Paramètres de dérivation utilisés par ETS pour le mot de passe du zip
ETS_SALT = b"21.project.ets.knx.org"
ETS_ITERATIONS = 65536


def derive_zip_password(password: str) -> bytes:
    """Mot de passe ETS -> mot de passe réel du zip (PBKDF2-SHA256 puis base64)."""
    key = hashlib.pbkdf2_hmac(
        "sha256", password.encode("utf-16-le"), ETS_SALT, ETS_ITERATIONS, dklen=32
    )
    return base64.b64encode(key)


def candidate_passwords(password: str):
    """Mots de passe à essayer : dérivé ETS en premier, brut en secours."""
    yield derive_zip_password(password)
    yield password.encode("utf-8")


def _is_encrypted(zf: pyzipper.AESZipFile) -> bool:
    return any(info.flag_bits & 0x1 for info in zf.infolist())


def _open_zip(data, password: str | None):
    """Ouvre un zip (chemin ou bytes) ; teste les mots de passe candidats si chiffré."""
    src = io.BytesIO(data) if isinstance(data, (bytes, bytearray)) else data
    zf = pyzipper.AESZipFile(src)
    if not _is_encrypted(zf):
        return zf
    if password is None:
        raise ValueError("Archive chiffrée mais aucun mot de passe fourni.")
    # on teste sur le premier fichier non-répertoire
    probe = next(i for i in zf.infolist() if not i.is_dir())
    for pwd in candidate_passwords(password):
        zf.setpassword(pwd)
        try:
            zf.read(probe)
            return zf
        except Exception:
            continue
    raise ValueError("Mot de passe incorrect.")


def unprotect(src: Path, dst: Path, password: str | None) -> None:
    outer = _open_zip(str(src), password)
    nb_inner = 0

    with zipfile.ZipFile(dst, "w", compression=zipfile.ZIP_DEFLATED) as out:
        for info in outer.infolist():
            if info.is_dir():
                continue
            data = outer.read(info)
            name = info.filename

            # Archive interne de projet : P-XXXX.zip -> dossier P-XXXX/
            m = re.fullmatch(r"(?:.*/)?(P-[0-9A-Fa-f]+)\.zip", name)
            if m:
                folder = m.group(1)
                inner = _open_zip(data, password)
                nb_inner += 1
                for iinfo in inner.infolist():
                    if iinfo.is_dir():
                        continue
                    iname = iinfo.filename
                    # évite un doublon P-XXXX/P-XXXX/... si déjà préfixé
                    if iname.startswith(folder + "/"):
                        iname = iname[len(folder) + 1:]
                    out.writestr(f"{folder}/{iname}", inner.read(iinfo))
                continue

            out.writestr(name, data)

    if nb_inner == 0:
        print("Note : aucune archive P-XXXX.zip trouvée, le fichier était peut-être "
              "déjà en clair (contenu simplement recopié).")
    else:
        print(f"OK : {nb_inner} projet(s) déchiffré(s) -> {dst}")


def main() -> None:
    ap = argparse.ArgumentParser(description="Retire le mot de passe d'un .knxproj")
    ap.add_argument("fichier", type=Path, help="fichier .knxproj protégé")
    ap.add_argument("-p", "--password", help="mot de passe du projet")
    ap.add_argument("-o", "--output", type=Path,
                    help="fichier de sortie (défaut : <nom>_unprotected.knxproj)")
    args = ap.parse_args()

    if not args.fichier.is_file():
        sys.exit(f"Fichier introuvable : {args.fichier}")

    dst = args.output or args.fichier.with_name(args.fichier.stem + "_unprotected.knxproj")
    if dst.resolve() == args.fichier.resolve():
        sys.exit("Le fichier de sortie doit être différent du fichier d'entrée.")

    password = args.password
    if password is None:
        password = getpass.getpass("Mot de passe du projet (laisser vide si aucun) : ") or None

    try:
        unprotect(args.fichier, dst, password)
    except ValueError as e:
        dst.unlink(missing_ok=True)
        sys.exit(f"Erreur : {e}")


if __name__ == "__main__":
    main()
Répondre


Messages dans ce sujet
KNX et L'IA - par filou59 - 01/11/2026, 16:42:07
RE: KNX et L'IA - par richardpub - 01/11/2026, 17:37:44
RE: KNX et L'IA - par Kevlille - 02/11/2026, 15:39:38
RE: KNX et L'IA - par filou59 - 02/11/2026, 17:41:49
RE: KNX et L'IA - par filou59 - 02/11/2026, 17:47:26
RE: KNX et L'IA - par richardpub - 02/11/2026, 17:51:30
RE: KNX et L'IA - par filou59 - 02/11/2026, 18:20:01
RE: KNX et L'IA - par richardpub - 02/11/2026, 19:22:13
RE: KNX et L'IA - par XeNo - 04/11/2026, 19:45:32
RE: KNX et L'IA - par Scorpio5 - 05/11/2026, 07:15:28
RE: KNX et L'IA - par filou59 - 05/11/2026, 08:32:12
RE: KNX et L'IA - par Scorpio5 - 05/11/2026, 09:11:11
RE: KNX et L'IA - par richardpub - 05/11/2026, 15:17:00

Atteindre :


Utilisateur(s) parcourant ce sujet : 1 visiteur(s)