Digital signature.

Besoin

Authentifier l'émetteur d'un message.

Analyse

En théorie la signature d'un message consiste à envoyer 2 informations :

  1. le message en clair
  2. le même message signé avec la clé privée de l'auteur du message.

Ensuite le destinataire :

  • décrypte le message signé à l'aide de la clé publique de l'émetteur
  • vérifie si le résultat correspond au message en clair.

En pratique, ce principe n'est pas vraiment satisfaisant car :

  • il faut signer le message dans sa totalité pour l'authentifier, ce qui peut être très consommateur en temps CPU et en débit réseau lors du transfert du message signé. Pour résoudre ce problème, on remplace le message signé par un condensé de message, toujours signé, mais plus petit, et tout aussi unique.
  • une signature garantit une provenance mais pas une identité. Pour résoudre ce problème, on utilise des certificats, où la clé publique d'un émetteur est certifiée par celle d'un autre, qui est elle-même certifiée par un autre, etc. jusqu'à parvenir à la clé publique d'un auteur dont l'identité est incontestable (une Autorité de Certification).

En pratique donc, l'envoi d'un message signé (mais non crypté) consiste à :

  1. générer un condensé du message qu'on souhaite envoyer
  2. crypter ce condensé de message avec sa clé privée
  3. envoiyer le condensé crypté + le message en clair

Pour vérifier si le message est bien celui de l'émetteur, le récepteur :

  1. décrypte le condensé avec la clé publique de l'émetteur supposé
  2. vérifie si le condensé obtenu est égal au condensé du message en clair

Un algorithme de signature est donc toujours composé d'algorithmes :

Implémentation

Dans le monde Java, le concept de signature peut être appliqué dans divers buts :

  • signer (auto-signer) un certificat : L'outil keytool de Java [1.2+] ne permet que de générer des certificats auto-signés. Parce que le rôle d'un certificat est d'authentifier, la signature d'un certificat requiert la clé privée de l'identité certifiante. Si vous n'en disposez pas déjà, vous pouvez générer votre paire de clés et un certificat par défaut (auto-signé) à l'aide de l'outil keytool. Pour générer votre paire de clés, keytool a besoin :
    • d'un alias vous identifiant (identifiant votre paire de clés dans la base de clés qu'il examine)
    • d'un mot de passe limitant l'accès à votre paire de clés (keypass).

    Par exemple :

    keytool -genkey -alias monNom -keypass monMotDePasse

    (keytool vous demandera le mot de passe d'accès à la base de clés) A la génération de votre paire de clés, keytool en profite pour vous générer un certificat auto-signé (signé par vous-même). Pour générer un certificat en général, et ce certificat en particulier, keytool a besoin de votre DN. Une fois ces informations entrées, keytool génère une paire de clés et un certificat auto-signé et l'insère dans la base de clés sous l'alias spécifié.

  • signer un objet Java : Les signatures se font à l'aide d'un objet de type java.security.Signature, récupérable via un mécanisme de fabrique permettant de spécifier la combinaison d'algorithmes utilisée :

    import java.security.*;

    Signature maSignature = Signature.getInstance ("SHA1withDSA");

    La spécification des algorithmes est obligatoire pour l'objet Signature, contrairement à keytool qui utilise SHA1withDSA par défaut. L'objet Signature ne vous permet que de signer des données avec une clé privée. La signature identifiant l'émetteur de l'objet, elle nécessite ensuite la clé privée de cet émetteur (de type java.security.PrivateKey) :

    maSignature.initSign (maClePrivee);

    La technique fournissant les données et générant la signature finale est ensuite similaire à celle du condensé de message. On fournit les données via la méthode update() :

    byte[] donnees1 = { 1, 21, 3, 4 };
    byte[] donnees2 = { 5, 2, 3, 7, 8, 12};

    maSignature.update (donnees1);
    maSignature.update (donnees2);

    et la génération de la signature se faisant via la méthode sign().

    byte[] donneesSignature = maSignature.sign();

    les données retournées constituant le condensé (SHA, MD2, MD5) signé (DSA, RSA) du message dépendant des algorithmes spécifiés à la création de l'objet signature ;

  • vérifier la signature d'un objet Java : Comme pour l'opération de signature, la vérification nécessite un objet java.security.Signature. La vérification consistant à vérifier l'identité de l'émetteur de l'objet, elle nécessite ensuite la clé publique de cette émetteur (de type java.security.PublicKey) :

    telleSignature.initVerify (telleClePublique);

    et la vérification de la signature se fait via la méthode verify().

    boolean signatureOk = maSignature.verify();

  • signer une applet : Signer une applet consiste à signer le fichier JAR contenant cette applet. On pourra par exemple signer une applet afin de lui permettre d'effectuer des opérations uniquement autorisées à une identité spécifique par la politique de sécurité en vigueur sur le ou les postes de déploiement. La signature du fichier JAR contenant l'applet s'effectue via l'outil jarsigner, qui supporte les combinaisons d'algorithmes fournies avec Java 2 (SHA1withDSA et MD5withRSA). Pour pouvoir signer, jarsigner a besoin de l'alias correspondant à votre clé privée dans la base de clés ainsi que le nom du fichier JAR (déjà existant) à signer. Par exemple : jarsigner MyApplet.jar monAlias. Cette opération de signature consiste en l'ajout de deux fichiers dans le répertoire META-INF/ cette archive :
    • un fichier de signature de type alias.sf contenant les signatures pour chaque fichier contenu dans le JAR (chaque entrée du fichier manifest).
    • un fichier bloc de signature de type alias.dsa ou alias.rsa contenant une signature pour le fichier alias.sf ainsi que le certificat (et la clé publique donc) du signataire.

Un fichier JAR peut être signé par plusieurs entités (en lançant jarsigner plusieurs fois sur ce fichier), afin de permettre différents profils d'autorisations pour la même applet ;

Cependant, d'une manière générale, Java 2 ne permet que de signer dans un but d'authentification, c'est-à-dire avec une clé privée.

La plate-forme Java [1.2+] supporte par défaut (fournisseur de sécurité Sun) les combinaisons suivantes :

Algorithme de condensé Algorithme de cryptage (clé) Description
SHA1 DSA Pour les signatures définies dans documents FIPS PUB 186
MD2 RSA pour les signatures conformes à PKCS#1
MD5 RSA pour les signatures conformes à PKCS#1
SHA1 RSA pour les signatures conformes à PKCS#1

La classe Java 2 correspondante est java.security.Signature, qui permet de générer des signatures (signer des données) et vérifier des signatures (des données signées).

Limitations

  • Ne garantit pas la confidentialité
  • En Java 1.1, l'API limitée aux signatures et condensés de messages (abscence de certificats). Ce manque a été comblé par des implémentations propriétaires (Netscape Capabilities API par exemple), puis par l'évolution de Java [1.2+].

Voir