Java AES-256加密:从我的固定字符串生成256位(32字节)的密钥

Java AES-256加密:从我的固定字符串生成256位(32字节)的密钥,java,encryption,cryptography,aes,Java,Encryption,Cryptography,Aes,我想用AES256加密文本,我想用我的电子邮件test@gmail.com作为密钥进行加密 这就是我所尝试的: String key = "test@gmail.com"; SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); byte iv[] = SOME_RANDOM_32_BYTES; IvParameterSpec ivSpec = new IvParameterSpec(iv); Ciph

我想用AES256加密
文本
,我想用我的电子邮件
test@gmail.com
作为
密钥进行加密

这就是我所尝试的:

String key = "test@gmail.com";
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

byte iv[] = SOME_RANDOM_32_BYTES;
IvParameterSpec ivSpec = new IvParameterSpec(iv);

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

byte[] encryptedResult = cipher.doFinal(text.getBytes("UTF-8"));
当我运行上述代码时,我得到了InvalidKeyException:

java.security.InvalidKeyException: Key length not 128/192/256 bits.

我在网上查过,原因是我的密钥不是128/192/256位。我的问题是,如何从电子邮件字符串
test@gmail.com

您可以散列密钥字符串(
test@gmail.com
)使用SHA256将其设置为256bit值

MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(yourEmail.getBytes());
byte[] encryptionKey = md.digest();

这可能有多种原因。其中一个在下面。 通常,当您的JRE中没有更新策略时,会出现此错误。
Java默认为AES提供128,对于256,我们必须使用Java提供的新策略。

您不应该烘焙自己的加密(除非您对此非常了解。)

您应该使用现有(且经过审核的)加密库

另外,您不应使用可猜测的字符串(如您的电子邮件地址)作为密码。请查看有关如何选择好密码的建议

我已经说过了,下面是更多的细节

实现基于密码的加密的正确方法是使用KDF()从密码生成加密密钥。以下是一些可用于此任务的KDF:,和

关键派生函数包括防御已知攻击的机制,如彩虹表和字典攻击,尤其是“salt”和功因子。Argon2等现代KDF还试图通过使用更适合该任务的硬件来防止攻击者获得优势

一般来说,这是如何使用的:

  • 选择工作系数(您能承受的最大值)
  • 使用一种特殊的方法来产生盐
  • 使用您选择的密码、salt和功因子生成加密密钥和密钥
  • 使用
  • 使用生成的加密密钥加密要保护的数据
  • 使用生成的密码计算加密消息的密码
  • 序列化salt、功因子、计算数据和加密数据。(可选地,指示所选加密方案的标识符,如果这些标识符不固定,也应包括在内。)
  • 加密消息是在步骤7中生成的序列化数据。如果任何一个步骤出错(这很容易),您的加密代码可能会以可怕的方式被破坏

    也许现在你明白了为什么应该使用现有的库了


    注意:当前的最佳实践是使用AEAD(关联数据的身份验证加密),而不是如上所述的加密然后MAC。如果您感兴趣,请查看此链接:我不打算在此讨论。

    可能重复@KonstantinV.Salikhov,我检查了您提供的链接,他在那里询问如何使用他的密码生成密钥,但在公认的解决方案中,我没有看到他的密码在哪里使用?@user842225关于链接,假设存在一个局部变量
    password
    。它用于以下行:
    KeySpec spec=new-PBEKeySpec(密码,salt,65536256)。当然,这个可能的副本假设密码是秘密的——在你的情况下,它不会是。这是一个错误的建议!正确的方法是使用密钥派生函数派生密钥。