2012-12-04 25 views
6

下面的代碼雖然有效,但是當我連續運行時會拋出「給定最終塊未正確填充」的情況以及其他情況。我覺得我在某個地方犯了一個小錯誤。 你能幫我解決這個問題嗎?在android中使用基於密碼的加密

異常堆棧:

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded 
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811) 
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676) 
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313) 
    at javax.crypto.Cipher.doFinal(Cipher.java:2086) 
    at MCrypt.decrypt(MCrypt.java:87) 
    at MCrypt.main(MCrypt.java:21) 

而且我的代碼:

import java.security.SecureRandom; 
import java.security.spec.KeySpec; 

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

public class MCrypt { 

    private int iterationCount = 10000; 
    private int saltLength = 8; // bytes; 64 bits 
    private int keyLength = 128; 

    public static void main(String[] args) throws Exception { 
     MCrypt mc = new MCrypt(); 
     String encryptedData = mc.encrypt("1234"); 
     MCrypt mc1 = new MCrypt(); 
     System.out.println(new String(mc1.decrypt(new String(encryptedData), 
       "1234"), "UTF-8")); 
    } 

    public MCrypt() { 
    } 

    public String encrypt(String text) throws Exception { 
     if (text == null || text.length() == 0) 
      throw new Exception("Empty string"); 

     byte[] encrypted = null; 

     SecureRandom random = new SecureRandom(); 
     byte[] salt = new byte[saltLength]; 
     random.nextBytes(salt); 

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

     byte[] iv = new byte[cipher.getBlockSize()]; 
     random.nextBytes(iv); 
     IvParameterSpec ivParams = new IvParameterSpec(iv); 

     KeySpec keySpec = new PBEKeySpec(text.toCharArray(), salt, 
       iterationCount, keyLength); 
     SecretKeyFactory keyFactory = SecretKeyFactory 
       .getInstance("PBKDF2WithHmacSHA1"); 
     byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded(); 
     SecretKey key = new SecretKeySpec(keyBytes, "AES"); 

     cipher.init(Cipher.ENCRYPT_MODE, key, ivParams); 

     encrypted = cipher.doFinal(text.getBytes("UTF-8")); 
     String encryptedStr = Base64.encodeBytes(encrypted); 

     StringBuffer strBuf = new StringBuffer(); 
     strBuf.append(new String(encryptedStr)); 
     strBuf.append("]"); 
     strBuf.append(new String(salt)); 
     strBuf.append("]"); 
     strBuf.append(new String(iv)); 

     return new String(Base64.encodeBytes(strBuf.toString().getBytes())); 
    } 

    public byte[] decrypt(String code, String pwd) throws Exception { 
     if (code == null || code.length() == 0) 
      throw new Exception("Empty string"); 

     String[] fields = new String(Base64.decode(code)).split("]"); 
     byte[] cipherBytes = Base64.decode(fields[0]); 
     byte[] salt = fields[1].getBytes(); 
     byte[] iv = fields[2].getBytes(); 

     KeySpec keySpec = new PBEKeySpec(pwd.toCharArray(), salt, 
       iterationCount, keyLength); 
     SecretKeyFactory keyFactory = SecretKeyFactory 
       .getInstance("PBKDF2WithHmacSHA1"); 
     byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded(); 
     SecretKey key = new SecretKeySpec(keyBytes, "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     IvParameterSpec ivParams = new IvParameterSpec(iv); 

     byte[] decrypted = null; 
     cipher.init(Cipher.DECRYPT_MODE, key, ivParams); 
     decrypted = cipher.doFinal(cipherBytes); 

     return decrypted; 
    } 

} 
+1

您的方法沒有意義,加密方法似乎使用文本進行加密以導出密鑰也。如果您的加密方法使用字符串並返回字符串,那麼您的解密方法也應如此。 –

+0

我解決了這個問題。 StringBuffer strBuf = new StringBuffer(); \t \t strBuf.append(encryptedStr); \t \t strBuf.append(「]」); \t \t String saltStr = Base64.encodeBytes(salt); \t \t strBuf.append(saltStr); \t \t strBuf.append(「]」); \t \t String ivStr = Base64.encodeBytes(iv); \t \t strBuf.append(ivStr); – user1876402

+0

是的,這是我想要的方式,我想這個方法「使用基於密碼的加密」。因此程序。如果你能提出比這更好的建議,我將不勝感激。 – user1876402

回答

0

看這個

import javax.crypto.Cipher; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.SecretKeySpec; 

import android.util.Base64; 
import android.util.Log; 

public class AesFileIo { 
// private static final String AES_ALGORITHM = "AES/CTR/NoPadding"; 
    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding"; 
    private SecretKeySpec secretKeySpec; 
    private IvParameterSpec ivSpec; 

    public AesFileIo(byte[] aesKey, byte[] iv) { 
     ivSpec = new IvParameterSpec(iv); 
     secretKeySpec = new SecretKeySpec(aesKey, "AES"); 
    } 

    public String decrypt(String text) { 

     StringBuilder stringBuilder = new StringBuilder(); 
     try { 
      Cipher cipher = Cipher.getInstance(AES_ALGORITHM); 
      cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec); 
      byte[] decordedValue = Base64.decode(text,Base64.DEFAULT); 
      String decryptedValue = new String(cipher.doFinal(decordedValue),"UTF-8"); 
      Log.e("decrypted Value :",decryptedValue); 
      return decryptedValue; 
     } catch (Exception e) { 
      Log.e(this.getClass().toString(), e.getMessage(), e); 
     } 
     return stringBuilder.toString(); 
    } 

    public String encrypt(String text) { 
     String encryptedValue=null; 
     try { 
      Cipher cipher = Cipher.getInstance(AES_ALGORITHM); 
      cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec); 
      byte[] encValue = cipher.doFinal(text.getBytes()); 
      encryptedValue = Base64.encodeToString(encValue,Base64.DEFAULT); 
     } catch (Exception e) { 
      Log.e(this.getClass().toString(), e.getMessage(), e); 
     } 
     return encryptedValue; 
    } 
} 

如何使用

public static byte[] iv = { '0', '0','0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' }; 
    private static final byte[] keyValue = new byte[] { 'b', 'i', 'r', 'a', 'j', 'z', 'a', 'l', 'a', 'v', 'a', 'd', 'i', 'y', 'a', 'r' }; 
AesFileIo aes = new AesFileIo(keyValue, iv); 
String encrypetedText = aes.encrypt(str); 
String decryptedText = aes.decrypt(encrypetedText); 

System.out.println("EncrypetedText : " + encrypetedText); 
System.out.println("DecryptedText : " + decryptedText); 
+0

這實際上是一個不完整的解決方案。我不認爲你應該傳遞一個固定的向量值爲0的值,並且你提供的密碼字節必須是16位長度 – IcedDante

+1

@ IcedD​​ante請編輯答案並使其成爲完整的解決方案。 –