Android 如何处理;解密中的最后一个块未完成”;
我有一个简单的类来尝试包装加密,以便在我的程序中的其他地方使用Android 如何处理;解密中的最后一个块未完成”;,android,encryption,aes,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(Stri
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“last block Completed in decryption”。以下是堆栈跟踪:
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)
位置:com.xxxxxx.android.StupidSimpleEncrypter.decrypt ln:49
解密中的最后一个块未完成
javax.crypto.IllegalBlockSizeException:解密中的最后一个块未完成
位于org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:711)
位于javax.crypto.Cipher.doFinal(Cipher.java:1090)
位于com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:44)
位于com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:34)
我已经做了大量的工作,我的头撞在我的桌子上,试图找出这个问题,但如果我有任何进展,它最终是一个不同的例外。通过搜索,我似乎也找不到什么
我错过了什么?非常感谢您的帮助。我不知道这是否是
非法BlockSizeException
的问题,但您不应该将密钥编码为字符串,尤其是在未指定字符编码的情况下。如果您想这样做,请使用Base-64之类的代码,它设计用于对任何“二进制”数据进行编码,而不是字符编码,它只将某些字节映射到字符
通常,密钥将包含与默认平台编码中的字符不对应的字节值。在这种情况下,当您创建字符串时,字节将被转换为“替换字符”,U+FFFD(�), 正确的值将无法挽回地丢失
稍后尝试使用损坏的键的字符串
表示将阻止恢复明文;这可能会导致非法块大小异常
,但我怀疑更可能出现无效填充异常
另一种可能性是源平台和目标平台字符编码不同,并且“解码”密文导致字节太少。例如,源编码为UTF-8,将输入中的两个字节解释为单个字符,而目标编码为ISO-Latin-1,将该字符表示为单个字节。您的getKeySpec()
方法错误。您为加密和解密方向生成了一个新的随机密钥。您必须为这两个方向使用相同的密钥。您应该注意到,您没有使用该方法的key
参数。如果您使用的是字节数组,则必须使用相同的缓冲区大小。例如,有一个bytearray,其大小为1000。加密后,此大小变为2000。(这些不是实际值)。
如果您使用缓冲区读取所有加密文件,那么您应该选择buffersize为2000。我用这种方法解决了相同的问题。对于我来说,当要解密的数据被破坏(缺少1个字符)时,我注意到了这个问题。这可能是由于通过WiFi传输数据造成的。我当时正为此焦头烂额“坏基64”和“最后一个块未完成”错误…当然,这是不对称的。下面是我最终如何做的要点,希望这比我试图解释的内容更能增加讨论的内容:
public String crypto(SecretKey key, String inString, boolean decrypt){
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
byte[] inputByte = inString.getBytes("UTF-8");
if (decrypt){
cipher.init(Cipher.DECRYPT_MODE, key);
return new String (cipher.doFinal(Base64.decode(inputByte, Base64.DEFAULT)));
} else {
cipher.init(Cipher.ENCRYPT_MODE, key);
return new String (Base64.encode(cipher.doFinal(inputByte), Base64.DEFAULT));
}
}
这是问题的一部分,我可能会花一段时间才注意到。谢谢。这是我问题的根本原因,但在我的情况下,是有效负载而不是始终是标准字符串的密钥。我更改了它,因此在string encrypt方法中,返回的密文从字节数组编码到Base64,然后在decrypt方法中,密文字符串被Base64解码为字节数组。这意味着数据不再丢失,代码现在可以正常工作。加密字符串本身也是如此。它必须存储为字节[]。仅用于撕下的头发。