【问题标题】:Using-password-based-encryption in android在android中使用基于密码的加密
【发布时间】:2012-11-22 15:57:46
【问题描述】:

下面的代码虽然有效,但是当我连续运行时,有时会抛出“给定最终块未正确填充”,有时也会出现。我觉得我在某个地方犯了一个小错误。 你能帮我解决这个问题吗?

异常堆栈:

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;
    }

}

【问题讨论】:

  • 您的方法没有意义,加密方法似乎也使用要加密的文本来派生密钥。如果您的加密方法采用字符串并返回字符串,那么您的解密方法也应如此。
  • 我解决了这个问题。 StringBuffer strBuf = new StringBuffer(); strBuf.append(encryptedStr); strBuf.append("]");字符串 saltStr = Base64.encodeBytes(salt); strBuf.append(saltStr); strBuf.append("]");字符串 ivStr = Base64.encodeBytes(iv); strBuf.append(ivStr);
  • 是的,这就是我想要的方式,我想要这种方法“使用基于密码的加密”。因此程序。如果您能提出比这更好的建议,我将不胜感激。
  • 所以你发布的都是废话,我在上面浪费了我的时间?
  • 为什么是废话?我也提出了决议。我没有做的就是对所有字符串进行编码。希望你理解代码,否则也离开它......因为我知道......

标签: android encryption


【解决方案1】:

看看这个

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 值的固定 iv 向量,并且您提供的密码字节长度必须为 16
  • @IcedD​​ante 请编辑答案并使其成为完整的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
  • 2015-04-21
  • 2021-06-21
  • 2015-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多