我正在创建一个算法,它必须使用JCE和AES加密和解密密码.我将把加密文本保存到数据库中,但是我面临两个问题.第一个问题是,加密文本返回的是奇怪的符号,而不是字母,如"cù"▼=¡£¡?Å♠?¡Ç²?",但它返回正确的普通文本.第二个问题是,算法每次都会返回不同的加密文本,如果我要将加密文本保存到数据库并稍后解密,它还会工作吗?或者我必须将值存储为字节[]或字符串.

public static void main(String[] args) throws Exception {

    byte[] text1 = "welcome back".getBytes();
    byte[] text2 = "hello guys".getBytes();

    KeyGenerator gen = KeyGenerator.getInstance("AES");
    SecretKey key = gen.generateKey();

    Cipher x = Cipher.getInstance("AES");
    x.init(Cipher.ENCRYPT_MODE, key);
    byte[] encryptedText1 = x.doFinal(text1);
    byte[] encryptedText2 = x.doFinal(text2);

    x.init(Cipher.DECRYPT_MODE,key);
    byte[] decryptedText2 = x.doFinal(encryptedText2);
    byte[] decryptedText1 = x.doFinal(encryptedText1);
    System.out.println(new String(encryptedText1));
    System.out.println(new String(encryptedText2));
    System.out.println(new String(decryptedText1));
    System.out.println(new String(decryptedText2));
}

结果如下:

c~ù▼=¡£¡?Å♠?¡Ç²?
àÉ?<-??Yò*?b?]?
welcome back
hello guys

我能做些什么来解决这些问题吗?非常感谢你.

推荐答案

第二个问题

第二个问题是,算法每次都会返回不同的加密文本,如果我将加密文本保存到数据库中,稍后再解密,它还会工作吗?

我不完全清楚问题出在哪里.至少对于您问题中的代码,对于same个密钥和same个输入字节,您将得到相同的加密字节.但在加密和解密时,必须使用相同的密钥.这意味着您需要(安全地!)把 keys 放在某个地方.

如果您担心每次运行示例代码时会看到不同的输出,那是因为每次生成new key.

但这可能会变得复杂,我想说的是,我不是一个密码专家.我认为要正确使用对称加密,您需要避免相同的纯文本导致相同的密码文本.AES也有不同的模式,需要不同的方法.我的观点是,你要么做a lot项研究,要么雇一位专家(如果不是两者都做的话).


第一个问题

第一个问题是,加密文本返回的是奇怪的符号,而不是字母,如"cù"▼=¡£¡?Å♠?¡Ç²?,但它返回正确的普通文本

这些"奇怪的符号"并不表示存在问题.当你试图将一个随机的字节序列解码成字符时,你应该看到这种情况.

您的代码首先将encodes个字符序列(String)转换为一个字节序列(byte[]).然后,您将encrypt个字节序列,并收到一个新的基本上是random个字节序列.加密的字节不再代表字符序列.试图将这些加密字节转换为字符序列可以产生所用字符集中的任何内容,包括"回退/错误"字符.不过这没关系,因为加密的字节也不代表字符序列.

当你输入decrypt个加密的字节时,你会得到原始的字节序列.当然,解密的字节确实代表一个字符序列,因此可以将decoded个字节转换为这些字符.注意:编码和解码纯文本时必须使用相同的字符集,以保证正确性.为了确保这一点,您应该指定一个字符集.例如:

// encode
byte[] bytes = "Hello, World!".getBytes(StandardCharasets.UTF_8);
// decode
String string = new String(bytes, StandardCharsets.UTF_8);

注意,这并不试图将encrypted个字节的序列设置为decode.它解码原始字节,与解密加密字节后返回的字节相同.

如果您想将加密的字节视为String,那么将这些字节编码为Base64是一种常见的解决方案.Base64还可以用于其他非字符字节,例如图像文件,甚至用于表示字符的字节.

byte[] bytes = "Hello, World!".getBytes(StandardCharasets.UTF_8);
byte[] encryptedBytes = encrypt(bytes);
String base64Text = Base64.getEncoder().encodeToString(encryptedBytes);

注意,如果存储base64Text,那么在进行解密时,首先需要将Base64字节解码为原始encrypted字节.

Java相关问答推荐

我们如何直接使用kerminldap服务票证来通过ldap进行身份验证并形成LDAP上下文

Cucumber TestNG Assert失败,出现java. lang. Numbercycle异常

如何在访问完所有文件后加入所有线程?

确定Java中Math.Ranb()输出的上限

使用Testcontainers与OpenLiberty Server进行集成测试会抛出SocketException

如何修复IndexOutOfBoundsException在ClerView适配器的onRowMoved函数?

Spark上下文在向Spark提交数据集时具有内容,但Spark在实际构建它时发现它为空

尽管通过中断请求线程死亡,但线程仍将继续存在

为什么Collectors.toList()不能保证易变性

在Ubuntu 23.10上使用mp3创建JavaFX MediaPlayer时出错

Spring Boot中的应用程序.properties文件中未使用的属性

EXCEL中的公式单元格显示#NAME?

S数学.exp的相同错误保证也适用于StrictMath.exp吗?

为什么这种递归会有这样的行为?

使用迭代器遍历HashMap不会因IF条件而停止

IntelliJ IDEA中的JavaFX应用程序无法在资源中找到CSS文件

在Java中比较同一多维数组的两个不同的字符串元素

没有Google Play服务,Firebase Auth无法工作

Spring Mapstruct如何获取Lazy初始化实体字段的信息?

元音变音字符:如何在 Java 中将Á<0x9c>转换为Ü?