【问题标题】:Why do I need two keys for this AES encryption?为什么这个 AES 加密需要两个密钥?
【发布时间】:2014-10-08 21:54:55
【问题描述】:

我正在尝试对某些文本实施 AES 加密,并且我一直在寻找一种解决方案,最终归结为一个用于加密和解密的密码。我在这个网站上找到了一个可行的解决方案:Simple Java AES encrypt/decrypt example

import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class Encryptor {
    public static String encrypt(String key1, String key2, String value) {
        try {
            IvParameterSpec iv = new IvParameterSpec(key2.getBytes("UTF-8"));

            SecretKeySpec skeySpec = new SecretKeySpec(key1.getBytes("UTF-8"),
                    "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string:"
                    + Base64.encodeBase64String(encrypted));
            return Base64.encodeBase64String(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String key1, String key2, String encrypted) {
        try {
            IvParameterSpec iv = new IvParameterSpec(key2.getBytes("UTF-8"));

            SecretKeySpec skeySpec = new SecretKeySpec(key1.getBytes("UTF-8"),
                    "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {

        String key1 = "Bar12345Bar12345"; // 128 bit key
        String key2 = "ThisIsASecretKet";
        System.out.println(decrypt(key1, key2,
                encrypt(key1, key2, "Hello World")));
    }
}

这个算法使用 key1 和 key2 并且不明白为什么他们需要这两个。每个密钥的用途是什么?让 key1 一直保持原样并用个人密码替换 key2 是否安全?

谢谢

【问题讨论】:

  • 为避免字符编码问题,总是在调用String.getBytes()new String() 时指定一个字符集。
  • 在互联网上你会发现很多加密样本,低至 1% 的样本会编译运行,并且会严重损坏或使用不安全。他们中的大多数人都有这些迹象,例如误解密钥和 IV,现在从密钥中知道密码(使用 UTF-8 作为密钥也是愚蠢的,编码可能会将字符编码为多个字节)感谢 dnault 指出它们.现在开始学习加密,不要从互联网上抓取任何随机代码来执行加密。
  • 顺便说一句,我喜欢上面代码中的异常处理。错误?不,null!
  • @owlstead:您会推荐哪个字符集作为密钥?
  • 我相信 owlstead 关于字符集的观点是,当将字符串转换为字节数组时,字符和字节之间不一定存在 1:1 的对应关系。在 UTF-8 中,单个字符最多可以使用 4 个字节进行编码,因此对具有 16 个字符的任意字符串调用 getBytes("UTF-8") 不能保证返回长度为 16 的数组。从密码生成密钥是使用像 PBKDF2 这样的算法。

标签: java encryption aes


【解决方案1】:

'key1' 是您的密钥。在此代码中,字节数组是通过对密码调用 String.getBytes() 获得的。请参阅 this answer 了解为什么不建议这样做,以及一些建议的替代方案。

'key2' 命名错误;它实际上是一个Initialization Vector(或简称“IV”)。这是一个随机的字节序列,可以防止相同的明文总是被转换为相同的密文。

应使用SecureRandom.getBytes() 为每条加密消息生成一个随机IV。对于 AES,IV 应该是 16 字节(128 位)。 IV是not a secret;它应该与密文一起发送,以便接收者可以使用它(连同密钥)来解密消息。

加密后,我建议将 IV 字节添加到密文字节,然后对生成的字节数组进行 Base64 编码。

至于代码的结构,无需将IV传递给encrypt方法; encrypt 方法可以在内部生成 IV。同样,如果密文以 IV 为前缀,则无需将 IV 传递给解密方法;相反,解密方法可以假设消息的前 16 个字节是 IV。

一般而言,仅加密并不能确保消息未被篡改。如果您想检测攻击者何时篡改您的加密消息,您可以apply a Message Authentication Code 将 HMAC 设为 iv + 密文。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 1970-01-01
  • 2016-05-23
  • 2010-09-10
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
相关资源
最近更新 更多