Finalmente sembra che qualche cliente inizi a capire l’utilita’ di cifrare contenuti piu’ o meno sensibili nei processi di scambio dati.
Ad oggi sinceramente non sono ancora molti e questo forse e’ dovuto alla difficolta’ iniziale nel capirne il funzionamento o forse per la poca competenza tecnica ma ogni volta che riesco a piazzarne uno mi sento meglio e sollevato :)
Livello:
Medio
Per chi:
Chiunque abbia la necessita’ di cifrare contenuti privati
Scenario:
Decifrare file crittati con GPG tramite Java
Non sto ad elencare il processo di installazione e funzioni di GnuPG(implementazione completa e gratuita di OpenPGP) visto che e’ tutto facilmente reperibile dal sito ufficiale ma cerchero’ brevemente(come al solito) di fornire una base per implementare un piccolo wrapper java utilizzabile all’interno dei propri sistemi con due funzioni semplici semplici, le piu’ utilizzate, crypt e decrypt, non prima pero’ di aver creato la coppia di chiavi privata/pubblica proprietaria e importato almeno una chiave pubblica di “qualcuno”.
Generazione della coppia pri/pub
La generazione della propria chiave e’ un processo veloce e semplice:
$ gpg --gen-key --no-secmem-warning
Dopo aver eseguito questo comando vi verranno chieste alcune informazioni, in ordine:
- che tipo di cifratura si vuole utilizzare
- la dimensione in della chiave
- la scadenza
- nome, email ed evenuale commento
- password
al termine avrete a disposizione la coppia di chiavi e sarete pronti per la cifratura.
Per vedere l’elenco delle chiavi in vostro possesso basta un semplice:
$ gpg --list-keys --no-secmem-warning ---------------------------- pub 1024D/DEBF8E3B 2008-02-02 uid Cristian <crx@example.com> sub 2048g/E3F5B59E 2008-02-02
La prima della serie e’ quella che ho appena creato e sara’ quela che utilizzero’ per cifrare e decifrare contenuti.
Esportazione della propria chiave pubblica
Questo processo si rende utile per fornire la propria chiave pubblica alle persone che dovranno cifrare i contenuti per voi
$ gpg --export --armor DEBF8E3B > miachiavepub.asc
Dove –armor indica di esportare la chiave in formato ASCII e specificare l’ID permette di selezionare, nel caso se ne possedesse piu’ di una, quale esportare.
In questo momento la mia chiave pubblica e’ contenuta nel file miachiavepub.asc e possiamo renderla disponibile alla persona che dovra’ utilizzarla.
Importazione della chiave pubblica di una persona
Per poter decifrare un contenuto crittato da una persona in possesso della nostra chiave pubblica e’ necessario disporre della sua chiave pubblica, una volta ottenuta importiamola
$ gpg --import chiavedaimportare.asc
e verifichiamo che sia presente nell’elenco
$ gpg --list-keys --no-secmem-warning ---------------------------- pub 1024D/DEBF8E3B 2008-02-02 uid Cristian <crx@example.com> sub 2048g/E3F5B59E 2008-02-02 pub 1024D/C034FE3F 2008-02-02 uid Tizio <tizio@example.com> sub 2048g/C034FE3F 2008-02-02
Processo di cifratura/decifratura
Velocemente vediamo come cifrare un contenuto per “Tizio”
$ gpg --encrypt -r C034FE3F filedacifrare.txt
avremo ottenuto un file filedacifrare.txt.gpg da inviare a “Tizio”, solo e unicamente lui potra’ decifrarlo utilizzando la sua chiave
Mentre se “Tizio” cifra un contenuto per noi il comando da eseguire per poterlo leggere e’:
gpg --decrypt --local-user DEBF8E3B fileditizio.txt.gpg > fileditizio.txt
Dopo la richiesta della password assegnata alla nostra chiave nel file fileditizio.txt avremo il contenuto decifrato, notare il parametro –local-user che serve ad indicare quale delle nostre chiavi(nel caso ne avessimo piu’ di una) utilizzare per decifrare il contenuto.
Il wrapper Java
Questo e’ molto semplice visto che si andranno ad utilizzare direttamente i comandi macchina con
Per il metodo decrypt viene utilizzato il parametro –passphrase-file che serve per andare a leggere la password in un file di testo cosi da evitare di dover creare la classe in modo da interagire con l’output gpg, in questo caso e’ consigliabile inserire la pass in un file accessibile in sola lettura/scrittura dall’utente che ne deve fare uso
$ chmod 600 /home/crx/.gnupg/passfile
import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class GPG { private String gpgBinary; private String gpgUser; private String gpgPass; /** * * @param gpgBinary path al binario gpg * @param gpgUser id utente gpg per cifrare e decifrare(il nostro) * @param gpgPass path al file contenete la pass */ public GPG(String gpgBinary, String gpgUser, String gpgPass) { super(); this.gpgBinary = gpgBinary; this.gpgUser = gpgUser; this.gpgPass = gpgPass; } /** * * @param id idutente per il quale si intende eseguire la cifratura * @param inputFile file da cifrare * @param outputFile file risultato dalla cifratura */ public void encrypt(String id, String inputFile, String outputFile) throws Exception { // comando base per la cifratura gpg String command = "%s --local-user %s -r %s " + "--no-secmem-warning --armor --batch " + "-o %s --encrypt %s"; Process exec = null; try { // esecuzione del comando con relativi parametri exec = Runtime.getRuntime().exec( String.format( command, this.gpgBinary, this.gpgUser, id, outputFile, inputFile)); } catch (IOException e) { e.printStackTrace(); } // intercetto STDERR OutputReader stderr = new OutputReader(exec.getErrorStream()); // inizio la lettura dello STDERR stderr.start(); try { // attendo che il processo gpg finisca exec.waitFor(); // attendo che la lettura dello STDERR finisca stderr.join(); } catch (InterruptedException e) { e.printStackTrace(); } // se il comando non termina correttamente if(exec.exitValue() != 0) { throw new Exception("Cifratura fallita: " + stderr.getOutput()); } } /** * * @param inputFile file da decifrare * @param outputFile file risultato dalla decifratura */ public void decrypt(String inputFile, String outputFile) throws Exception { // comando base per la decifratura gpg String command = "%s --no-secmem-warning " + "--local-user %s " + "--passphrase-file %s " + "--batch --yes " + "-o %s --decrypt %s "; Process exec = null; try { // esecuzione del comando con relativi parametri exec = Runtime.getRuntime().exec( String.format( command, this.gpgBinary, this.gpgUser, this.gpgPass, outputFile, inputFile)); } catch (IOException e) { e.printStackTrace(); } // intercetto STDERR OutputReader stderr = new OutputReader(exec.getErrorStream()); // inizio la lettura dello STDERR stderr.start(); try { // attendo che il processo gpg finisca exec.waitFor(); // attendo che la lettura dello STDERR finisca stderr.join(); } catch (InterruptedException e) { e.printStackTrace(); } // se il comando non termina correttamente if(exec.exitValue() != 0) { throw new Exception("Decifratura fallita: " + stderr.getOutput()); } } } /** * Con questo oggetto andiamo a leggere l'output dell'applicazione gpg * */ class OutputReader extends Thread { StringBuffer buffer = new StringBuffer(); InputStreamReader inputStream; OutputReader(InputStream in) { this.inputStream = new InputStreamReader(in); } public void run() { try { int read; char[] c = new char[1024]; while ((read = inputStream.read(c, 0, c.length)) != -1) { buffer.append(c, 0, read); } } catch (IOException e) { e.printStackTrace(); } } String getOutput() { return buffer.toString(); } }
Ora facciamo una classe Tester.java per verificarne il funzionamento, per comodita eseguo crypt e decript per il mio utente DEBF8E3B, in sostanza sto cifrando e decifrando un file per me stesso.
public class Tester { public static void main(String[] args) { // init dell'oggetto al quale // pass i parametri principali GPG gpg = new GPG( "/usr/bin/gpg", "DEBF8E3B", "/home/crx/.gnupg/passfile"); try { gpg.encrypt("DEBF8E3B", "/home/crx/file.pdf", "/home/crx/file.pdf.asc"); } catch (Exception e) { e.printStackTrace(); System.exit(1); } try { gpg.decrypt("/home/crx/file.pdf.asc", "/home/crx/file_copy.pdf"); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } }
Eseguiamo…
$ java Tester $ ls -l ~/file* -rw-r--r-- 1 crx users 127946 2008-02-02 18:38 /home/crx/file.pdf -rw-r--r-- 1 crx users 137434 2008-02-02 18:41 /home/crx/file.pdf.asc -rw-r--r-- 1 crx users 127946 2008-02-02 18:41 /home/crx/file_copy.pdf
In questo caso tutto e’ andato bene, se rieseguo senza toccare i file appena creati lo STDERR verra’ intercettato
$ java Tester
java.lang.Exception: Cifratura fallita: gpg: /home/crx/file.pdf: encryption failed: file exists
at GPG.encrypt(GPG.java:73)
at Tester.main(Tester.java:22)Nota
Come detto sopra abbiamo messo la nostra password in un file per passarla a gpg tramite il comando –passphrase-file cosi da evitare che il programma la chieda runtime, nonostante questo algune versioni gpg NON hanno questo parametro di conseguenza fisogna fare in modo che il wrapper sia ingrado di passarla attraverso lo STDINE’ possibile utilizzare GnuPG per diversi OS
Questo wrapper l’ho creato diverso tempo fa sullo spunto di un esempio trovato in rete del quale purtroppo non ricordo la fonte
A while ago I’ve create this wrapper draw on a source code find somewhere, but I don’t remember where
Al solito spero di essere stato d’aiuto.
Ciao e alla prossima,
Cristian.
RSS feed for comments on this post · TrackBack URI
Leave a reply
You must be logged in to post a comment.