2015-02-20 26 views
8

Ho trovato una guida per l'implementazione della crittografia/decrittografia AES in Java e ho cercato di capire ogni riga come la inserisco nella mia soluzione. Tuttavia, non lo capisco completamente e sto avendo problemi di conseguenza. L'obiettivo finale è quello di avere crittografia/decrittografia basata su passphrase. Ho letto altri articoli/post StackOverflow su questo, ma la maggior parte non forniscono abbastanza spiegazione (Sono molto di nuovo da Crypto in Java)AES-256 Crittografia/decrittografia basata su password in Java

I miei problemi principali in questo momento sono che anche quando ho impostato byte[] saltBytes = "Hello".getBytes(); ho ancora ottenere un diverso risultato Base64 alla fine (char[] password è casuale ogni volta, ma ho letto che è più sicuro di lasciare le password in char[] modulo. il mio altro problema è che quando il programma arriva a decrypt(), ho un NullPointerException al byte[] saltBytes = salt.getBytes("UTF-8");

Grazie in anticipo per qualsiasi aiuto/consiglio che possa darmi.

Il codice in questione:

import java.security.AlgorithmParameters; 
import java.security.NoSuchAlgorithmException; 
import java.security.SecureRandom; 

import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 
import javax.xml.bind.DatatypeConverter; 

public class EncryptionDecryption { 

    private static String salt; 
    private static int iterations = 65536 ; 
    private static int keySize = 256; 
    private static byte[] ivBytes; 

    public static void main(String []args) throws Exception { 

     char[] message = "PasswordToEncrypt".toCharArray(); 
     System.out.println("Message: " + message.toString()); 
     System.out.println("Encrypted: " + encrypt(message)); 
     System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray())); 
    } 

    public static String encrypt(char[] plaintext) throws Exception { 

     salt = getSalt(); 
     byte[] saltBytes = salt.getBytes(); 

     SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize); 
     SecretKey secretKey = skf.generateSecret(spec); 
     SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secretSpec); 
     AlgorithmParameters params = cipher.getParameters(); 
     ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV(); 
     byte[] encryptedTextBytes = cipher.doFinal(plaintext.toString().getBytes("UTF-8")); 

     return DatatypeConverter.printBase64Binary(encryptedTextBytes); 
    } 

    public static String decrypt(char[] encryptedText) throws Exception { 

     byte[] saltBytes = salt.getBytes("UTF-8"); 
     byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(encryptedText.toString()); 

     SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     PBEKeySpec spec = new PBEKeySpec(encryptedText, saltBytes, iterations, keySize); 
     SecretKey secretkey = skf.generateSecret(spec); 
     SecretKeySpec secretSpec = new SecretKeySpec(secretkey.getEncoded(), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes)); 

     byte[] decryptedTextBytes = null; 

     try { 
      decryptedTextBytes = cipher.doFinal(encryptedTextBytes); 
     } catch (IllegalBlockSizeException e) { 
      e.printStackTrace(); 
     } catch (BadPaddingException e) { 
      e.printStackTrace(); 
     } 

     return decryptedTextBytes.toString(); 

    } 

    public static String getSalt() throws Exception { 

     SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
     byte[] salt = new byte[20]; 
     sr.nextBytes(salt); 
     return salt.toString(); 
    } 
} 

risposta

17

penso che si stanno facendo due errori :)

ho corretto il codice di esempio per farlo funzionare:

import java.security.AlgorithmParameters; 
import java.security.NoSuchAlgorithmException; 
import java.security.SecureRandom; 

import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 
import javax.xml.bind.DatatypeConverter; 

public class EncryptionDecryption { 

    private static String salt; 
    private static int iterations = 65536 ; 
    private static int keySize = 256; 
    private static byte[] ivBytes; 

    private static SecretKey secretKey; 

    public static void main(String []args) throws Exception { 

     salt = getSalt(); 

     char[] message = "PasswordToEncrypt".toCharArray(); 
     System.out.println("Message: " + String.valueOf(message)); 
     System.out.println("Encrypted: " + encrypt(message)); 
     System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray())); 
    } 

    public static String encrypt(char[] plaintext) throws Exception { 
     byte[] saltBytes = salt.getBytes(); 

     SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize); 
     secretKey = skf.generateSecret(spec); 
     SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secretSpec); 
     AlgorithmParameters params = cipher.getParameters(); 
     ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV(); 
     byte[] encryptedTextBytes = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8")); 

     return DatatypeConverter.printBase64Binary(encryptedTextBytes); 
    } 

    public static String decrypt(char[] encryptedText) throws Exception { 

     System.out.println(encryptedText); 

     byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedText)); 
     SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes)); 

     byte[] decryptedTextBytes = null; 

     try { 
      decryptedTextBytes = cipher.doFinal(encryptedTextBytes); 
     } catch (IllegalBlockSizeException e) { 
      e.printStackTrace(); 
     } catch (BadPaddingException e) { 
      e.printStackTrace(); 
     } 

     return new String(decryptedTextBytes); 

    } 

    public static String getSalt() throws Exception { 

     SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
     byte[] salt = new byte[20]; 
     sr.nextBytes(salt); 
     return new String(salt); 
    } 
} 

Il primo errore è che si generano 2 diversi sali (quando si utilizza il metodo di crittografia), quindi i registri crittografati/decrittografati erano diversi (logici, ma la decifrazione funzionerebbe comunque perché si sta chiamando la decrittografia direttamente dopo la crittografia).

Il secondo errore era per la chiave segreta. È necessario generare una chiave segreta quando si esegue la crittografia, ma non la decrittografia. Per dirla in modo più semplice, è come se stessi crittografando con la password "encrypt" e che si stia tentando di decodificarlo con la password "decrypt".

Vorrei consigliarvi di generare ogni cosa casuale (come la chiave privata, il sale ecc. All'avvio). Ma attenzione che quando interromperai la tua app, non sarai in grado di decifrare le vecchie cose a meno di non ottenere esattamente le stesse cose casuali.

Speranza ho aiutato :)

saluti,

+0

DatatypeConverter non è supportato in questo momento? –

Problemi correlati