Java密码AES不加密整个字符串

huangapple go评论71阅读模式
英文:

Java Cipher AES not encrypting whole String

问题

我正在尝试使用Java Cipher和AES算法加密和解密字符串。但不知何故,它似乎无法加密整个字符串。我的目标不是特别安全地加密某些内容,我只是希望别人不能轻松地阅读这个字符串(稍后存储在文件中)。

要进行加密,我使用以下代码:

Cipher cipher = Cipher.getInstance("AES");
byte[] input = plain.getBytes();
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(input);

return new String(encrypted);

要进行解密,我使用以下代码:

Cipher cipher = Cipher.getInstance("AES");
byte[] input = encrypted.getBytes();
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(input);

return new String(decrypted);

为了测试上述代码,我使用以下参数:

SecretKeySpec key = new SecretKeySpec(new byte[]{103,38,125,-67,-71,-23,-119,102,78,-3,-33,-23,-5,32,-112,-124}, "AES");
String plain = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur auctor ornare bibendum.";

该测试结果是加密然后再解密的字符串:

�T���Ѩ�%���Kr sit amet, consectetur adipiscing elit. Curabitur auctor ornare bibendum.
英文:

I am trying to encrypt and decrypt a string using java Cipher with the AES algorithm. But somehow it does not want to encrypt the whole string. My goal is not to encrypt something particullary safely, I want that someone just cant read the String very easily (later stored in a file).

To encrypt, I use the following code:

Cipher cipher = Cipher.getInstance("AES");
byte[] input = plain.getBytes();
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(input);

return new String(encrypted);

And to decrypt, I use the following code:

Cipher cipher = Cipher.getInstance("AES");
byte[] input = encrypted.getBytes();
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(input);

return new String(decrypted);

To test the code mentioned above, I use the following parameters:

SecretKeySpec key = new SecretKeySpec(new byte[]{103,38,125,-67,-71,-23,-119,102,78,-3,-33,-23,-5,32,-112,-124}, "AES");
String plain = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur auctor ornare bibendum."

That test results in the encrypted and then again decrypted string:

�T���Ѩ�%���Kr sit amet, consectetur adipiscing elit. Curabitur auctor ornare bibendum.

答案1

得分: 3

有几个问题:

byte[] encrypted = cipher.doFinal(input);
return new String(encrypted);

问题在于你不能仅仅将一个字节数组转换为字符串,你需要使用不同的格式表示字节数组,比如Base64或者Hex。String 只适用于可打印字符。

byte[] encrypted = cipher.doFinal(input);
return Base64.getEncoder().encodeToString(encrypted);

同样的方法 - 在解密之前,你需要将编码后的字符串解码成字节数组。

编辑:

另一个问题 - 你应该指定完整的操作模式

默认情况下,“AES”参数应该使用CBC模式,如果提供了IV(初始化向量),如果没有定义IV,则使用ECB模式(至少我知道Oracle JDK是这样工作的)。

但这并不保证适用于所有的运行时。你使用的是哪个平台/Java运行环境?由于你的第一个字节块被混淆了,我猜实现是在使用随机IV(你可以使用cipher.getIV()),并且你在解密时必须传递IV。

cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
SecretKey symmetricKey = new 
SecretKeySpec(encryptionParams.getKey(), SYMMETRIC_KEY_ALG);

cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivParamSpec);

对于CBC,IV必须是一个随机的字节数组,长度为AES块大小(128位=16字节),常见做法是在密文前添加IV。

请务必学习如何正确使用加密,否则可能会得到不安全的解决方案。

我有一个小的参考项目,你可以尝试使用。

英文:

There are several issues:

byte[] encrypted = cipher.doFinal(input);
return new String(encrypted);

The problen is that you cannot just "stringify" a byte array, you need to represent the byte array in a different format, such as Base64 or Hex. String is intended only for printable characters.

https://stackoverflow.com/questions/9098022/problems-converting-byte-array-to-string-and-back-to-byte-array/9098905

byte[] encrypted = cipher.doFinal(input);
return Base64.getEncoder().encodeToString(encrypted);

And the same way - you need to decode the encoded string into a byte array before decryption.

Edit:

Another issue - you should specify full mode of operation

By default the "AES" parameter should use the CBC mode if IV (initialization vector) is supplied and ECB mode if IV is not defined (at lease this is how Oracle JDK works as far I know).

it is not guaranteed for all runtimes. Which platform/jre are you using? . As your first block of bytes is scrambled I assume the implementation is using random IV (you can use cipher. getIV()) and you have to pass the IV when decrypting.

cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
SecretKey symmetricKey = new 
SecretKeySpec(encryptionParams.getKey(), SYMMETRIC_KEY_ALG);

cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivParamSpec);

For CBC the IV must be a random byte array of length of the AES block size (128 bit =16 bytes) and the common practice is to prepend the IV to the ciphertext.

Please do learn something about using encryption properly, otherwise you may end up with unsecure solution.

I have a small reference project you may try to use.

huangapple
  • 本文由 发表于 2020年9月9日 03:33:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/63800489.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定