Pour résumer, il transforme un mot de passe humain en une clé cryptographique de 512 bits via PBKDF2, puis l'utilise pour chiffrer/déchiffrer un conteneur de données avec AES-XTS, avec vérification d'intégrité par un token stocké dans le conteneur.
Le schéma est le suivant :
Code : Tout sélectionner
MOT DE PASSE (ex: "MonSuperMotDePasse!2024") - prévoyez au moins 32 caractères
│
▼
PBKDF2 (1 000 000+ itérations) - plus d'un million d'itérations conseillé pour ralentir les attaques par dictionnaire
+ SEL dérivé d'un second mot de passe - là aussi, au moins 16 caractères
│
▼
CLÉ MAÎTRE (512 bits)
│
▼
AES-XTS-PLAIN64 (chiffrement par blocs)
│
▼
DONNÉES CHIFFRÉES dans coffre.dat- La corruption du conteneur
- La modification accidentelle des métadonnées
- La récupération après suppression de l'en-tête
Pour bien comprendre de quoi on parle, le schéma suivant devrait vous éclairer :
Code : Tout sélectionner
┌─────────────────────────────────────────────────────────────┐
│ OFFSET (ex: 3333 octets = 3.3 Ko) │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ ESPACE LIBRE RÉSERVÉ ││
│ │ - Non utilisé par le chiffrement ││
│ │ - Accessible directement sans déchiffrement ││
│ │ - Peut servir de "piège" ou d'espace de métadonnées ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ ZONE CHIFFRÉE (à partir de l'offset) │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Données chiffrées - Inaccessibles sans la clé ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘- Chiffrement fort (AES-XTS 512 bits)
- Protection contre la force brute (PBKDF2)
- Absence de traces (100% PIPE)
- Vérification par token (confirmation d'intégrité)
CRITIQUE
Je n'utilise volontairement pas le mécanisme LUKS de cryptsetup, qui propose notamment une protection contre la corruption du conteneur, et des slots de clés multiples (ce que je considère perso comme une faiblesse...).
Pensez donc à faire des sauvegardes du conteneur pour éviter les catastrophes !
Le script est fournit tel que sous GPLv2, à vos risques et périls comme tout autre Logiciel Libre !
FONCTIONNEMENT
Dans un premier temps, il faut créer manuellement son conteneur non chiffré via (le paramètre count= est à adapter suivant vos besoin) :
Code : Tout sélectionner
dd if=/dev/urandom of=/root/coffre.dat bs=1G count=3pour un "coffre" de 3Go ici donné en exemple.
N.B. : Attention à bien utiliser /dev/urandom pour remplir le conteneur avec des données aléatoires ! Cette étape assure que le décalage de la clé sera "noyé" dans le flux aléatoire, et donc plus difficile à trouver !
Puis il faut utiliser le script avec l'option 1, avec les paramètres, qui va formater le conteneur en ext4, et créer un petit fichier invisible .secret_token dans le conteneur, monté par défaut dans /mnt ici, qu'il ne faut pas effacer par la suite (il est utilisé dans les tests).
Ensuite on peut tester le résultat avec l'option 4 : le premier test de montage doit réussir, mais tous les autres doivent échouer (mauvais passe, mauvais sel, mauvaises itérations, mauvais décalage et enfin tout mauvais).
Pourquoi cette phase de test est importante avec de remplir votre conteneur ?
Parce que suivant la version de vos outils, et votre distribution, je me suis aperçu que les comportements pouvaient parfois varier, voire échouer.
En testant une fois pour toute les paramètres d'ouverture (mot de passe, sel, ...), un par un, on s'assure du comportement attendu et de la sécurité réelle.
En utilisation normale, l'option 2 permet de monter le conteneur dans /mnt, et l'option 3 de le démonter proprement à tout moment.
Bien entendu : il n'y a aucun moyen de récupérer vos données si vous oubliez les paramètres d'ouverture qui ont servi à créer le coffre !
LE SCRIPT (à sauvegarder par exemple en coffre.sh, et à rendre exécutable via chmod +x coffre.sh) :
Code : Tout sélectionner
#!/bin/bash
# Script PBKDF2 - Version avec DEV_MAPPER configurable
# Version 7.13 - Nom du mapping personnalisable
# Licence GPLv2
# Jean Luc BIELLLMANN - contact@alsatux.com
set -euo pipefail
# Configuration
CONTAINER_PATH="/root/coffre.dat"
# Point de montage du container
MOUNT_POINT="/mnt"
# Nom du device dans /dev/mapper/
DEV_MAPPER="coffre"
# chiffrement
CYPHER="aes-xts-plain64"
# Longueur de la clé
KEYSIZE=512
# Algo de hashage
HASH_ALGO="sha512"
# Token FIXE (fichier caché à laisser dans le container)
TOKEN_FILE=".secret_token"
TOKEN_CONTENT="MON_TOKEN_ADORE_123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
# Mode débogage (1=activé, 0=désactivé)
DEBUG=1
# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
print_ok() { echo -e "${GREEN}✅ $1${NC}"; }
print_error() { echo -e "${RED}❌ $1${NC}"; }
print_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
print_info() { echo -e "${BLUE}ℹ️ $1${NC}"; }
print_title() { echo -e "\n${BOLD}📌 $1${NC}"; }
print_debug() {
if [ "$DEBUG" -eq 1 ]; then
echo -e "${CYAN}🔍 $1${NC}" >&2
fi
}
print_cmd() {
if [ "$DEBUG" -eq 1 ]; then
echo -e "${YELLOW}🔧 CMD: $1${NC}" >&2
fi
}
show_hash_summary() {
local hash="$1"
local prefix="${2:-}"
if [ ${#hash} -le 16 ]; then
echo "${prefix}${hash}"
else
echo "${prefix}${hash:0:16}...${hash: -8}"
fi
}
generate_salt() {
local salt_password="$1"
local salt
salt=$(echo -n "$salt_password" | sha512sum | cut -d' ' -f1 | cut -c1-64)
print_debug "Génération du sel"
print_debug "Sel généré: $salt"
echo "$salt"
return 0
}
# Génération PBKDF2 avec debug visible (sortie hex)
generate_pbkdf2_debug() {
local password="$1"
local iterations="$2"
local salt="$3"
local key_length="$4"
local key_bits=$((key_length * 8))
echo "" >&2
print_debug "=========================================="
print_debug "🔐 GÉNÉRATION PBKDF2 (DEBUG)"
print_debug " - Mot de passe: (masqué)"
print_debug " - Itérations: $iterations"
print_debug " - Sel: $salt"
print_debug " - Longueur clé: $key_length octets ($key_bits bits)"
print_debug " - Hash: $HASH_ALGO"
print_debug "=========================================="
# Commande complète visible
local cmd="openssl kdf -keylen $key_length -kdfopt digest:$HASH_ALGO -kdfopt iter:$iterations -kdfopt salt:$salt -kdfopt pass:$password -binary PBKDF2"
print_cmd "$cmd"
# Génération de la clé en hex pour debug
local key_hex
key_hex=$(openssl kdf \
-keylen "$key_length" \
-kdfopt "digest:$HASH_ALGO" \
-kdfopt "iter:$iterations" \
-kdfopt "salt:$salt" \
-kdfopt "pass:$password" \
-binary \
PBKDF2 2>/dev/null | xxd -p -c 256 | tr -d '\n')
local ret=$?
if [ $ret -ne 0 ]; then
print_error "❌ Échec de la génération PBKDF2 (code: $ret)"
return $ret
fi
local key_len=${#key_hex}
print_debug "✅ Génération PBKDF2 réussie"
print_debug " - Longueur hex: $key_len caractères"
print_debug " - Condensat: ${key_hex:0:32}...${key_hex: -8}"
return 0
}
# Génération PBKDF2 pour la vraie execution (sortie binaire)
generate_pbkdf2_binary() {
local password="$1"
local iterations="$2"
local salt="$3"
local key_length="$4"
# Exécution silencieuse - sortie binaire
openssl kdf \
-keylen "$key_length" \
-kdfopt "digest:$HASH_ALGO" \
-kdfopt "iter:$iterations" \
-kdfopt "salt:$salt" \
-kdfopt "pass:$password" \
-binary \
PBKDF2 2>/dev/null
return $?
}
# Vérification du superblock ext4
check_ext4_superblock() {
local device="$1"
if [ ! -b "$device" ]; then
return 1
fi
print_debug "Vérification du superblock ext4 sur $device"
local magic
magic=$(dd if="$device" bs=1 skip=1080 count=2 2>/dev/null | xxd -p 2>/dev/null | tr -d '\n')
print_debug "Signature détectée: $magic (attendue: 53ef)"
if [ "$magic" = "53ef" ]; then
print_debug "✅ Superblock ext4 valide"
return 0
else
print_debug "❌ Superblock ext4 invalide"
return 1
fi
}
# Fonction de montage avec vérification STRICTE
mount_with_key_and_check_strict() {
local password="$1"
local salt="$2"
local iterations="$3"
local offset="$4"
local test_name="${5:-Test}"
# Utiliser un nom de mapping unique pour les tests
local test_mapper="pbkdf2_test_$$"
local test_device="/dev/mapper/$test_mapper"
print_title "TEST: $test_name"
print_info "Paramètres:"
print_info " - Itérations: $iterations"
print_info " - Offset: $offset octets"
print_info " - Sel: $(show_hash_summary "$salt")"
print_info " - Mot de passe: (masqué)"
print_info " - Mapping de test: $test_mapper"
# Debug : génération de la clé visible
local key_length=$((KEYSIZE / 8))
print_info "Debug de la génération de clé..."
if ! generate_pbkdf2_debug "$password" "$iterations" "$salt" "$key_length"; then
print_error "Debug de génération échoué"
return 1
fi
echo ""
local LOOP
LOOP=$(losetup -f)
if [ -z "$LOOP" ]; then
print_error "Pas de loop device disponible"
return 1
fi
print_debug "Loop device: $LOOP"
print_cmd "losetup $LOOP $CONTAINER_PATH"
if ! losetup "$LOOP" "$CONTAINER_PATH" 2>/dev/null; then
print_error "Échec attachement loop"
losetup -d "$LOOP" 2>/dev/null
return 1
fi
print_ok "Loop device attaché"
local temp_mount="/tmp/mount_test_$$"
mkdir -p "$temp_mount" 2>/dev/null
print_debug "Point de montage temporaire: $temp_mount"
# Génération de la clé en binaire et création du mapping
print_info "Création du mapping de test..."
local cmd_crypt="cryptsetup create $test_mapper $LOOP -c $CYPHER -o $offset -s $KEYSIZE --key-file -"
print_cmd "$cmd_crypt"
# Exécution réelle avec sortie binaire
if ! generate_pbkdf2_binary "$password" "$iterations" "$salt" "$key_length" | \
cryptsetup create "$test_mapper" "$LOOP" \
-c "$CYPHER" \
-o "$offset" \
-s "$KEYSIZE" \
--key-file - 2>/dev/null; then
print_error "Échec création mapping"
losetup -d "$LOOP" 2>/dev/null
rmdir "$temp_mount" 2>/dev/null
return 1
fi
print_ok "Mapping créé: $test_device"
# Montage en lecture seule
print_debug "Montage en lecture seule..."
print_cmd "mount -t ext4 -o noatime,nodev,nosuid,ro $test_device $temp_mount"
if ! mount -t ext4 -o noatime,nodev,nosuid,ro "$test_device" "$temp_mount" 2>/dev/null; then
print_error "Échec montage"
cryptsetup remove "$test_mapper" 2>/dev/null
losetup -d "$LOOP" 2>/dev/null
rmdir "$temp_mount" 2>/dev/null
return 1
fi
print_ok "Montage réussi"
# Vérification STRICTE du token
print_debug "Vérification du token..."
local result=1
if [ -f "$temp_mount/$TOKEN_FILE" ]; then
local content
content=$(cat "$temp_mount/$TOKEN_FILE" 2>/dev/null)
print_debug "Token trouvé: $content"
print_debug "Token attendu: $TOKEN_CONTENT"
if [ "$content" = "$TOKEN_CONTENT" ]; then
print_ok "✅ Token correspond !"
result=0
else
print_error "❌ Token incorrect !"
result=1
fi
else
print_warning "⚠️ Token absent"
result=1
fi
# Nettoyage
print_debug "Nettoyage..."
print_cmd "umount $temp_mount"
umount "$temp_mount" 2>/dev/null
print_cmd "cryptsetup remove $test_mapper"
cryptsetup remove "$test_mapper" 2>/dev/null
print_cmd "losetup -d $LOOP"
losetup -d "$LOOP" 2>/dev/null
rmdir "$temp_mount" 2>/dev/null
print_debug "Nettoyage terminé"
return $result
}
# Fonction de montage normale
mount_with_key_and_check() {
local password="$1"
local salt="$2"
local iterations="$3"
local offset="$4"
local token_check="${5:-1}"
local test_name="${6:-Test}"
local test_mapper="pbkdf2_test_$$"
local test_device="/dev/mapper/$test_mapper"
print_debug "Montage avec vérification"
print_debug " - Token check: $token_check"
print_debug " - Mapping de test: $test_mapper"
# Debug : génération de la clé visible
local key_length=$((KEYSIZE / 8))
print_info "Debug de la génération de clé..."
if ! generate_pbkdf2_debug "$password" "$iterations" "$salt" "$key_length"; then
print_error "Debug de génération échoué"
return 1
fi
echo ""
local LOOP
LOOP=$(losetup -f)
if [ -z "$LOOP" ]; then
print_error "Pas de loop device disponible"
return 1
fi
print_debug "Loop device: $LOOP"
print_cmd "losetup $LOOP $CONTAINER_PATH"
if ! losetup "$LOOP" "$CONTAINER_PATH" 2>/dev/null; then
print_error "Échec attachement loop"
losetup -d "$LOOP" 2>/dev/null
return 1
fi
print_ok "Loop device attaché"
local temp_mount="/tmp/mount_test_$$"
mkdir -p "$temp_mount" 2>/dev/null
# Génération de la clé en binaire et création du mapping
print_info "Création du mapping de test..."
local cmd_crypt="cryptsetup create $test_mapper $LOOP -c $CYPHER -o $offset -s $KEYSIZE --key-file -"
print_cmd "$cmd_crypt"
# Exécution réelle avec sortie binaire
if ! generate_pbkdf2_binary "$password" "$iterations" "$salt" "$key_length" | \
cryptsetup create "$test_mapper" "$LOOP" \
-c "$CYPHER" \
-o "$offset" \
-s "$KEYSIZE" \
--key-file - 2>/dev/null; then
print_error "Échec création mapping"
losetup -d "$LOOP" 2>/dev/null
rmdir "$temp_mount" 2>/dev/null
return 1
fi
print_ok "Mapping créé: $test_device"
# Montage en lecture seule
print_debug "Montage en lecture seule..."
print_cmd "mount -t ext4 -o noatime,nodev,nosuid,ro $test_device $temp_mount"
if ! mount -t ext4 -o noatime,nodev,nosuid,ro "$test_device" "$temp_mount" 2>/dev/null; then
print_error "Échec montage"
cryptsetup remove "$test_mapper" 2>/dev/null
losetup -d "$LOOP" 2>/dev/null
rmdir "$temp_mount" 2>/dev/null
return 1
fi
print_ok "Montage réussi"
local result=0
if [ "$token_check" -eq 1 ]; then
print_debug "Vérification du token..."
if [ -f "$temp_mount/$TOKEN_FILE" ]; then
local content
content=$(cat "$temp_mount/$TOKEN_FILE" 2>/dev/null)
print_debug "Token trouvé: $content"
print_debug "Token attendu: $TOKEN_CONTENT"
if [ "$content" = "$TOKEN_CONTENT" ]; then
print_ok "✅ Token correspond !"
result=0
else
print_error "❌ Token incorrect !"
result=1
fi
else
print_warning "⚠️ Token absent, fallback sur superblock"
if check_ext4_superblock "$test_device"; then
print_ok "✅ Superblock ext4 valide (fallback)"
result=0
else
print_error "❌ Superblock ext4 invalide"
result=1
fi
fi
else
print_debug "Vérification du token désactivée"
fi
# Nettoyage
print_debug "Nettoyage..."
print_cmd "umount $temp_mount"
umount "$temp_mount" 2>/dev/null
print_cmd "cryptsetup remove $test_mapper"
cryptsetup remove "$test_mapper" 2>/dev/null
print_cmd "losetup -d $LOOP"
losetup -d "$LOOP" 2>/dev/null
rmdir "$temp_mount" 2>/dev/null
print_debug "Nettoyage terminé"
return $result
}
# Mode diagnostic
diagnostic_mode() {
echo ""
echo "=========================================="
echo -e " ${BOLD}🔬 MODE DIAGNOSTIC${NC}"
echo "=========================================="
echo -e " ${YELLOW}🐛 DÉBOGAGE ACTIVÉ${NC}"
echo "=========================================="
echo ""
echo -e "${BLUE}ℹ️ Le mode diagnostic teste la robustesse du système${NC}"
echo -e "${BLUE} en vérifiant que seuls les paramètres CORRECTS${NC}"
echo -e "${BLUE} permettent le montage du conteneur.${NC}"
echo ""
echo -e "${YELLOW}⚠️ Les tests avec des paramètres ERRONÉS DOIVENT ÉCHOUER${NC}"
echo -e "${YELLOW} C'est le comportement attendu et SOUHAITABLE !${NC}"
echo -e "${YELLOW} Un échec signifie que le système a rejeté les mauvais paramètres.${NC}"
echo ""
echo -e "${GREEN}✅ Un SUCCÈS avec des paramètres ERRONÉS indiquerait${NC}"
echo -e "${GREEN} une FAILLE DE SÉCURITÉ !${NC}"
echo ""
if [ ! -f "$CONTAINER_PATH" ]; then
print_error "Fichier conteneur introuvable: $CONTAINER_PATH"
return 1
fi
local size
size=$(stat -c%s "$CONTAINER_PATH" 2>/dev/null)
echo ""
print_info "Conteneur: $CONTAINER_PATH ($((size/1048576))Mo)"
echo ""
echo "📝 Entrez le mot de passe PRINCIPAL CORRECT :"
read -s password_correct
echo ""
echo "📝 Entrez le mot de passe pour le SEL CORRECT :"
read -s salt_password_correct
echo ""
echo "📝 Entrez le nombre d'itérations CORRECT :"
read -r iterations_correct
echo "📝 Entrez l'offset CORRECT (octets) :"
read -r offset_correct
if ! [[ "$iterations_correct" =~ ^[0-9]+$ ]] || [ "$iterations_correct" -lt 1000 ]; then
print_error "Itérations invalides"
return 1
fi
if ! [[ "$offset_correct" =~ ^[0-9]+$ ]] || [ "$offset_correct" -lt 0 ]; then
print_error "Offset invalide"
return 1
fi
local salt_correct
salt_correct=$(generate_salt "$salt_password_correct")
echo ""
echo "=========================================="
print_title "PARAMÈTRES CORRECTS"
echo " - Mot de passe: (masqué)"
echo " - Sel: $salt_correct"
echo " - Sel (condensat): $(show_hash_summary "$salt_correct")"
echo " - Itérations: $iterations_correct"
echo " - Offset: $offset_correct octets"
echo " - Token: $TOKEN_CONTENT"
echo "=========================================="
echo ""
echo -e "${YELLOW}⚠️ Rappel : Seul le TEST 1 doit réussir.${NC}"
echo -e "${YELLOW} Les tests 2 à 6 DOIVENT ÉCHOUER.${NC}"
echo ""
echo -n "Appuyez sur ENTRÉE pour lancer les tests... "
read -r
local test_results=()
# Test 1 : Paramètres corrects
print_title "TEST 1 : PARAMÈTRES CORRECTS (RÉFÉRENCE)"
echo " → Résultat attendu: ✅ SUCCÈS"
echo " → Ce test vérifie que le système fonctionne avec les bons paramètres"
echo ""
if mount_with_key_and_check "$password_correct" "$salt_correct" "$iterations_correct" "$offset_correct" 0 "Paramètres corrects"; then
print_ok "Montage réussi ✓"
test_results+=("✅ TEST 1: Paramètres corrects → SUCCÈS")
else
print_error "Échec du montage avec les paramètres corrects !"
test_results+=("❌ TEST 1: Paramètres corrects → ÉCHEC")
fi
echo ""
echo -n "Appuyez sur ENTRÉE pour continuer... "
read -r
# Test 2 : Mot de passe bidon
print_title "TEST 2 : MOT DE PASSE BIDON"
echo " → Mot de passe: 'motdepassebidon123'"
echo " → Résultat attendu: ❌ ÉCHEC (token absent)"
echo " → Un succès indiquerait qu'un mot de passe incorrect peut ouvrir le conteneur"
echo ""
local fake_password="motdepassebidon123"
if mount_with_key_and_check_strict "$fake_password" "$salt_correct" "$iterations_correct" "$offset_correct" "Mot de passe bidon"; then
print_error "⚠️ Le montage a réussi avec un mot de passe bidon !"
test_results+=("❌ TEST 2: Mot de passe bidon → SUCCÈS (FAILLE DE SÉCURITÉ!)")
else
print_ok "Échec du montage ✓ (comme attendu)"
test_results+=("✅ TEST 2: Mot de passe bidon → ÉCHEC (bon)")
fi
echo ""
echo -n "Appuyez sur ENTRÉE pour continuer... "
read -r
# Test 3 : Sel bidon
print_title "TEST 3 : SEL BIDON"
echo " → Mot de passe sel: 'fauxsel123'"
echo " → Résultat attendu: ❌ ÉCHEC"
echo " → Un sel différent génère une clé différente → montage impossible"
echo ""
local fake_salt_password="fauxsel123"
local fake_salt
fake_salt=$(generate_salt "$fake_salt_password")
echo " → Sel généré: $fake_salt"
echo " → Sel (condensat): $(show_hash_summary "$fake_salt")"
if mount_with_key_and_check_strict "$password_correct" "$fake_salt" "$iterations_correct" "$offset_correct" "Sel bidon"; then
print_error "Le montage a réussi avec un sel bidon !"
test_results+=("❌ TEST 3: Sel bidon → SUCCÈS (FAILLE!)")
else
print_ok "Échec du montage ✓ (comme attendu)"
test_results+=("✅ TEST 3: Sel bidon → ÉCHEC (bon)")
fi
echo ""
echo -n "Appuyez sur ENTRÉE pour continuer... "
read -r
# Test 4 : Itérations bidon
print_title "TEST 4 : ITÉRATIONS BIDON"
echo " → Itérations: 1000 (au lieu de $iterations_correct)"
echo " → Résultat attendu: ❌ ÉCHEC"
echo " → Un nombre d'itérations différent génère une clé différente"
echo ""
local fake_iterations=1000
if mount_with_key_and_check_strict "$password_correct" "$salt_correct" "$fake_iterations" "$offset_correct" "Itérations bidon"; then
print_error "Le montage a réussi avec des itérations bidon !"
test_results+=("❌ TEST 4: Itérations bidon → SUCCÈS (FAILLE!)")
else
print_ok "Échec du montage ✓ (comme attendu)"
test_results+=("✅ TEST 4: Itérations bidon → ÉCHEC (bon)")
fi
echo ""
echo -n "Appuyez sur ENTRÉE pour continuer... "
read -r
# Test 5 : Offset bidon
print_title "TEST 5 : OFFSET BIDON"
local fake_offset=$((offset_correct + 4096))
if [ $((fake_offset % 512)) -ne 0 ]; then
fake_offset=$((fake_offset - (fake_offset % 512) + 512))
fi
echo " → Offset: $fake_offset octets (au lieu de $offset_correct)"
echo " → Résultat attendu: ❌ ÉCHEC"
echo " → Un offset incorrect déchiffre au mauvais endroit"
echo ""
if mount_with_key_and_check_strict "$password_correct" "$salt_correct" "$iterations_correct" "$fake_offset" "Offset bidon"; then
print_error "Le montage a réussi avec un offset bidon !"
test_results+=("❌ TEST 5: Offset bidon → SUCCÈS (FAILLE!)")
else
print_ok "Échec du montage ✓ (comme attendu)"
test_results+=("✅ TEST 5: Offset bidon → ÉCHEC (bon)")
fi
echo ""
echo -n "Appuyez sur ENTRÉE pour continuer... "
read -r
# Test 6 : Tout bidon
print_title "TEST 6 : TOUT BIDON"
echo " → Tous les paramètres sont faux"
echo " → Résultat attendu: ❌ ÉCHEC"
echo " → Combiné, toutes les erreurs doivent échouer"
echo ""
if mount_with_key_and_check_strict "$fake_password" "$fake_salt" "$fake_iterations" "$fake_offset" "Tout bidon"; then
print_error "Le montage a réussi avec tous les paramètres bidon !"
test_results+=("❌ TEST 6: Tout bidon → SUCCÈS (FAILLE!)")
else
print_ok "Échec du montage ✓ (comme attendu)"
test_results+=("✅ TEST 6: Tout bidon → ÉCHEC (bon)")
fi
echo ""
echo -n "Appuyez sur ENTRÉE pour continuer... "
read -r
# Résumé
echo ""
echo "=========================================="
echo -e " ${BOLD}📊 RÉSUMÉ DES TESTS${NC}"
echo "=========================================="
echo -e "${BLUE}ℹ️ Lecture des résultats :${NC}"
echo -e "${GREEN} ✅ → Comportement correct${NC}"
echo -e "${RED} ❌ → Comportement incorrect (faille de sécurité)${NC}"
echo ""
local nb_ok=0
local nb_fail=0
for result in "${test_results[@]}"; do
if [[ "$result" == ✅* ]]; then
echo -e "${GREEN}$result${NC}"
((nb_ok++))
else
echo -e "${RED}$result${NC}"
((nb_fail++))
fi
done
echo ""
echo "=========================================="
echo -e " ${BOLD}📈 BILAN${NC}"
echo "=========================================="
echo " Tests passés: $nb_ok/${#test_results[@]}"
echo " Échecs: $nb_fail/${#test_results[@]}"
if [ $nb_fail -eq 0 ]; then
print_ok "✅ Tous les tests sont passés !"
echo -e "${GREEN} La sécurité est bonne : seuls les paramètres corrects"
echo -e " permettent le montage du conteneur.${NC}"
else
print_error "❌ Des tests ont échoué !"
echo -e "${RED} La sécurité est compromise : des paramètres erronés"
echo -e " permettent le montage du conteneur.${NC}"
fi
echo "=========================================="
}
# Menu création
create_container() {
echo ""
echo "=========================================="
echo " 🔐 CRÉATION DU MAPPING"
echo "=========================================="
if [ ! -f "$CONTAINER_PATH" ]; then
print_error "Fichier introuvable: $CONTAINER_PATH"
return 1
fi
echo "📝 Mot de passe PRINCIPAL :"
read -s password_main
echo ""
echo "📝 Mot de passe pour le SEL :"
read -s password_salt
echo ""
echo "📝 Nombre d'itérations (100000+) :"
read -r iterations
echo "📝 Offset (octets, multiple de 512) :"
read -r offset
if ! [[ "$iterations" =~ ^[0-9]+$ ]] || [ "$iterations" -lt 100000 ]; then
print_error "Itérations invalides"
return 1
fi
if ! [[ "$offset" =~ ^[0-9]+$ ]] || [ "$offset" -lt 0 ]; then
print_error "Offset invalide"
return 1
fi
local salt
salt=$(generate_salt "$password_salt")
echo ""
echo "📌 RÉSUMÉ :"
echo " - Itérations: $iterations"
echo " - Offset: $offset octets"
echo " - Sel: $salt"
echo " - Token: $TOKEN_CONTENT"
echo " - Mapping: $DEV_MAPPER (/dev/mapper/$DEV_MAPPER)"
echo ""
# Vérification si le fichier conteneur semble déjà formaté
local already_formatted=0
if [ -f "$CONTAINER_PATH" ]; then
local size
size=$(stat -c%s "$CONTAINER_PATH" 2>/dev/null)
if [ "$size" -gt 0 ]; then
# Vérification rapide : chercher la signature ext4
local magic
magic=$(dd if="$CONTAINER_PATH" bs=1 skip=$((offset + 1080)) count=2 2>/dev/null | xxd -p 2>/dev/null | tr -d '\n')
if [ "$magic" = "53ef" ]; then
already_formatted=1
fi
fi
fi
if [ $already_formatted -eq 1 ]; then
echo ""
echo -e "${RED}⚠️ ATTENTION : Un système de fichiers ext4 semble déjà présent !${NC}"
echo -e "${RED} Le formatage DÉTRUIRA toutes les données du conteneur !${NC}"
echo ""
echo -e "${YELLOW} Si vous avez des données dans ce conteneur, arrêtez-vous maintenant.${NC}"
echo -e "${YELLOW} Le formatage efface TOUT de manière irréversible.${NC}"
echo ""
echo -n "Voulez-vous vraiment FORMATER ce conteneur ? (oui/NON) "
read -r confirm_format
if [[ ! "$confirm_format" =~ ^(oui|Oui|OUI)$ ]]; then
print_warning "Formatage annulé"
return 1
fi
echo ""
echo -e "${RED}⚠️ DERNIER AVERTISSEMENT :${NC}"
echo -e "${RED} Vous êtes sur le point de DÉTRUIRE toutes les données${NC}"
echo -e "${RED} du conteneur $CONTAINER_PATH${NC}"
echo ""
echo -n "Confirmer le formatage définitif ? (OUI/DESTRUCTION) "
read -r confirm_final
if [[ ! "$confirm_final" =~ ^(OUI|DESTRUCTION)$ ]]; then
print_warning "Formatage annulé"
return 1
fi
echo -e "${RED}⚠️ FORMATAGE CONFIRMÉ - LES DONNÉES VONT ÊTRE DÉTRUITES${NC}"
echo ""
else
echo ""
echo -e "${BLUE}ℹ️ Aucun système de fichiers détecté sur ce conteneur.${NC}"
echo -e "${BLUE} Le formatage est sûr (création d'un nouveau conteneur).${NC}"
echo ""
echo -n "Confirmer le formatage ? (o/N) "
read -r confirm_format
if [[ ! "$confirm_format" =~ ^[OoYy]$ ]]; then
print_warning "Opération annulée"
return 1
fi
fi
echo ""
echo -n "Appuyez sur ENTRÉE pour continuer... "
read -r
# Debug de la génération de clé
local key_length=$((KEYSIZE / 8))
print_info "Debug de la génération de clé..."
if ! generate_pbkdf2_debug "$password_main" "$iterations" "$salt" "$key_length"; then
print_error "Debug de génération échoué"
return 1
fi
echo ""
local LOOP
LOOP=$(losetup -f)
if [ -z "$LOOP" ]; then
print_error "Pas de loop device"
return 1
fi
print_cmd "losetup $LOOP $CONTAINER_PATH"
if ! losetup "$LOOP" "$CONTAINER_PATH" 2>/dev/null; then
print_error "Échec attachement loop"
return 1
fi
print_info "Création du mapping $DEV_MAPPER..."
local cmd_crypt="cryptsetup create $DEV_MAPPER $LOOP -c $CYPHER -o $offset -s $KEYSIZE --key-file -"
print_cmd "$cmd_crypt"
# Exécution réelle avec sortie binaire
if ! generate_pbkdf2_binary "$password_main" "$iterations" "$salt" "$key_length" | \
cryptsetup create "$DEV_MAPPER" "$LOOP" \
-c "$CYPHER" \
-o "$offset" \
-s "$KEYSIZE" \
--key-file - 2>/dev/null; then
print_error "Échec création mapping"
losetup -d "$LOOP" 2>/dev/null
return 1
fi
echo ""
print_info "Formatage en ext4 et création du token..."
print_cmd "mkfs.ext4 -F /dev/mapper/$DEV_MAPPER"
if ! mkfs.ext4 -F "/dev/mapper/$DEV_MAPPER" 2>/dev/null; then
print_error "Échec du formatage"
return 1
fi
mkdir -p "$MOUNT_POINT" 2>/dev/null
print_cmd "mount -t ext4 /dev/mapper/$DEV_MAPPER $MOUNT_POINT"
if ! mount -t ext4 "/dev/mapper/$DEV_MAPPER" "$MOUNT_POINT" 2>/dev/null; then
print_error "Échec du montage pour création du token"
return 1
fi
echo "$TOKEN_CONTENT" > "$MOUNT_POINT/$TOKEN_FILE"
sync
print_ok "Token créé: $MOUNT_POINT/$TOKEN_FILE"
print_cmd "umount $MOUNT_POINT"
umount "$MOUNT_POINT" 2>/dev/null
print_cmd "cryptsetup remove $DEV_MAPPER"
cryptsetup remove "$DEV_MAPPER" 2>/dev/null
print_cmd "losetup -d $LOOP"
losetup -d "$LOOP" 2>/dev/null
echo ""
print_ok "✅ Conteneur créé et formaté avec succès !"
echo ""
echo "📌 Pour monter : Option 2 du menu"
echo " Device: /dev/mapper/$DEV_MAPPER"
}
# Menu montage
mount_container() {
echo ""
echo "=========================================="
echo " 🔓 MONTAGE"
echo "=========================================="
if [ ! -f "$CONTAINER_PATH" ]; then
print_error "Fichier introuvable: $CONTAINER_PATH"
return 1
fi
echo "📝 Mot de passe PRINCIPAL :"
read -s password_main
echo ""
echo "📝 Mot de passe pour le SEL :"
read -s password_salt
echo ""
echo "📝 Nombre d'itérations :"
read -r iterations
echo "📝 Offset (octets) :"
read -r offset
if ! [[ "$iterations" =~ ^[0-9]+$ ]] || [ "$iterations" -lt 1000 ]; then
print_error "Itérations invalides"
return 1
fi
if ! [[ "$offset" =~ ^[0-9]+$ ]] || [ "$offset" -lt 0 ]; then
print_error "Offset invalide"
return 1
fi
local salt
salt=$(generate_salt "$password_salt")
echo ""
echo "📌 RÉSUMÉ :"
echo " - Itérations: $iterations"
echo " - Offset: $offset octets"
echo " - Sel: $salt"
echo " - Mapping: $DEV_MAPPER (/dev/mapper/$DEV_MAPPER)"
echo ""
echo -n "Appuyez sur ENTRÉE pour continuer... "
read -r
# Debug de la génération de clé
local key_length=$((KEYSIZE / 8))
print_info "Debug de la génération de clé..."
if ! generate_pbkdf2_debug "$password_main" "$iterations" "$salt" "$key_length"; then
print_error "Debug de génération échoué"
return 1
fi
echo ""
local LOOP
LOOP=$(losetup -f)
if [ -z "$LOOP" ]; then
print_error "Pas de loop device"
return 1
fi
print_cmd "losetup $LOOP $CONTAINER_PATH"
if ! losetup "$LOOP" "$CONTAINER_PATH" 2>/dev/null; then
print_error "Échec attachement loop"
return 1
fi
print_info "Création du mapping $DEV_MAPPER..."
local cmd_crypt="cryptsetup create $DEV_MAPPER $LOOP -c $CYPHER -o $offset -s $KEYSIZE --key-file -"
print_cmd "$cmd_crypt"
# Exécution réelle avec sortie binaire
if ! generate_pbkdf2_binary "$password_main" "$iterations" "$salt" "$key_length" | \
cryptsetup create "$DEV_MAPPER" "$LOOP" \
-c "$CYPHER" \
-o "$offset" \
-s "$KEYSIZE" \
--key-file - 2>/dev/null; then
print_error "Échec création mapping"
losetup -d "$LOOP" 2>/dev/null
return 1
fi
mkdir -p "$MOUNT_POINT" 2>/dev/null
print_cmd "mount -t ext4 -o noatime,nodev,nosuid /dev/mapper/$DEV_MAPPER $MOUNT_POINT"
if ! mount -t ext4 -o noatime,nodev,nosuid "/dev/mapper/$DEV_MAPPER" "$MOUNT_POINT" 2>/dev/null; then
print_error "Échec montage"
cryptsetup remove "$DEV_MAPPER" 2>/dev/null
losetup -d "$LOOP" 2>/dev/null
return 1
fi
# Vérification du token
if [ -f "$MOUNT_POINT/$TOKEN_FILE" ]; then
local content
content=$(cat "$MOUNT_POINT/$TOKEN_FILE" 2>/dev/null)
if [ "$content" = "$TOKEN_CONTENT" ]; then
print_ok "✅ Token vérifié avec succès"
else
print_warning "⚠️ Token incorrect !"
print_info " Attendu: $TOKEN_CONTENT"
print_info " Trouvé: $content"
fi
else
print_warning "⚠️ Token absent (fallback sur superblock)"
if check_ext4_superblock "/dev/mapper/$DEV_MAPPER"; then
print_ok "✅ Superblock ext4 valide"
else
print_warning "⚠️ Superblock non détecté"
fi
fi
echo ""
print_ok "✅ Conteneur monté sur $MOUNT_POINT"
echo " Device: /dev/mapper/$DEV_MAPPER"
df -h "$MOUNT_POINT"
cryptsetup status "$DEV_MAPPER" 2>/dev/null || true
}
# Menu démontage
unmount_container() {
echo "=========================================="
echo " 🔒 DÉMONTAGE"
echo "=========================================="
local mapper_name="$DEV_MAPPER"
if mount | grep -q "/dev/mapper/$mapper_name"; then
print_cmd "umount $MOUNT_POINT"
sync
umount "$MOUNT_POINT" 2>/dev/null || umount -l "$MOUNT_POINT" 2>/dev/null
print_ok "Démonté"
fi
if dmsetup ls | grep -q "$mapper_name"; then
print_cmd "cryptsetup remove $mapper_name"
cryptsetup remove "$mapper_name" 2>/dev/null || dmsetup remove "$mapper_name" 2>/dev/null
print_ok "Mapping supprimé"
fi
local loops
loops=$(losetup -a 2>/dev/null | grep "$CONTAINER_PATH" | cut -d: -f1)
if [ -n "$loops" ]; then
for loop in $loops; do
print_cmd "losetup -d $loop"
losetup -d "$loop" 2>/dev/null
done
print_ok "Loop devices nettoyés"
fi
echo "✅ Conteneur démonté"
}
# Menu principal
main() {
if [ "$EUID" -ne 0 ]; then
print_error "Root requis"
exit 1
fi
echo ""
echo "=========================================="
echo -e " ${BOLD}🔐 PBKDF2 + PLAIN${NC}"
echo "=========================================="
echo " Conteneur: $CONTAINER_PATH"
echo " Point de montage: $MOUNT_POINT"
echo " Mapping: /dev/mapper/$DEV_MAPPER"
echo " Chiffrement: $CYPHER - $KEYSIZE bits"
echo " 🔒 100% PIPE - Aucun fichier temporaire"
echo -e " ${YELLOW}🐛 Mode débogage: ACTIVÉ${NC}"
echo "=========================================="
echo " 1: Créer (formate + token)"
echo " 2: Monter"
echo " 3: Démonter"
echo -e " ${YELLOW}4: 🔬 Mode diagnostic${NC}"
echo " 5: Quitter"
echo "=========================================="
echo -n "Choix : "
read -r choix
case "$choix" in
1) create_container ;;
2) mount_container ;;
3) unmount_container ;;
4) diagnostic_mode ;;
5) echo "Au revoir !" ; exit 0 ;;
*) print_error "Choix invalide" ; exit 1 ;;
esac
}
main "$@"