Files
pmomusic/pmoconfig/PASSWORD_ENCRYPTION.md

233 lines
6.8 KiB
Markdown
Raw Permalink Normal View History

2025-12-08 22:32:42 +01:00
# Chiffrement des mots de passe dans la configuration
## Vue d'ensemble
`pmoconfig` fournit un système de chiffrement transparent des mots de passe basé sur l'**UUID matériel de la machine**. Cette approche offre un bon compromis entre sécurité et simplicité d'utilisation.
## Principe de fonctionnement
### Clé de chiffrement dérivée de la machine
- La clé de chiffrement AES-256 est dérivée de l'UUID matériel de votre machine
- Sur macOS : utilise `IOPlatformUUID` (via `ioreg`)
- Sur Linux : utilise `/etc/machine-id` ou `/var/lib/dbus/machine-id`
- Sur Windows : utilise l'UUID du BIOS (via `wmic`)
### Algorithme
- **Chiffrement** : AES-256-GCM (Authenticated Encryption)
- **Dérivation de clé** : SHA-256 sur UUID machine + salt
- **Nonce** : Dérivé du mot de passe (chiffrement déterministe)
- **Format** : `encrypted:BASE64(nonce + ciphertext)`
### Avantages
**Pas de keyring** - Aucune dépendance système complexe
**Transparent** - Pas de clé maître à gérer
**Machine-specific** - Le fichier config chiffré ne fonctionne que sur cette machine
**Déchiffrement automatique** - Détection automatique du format
**Déterministe** - Même password = même ciphertext (évite les modifications inutiles du fichier)
### Inconvénients
⚠️ **Non portable** - Le fichier config ne fonctionne pas sur une autre machine
⚠️ **Sécurité limitée** - Un utilisateur avec accès physique peut déchiffrer
⚠️ **Pas de rotation** - Si l'UUID change, les mots de passe deviennent inaccessibles
## Utilisation
### 1. Chiffrer un mot de passe
```bash
cd pmoconfig
cargo run --example encrypt_password -- encrypt "MonMotDePasse123"
```
**Sortie** :
```
Original: MonMotDePasse123
Encrypted: encrypted:yRyu/jNlJRSdVz0eE+JX56UC2Tk016TmESDoLT6npLBJB3ZuhJ0XTqNOQjiXkkcB
Add this to your config.yaml:
password: "encrypted:yRyu/jNlJRSdVz0eE+JX56UC2Tk016TmESDoLT6npLBJB3ZuhJ0XTqNOQjiXkkcB"
```
### 2. Mettre à jour le fichier config.yaml
Remplacez le mot de passe en clair par la version chiffrée :
**Avant** :
```yaml
accounts:
qobuz:
username: user@example.com
password: MonMotDePasse123
```
**Après** :
```yaml
accounts:
qobuz:
username: user@example.com
password: encrypted:yRyu/jNlJRSdVz0eE+JX56UC2Tk016TmESDoLT6npLBJB3ZuhJ0XTqNOQjiXkkcB
```
### 3. Déchiffrement automatique
Le code de l'application déchiffre automatiquement les mots de passe :
```rust
use pmoconfig::get_config;
use pmoqobuz::QobuzConfigExt;
let config = get_config();
// Déchiffrement automatique si le password commence par "encrypted:"
let password = config.get_qobuz_password()?;
// password contient le mot de passe en clair
```
### 4. Tester le chiffrement
```bash
cargo run --example encrypt_password -- test
```
Cette commande teste le chiffrement/déchiffrement avec différents mots de passe.
### 5. Déchiffrer un mot de passe manuellement
```bash
cargo run --example encrypt_password -- decrypt "encrypted:ABC123..."
```
**Note** : Cela ne fonctionnera que sur la machine où le mot de passe a été chiffré.
## Format du mot de passe chiffré
```
encrypted:BASE64(nonce || ciphertext)
│ │ │ └─ Données chiffrées (longueur variable)
│ │ └─ Nonce de 12 bytes (96 bits)
│ └─ Encodage Base64
└─ Préfixe pour identifier les passwords chiffrés
```
## API de chiffrement
### Fonctions principales
```rust
use pmoconfig::encryption;
// Chiffrer un mot de passe
let encrypted = encryption::encrypt_password("secret")?;
// encrypted = "encrypted:ABC123..."
// Déchiffrer un mot de passe
let password = encryption::decrypt_password(&encrypted)?;
// password = "secret"
// Déchiffrement automatique (gère plaintext et encrypted)
let password = encryption::get_password("encrypted:ABC123...")?;
let password = encryption::get_password("plaintext")?; // Retourne tel quel
// Vérifier si un mot de passe est chiffré
if encryption::is_encrypted(&value) {
// C'est un mot de passe chiffré
}
```
## Migration progressive
Le système supporte à la fois les mots de passe en clair et chiffrés. Vous pouvez migrer progressivement :
1. **Phase 1** : Le système fonctionne avec des mots de passe en clair
2. **Phase 2** : Chiffrez les mots de passe avec l'outil
3. **Phase 3** : Mettez à jour config.yaml avec les versions chiffrées
4. **Phase 4** : L'application déchiffre automatiquement
Le code fonctionne avec les deux formats, vous n'avez donc pas besoin de tout migrer en même temps.
## Sécurité
### Protection offerte
- ✅ Protection contre la lecture directe du fichier config.yaml
- ✅ Protection si le fichier config est accidentellement partagé/commité
- ✅ Protection contre l'inspection casual du système de fichiers
### Limitations
-**Pas de protection contre un utilisateur root** - root peut lire l'UUID et déchiffrer
-**Pas de protection physique** - Quelqu'un avec accès physique peut extraire l'UUID
-**Pas de protection contre les malwares** - Un malware peut lire l'UUID et déchiffrer
### Recommandations
Pour une sécurité maximale, utilisez plutôt :
- **macOS** : Keychain (`security add-generic-password`)
- **Linux** : Secret Service API (GNOME Keyring, KWallet)
- **Windows** : Credential Manager
Cette implémentation est un **compromis pragmatique** pour :
- Éviter les dépendances lourdes (keyring, etc.)
- Fonctionner sur tous les OS
- Être simple et transparent
- Offrir une protection de base
## Dépannage
### "Decryption failed (wrong machine or corrupted data)"
Ce message apparaît si :
- Le mot de passe a été chiffré sur une autre machine
- L'UUID de la machine a changé (réinstallation OS, nouvelle carte mère)
- Les données sont corrompues
**Solution** : Rechiffrez le mot de passe sur cette machine.
### "Invalid encrypted password format"
Le mot de passe ne commence pas par `encrypted:` ou le format Base64 est invalide.
**Solution** : Vérifiez le format du mot de passe dans config.yaml.
### "Failed to extract IOPlatformUUID" (macOS)
Impossible de lire l'UUID de la machine.
**Solution** : Vérifiez que vous avez les droits d'exécuter `ioreg`.
## Exemple complet
```rust
// Dans pmoqobuz/src/config_ext.rs
impl QobuzConfigExt for Config {
fn get_qobuz_password(&self) -> Result<String> {
match self.get_value(&["accounts", "qobuz", "password"])? {
Value::String(s) => {
// Déchiffrement automatique si le mot de passe est chiffré
pmoconfig::encryption::get_password(&s)
.map_err(|e| anyhow!("Failed to decrypt password: {}", e))
}
_ => Err(anyhow!("Qobuz password not configured")),
}
}
}
```
## Tests
```bash
# Tester le module de chiffrement
cargo test -p pmoconfig encryption
# Tester l'outil CLI
cargo run --example encrypt_password -- test
# Tester avec un vrai service (Qobuz)
cargo run --example basic_usage
```