Come cifrare un oggetto java tramite JCA

Ultimo aggiornamento: 28-10-2013

In Java per il salvataggio di oggetti cifrati si può utilizzare la JCA: Java Cryptography Architecture, presente di default nell’ambiente Java.

Il JCA è stato progettato su “engine” criptografici e definendo delle classi che forniscono le funzionalità a questi engine.
Per i nostri scopi useremo l’engine Cipher insieme agli oggetti Sealed, utilizzati proprio per memorizzare oggetti cifrati.
Il cifrario usato è un AES con mode:CBC e padding:PKCS5Padding.

La chiave viene generata con PBKDF2WithHmacSHA1 a partire da una password data. PBKDF2 è una funzione di derivazione di password a partire da una data password e da altri parametri: come il sale ed il numero d’iterazioni. La versione usata utilizza HMAC con SHA1 per generare la password, dove al posto del messaggio viene passato il sale.

Per salvare un oggetto cifrato, basta creare un oggetto qualsiasi ed inserirlo in un oggetto di tipo Sealed.

La classe SealedObject

SealedObject(Serializable object, Cipher c)
Constructs a SealedObject from any Serializable object.

permette di proteggere un oggetto Serializable con un algoritmo di cifratura, usando un’istanza di Cipher, ovviamente l’oggetto cifrato può essere decifrato e de-serializzato portandolo allo stato originario.

JAC supporta due rappresentazioni per le chiavi:

  • Rappresentazione opaca delle chiavi: nelle quali non si ha accesso diretto ai parametri che costituiscono la chiave: si ha accesso solo alla chiave tramite l’interfaccia Key.
  • Rappresentazione trasparente delle chiavi: in cui si può accedere ad ogni parametro che serve a generare la chiave tramite l’interfaccia KeySpec ed i suoi metodi. Utile per la trasmissione ed il salvataggio delle chiavi.

Per convertire le chiavi dalla rappresentazione opaca a quella trasparente e viceversa, ci sono le classi KeyFactory e SecretKeyFactory, io ho usato la specializzazione SecretKeyFactory poiché lavora sulle chiavi SecretKey (sarebbe a dire le chiavi simmetriche) che è proprio quella usata da AES.
Come già spiegato in precedenza viene passata una chiave generata tramite PBKDF2.

Dopo aver spiegato un pò come funziona la cifratura in JAVA, ecco come ho effettuato la cifratura con AES ed il salvataggio dell’oggetto,

  1. Instanzio un PBEKeySpec (rappresentazione trasparente) che contiene le informazioni per generare la chiave con PBKDF2: password originale, sale, numero d’iterazioni e la lunghezza della password da generare.
  2. Passo l’instanza a SecretKeyFactory alla quale faccio generare la SecretKey (rappresentazione opaca) tramite il metodo generateSecret.
  3. Creo una SecretKeySpec, e gli passo la SecretKey sotto forma di byte e l’algoritmo su cui usarlo: AES.
  4. Prendo un’ istanza di AES dall’engine di Cipher, e gli passo la KeySpec e l’initVector (IV)
  5. Creo un oggetto SealedObject a cui passo l’oggetto da cifrare e il cifrario da utilizzare.

Implementazione

Cipher cipher = null;
try {
cipher = Cipher.getInstance(“AES/CBC/PKCS5Padding”);
} catch (NoSuchAlgorithmException e1) {
System.out.println(“Error: ” + e1.getMessage());
return false;
} catch (NoSuchPaddingException e1) {
System.out.println(“Error: ” + e1.getMessage());
return false;
}

SecretKeyFactory secKeyFactory = null;
try {
secKeyFactory = SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA1”);
} catch (NoSuchAlgorithmException e1) {
System.out.println(“Error: ” + e1.getMessage());
return false;
}

KeySpec keySpec = new PBEKeySpec(password.toCharArray(), SALT, 10, 128);
SecretKey key = null;
try {
key = secKeyFactory.generateSecret(keySpec);
} catch (InvalidKeySpecException e) {
System.out.println(“Error: ” + e.getMessage());
return false;
}

SecretKey AESKey = new SecretKeySpec(key.getEncoded(), “AES”);
try {
cipher.init(Cipher.ENCRYPT_MODE, AESKey, new IvParameterSpec(mInitVec));
} catch (InvalidAlgorithmParameterException e) {
System.out.println(“Error: ” + e.getMessage());
return false;
} catch (InvalidKeyException e) {
System.out.println(“Error: ” + e.getMessage());
return false;
}

 

SealedObject objEncr = null;
try {
objEncr = new SealedObject(signature, cipher);
} catch (IllegalBlockSizeException e) {
System.out.println(“Error: ” + e.getMessage());
return false;
} catch (IOException e) {
System.out.println(“Error: ” + e.getMessage());
return false;
}

//save the file
ObjectOutputStream  oos = null;
try {

oos = new ObjectOutputStream(new FileOutputStream(“file.obj”));
oos.writeObject(objEncr);
oos.flush();
} catch (FileNotFoundException e) {
System.out.println(“Error: ” + e.getMessage());
} catch (IOException e) {
System.out.println(“Error: ” + e.getMessage());
} finally {
try {
if(oos !=  null)
oos.close();
else
return false;
} catch (IOException e) {}
}