我刚刚拥有了#34;伟大的"想法加密来自我的客户端和服务器的发送/接收数据。但现在每次拨打IllegalBlockSizeException (Input length must be multiple of 16 when decrypting with padded cipher)
时,我都会收到cipher.doFinal()
。
我的代码:
我创建了一个名为SecurityHandler
的单例类,SecretKeySpec keyspec
,Cipher cipher
和String securitykey
作为私有变量,在构造函数中初始化:
private SecurityHandler()
{
securitykey = "adnanyc83z43h1jbncxgsdfgs2134y"; // Example key
try
{
keyspec = new SecretKeySpec(Arrays.copyOf(securitykey.getBytes("UTF-8"), 16), "AES");
cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
}
catch (final Exception e)
{
Logger.log("CipherInitializationException (" + e.getMessage() + ")", e);
}
}
获取AlgorithmParameterSpec
的方法:
public AlgorithmParameterSpec getIV()
{
final byte[] iv = new byte[cipher.getBlockSize()];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
我的enrypt / decrypt方法:
public String encrypt(final String text)
{
try
{
cipher.init(Cipher.ENCRYPT_MODE, keyspec, getIV());
final byte[] encrypted = cipher.doFinal(text.getBytes("UTF-8")); // Exception thrown here by doFinal()
return Base64.encode(encrypted);
}
catch (final Exception e)
{
Logger.log("StringEncryptionException (" + e.getMessage() + ")", e);
}
return text;
}
public String decrypt(final String text)
{
try
{
cipher.init(Cipher.DECRYPT_MODE, keyspec, getIV());
final byte[] decoded = Base64.decode(text);
final byte[] decrypted = cipher.doFinal(decoded); // Exception thrown here by doFinal()
return new String(decrypted);
}
catch (final Exception e)
{
Logger.log("StringDecryptionException (" + e.getMessage() + ")", e);
}
return text;
}
解决
我创建了一个方法,使数组长度为16的倍数:
public static byte[] getBytesM16(final String text) throws UnsupportedEncodingException
{
final byte[] bytes = text.getBytes("UTF-8");
if (bytes.length % 16 == 0)
{
return bytes;
}
return Arrays.copyOf(bytes, bytes.length + (16 - (bytes.length % 16)));
}
public static byte[] getBytesM16(final byte[] bytes)
{
if (bytes.length % 16 == 0)
{
return bytes;
}
return Arrays.copyOf(bytes, bytes.length + (16 - (bytes.length % 16)));
}
public String encrypt(final String text)
{
try
{
cipher.init(Cipher.ENCRYPT_MODE, keyspec, getIV());
final byte[] encrypted = cipher.doFinal(StringHandler.getBytesM16(text));
return Base64.getEncoder().encodeToString(encrypted);
}
catch (final Exception e)
{
Logger.log("StringEncryptionException (" + e.getMessage() + ")", e);
}
return text;
}
public String decrypt(final String text)
{
try
{
cipher.init(Cipher.DECRYPT_MODE, keyspec, getIV());
final byte[] decoded = Base64.getDecoder().decode(text);
final byte[] decrypted = cipher.doFinal(StringHandler.getBytesM16(decoded));
return new String(decrypted);
}
catch (final Exception e)
{
Logger.log("StringDecryptionException (" + e.getMessage() + ")", e);
}
return text;
}
之后我遇到了前16个字节未正确解密的问题,因为服务器在启动时创建了自己的随机IVKey
。为了解决这个问题,我确保服务器和客户端IVKey
是相同的,通过将密钥作为非加密数据包发送,就在新客户端尝试连接时。