【问题标题】:How to generate an AES key with AES/CBC/PKCS5Padding for encrypting and decrypting如何使用 AES/CBC/PKCS5Padding 生成用于加密和解密的 AES 密钥
【发布时间】:2020-02-24 05:17:45
【问题描述】:

我正在尝试使用此代码创建 AES 密钥

    public static SecretKey generateSecretKey() {

        KeyGenerator generator;
        try {

            generator = KeyGenerator.getInstance(StaticHandler.AES_KEY_MODE); // Is "AES"
            generator.init(StaticHandler.AES_KEY_SIZE); // The AES key size in number of bits // Is "128"

            return generator.generateKey();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

但是使用此代码进行加密/解密


    public static String encrypt(String data, SecretKey secret, Charset charset) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secret);

            return new String(cipher.doFinal(data.getBytes()), charset);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static String decrypt(String data, @NonNull SecretKey secret, Charset charset) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secret);

            return new String(cipher.doFinal(data.getBytes()), charset);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

得到错误 java.security.InvalidKeyException: Parameters missing

我猜我需要添加一些盐,虽然我不知道如何使用生成的密钥来做到这一点。我想远离生成密码,但如果它是安全生成的密码,我不介意。

编辑:只是事后考虑,如果我通过网络发送数据包,我应该使用 GCM 还是 CBC 加密?请记住,我使用的是随机生成的密钥,我不会将它们保留在会话中,每个客户端和服务器会话随机生成。

【问题讨论】:

标签: java encryption cryptography


【解决方案1】:

不,您不需要盐,而且您的密钥实际上很好。 CBC 模式需要一个 IV(初始化向量)see wikipedia,并且每个加密数据的 IV 应该不同,但每次解密必须使用与相应加密相同的值。 (补充)对于 CBC,虽然不是其他一些模式,但对于安全性来说,IV 不能被对手预测也是至关重要的;实现唯一性和不可预测性的最简单和最常见的方法是使用 secure 随机数(又名位)生成器,例如 Java 的 SecureRandom。如果您想了解其他方法,那并不是真正的编程问题,而是更适合已存在多个 Q 的 crypto.SX 或 security.SX。

您可以显式生成 IV 并将其指定为加密和解密,或者允许加密操作自己生成 IV,从 encrypt Cipher 中获取它,并将其指定给解密 Cipher。在任何一种情况下,加密器都必须提供解密器将使用的值;一种常见的方法是简单地将 IV 与密文连接起来(使得它们很容易保持正确匹配),但还有其他关于加密和安全性的方法进行了讨论。请参阅名为“初始化密码对象”(方法声明框后的两段)和“管理算法参数”部分中的 https://docs.oracle.com/en/java/javase/11/security/java-cryptography-architecture-jca-reference-guide.html


另外不要将密文存储在String中。 Java String 旨在处理有效字符而不是任意字节。将密文“解码”为字符串并将其“编码”回二进制几乎总是会丢失或更改某些数据,特别是如果您允许字符集在两端不同,并且使用现代密码学对密文进行任何更改将销毁您的全部或大部分数据。由于密文个字节,最好将其处理为byte[];如果这是不可能的,因为您想将它放在像 URL 这样的 is 字符中,请使用旨在将任意字节编码为文本以便正确恢复它们的众多方案之一:base64 ( 3 或 4 个主要变体,以及许多次要变体)、base32、十六进制/base16、URL 'percent' 编码、MIME 引用打印、yencode、Kermit、PPP 等。j8+ java.util.Base64 提供更新的 base64 变体(即不是 uuencode )。

相反,尽管现代加密中的“明文”实际上可以是任何形式的数据,但如果您的数据确实是文本并且属于String,则您应该在加密之前使用合适的字符集对其进行编码,并在解密后使用 same 字符集进行解码,即

 byte[] ctext = encCipher.doFinal (input.getBytes(charset));
 ...
 String output = new String (decCipher.doFinal (ctext), charset);

虽然“最佳”字符集可能会因您的数据而异,但如果您不知道数据将是什么或不想费心分析它,UTF-8 对于大多数文本数据来说相当不错,并且非常受欢迎和标准。

【讨论】:

  • 您能否补充一下 IV 必须是不可预测的?
  • 我本来打算使用 byte[] 而不是 string,但首先我希望加密能够正常工作。如果我得到它与您的答案相符,如果我记得的话,我会将其设置为已解决。
  • @kelalaka:很好。我有点着急,这让我忘记了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2021-08-13
  • 1970-01-01
  • 2013-08-11
  • 2021-01-05
相关资源
最近更新 更多