2014-07-26 69 views
-1

當我運行scrypt我第一次解密結果是正確的:Java的AES解密不同的結果保存並解密後,再次

哥哥人羣意味着之前完美眩光 憤怒某些傢伙古代需求社會

當我保存encryptedText,salt(例如到一個數據庫)並且想要解密時,我得到這個。

S,& 6;完美前人的傢伙古代社會需求怒瞪着一定

*更新 我認爲這個問題是我處理的方式數據(鹽和iv)。現在,我們可以加密並保存-encryptText,randomIV,randomSalt到數據庫並使用masterPassword解密而不會出現問題。

感謝您爲大家提供的幫助!

*編輯的代碼,我結束了這個解決方案

import java.io.UnsupportedEncodingException; 
import java.security.InvalidAlgorithmParameterException; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 
import java.security.SecureRandom; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.InvalidParameterSpecException; 
import java.util.Random; 
import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
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 org.apache.commons.codec.binary.Base64; 

public class Aes { 
private static int pswdIterations = 65536; 
private static int keySize = 256; 

public static String encrypt(String plainText, String password, String salt, String initializationVector) throws 
    NoSuchAlgorithmException, 
    InvalidKeySpecException, 
    NoSuchPaddingException, 
    InvalidParameterSpecException, 
    IllegalBlockSizeException, 
    BadPaddingException, 
    UnsupportedEncodingException, 
    InvalidKeyException, 
    InvalidAlgorithmParameterException 
{ 
    byte[] saltBytes = salt.getBytes("UTF-8"); 
    byte[] ivBytes = initializationVector.getBytes("UTF-8"); 

    // Derive the key, given password and salt. 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    PBEKeySpec spec = new PBEKeySpec(
      password.toCharArray(), 
      saltBytes, 
      pswdIterations, 
      keySize 
    ); 

    SecretKey secretKey = factory.generateSecret(spec); 
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

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

    byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8")); 
    return new Base64().encodeAsString(encryptedTextBytes); 
} 

    public static String decrypt(String encryptedText, String password, String salt, String initializationVector) throws 
    NoSuchAlgorithmException, 
    InvalidKeySpecException, 
    NoSuchPaddingException, 
    InvalidKeyException, 
    InvalidAlgorithmParameterException, 
    UnsupportedEncodingException 
{ 
    byte[] saltBytes = salt.getBytes("UTF-8"); 
    byte[] ivBytes = initializationVector.getBytes("UTF-8"); 
    byte[] encryptedTextBytes = new Base64().decodeBase64(encryptedText); 

    // Derive the key, given password and salt. 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    PBEKeySpec spec = new PBEKeySpec(
      password.toCharArray(), 
      saltBytes, 
      pswdIterations, 
      keySize 
    ); 

    SecretKey secretKey = factory.generateSecret(spec); 
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

    // Decrypt the message, given derived key and initialization vector. 
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, secret, 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 String generateSalt() { 
     SecureRandom random = new SecureRandom(); 
     byte bytes[] = new byte[16]; 
     random.nextBytes(bytes); 
     String s = new String(bytes); 
     return s; 
    } 

    public String generateIV(String chars, int length) { 
    Random rand = new Random(); 
    StringBuilder buf = new StringBuilder(); 
    for (int i=0; i<length; i++) { 
     buf.append(chars.charAt(rand.nextInt(chars.length()))); 
    } 
    return buf.toString(); 
    } 

    } 

* Edited.Run測試

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

//Passphrase and masterPassword 
    String passPhrase = "stackoverflow is great"; 
    String masterPassword = "password"; 

    //-Aes 
    Aes crypt = new Aes(); 

    // Aes generate random salt 
    String genSalt = crypt.generateSalt(); 
    String tmpSalt = genSalt; 
    // Aes generate random Iv 
    String genIV = crypt.generateIV("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 16); 
    String tmpIV = genIV; 

// Aes encrypt phrase 
    String cipherPassPhrase = crypt.encrypt(passPhrase, masterPassword, tmpSalt, tmpIV); 

    System.out.println(cipherPassPhrase); 

// save cipherPassPhrase, tmpSalt, tmpIV to database ....decrypt with not stored masterPassword 
} 
+0

似乎是編碼problem.Try UTF-16.Bud仍然如果你只是使用普通的ASCII字符這shoud沒有發生。你的數據庫使用什麼編碼? –

+0

這似乎是保存或檢索數據的問題。你能顯示相應的代碼嗎? – Henry

+0

即使我不保存到數據庫它有這個問題。當我從控制檯取出salt字符串和加密字符串並解密時,它也顯示出這些不可讀的東西^^但是爲什麼80%的文本確定只有開始不行? – wook

回答

0

有你的代碼的幾個不同的問題。首先是你是如何產生的鹽......

SecureRandom random = new SecureRandom(); 
byte bytes[] = new byte[20]; 
random.nextBytes(bytes); 
String s = new String(bytes); 
return s; 

你把隨機數據,並試圖把它在一個字符串,但字符串構造並不期望任何只是隨機數據,預計一些編碼中的文本字符串(UTF-8,UTF-16或其他)。只有在編碼它時,才能將二進制數據轉換爲字符串,我只需返回bytes數組即可。

public byte[] generateSalt(int length) { 
    SecureRandom random = new SecureRandom(); 
    byte bytes[] = new byte[length]; 
    random.nextBytes(bytes); 
    return bytes; 
} 

下,很難說爲什麼你的輸出被解密你說(只有第一塊損壞)的具體方式,但我打賭猜測它與正確編碼IV做當你將它保存到數據庫時。更好的解決方案是將salt和IV預先加密到加密數據中,然後在需要解密時將其剝離。

public String encrypt(String plainText) throws Exception { 
    //get salt  
    byte[] saltBytes = generateSalt(saltLength); 

    // Derive the key 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize); 

    SecretKey secretKey = factory.generateSecret(spec); 
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

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

    //prepend the salt and IV 
    byte[] buffer = new byte[saltBytes.length + ivBytes.length + encryptedTextBytes.length]; 
    System.arraycopy(saltBytes, 0, buffer, 0, saltBytes.length); 
    System.arraycopy(ivBytes, 0, buffer, saltBytes.length, ivBytes.length); 
    System.arraycopy(encryptedTextBytes, 0, buffer, saltBytes.length + ivBytes.length, encryptedTextBytes.length); 
    return new Base64().encodeToString(buffer); 
} 

public String decrypt(String encryptedText) throws Exception { 

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 

    //strip off the salt and IV 
    ByteBuffer buffer = ByteBuffer.wrap(new Base64().decode(encryptedText)); 
    byte[] saltBytes = new byte[saltLength]; 
    buffer.get(saltBytes, 0, saltBytes.length); 
    byte[] ivBytes = new byte[cipher.getBlockSize()]; 
    buffer.get(ivBytes, 0, ivBytes.length); 
    byte[] encryptedTextBytes = new byte[buffer.capacity() - saltBytes.length - ivBytes.length]; 
    buffer.get(encryptedTextBytes); 

    // Derive the key 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize); 

    SecretKey secretKey = factory.generateSecret(spec); 
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); 
    cipher.init(Cipher.DECRYPT_MODE, secret, 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); 
} 

這是非常重要的是使用每次加密數據的時候一個新的IV,因爲它helps to avoid known text attacks

-1

您的代碼可以加密和解密,但不加密,加密B並解密A. 因爲當加密A時加密和初始化向量在加密時被覆蓋B. 我不知道你wa nt歸檔。我留下了一個可用的代碼示例。

import java.security.AlgorithmParameters; 
import java.security.SecureRandom; 
import java.util.HashMap; 
import java.util.Map; 

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 org.apache.commons.codec.binary.Base64; 

public class AESDemo { 

    private static final String password = "test"; 
    private static String salt; 
    private static int pswdIterations = 65536; 
    private static int keySize = 256; 
    //read from DB 
    private byte[] ivBytes = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 

    public String encrypt(String plainText) throws Exception { 

     // get salt 
     if (salt == null) 
      salt = generateSalt(); 
     byte[] saltBytes = salt.getBytes("UTF-8"); 

     // Derive the key 
     SecretKeyFactory factory = SecretKeyFactory 
       .getInstance("PBKDF2WithHmacSHA1"); 
     PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 
       pswdIterations, keySize); 

     SecretKey secretKey = factory.generateSecret(spec); 
     SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

     // encrypt the message 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(ivBytes)); 
     byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8")); 

     return new Base64().encodeAsString(encryptedTextBytes); 
    } 

    @SuppressWarnings("static-access") 
    public String decrypt(String encryptedText) throws Exception { 

     byte[] saltBytes = salt.getBytes("UTF-8"); 
     byte[] encryptedTextBytes = new Base64().decodeBase64(encryptedText); 

     // Derive the key 
     SecretKeyFactory factory = SecretKeyFactory 
       .getInstance("PBKDF2WithHmacSHA1"); 
     PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 
       pswdIterations, keySize); 

     SecretKey secretKey = factory.generateSecret(spec); 
     SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

     // Decrypt the message 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.DECRYPT_MODE, secret, 
       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 String generateSalt() { 
     //get the salt from DB 
     return "I hate salt"; 
    } 
} 

public class stackoverflow_test { 

    public static void main(String[] ag) throws Exception{ 
     AESDemo d = new AESDemo(); 

     System.out.println("Encrypted string:" + d.encrypt("brother crowd mean guy ancient demand society before perfection glare anger certain"));   
     String encryptedText = d.encrypt("brother crowd mean guy ancient demand society before perfection glare anger certain"); 
     String encryptedText2 = d.encrypt("Hello World"); 
     System.out.println("Decrypted string:" + d.decrypt(encryptedText2));   
     System.out.println("Decrypted string:" + d.decrypt(encryptedText));   

    } 
} 

結果

Encrypted string:c7NXCBiq7tqzon39iPtkQLJ0chuXudS5oVDPdAr5S3q1245d3uJUVcyNUY77rpGeNvOp9hOldhiOM8mp2C/aOqqNyXx82zJt2V2EFtQkauCl/oY2EMENh1jCR6Nqf1lJ 
Decrypted string:Hello World 
Decrypted string:brother crowd mean guy ancient demand society before perfection glare anger certain 
+0

謝謝。但用你的解決方案,我無法做到這一點。的System.out.println(「解密的字符串:」 + d.decrypt(06scBq7GNv + jjJPpsJdOm + 1mIdaWrk/SH2lO5yIIWvAQyiFo6gmq8anUloYlWLJQjW4NuUXRVfLN5Yp/OikicB9H/dMu7TGz5PPPV8yPqTOYYdK823mEOE5N0T084Cwv);我想保存的加密和在例如,比解密分貝種子 – wook

+0

我修改。代碼中的IV和salt是代碼中的一個常數,這樣你只需要將加密的文本保存在DB中,當然你也可以在數據庫中保存IV和salt,並在代碼開始時讀取它。 – tom87416

+0

Thanks dude!稍微修改一下,適用於我;) – wook