Sécurité des données ? Elémentaire mon cher Java !

Lors de l'introduction de la gestion de la sécurité en Java, les solutions se déclinaient sous forme d'extensions aux noms plus ou moins sympathique comme JAAS, JSSE et JCE, qu'il fallait venir rajouter dans ses applications. Et encore, suivant les régions, toutes n'étaient malheureusement pas disponibles.

Heureusement ce n'est plus que de l'histoire ancienne car désormais, Java propose en standard tous les outils qu'il vous faut pour sécuriser facilement vos données. Intéressons nous en particulier à deux aspects : La génération d'empreinte de fichier et le chiffrement de ces derniers.

Génération d'empreinte

La génération d'empreinte numérique permet de garantir l'intégrité d'un fichier. Vous les rencontrez lorsque vous téléchargez par exemple des artefacts via Maven : en effet toute récupération de données, par exemple la librairie spring-core-3.0.2.RELEASE.jar, donnera lieu au téléchargement d'une empreinte spring-core-3.0.2.RELEASE.jar.sha1 qui contiendra une "simple" chaîne de caractères "3d81822d0759a190cb6e11d80c2c020a9775206b".

Cette chaine représente l'empreinte du fichier, au format SHA1. Vous pouvez donc vous assurer que le téléchargement de votre fichier s'est correctement passé, en comparant le contenu du fichier d'empreinte et en générant l'empreinte SHA1 du fichier. Oui mais comment la générer ?

La génération d'empreinte s'effectue par l'utilisation de la classe MessageDigest. Tout d'abord, vous devez choisir le type d'empreinte que vous souhaitez générer : SHA1, SHA512 ou MD5, le choix vous appartient. Dès lors, vous récupérer votre instance d'encodeur, configuré avec le type d'empreinte par la commande suivante :

// Type d'empreinte SHA1
final String checksumType = "SHA1";
// Génération de l'encodeur
final MessageDigest md = MessageDigest.getInstance(checksumType);

L'encodeur travaille sur des tableaux de bytes, ce qui facilite grandement les types de sources que vous souhaitez traiter, du nom d'une classe sous forme de tableau de bytes au flux d'envoi d'un fichier uploadé sur un serveur web. La constitution de l'empreinte s'effectue alors de la façon suivante :

// Ma source de bytes
final ByteArrayInputStream is = new ByteArrayInputStream(
	MaClasseDeTest.class.getName().getBytes());
// Mes tableaux de traitement
final byte[] dataBytes = new byte[2048];
int nread = 0;
while ((nread = is.read(dataBytes)) != -1)
{
	// Mise à jour de l'empreinte
	md.update(dataBytes,0,nread);
}

L'empreinte est désormais constituée, mais comment la récupérer et la consulter de façon simple ? La solution réside dans l'appel de la méthode "digest()" de l'encodeur qui génère l'empreinte finale de la source :

// Récupération de l'empreinte
final byte[] mdbytes = md.digest();

Il ne reste plus qu'à l'exporter sous forme de chaine de caractères, via un petit tour de passe-passe :

final StringBuffer sb = new StringBuffer();		
// Constitution de l'empreinte "lisible" 
for (int i = 0; i < mdbytes.length; i++)
{
	sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100,
		16).substring(1));
}
result = sb.toString();

Et voilà le résultat : af9bb094f2fe982814a33f81315d3b12736ee964 . Votre empreinte est prête ! Oui mais......
Une empreinte est alors facilement falsifiable vu qu'il ne s'agit que d'une chaîne de caractère : c'est là que le chiffrement de données rentre en jeu.

Chiffrement d'empreinte

Dans le cadre de systèmes où la sécurité des données est primordiale comme des transferts bancaires ou encore votre déclaration d'impôts, la preuve comme quoi les données soumises n'ont pas été altérées est cruciale. Intéressons-nous au chiffrement de l'empreinte que nous avons généré précédemment.

Tout d'abord nous devons générer notre trousseau de clef : une publique utilisée pour le chiffrement, et une privée pour déchiffrer un contenu préalablement chiffré. Nous pouvons utiliser la classe KeyPairGenerator pour notre exercice, mais bien sûr, dans le cas d'un véritable système, l'utilisation de certificats signés de sécurité, stocké par exemple dans un coffre-fort (dit keystore), est la seule solution viable car les clefs du générateur ne sont pas identiques à chaque demande de génération.

Dès lors, vous récupérez votre trousseau, configuré avec le type de sécurité choisit, par la commande suivante :

// Taille de la clef.
final int keySize = 2048;
// Type d'encodage RSA
final String encoding = "RSA";
final KeyPairGenerator kpg = KeyPairGenerator.getInstance(encoding);
kpg.initialize(keySize);
// Génération du trousseau de clef
final KeyPair keyPair = kpg.genKeyPair();

Une fois le trousseau généré, nous pouvons construire nos classes pour le chiffrement / déchiffrement.

// Encodeur.
final Cipher rsaEncCipher = Cipher.getInstance(encoding);
rsaEncCipher.init(Cipher.ENCRYPT_MODE,
	keyPair.getPublic());
// Decodeur.
final Cipher rsaDecipher = Cipher.getInstance(encoding);
rsaDecipher.init(Cipher.DECRYPT_MODE,
	keyPair.getPrivate());

Maintenant, nous pouvons coder n'importe quel contenu sous forme de tableau de bytes, comme notre empreinte et le décoder à la volée.

final String inData = "af9bb094f2fe982814a33f81315d3b12736ee964";
final byte[] resultCipher = rsaEncCipher.doFinal(inData.getBytes());
final byte[] resultDeCipher = rsaDecipher.doFinal(resultCipher);
System.out.println(inData+ "
"+ new String(resultDeCipher));

Et voila, dans notre scénario de remise de preuve de dépôt (Impôts, Banque), la version chiffrée de l'empreinte est remise au demandeur qui ne pourra en aucun cas la modifier. Seul l'organisme émetteur, possédant la clef privée, pourra déchiffrer la preuve en cas de litige.

La sécurité ? Elémentaire mon cher Java !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.