2016-02-28 30 views
5

Sto lavorando a un programma che deve memorizzare le informazioni binarie crittografate a riposo. Sfortunatamente, non riesco a trovare una risorsa che spieghi quali schemi di crittografia sono i migliori per le diverse applicazioni.Crittografia Java: quali algoritmi dovrei usare?

Poiché la crittografia è complicata e non sono un esperto, ho deciso di utilizzare una libreria denominata Jasypt che avvolge le funzioni di crittografia incorporate di Java. Per capire quali algoritmi sono disponibili per me, ho scritto alcuni test unitari.

Il primo test chiama la funzione di Jasypt AlgorithmRegistry.getAllPBEAlgorithms() ed elenca tutti gli algoritmi di crittografia disponibili:

PBEWITHHMACSHA1ANDAES_128 
PBEWITHHMACSHA1ANDAES_256 
PBEWITHHMACSHA224ANDAES_128 
PBEWITHHMACSHA224ANDAES_256 
PBEWITHHMACSHA256ANDAES_128 
PBEWITHHMACSHA256ANDAES_256 
PBEWITHHMACSHA384ANDAES_128 
PBEWITHHMACSHA384ANDAES_256 
PBEWITHHMACSHA512ANDAES_128 
PBEWITHHMACSHA512ANDAES_256 
PBEWITHMD5ANDDES 
PBEWITHMD5ANDTRIPLEDES 
PBEWITHSHA1ANDDESEDE 
PBEWITHSHA1ANDRC2_128 
PBEWITHSHA1ANDRC2_40 
PBEWITHSHA1ANDRC4_128 
PBEWITHSHA1ANDRC4_40 

In fase di esecuzione, Jasypt getterà un EncryptionOperationNotPossibleException se si tenta di utilizzare un algoritmo che per qualche motivo non è supportato o viola le regole di crittografia di Java. È interessante notare che, se tento di usare ognuno degli algoritmi 'disponibili' per cifrare e decifrare alcuni dati arbitrari, e solo stampare i quelli che non gettano tale eccezione, ho questa snellita lista:

PBEWITHMD5ANDDES 
PBEWITHSHA1ANDDESEDE 
PBEWITHSHA1ANDRC2_128 
PBEWITHSHA1ANDRC2_40 
PBEWITHSHA1ANDRC4_128 
PBEWITHSHA1ANDRC4_40 

L'elenco degli algoritmi disponibili può essere ampliato inserendo il JCE BouncyCastle e registrandolo eseguendo Security.addProvider(new BouncyCastleProvider()). Se ripeto il test precedente dopo aver fatto questo, ottenere una lista molto più grande di algoritmi tra cui scegliere:

PBEWITHMD2ANDDES 
PBEWITHMD5AND128BITAES-CBC-OPENSSL 
PBEWITHMD5AND192BITAES-CBC-OPENSSL 
PBEWITHMD5AND256BITAES-CBC-OPENSSL 
PBEWITHMD5ANDDES 
PBEWITHMD5ANDRC2 
PBEWITHSHA1ANDDES 
PBEWITHSHA1ANDDESEDE 
PBEWITHSHA1ANDRC2 
PBEWITHSHA1ANDRC2_128 
PBEWITHSHA1ANDRC2_40 
PBEWITHSHA1ANDRC4_128 
PBEWITHSHA1ANDRC4_40 
PBEWITHSHA256AND128BITAES-CBC-BC 
PBEWITHSHA256AND192BITAES-CBC-BC 
PBEWITHSHA256AND256BITAES-CBC-BC 
PBEWITHSHAAND128BITAES-CBC-BC 
PBEWITHSHAAND128BITRC2-CBC 
PBEWITHSHAAND128BITRC4 
PBEWITHSHAAND192BITAES-CBC-BC 
PBEWITHSHAAND2-KEYTRIPLEDES-CBC 
PBEWITHSHAAND256BITAES-CBC-BC 
PBEWITHSHAAND3-KEYTRIPLEDES-CBC 
PBEWITHSHAAND40BITRC2-CBC 
PBEWITHSHAAND40BITRC4 
PBEWITHSHAANDIDEA-CBC 
PBEWITHSHAANDTWOFISH-CBC 

Purtroppo, ora non ho idea di quale di questi molti algoritmi è più appropriato per la mia applicazione. Ho l'impressione che AES sia la strada giusta da fare, e sembra che l'PBEWITHSHA256AND256BITAES-CBC-BC sia l'implementazione AES con la lunghezza della chiave più lunga, ma non so dove andare per confermare questo sospetto.

Quali di questi schemi fornirebbero i più alti livelli di sicurezza e che hanno evidenti problemi di sicurezza?

EDIT: Voglio essere in grado di distribuire il mio codice senza richiedere all'utente finale di installare i file di crittografia illimitate, come che quasi certamente oltre le capacità degli utenti esperti non così tech. Quello che voglio veramente è la crittografia più potente che riesco a ottenere senza usare i file di giurisdizione della forza illimitata.

+0

non lo fanno. Utilizza le librerie wrapper che prendono tutte le decisioni corrette. Leggi http://blog.slaks.net/2015-11-18/common-crypto-pitfalls/ – SLaks

+1

Ho cambiato la domanda per spiegare direttamente quale schema fornisce "i più alti livelli di sicurezza". Chiedere spiegazioni/indicazioni fuori sede è fuori tema e chiedere "il meglio" è soggettivo. Entrambi sarebbero motivi per chiudere la domanda. –

+0

non hai bisogno di una libreria; non troppo difficile da usare API java. il mio esempio - https://gist.github.com/zhong-j-yu/9d23c850e580d60ddd46 – ZhongYu

risposta

3

Prima di tutto è necessario installare i file di crittografia illimitati da Oracle. Dopo averlo fatto dovresti avere un minor numero di EncryptionOperationNotPossibleException se diventeranno disponibili livelli di sicurezza più elevati.

Inoltre, per la massima crittografia possibile, non utilizzerei affatto JaSypt, perché it doesn't seem to provide any integrity checking or authentication of ciphertext. Per motivi di riservatezza, non importa che sembri. Ma in pratica dovresti controllarlo contro il tuo modello di minaccia.

Se decidessi di utilizzare JaSypt (che personalmente non mi piace) dovresti probabilmente cercare PBEWITHHMACSHA512ANDAES_256 come possibilità di livello più alto. Assicurarsi di aver compreso PBKDF2 e fattori di lavoro (numero di iterazioni, ad esempio setKeyObtentionIterations

Non è necessario Bouncy Castle AES è considerato sicuro, tutti Bouncy Castle fa - per il vostro esempio che utilizza JaSypt - è l'aggiunta di cifrari oscuro... nell'elenco precedente, tutto ciò che non è AES è meno sicuro di AES.

+0

Il problema, nel mio caso, è che voglio essere in grado di distribuire il mio codice senza richiedere all'utente finale di installare i file di crittografia illimitati, in quanto quasi sicuramente andrà oltre le capacità degli utenti meno esperti di tecnologia. Quello che voglio veramente è la crittografia più potente che riesco a ottenere senza utilizzare i file di giurisdizione di forza illimitata. Forse dovrei modificare la domanda per dirlo. – MusikPolice

+0

Sì, dovresti. Su quale runtime sei presente che non esiste un algoritmo AES 128 disponibile per impostazione predefinita? –

+0

Sono in esecuzione sul JDK Java 8 standard da Oracle. Ha un algoritmo AES 128 disponibile, ma ottengo eccezioni ogni volta che cerco di usarlo nella pratica. – MusikPolice

-2

La domanda originale che avevi era come crittografare i dati. Quale algoritmo utilizzare e quale libreria java?

package cryptography; 

import java.security.AlgorithmParameters; 
import java.security.InvalidAlgorithmParameterException; 
import java.security.InvalidKeyException; 
import java.security.Key; 
import java.security.NoSuchAlgorithmException; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.InvalidParameterSpecException; 
import java.security.spec.KeySpec; 

import javax.crypto.Cipher; 
import javax.crypto.NoSuchPaddingException; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 

import java.util.Base64; 
import java.util.Base64.Decoder; 
import java.util.Base64.Encoder; 

public class BasicAESEncrypt { 
private final byte[] SALT = { 
     (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, 
     (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 
    }; 

private Cipher ecipher; 
private Cipher dcipher; 
Encoder encoder = Base64.getEncoder(); 
Decoder decoder = Base64.getDecoder(); 


BasicAESEncrypt(String password) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, InvalidAlgorithmParameterException{ 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 

    KeySpec spec = new PBEKeySpec(password.toCharArray(), SALT, 65536, 256); 
    SecretKey tmp = factory.generateSecret(spec);   

    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); 

    ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    ecipher.init(Cipher.ENCRYPT_MODE, secret); 

    AlgorithmParameters params = ecipher.getParameters(); 
    byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV(); 

    dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); 
} 

public String encrypt(String encrypt) throws Exception { 
    byte[] bytes = encrypt.getBytes("UTF8"); 
    byte[] encrypted = encrypt(bytes); 
    return encoder.encodeToString(encrypted); 
} 

public byte[] encrypt(byte[] plain) throws Exception { 
    return ecipher.doFinal(plain); 
} 

public String decrypt(String encrypt) throws Exception { 
    byte[] decodedData = decoder.decode(encrypt); 
    byte[] decrypted = decrypt(decodedData); 
    return new String(decrypted, "UTF8"); 
} 

public byte[] decrypt(byte[] encrypt) throws Exception { 
    return dcipher.doFinal(encrypt); 
} 

public static void main(String[] args) throws Exception { 
    String message = "Wire message for encryption"; 
    String password = "TopSecretKey"; 

    try { 
     BasicAESEncrypt app = new BasicAESEncrypt(password); 

     String encrypted = app.encrypt(message); 
     System.out.println("Encrypted string is: " + encrypted); 

     String decrypted = app.decrypt(encrypted); 
     System.out.println("Decrypted string is: " + decrypted); 
    } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException 
      | InvalidParameterSpecException | InvalidAlgorithmParameterException e1) { 
     e1.printStackTrace(); 
    } 
    try { 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

}

+2

Se si utilizza un sale non statico, si otterrebbe lo stesso livello di sicurezza che JaSypt è in grado di fornire. In questo senso è molto meglio di quello che hai postato prima (tranne che non avresti implementato la funzionalità aggiuntiva fornita da JaSypt, ma ti preghiamo di fare attenzione che ci sono molti metodi per crittografare qualcosa. Se qualcuno posta una domanda su JaSypt, pubblicando un a mio parere, il nuovo metodo di crittografia non è davvero una risposta. Rimuoverò il mio downvote per ottenere molto di più al secondo tentativo. –