密码算法 AES CBC 不安全的安卓系统

0 人关注

我目前在我的Android应用程序上使用Cipher cipher = Cipher.getInstance ("AES / CBC / PKCS5Padding")。 那些负责该应用程序安全的人这样告诉我。"还需要注意的是,当AES加密不是AES CBC时,它是安全的。",所以他们希望我修改算法。

我尝试了AES/GCM/NoPadding和AES/CTR/PKCS5Padding,如果我卸载旧版本并重新安装,应用程序可以工作,但如果我把它安装在带有CBC的版本上面,我得到了以下错误:javax.crypto.BadPaddingException: pad block corrupted

我怎样才能解决这个问题?我担心如果我更新商店里的应用程序,这个错误就会发生在终端用户身上。

Notes:

public static String encrypt (String plaintext, String pwd) {
        try {
            byte [] salt = generateSalt ();
            SecretKey key = deriveKey (salt, pwd);
            Cipher cipher = Cipher.getInstance (CIPHER_ALGORITHM);
            byte [] iv = generateIv (cipher.getBlockSize ());
            IvParameterSpec ivParams = new IvParameterSpec (iv);
            cipher.init (Cipher.ENCRYPT_MODE, key, ivParams);
            byte [] cipherText = cipher.doFinal (plaintext.getBytes ("UTF-8"));
            if (salt! = null) {
                return String.format ("% s% s% s% s% s", toBase64 (salt), DELIMITER,
                        toBase64 (iv), DELIMITER, toBase64 (cipherText));
            return String.format ("% s% s% s", toBase64 (iv), DELIMITER,
                    toBase64 (cipherText));
        } catch (GeneralSecurityException e) {
            throw new RuntimeException (e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException (e);
public static String decrypt (byte [] cipherBytes, SecretKey key, byte [] iv) {
        try {
            Cipher cipher = Cipher.getInstance (CIPHER_ALGORITHM);
            IvParameterSpec ivParams = new IvParameterSpec (iv);
            cipher.init (Cipher.DECRYPT_MODE, key, ivParams);
            byte [] plaintext = cipher.doFinal (cipherBytes);
            String plainrStr = new String (plaintext, "UTF-8");
            return plainrStr;
        } catch (GeneralSecurityException e) {
            throw new RuntimeException (e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException (e);
etc...

Update!

我决定让代码更简洁,在这里让大家了解一下。我的目标是用 "AES / CBC / PKCS7Padding "取代 "AES / GCM / NoPadding",因为他们认为AES与CBC不安全:( 对于这个GCM的实现,出现了一些问题:我是否必须在密码上使用GCMParameterSpec?我需要导入BouncyCastle提供商吗?

public static final String PBKDF2_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
//private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
private static String DELIMITER = "]";
private static final int PKCS5_SALT_LENGTH = 8;
private static SecureRandom random = new SecureRandom();
private static final int ITERATION_COUNT = 1000;
private static final int KEY_LENGTH = 256;
 public static String encrypt(String plaintext, String pwd) {
    byte[] salt = generateSalt();
    SecretKey key = deriveKey(pwd, salt);
    try {
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        byte[] iv = generateIv(cipher.getBlockSize());
        IvParameterSpec ivParams = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);
        byte[] cipherText = cipher.doFinal(plaintext.getBytes("UTF-8"));
        return String.format("%s%s%s%s%s", toBase64(salt), DELIMITER, toBase64(iv), DELIMITER, toBase64(cipherText));
    } catch (GeneralSecurityException | UnsupportedEncodingException e) {
        throw new RuntimeException(e);
public static String decrypt(String ciphertext, String pwd) {
    String[] fields = ciphertext.split(DELIMITER);
    if (fields.length != 3) {
        throw new IllegalArgumentException("Invalid encypted text format");
    byte[] salt = fromBase64(fields[0]);
    byte[] iv = fromBase64(fields[1]);
    byte[] cipherBytes = fromBase64(fields[2]);
    SecretKey key = deriveKey(pwd, salt);
    try {
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        IvParameterSpec ivParams = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, key, ivParams);
        byte[] plaintext = cipher.doFinal(cipherBytes);
        return new String(plaintext, "UTF-8");
    } catch (GeneralSecurityException e) {
        throw new RuntimeException(e);
    } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(e);
private static byte[] generateSalt() {
    byte[] b = new byte[PKCS5_SALT_LENGTH];
    random.nextBytes(b);
    return b;
private static byte[] generateIv(int length) {
    byte[] b = new byte[length];
    random.nextBytes(b);
    return b;
private static SecretKey deriveKey(String pwd, byte[] salt) {
    try {
        KeySpec keySpec = new PBEKeySpec(pwd.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(PBKDF2_DERIVATION_ALGORITHM);
        byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
        return new SecretKeySpec(keyBytes, "AES");
    } catch (GeneralSecurityException e) {
        throw new RuntimeException(e);
private static String toBase64(byte[] bytes) {
    return Base64.encodeToString(bytes, Base64.NO_WRAP);