Réfléchissant à la mise en œuvre de mon testament numérique, je me suis résolu à envisager le partage de quelques secrets (mots de passe verrouillant l’accès à mes clés GnuPG et SSH, à mes bases KeePassXC et autres ressources chiffrées) avec mes proches. Mais voilà, je suis plus vigilant que la moyenne – d’aucuns diront paranoïaque – en matière de sécurité informatique et je sais que ce n’est pas le cas de mon entourage. Si plusieurs de mes proches ont récemment compris l’urgence d’adopter KeePassXC en lieu et place de post-it, ils conservent beaucoup de mauvaises pratiques. L’idée de partager avec eux mes secrets a généré une réelle anxiété chez moi. Le partage passant en outre par l’écrit, il ne faut pas négliger le risque de divulgation des secrets au détour d’un cambriolage ou d’un piratage informatique. Bref, la question qui se posait à moi était de savoir comment sécuriser un partage d’information avec des personnes en lesquelles j’ai confiance, sans pour autant avoir confiance en leurs pratiques et sans vouloir faire reposer sur les épaules d’une seule la préservation du secret.

Dans les romans et les films, la parade à ce problème de « confiance relative » est simple : la carte au trésor est découpée en plusieurs parties, détenues par autant de personnes différentes. Elles doivent se réunir pour reconstituer la carte complète et trouver le trésor. Mais les écrivains et scénaristes exploitent volontiers la faiblesse inhérente à ce partage : absolument tous les fragments doivent être réunis pour reconstituer la carte. S’il en manque un seul, les autres restent inexploitables (s’en suit une quête dont la difficulté augmente au fur et à mesure que le nombre de fragments restant à trouver s’amenuise). Dans la vraie vie, on préfère s’épargner une contrainte aussi forte et se prémunir de la perte d’un fragment ou de l’indisponibilité prolongée d’une personne. Pour cela, il faut envisager une certaine redondance (i.e. un recouvrement partiel des parties de la carte), tout en s’assurant qu’un nombre minimal de fragments soit nécessaire à la reconstitution de l’information (i.e. de la carte intégrale). Voici une illustration de cette redondance.

Supposons que je souhaite partager le secret suivant :

MONSUPERMOTDEPASSE

Je le découpe en trois morceaux, confiés à trois personnes différentes, A, B et C. Cela donne :

  • (A) : MONSUP / ______ / ______
  • (B) : ______ / ERMOTD / ______
  • (C) : ______ / ______ / EPASSE

Les personnes A, B et C sont bel et bien obligées de réunir leurs fragments pour reconstituer le secret. Mais si l’une d’entre elles manque à l’appel, tout espoir de reconstituer le secret tombe à l’eau.

On peut modérer ce risque en introduisant de la redondance. Par exemple, on peut confier deux fragments à chaque personne, de manière à ce que chaque fragment soit détenu par deux personnes et deux seulement :

  • (A) : MONSUP / ERMOTD / ______
  • (B) : MONSUP / ______ / EPASSE
  • (C) : ______ / ERMOTD / EPASSE

Il saute aux yeux qu’ainsi, il suffit à deux personnes (A et B, A et C, B et C) de mettre en commun leurs fragments pour reconstituer le secret. Mais aucune d’entre elles ne dispose de l’intégralité du secret.

Partage de clé secrète de Shamir

L’illustration qui précède est bien sûr simpliste et on peut lui faire plusieurs reproches. Heureusement, en 1979, le brillant cryptologue Adi Shamir nous a offert une solution mathématique élégante, aujourd’hui connue sous le nom de partage de clé secrète de Shamir (Shamir Secret Sharing ou SSS en anglais). Elle permet de fragmenter une information en N parties, de manière à ce que K parties, et K seulement, soient nécessaires pour reconstituer l’information. K est appelé le seuil (threshold). J’ai vu cette technique mise en œuvre pour la première fois en 2002, pour sécuriser un composant critique du système d’information d’un grand industriel. J’ai trouvé le concept génial ! Je ne pensais pas que j’en aurais moi-même besoin un jour.

Si vous administrez une instance de HashiCorp Vault, ce découpage doit vous rappeler quelque chose. Au lancement, Vault est scellé, il n’accepte ni consultation, ni modification des informations qu’il détient. Pour le desceller, vous devez lui fournir 3 des 5 chaines qu’il vous a communiquées à l’installation et qu’il vous a invité à distribuer à autant de personnes de confiance (donc, ici, N = 5 et K = 3).

Le but de cet article n’est pas de vous expliquer les fondements mathématiques de la technique SSS – je n’ai pas les compétences requises – mais de vous présenter comment j’ai procédé et transmis l’information.

Parmi les outils qui implantent la technique SSS sur GNU/Linux, j’ai opté pour ssss (oui, 4 « s », qui dit mieux ?). Cet outil sans fioritures suffit à mon besoin. Il fournit deux commandes. La première, ssss-split, découpe le secret selon les règles spécifiées sur la ligne de commande. La seconde, ssss-combine, reconstitue le secret à partir du nombre minimal de fragments requis.

Voici un exemple de découpage de mot de passe en 3 fragments, pour lequel 2 d’entre eux seulement sont nécessaires à la reconstitution :

$ echo '5uper 9enial m0n Mot 2 Passe est' | \
      ssss-split -q -t 2 -n 3 -w cible > /tmp/fragments.txt
$ cat /tmp/fragments.txt
cible-1-c5790377dcced729cef35106f15f1456c0cffbeb78a353fa4d033ab028cdfccc
cible-2-723115ef70a2434529d805923a0e32869152f193014bf12e414b6c1dc1b8bfd6
cible-3-1f0918671486309e8b3ec9e1833ed0c95e260844d613909dba8ca186996b8122

Le préfixe cible a pour seul objet de discriminer les fragments issus de différents découpages. En choisissant un préfixe parlant, on sait à quel secret se réfère le fragment et on sait lesquels assembler pour reconstituer un secret donné, même si on vient à les mélanger. Par exemple :

$ echo "4%Baluche-31_KioPlache" | \
      ssss-split -q -t 2 -n 3 -w gnupg > /tmp/fragments.txt
$ echo "ArcaBufla.314/Pouchard" | \
      ssss-split -q -t 2 -n 3 -w keepassxc >> /tmp/fragments.txt
$ cat /tmp/fragments.txt
gnupg-1-f4b0708067848c529730af1ee865e07f1d5b834f2c88
gnupg-2-11d66f8763976700b50947c5774c7bc11b05033e0168
gnupg-3-b2f4657a60663e3154e1e073fdab0d54e6cf7ceee231
keepassxc-1-ed5100988ead31d1f209fec177ee3a6dc3de757c2cc2
keepassxc-2-9150a19b52efa354248774b106ee6bd38a2b1b9cd926
keepassxc-3-45503e9a192e2d2896fd0d6129ee5b464d783e3c8d83

Et voici comment reconstituer le premier secret :

$ ssss-combine -q -t 2 <<EOF
gnupg-1-f4b0708067848c529730af1ee865e07f1d5b834f2c88
gnupg-2-11d66f8763976700b50947c5774c7bc11b05033e0168
EOF
4%Baluche-31_KioPlache

Comme prévu, on constate que deux fragments seulement ont été nécessaires à la commande ssss-combine pour reconstituer le mot de passe.

Fourniture sous forme de QR-Code

Je compte communiquer ces fragments sous forme imprimée aux personnes de confiance, autrement dit, en évitant d’utiliser un moyen de communication électronique, vu que ces personnes ne connaissent l’existence ni de GnuPG, ni d’Enigmail, ni de Signal. Le problème est que ces séquences seront malaisées à saisir le jour où ces personnes devront les exploiter ou les transmettre. Je peux leur faciliter grandement la tâche en les fournissant aussi sous forme de QR-Code. Plusieurs générateurs de QR-Code sont disponibles sur GNU/Linux ; j’ai choisi qrencode :

$ qrencode -l H -o gnupg-1.png gnupg-1-f4b0708067848c529730af1ee865e07f1d5b834f2c88

Voici le résultat :

QR-Code

La commande zbarimg fournie par le projet libre de lecture de QR-Code zbar, nous permet de vérifier que nous arrivons bien à décoder le QR-Code :

$ zbarimg -q --raw gnupg-1.png
gnupg-1-f4b0708067848c529730af1ee865e07f1d5b834f2c88

Préparation des données

Il serait stupide de prendre autant de précautions et de laisser ces informations sensibles en clair ou presque, à la portée de tous. De ce fait, même si mon disque dur est chiffré, j’ai ajouté une précaution en travaillant dans un conteneur lui-même chiffré via LUKS. Ce conteneur peut être créé et manipulé via les commandes cryptsetup ou cryptmount. Voici par exemple comment procéder avec cryptmount :

En tant que simple utilisateur, on crée un fichier binaire au contenu bruité par le hasard :

$ dd if=/dev/urandom \
     of=/home/user/secrets/img/tst.img \
     bs=128M count=1 iflag=fullblock

En tant que root, on édite le fichier /etc/cryptmount/cmtab, dont le contenu doit être :

tst {
    keyformat=luks
    dev=/home/user/secrets/img/tst.img  keyfile=/home/user/secrets/img/tst.img
    dir=/home/user/secrets/mnt/tst      fstype=ext3
}

Puis, toujours en utilisant les privilèges root, on termine l’initialisation du conteneur :

$ sudo cryptmount --generate-key 32 tst
$ sudo cryptmount --prepare tst
$ sudo mkfs.ext3 /dev/mapper/tst
$ sudo cryptmount --release tst

Le compte non privilégié peut alors monter ce volume chiffré :

$ cryptmount tst
Donnez mot de passe pour la cible "tst":
e2fsck 1.46.4 (18-Aug-2021)
/dev/mapper/tst : propre, 43/32256 fichiers, 14239/129024 blocs

Mais l’utilisateur n’a pas le droit d’écrire à la racine de cette partition. Il faut la lui attribuer (ou lui créer un répertoire dédié) :

$ sudo chown user:user /home/user/secrets/mnt/tst

Le compte non privilégié peut alors travailler dans ce répertoire, y créer des fichiers, puis, lorsqu’il a terminé, démonter ce volume :

$ cryptmount -u tst

Même stockés en clair, les secrets sont alors bien à l’abri.