Voici les notions cryptographiques de base utilisées dans ce cours :
On va se servir de la classe KeyPairGenerator pour créer une clé RSA :
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024, new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
Les clés publiques et privées sont alors :
PublicKey pub = pair.getPublic();
PrivateKey priv = pair.getPrivate();
Pour sauver une clé (ou tout autre objet java sérialisable) on va utiliser un ObjectOutputStream dans le package java.io :
PublicKey pub = .... ;
FileOutputStream fout = new FileOutputStream("public.key");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(pub);
oos.close();
Pour la manipulation inverse où l'on créé l'objet pub
à partir du fichier public.key il suffit d'utiliser
un ObjectInputStream dans le package java.io :
FileInputStream fis = new FileInputStream("public.key");
ObjectInputStream ois = new ObjectInputStream(fis);
PublicKey pub = (PublicKey) ois.readObject();
ois.close();
Maintenant que nous avons les clés il faut créer un objet signature basé sur cette clé :
Signature rsa = Signature.getInstance("MD5withRSA");
rsa.initSign(priv);
L'initialisation à l'aide de la méthode initSign est réalisée
car on va signer le fichier. Si cela avait été pour vérifier
la signature on aurait appelé initVerify(pub)
où pub est la clé publique correspondant
à la clé privée générée.
Il faut alors faire ``passer'' tout le fichier à signer dans l'instance rsa :
FileInputStream fis = new FileInputStream(new File("nomdufichier"));
while (fis.available() != 0) {
rsa.update(fis.read());
}
fis.close();
Le résultat de la signature est alors obtenu par la commande :
byte [] sig = rsa.sign();
Java est pratique : on peut facilement télécharger du bytecode. Cependant dès lors que l'on télécharge du code que l'on ne connais pas, il est pratique de pouvoir restreindre les droits de ce dernier.
Considérons le code suivant d'une classe OpenFile qui affiche le contenu du fichier build.xml :
FileInputStream f = new FileInputStream ("build.xml");
int i=0;
byte [] b = new byte[1024];
while ((i=f.read(b))!=-1) {
System.out.println(new String(b));
}
Une fois compilé, ce code s'exécute sans problème avec par exemple
la commande : java OpenFile.
Rajoutons maintenant un fichier java.policy vide et lançons la ligne de commande :
java -Djava.security.manager -Djava.security.policy=java.policy OpenFileOn obtient alors l'erreur suivante :
java.security.AccessControlException: access denied
(java.io.FilePermission build.xml read)
Explication : le fichier java.policy vide ne donne aucun droit au code qui s'exécute. On dit que le code est contraint de jouer dans son bac à sable (ou sand box en anglais).
Le code réalisant ce test ainsi que le fichier ant correspondant sont téléchargeables à l'url :
Le code qui s'exécute peut obtenir des informations sur le SecurityManager (i.e., le bac à sable) dans lequel il s'exécute :
if (System.getSecurityManager()!=null) {
// alors il y a un security manager
java.security.AccessController.checkPermission
(new java.io.FilePermission("build.xml","write"));
}
Le code suivant génère une exception de type
java.security.AccessControlException si le code n'est pas autorisé
à écrire dans le fichier build.xml.
Si par exemple dans l'exemple précédent on veut donner seulement le droit de lire le fichier build.xml voici le contenu du fichier java.policy :
grant {
permission java.io.FilePermission "build.xml", "read";
};
Si on a vraiment confiance dans des classes situées dans un répertoire
donné on peut leur donner tous les privilèges :
grant codeBase "file:/chemin/vers/mes/classes/*" {
permission java.security.AllPermission;
};
Remarque : sous windows les chemins ne sont pas spécifiés
sous la forme file:/mon/chemin mais file:/C:/mon/chemin
pour c:\mon\chemin.
Pour plus de détails sur le fichier java.policy se reporter à l'url :
Plutôt que de stocker les clés dans des fichiers comme nous avons fait précédemment, java propose une interface manipulable en ligne de commande ou par un programme.
Cet endroit ou nous allons stocker les clés se nomme le keystore.
Il faut pour cela utiliser l'application keytool qui vient avec le JDK. L'option à rajouter sur la ligne de commande est -genkey, on peut en outre préciser le nom de clé générée (ici mykey), le type de clé (ici RSA), la taille (ici 1024) et le fichier de stockage (ici keystore) :
keytool -genkey -alias mykey -keyalg RSA -keysize 1024 -keystore keystore
Pour voir les clés qui sont stockées il suffit de taper :
keytool -list -keystore keystore
Si dans la liste on a une clé nommée mykey il suffit alors pour signer un fichier jar de taper :
jarsigner -keystore keystore monfichier.jar mykeyLes fichiers META-INF/MYKEY.SF et META-INF/MYKEY.DSA ont alors été rajoutés dans l'archive jar. Le fichier MANIFEST.MF a également été modifié, et contient en plus :
Name: ex1/ToDownload.class SHA1-Digest: Q4wliYWpbRKBTzUICVWjuo0+6fc=c'est à dire la liste des classes ainsi que leur signature par la clé mykey.
Le certificat public peut être créé à l'aide de la commande :
keytool -export -keystore keystore -alias mykey -file derepas.cer
Si l'on dispose d'une source de confiance nommée par exemple mykey, on a envie d'écrire un fichier java.policy de la forme :
grant signedBy "mykey" {
permission java.security.AllPermission;
};
dont la sémantique est la suivante :
fait entièrement confiance au code situé
dans un fichier jar qui a été signé
par la clé privée correspondant au certificat
de la clé publique dans le registre de clé
pour l'entrée nommée mykey.
Il faut charger le bon certificat. Pour cela récupérer le certificat public, puis l'importer dans le KeyStore :
keytool -import -alias mykey -file derepas.cer
Pour plus d'informations :
Javadoc est un système de documentation du code java à partir des commentaires. Vous l'utilisez quand vous lisez les pages de documentation sur l'API du JDK :
Cette section décrit la forme que doivent prendre les commentaires pour être pris en compte par javadoc
Voici un exemple de documentation d'une méthode :
/**
* La methode ajoutePomme permet de rajouter une pomme dans le rayon.
* @param t le nombre de pommes a ajouter dans le rayon.
* @return objet de type java.lang.Integer contenant le nombre
* de pommes effectivement ajoutees
*/
public Object ajoutePomme(ChangeRayon t) {
...
}
Le commentaire doit commencer par /**, les * en début
de ligne ne sont pas pris en compte.
Les arguments de la méthode sont documentés à l'aide
de la déclaration @param @return
On peut de même mettre un commentaire similaire juste avant la déclaration d'une classe. Ce commentaire sera placé en tête de la classe.
/**
* Cette classe represente un type particulier de rayon.
* @author Fabrice Derepas
*/
public class FruitsEtLegumes
extends java.rmi.server.UnicastRemoteObject
implements boutique.Rayon
{
...
}
Pour exécuter javadoc en ligne de commande, il suffit de taper, si toutes les sources sont dans le répertoire src :
javadoc -classpath src ex2Les fichiers html sont alors générés dans le répertoire courant.
On peut également créé une cible ant qui appelle javadoc :
<target name="doc">
<javadoc packagenames="ex2.*"
sourcepath="src"
defaultexcludes="yes"
destdir="docs"
author="true"
version="true"
use="true"
windowtitle="Exemple 2">
<doctitle><![CDATA[<h1>Exemple 2</h1>]]></doctitle>
<bottom><![CDATA[<i>Copyright © 2005 Fabrice Derepas.</i>]]></bottom>
</javadoc>
</target>
Ici l'appel à javadoc va mettre comme nom de document
Exemple 2, et écrira en bas de chaque
page Copyright
Téléchargez l'archive :
Exécuter la cible doc dans le fichier build.xml. On remarque qu'un répertoire docs a été créé. On peut alors visualiser le fichier index.html.Pour plus de détails se reporter à l'url :
Q1 Ecrire une classe Signataire qui génère une clé RSA de 1024 bits et signe un fichier.
Q2 Ecrire une classe Chargeur qui vérifie la signature d'un fichier étant donné la clé publique utilisée pour générer la signature. Pour comparer les signatures on utilisera la méthode Signature.verify.
Ces classes peuvent ensuite être utilisées pour effectuer des téléchargements sûrs sur internet.
Q1 Récupérer le certificat :
et l'installer dans un keystore.
Q2 Téléchargez le fichier jar
l'exécuter sans politique de sécurité. L'exécuter avec une politique de sécurité interdisant tout.
Q3 Exécuter le fichier jar précédent avec une politique de sécurité autorisant l'écriture des classes certifiées par le certificat de la première question. Pour spécifier comment utiliser le keystore de la question 1, se reporter à l'url :