android - 如何处理 "last block incomplete in decryption"

标签 android encryption aes

我有一个简单的类来尝试包装加密以便在我的程序的其他地方使用。

import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;

public final class StupidSimpleEncrypter
{
    public static String encrypt(String key, String plaintext)
    {
        byte[] keyBytes = key.getBytes();
        byte[] plaintextBytes = plaintext.getBytes();
        byte[] ciphertextBytes = encrypt(keyBytes, plaintextBytes);
        return new String(ciphertextBytes);
    }

    public static byte[] encrypt(byte[] key, byte[] plaintext)
    {
        try
        {
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            SecretKeySpec spec = new SecretKeySpec(getRawKey(key), "AES");
            cipher.init(Cipher.ENCRYPT_MODE, spec);
            return cipher.doFinal(plaintext);
        }
        catch(Exception e)
        {
            // some sort of problem, return null because we can't encrypt it.
            Utility.writeError(e);
            return null;
        }
    }

    public static String decrypt(String key, String ciphertext)
    {
        byte[] keyBytes = key.getBytes();
        byte[] ciphertextBytes = ciphertext.getBytes();
        byte[] plaintextBytes = decrypt(keyBytes, ciphertextBytes);
        return new String(plaintextBytes);
    }

    public static byte[] decrypt(byte[] key, byte[] ciphertext)
    {
        try
        {
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            SecretKeySpec spec = new SecretKeySpec(getRawKey(key), "AES");
            cipher.init(Cipher.DECRYPT_MODE, spec);
            return cipher.doFinal(ciphertext);
        }
        catch(Exception e)
        {
            // some sort of problem, return null because we can't encrypt it.
            Utility.writeError(e);
            return null;
        }
    }

    private static byte[] getRawKey(byte[] key)
    {
        try
        {
            KeyGenerator gen = KeyGenerator.getInstance("AES");
            SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
            rand.setSeed(key);
            gen.init(256, rand);
            return gen.generateKey().getEncoded();
        }
        catch(Exception e)
        {
            return null;
        }
    }
}

它似乎正确地处理了加密,但在解密时却没有那么多,这会在突出显示的行抛出 javax.crypto.IllegalBlockSizeException“解密中的最后一个 block 不完整”。这是堆栈跟踪:

Location:com.xxxxxx.android.StupidSimpleEncrypter.decrypt ln:49
last block incomplete in decryption
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
     at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:711)
     at javax.crypto.Cipher.doFinal(Cipher.java:1090)
     at com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:44)
     at com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:34)

我已经用我的头撞了很多次 table 来尝试解决这个问题,但如果我有任何进展,它最终会成为一个不同的异常(exception)。我似乎也无法通过搜索找到很多东西。

我错过了什么?如果有任何帮助,我将不胜感激。

最佳答案

我不知道这是否是 IllegalBlockSizeException 的问题,但您不应将 key 编码为 String,尤其是在未指定字符编码的情况下。如果要执行此操作,请使用 Base-64 之类的东西,它旨在对任何“二进制”数据进行编码,而不是仅将某些字节映射到字符的字符编码。

一般而言, key 将包含不对应于默认平台编码中的字符的字节值。在这种情况下,当您创建 String 时,字节将被转换为“替换字符”,U+FFFD (�),并且正确的值将无法挽回地丢失。

稍后尝试使用 key 的损坏 String 表示将阻止恢复明文;它可能会导致 IllegalBlockSizeException,但我怀疑更有可能出现无效填充异常。

另一种可能是源平台和目标平台字符编码不同,“解码”密文导致字节太少。例如,源编码是 UTF-8,将输入中的两个字节解释为单个字符,而目标编码是 ISO-Latin-1,它将那个字符表示为单个字节。

关于android - 如何处理 "last block incomplete in decryption",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4598873/

相关文章:

encryption - SonarQube : Make sure that encrypting data is safe here. AES/GCM/NoPadding、RSA/ECB/PKCS1Padding

python - 在 Django 中安全地存储加密凭证

ios - 如何下载 CoreCrypto.framework?

php - Android中使用AES方法解密文件

android - 如何在调用 FragmentManager.replace() 时不调用 onCreateOptionsMenu

android - 使用gradle更新Android应用程序版本(存储在build.gradle中)

android - 安装完成后强制打开android应用程序

android - 当我从 Notification 添加 Extras 到 PendinIntent 时,RemoveExtras 没有效果

java - 如何使用密码和盐进行 AES 加密,以便在 Java 中仅使用相同的密码和盐进行解密

Java AES 加密问题