Groovy et BouncyCastle

24/06/2004

L’installation de BouncyCastle permet de rajouter une implémentation tierce, Open Source, des algorithmes liés à la crypographie. La simplicité des tests avec Groovy permet de vérifier que tout fonctionne dans l’environnement Java.

Avant d’installer BouncyCastle, un petit test des fournisseurs existants (ceux par défaut)

import java.security.*
p = Security.getProviders()
count=1
p.each { println("[${count++}] ${it.getName()} -> version : ${it.getVersion()}")}

[1] SUN -> version : 1.42
[2] SunJSSE -> version : 1.42
[3] SunRsaSign -> version : 1.42
[4] SunJCE -> version : 1.42
[5] SunJGSS -> version : 1.0

Après téléchargement de la dernière version, on obtient un fichier zip qui contient un répertoire jars. Celui-ci contient les archives adaptées à chaque JVM. Il faut copier le bon (par exemple bcprov-jdk14-124.jar pour le jdk 1.4) dans le répertoire javahome/jre/lib/ext. (Une autre solution consiste à le fournir à la JVM par le biais de l’argument XBootclasspath)

Ensuite pour indiquer à la JVM de prendre en compte les nouveaux paquetages, il faut éditer le fichier jre/lib/security/java.security et ajouter la ligne suivante :

security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider

Le nombre 6 vient du fait que le dernier index, celui de SunJGSS, était 5. En exécutant de nouveau le script, on note que le fournisseur est bien disponible

[1] SUN -> version : 1.42
[2] SunJSSE -> version : 1.42
[3] SunRsaSign -> version : 1.42
[4] SunJCE -> version : 1.42
[5] SunJGSS -> version : 1.0
[6] BC -> version : 1.24

Pour permettre l’usage d’une librairie tierce concernant la sécurité, il faut télécharger sur le site de Sun deux nouveaux jar qui lèvent des contrôles de sécurité quant aux fournisseurs. Cette archive zip est disponible sur la même page de téléchargement que le JSDK lui-même et se nomme «Unlimited Strength Jurisdiction Policy Files 1.4.2» Une fois téléchargés, les fichiers local_policy.jar et US_export_policy.jar remplacent ceux situés dans le répertoire jre/lib/security.

Il faut également spécifier dans le programme Java le fournisseur, par

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())

BounceCastle possède «BC» comme nom de fournisseur, il faut donc l’utiliser lors de la récupération de l’instance du KeyGenerator

import javax.crypto.*
import java.security.*

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())
kg = KeyGenerator.getInstance("DES","BC")
kg.init(new SecureRandom())
key = kg.generateKey()
println(key)
println("format : " + key.getFormat())
println("Key algorithm: " + key.getAlgorithm())

produit le résultat suivant :

javax.crypto.spec.SecretKeySpec@fffe7ab9
format : RAW
Key algorithm: DES

Enfin, un petit test d’encodage avec l’algorithme symétrique DES

import javax.crypto.*
import java.security.*
import java.io.*
import org.apache.commons.codec.binary.Hex

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())
kg = KeyGenerator.getInstance("DES","BC")
kg.init(new SecureRandom())
key = kg.generateKey()
encrypt = Cipher.getInstance("DES/CBC/PKCS5Padding", "BC")
encrypt.init(Cipher.ENCRYPT_MODE, key)

texteclair = "abracadabrantesque"

println("format : ${key.getFormat()}, algorithme : ${key.getAlgorithm()}")

// affichage du texte en clair
println("texte en clair ${texteclair} [len=${texteclair.length()}]")
hexRepr = new String(Hex.encodeHex(texteclair.getBytes()))
println("texte en clair (hex) : ${hexRepr.toUpperCase()} [len=${hexRepr.length()}]")

// encodage
cryptext = encrypt.doFinal(texteclair.getBytes())

// affichage du texte crypté
hexRepr = new String(Hex.encodeHex(cryptext))
println("texte encrypte (hex) : ${hexRepr.toUpperCase()} [len=${hexRepr.length()}]")

produit le résultat suivant :

format : RAW, algorithme : DES
texte en clair abracadabrantesque [len=18]
texte en clair (hex) : 61627261636164616272616E746573717565 [len=36]
texte encrypte (hex) : 7CF8D889EB271236793A4C7002AF3D2BEA6816B3AF36D225 [len=48]

La librairie common.codec d’Apache est bien pratique ici pour afficher sous forme hexadécimale, un tableau d’octets. Si c’est très simple en Python :

>>> for c in texteclair:
...     print hex(ord(c)),
...
0x61 0x62 0x72 0x61 0x63 0x61 0x64 0x61 0x62 0x72 0x61 0x6e 0x74 0x65 0x73 0x71 0x75 0x65

c’est un peu pénible à faire en Java ! :( Merci Apache...