Cryptographie pratique

2014-09-26

Ce document est à l'origine un article expliquant comment créer un certificat X.509 avec OpenSSL publié le 26 septembre 2012.

Les logiciels utilisés sont OpenSSL et GPG, installés par défaut sur les systèmes GNU/Linux et utilisables depuis la ligne de commande. Pour l'utilisation de GPG dans Thunderbird (chiffrement de courriers électroniques), consultez l'article du Hollandais Volant. Enigmail repose sur GPG et les mêmes clés peuvent donc être utilisées pour les deux programmes.

Généralités

La cryptographie consiste à rendre des informations (document ou flux) lisibles uniquement par le destinataire choisi. Par exemple, il est possible de chiffrer des courriers électroniques ou une conversation téléphonique. Un autre exemple d'utilisation est le chiffrement de fichiers sur un disque local ; dans ce cas, le destinataire est généralement soi-même.

La cryptographie a deux aspects : le chiffrement à proprement parler, qui restreint la lisibilité des informations, et l'authentification, qui permet de s'assurer que l'on va chiffrer pour la bonne personne. L'authentification est généralement faite à l'aide de « certificats », un concept qui repose sur la cryptographie asymétrique.

L'authentification est un aspect aussi important que le chiffrement : si l'émetteur chiffre les donnés pour l'adversaire plutôt que le destinataire, le message sera trivialement compromis.

Chiffrement

Le chiffrement peut être symétrique ou asymétrique.

Symétrique

Dans le cas symétrique, vous devez initialement partager un « secret » (un mot de passe) avec votre destinataire afin qu'il puisse déchiffrer les données ; en général, cela permet en même temps de repousser le problème de l'authentification à celui de l'échange du secret. Le chiffrement est dit « symétrique » car le même secret se trouve de part et d'autre.

Pour chiffrer (-e pour encrypt) un fichier file en file.enc :

$ openssl aes-256-cbc -e -in file -out file.enc
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:

Pour déchiffrer (-d pour decrypt) ce fichier :

$ openssl aes-256-cbc -d -in file.enc -out file
enter aes-256-cbc decryption password:

OpenSSL demande d'entrer le secret pour chiffrer ou pour déchiffrer. Rien ne s'affiche lors de cette saisie (comme pour la plupart des entrées de mots de passe en ligne de commande), afin de ne pas révéler d'informations sur le secret (comme sa longueur). Il est demandé deux fois lors du chiffrement, uniquement pour s'assurer que vous ne faite pas de faute de frappe en l'écrivant (ce qui rendrait le fichier chiffré inutilisable).

L'option aes-256-cbc indique à OpenSSL quel algorithme de chiffrement (ou « chiffre ») utiliser. Afin de savoir quels autres algorithmes sont disponibles, utilisez la commande :

openssl list-cipher-commands

ou (pas une vraie commande, mais le message d'erreur est utile) :

openssl help

Tous les chiffres ne sont pas aussi sûrs et il vaut mieux s'en tenir à AES en mode CBC (qui est déjà extrêmement rapide). Pour tester la rapidité d'un chiffre :

$ openssl speed aes-128-cbc
...
aes-128 cbc ... 139796.48k

Dans ce cas, cela signifie que aes-128-cbc peut chiffrer ou déchiffrer 140Mo d'information par seconde (139796.48ko/s). Le résultat varie selon l'ordinateur sur lequel est exécuté le test.

Asymétrique

Le chiffrement asymétrique utilise deux clés. La « clé publique » peut-être partagée sans risque de manière à ce que n'importe qui puisse chiffrer un message ; la « clé privée » est à tenir secrète car elle sert à déchiffrer les messages protégés par la clé publique. Dans ce type de situation, c'est le destinataire qui crée les clés publique et privée et transmet la clé publique à l'émetteur. Le problème d'authentification est alors pour l'émetteur de trouver la bonne clé publique pour un destinataire (un adversaire pourrait se faire passer pour le destinataire et donner sa propre clé publique).

Le chiffre asymétrique le plus courant est RSA. OpenSSL propose également des commandes pour DSA et pour Diffie-Hellman (dh).

Pour générer une paire de clés publique/privée puis mettre la clé publique dans un fichier séparé (rsa.priv contient la clé privée et la clé publique) :

$ openssl genrsa -out rsa.priv
$ openssl rsa -in rsa.priv -pubout -out rsa.pub

Pour chiffrer un message avec la clé publique :

$ openssl pkeyutl -encrypt -pubin -inkey rsa.pub -in file -out file.enc

Pour déchiffrer ce message avec la clé privée :

$ openssl pkeyutl -decrypt -inkey rsa.priv -in file.enc -out file

Signature

Une propriété intéressante du chiffrement asymétrique est la possibilité de signer cryptographiquement un document. L'émetteur chiffre une information publique avec sa clé privée ; de cette manière n'importe qui peut déchiffrer le message avec la clé publique. Puisqu'un message que l'on peut déchiffrer avec la clé publique doit avoir été chiffré avec la clé privée, on sait que c'est bien l'émetteur qui a chiffré le message.

Pour signer file avec la clé privée rsa.priv (file.sig contient la signature) :

$ openssl pkeyutl -sign -inkey rsa.priv -in file -out file.sig

Pour vérifier la signature :

$ openssl pkeyutl -verify -pubin -inkey rsa.pub -in file -sigfile file.sig
Signature Verified Successfully

Certificats

Autorité de certification

Une autorité de certification (CA) est un organisme qui se charge de vérifier l'identité d'un porteur de certificat. Par exemple, si je veux créer un certificat pour example.com, une CA peut envoyer un courrier électronique à webmaster@example.com pour confirmer qu'il s'agit bien de mon domaine.

Par défaut, les navigateurs connaissent de nombreuses CA auxquelles ils font confiance. Pour vérifier que l'utilisateur se connecte au bon site, le navigateur vérifie que le certificat fourni par le site est bien signé par une des CA.

Serveur

Il vous faudra une clé de chiffrement asymétrique :

$ openssl genrsa -out server.key

Créer un certificat se fait avec la commande suivante :

$ openssl req -new -x509 -key server.key -subj "/CN=example.com" -out server.crt

Si vous voulez faire signer votre certificat par une autorité de certification (CA), afin qu'il soit accepté automatiquement par les navigateurs web, il faut préparer une requête server.csr (CSR pour Certificate Signing Request) à lui transmettre.

$ openssl req -new -key server.key -subj "/CN=example.com" -out server.csr

C'est la même requête que pour un certificat, l'argument -x509 en moins. La CA devrait vous renvoyer un fichier server.crt signé avec sa propre clé privée.

Client

Similairement, le client crée une requête de certificat client.csr :

$ openssl genrsa -out client.key
$ openssl req -new -key client.key -out client.csr -subj "/CN=user@example.com" 

Cette fois, le serveur joue le rôle de la CA :

$ openssl x509 -req -CA server.crt -CAkey server.key -in client.csr -out client.crt

Optionnellement, le client peut ensuite regrouper sa clé privée et le certificat dans un fichier PKCS #12 (reconnu par Firefox) :

$ openssl pkcs12 -export -in client.pem -inkey client.key -out client.p12

GPG

Créer une identité

La génération d'une paire de clés publique/privée GPG, ou « identité » est simple mais demande prend plusieurs minutes (le programme prend du temps pour créer une clé privée la plus aléatoire possible).

$ gpg --gen-key
...
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 
...
What keysize do you want? (2048) 
...
Key is valid for? (0) 
...
Is this correct? (y/N) y
...
Real name: Anonymous
Email address: user@example.com
Comment: 
...
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
...
Enter passphrase:
Repeat passphrase:
...
pub   2048R/E1266ECD 2014-09-26
      Key fingerprint = 1546 F30B A1E0 22C1 89BF  5033 0C8C DB51 E126 6ECD
uid                  Anonymous <user@example.com>
sub   2048R/323F77C4 2014-09-26

Une fois l'identité créée, GPG devrait la lister parmi les clés publiques connues :

$ gpg -k
~/.gnupg/pubring.gpg
-----------------------------
pub   2048R/E1266ECD 2014-09-26
uid                  Anonymous <user@example.com>
sub   2048R/323F77C4 2014-09-26

ainsi que parmi les clés privées connues :

$ gpg -K
~/.gnupg/secring.gpg
-----------------------------
sec   2048R/E1266ECD 2014-09-26
uid                  Anonymous <user@example.com>
ssb   2048R/323F77C4 2014-09-26

Chiffrement

Chiffrer un fichier avec GPG est très simple. L'argument --armor est optionnel mais permet de rendre le fichier chiffré plus facile à transférer ; l'argument -r indique le destinataire (recipient).

$ gpg -r user@example.com --armor --encrypt file 

Pour déchiffrer, GPG demandera le mot de passe de la clé privée.

$ gpg --decrypt file.asc

Signature

Signer nécessite de renseigner le mot de passe de la clé privée :

$ gpg --armor --sign file

Il est possible de déchiffrer le message avec la clé publique (pas de demande de mot de passe). La signature est alors vérifiée :

$ gpg --decrypt file.asc