Para conocer un breve historia de la evolución de Security en Java revise el overview del tutorial de JDK 1.2
El paquete de Security en JDK 1.2 tiene muchas funcionalidades diferentes y en esta presentación solo nos referiremos a un aspectos, que es firmar digitalmente archivos y verificar esta firma. Esto será ilustrado con dos ejemplos.
Mostraremos usando la API como generar llaves, una firma digital para datos usando la llave privada, y a exportar la llave pública y la firma a archivos.
import java.io.*; import java.security.*; class GenSig { public static void main(String[] args) { /* Generamos la firma DSA */ if (args.length != 1) { System.out.println("Usage: GenSig nameOfFileToSign"); } else try { // El resto del código va aquí } catch (Exception e) { System.err.println("Caught exception " + e.toString()); } } }
Generaremos las llaves usando la clase KeyPairGenerator
Agregamos en el código anterior después de:
else try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN"); keyGen.initialize(1024, random);
KeyPair pair = keyGen.generateKeyPair(); PrivateKey priv = pair.getPrivate(); PublicKey pub = pair.getPublic();
Ahora que tenemos las llaves públicas y privadas podemos firmar la información. Una firma digital puede ser verificada o creada usando una instancia de la clase Signature.
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
dsa.initSign(priv);
FileInputStream fis = new FileInputStream(args[0]); BufferedInputStream bufin = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; int len; while (bufin.available() != 0) { len = bufin.read(buffer); dsa.update(buffer, 0, len); }; bufin.close();
byte[] realSig = dsa.sign();
/* guardamos la firma en un archivo */ FileOutputStream sigfos = new FileOutputStream("sig"); sigfos.write(realSig); sigfos.close();
/* guardamos la llave publica en un archivo */ byte[] key = pub.getEncoded(); FileOutputStream keyfos = new FileOutputStream("pk"); keyfos.write(key); keyfos.close();
El código completo del programa esta disponible, GenSig.java y se una vez compilado se ejecuta de la siguiente manera:
%java GenSig data
Este programa sólo lee el archivo data,
no lo modifica y genera un archivo sig
que contiene la firma digital acorde la llave privada pk
y a los datos.
Para poder verificar una firma digital incluida junto a algun archivo de datos necesitamos:
import java.io.*; import java.security.*; import java.security.spec.*; class VerSig { public static void main(String[] args) { /* Verificamos la firma DSA */ if (args.length != 3) { System.out.println("Usage: VerSig publickeyfile signaturefile datafile"); } else try { // El resto del código va aquí } catch (Exception e) { System.err.println("Caught exception " + e.toString()); } } }
FileInputStream keyfis = new FileInputStream(args[0]); byte[] encKey = new byte[keyfis.available()]; keyfis.read(encKey); keyfis.close();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA", "SUN");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
FileInputStream sigfis = new FileInputStream(args[1]); byte[] sigToVerify = new byte[sigfis.available()]; sigfis.read(sigToVerify); sigfis.close();
Signature sig = Signature.getInstance("SHA1withDSA", "SUN"); sig.initVerify(pubKey);
FileInputStream datafis = new FileInputStream(args[2]); BufferedInputStream bufin = new BufferedInputStream(datafis); byte[] buffer = new byte[1024]; int len; while (bufin.available() != 0) { len = bufin.read(buffer); sig.update(buffer, 0, len); };
boolean verifies = sig.verify(sigToVerify); System.out.println("signature verifies: " + verifies);
El código completo del programa esta disponible, VerSig.java y se una vez compilado se ejecuta de la siguiente manera:
%java VerSig pk sig data signature verifies: true