【问题标题】:Why AES Produce Different result and Why DES not Produce为什么 AES 产生不同的结果以及为什么 DES 不产生
【发布时间】:2019-08-12 06:55:28
【问题描述】:

我正在尝试更改现有项目的加密算法。但我有点困惑。当我使用“PBEWithHmacSHA512AndAES_256”作为参数时,它会产生不同的结果,但是当我使用“PBEWithMD5AndDES”作为参数时,它会产生相同的结果。我的功能是:

 public static synchronized String encrypt1(final String textToEncrypt, final String pathPublicKey) throws Exception {
    final KeySpec pbeKeySpec = new PBEKeySpec(DbKeyHandler.getDbKey(pathPublicKey).toCharArray());
    final SecretKey pbeKey = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(pbeKeySpec);
    // Prepare the parameter to the ciphers
    final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
    final Cipher cipher = Cipher.getInstance(pbeKey.getAlgorithm());

    // Create the ciphers
    cipher.init(Cipher.ENCRYPT_MODE, pbeKey, paramSpec);

    // Encode the string into bytes using utf-8
    final byte[] utf8 = textToEncrypt.getBytes("UTF8");

    // Encrypt
    final byte[] enc = cipher.doFinal(utf8);

    // Encode bytes to base64 to get a string
    return new sun.misc.BASE64Encoder().encode(enc);
}


public static synchronized String encrypt2 (final String textToEncrypt, final String pathPublicKey) throws Exception {
    final KeySpec pbeKeySpec = new PBEKeySpec(DbKeyHandler.getDbKey(pathPublicKey).toCharArray());
    final SecretKey pbeKey = SecretKeyFactory.getInstance("PBEWithHmacSHA512AndAES_256").generateSecret(pbeKeySpec);
    // Prepare the parameter to the ciphers
    final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
    final Cipher cipher = Cipher.getInstance(pbeKey.getAlgorithm());

    // Create the ciphers
    cipher.init(Cipher.ENCRYPT_MODE, pbeKey, paramSpec);

    // Encode the string into bytes using utf-8
    final byte[] utf8 = textToEncrypt.getBytes("UTF8");

    // Encrypt
    final byte[] enc = cipher.doFinal(utf8);

    // Encode bytes to base64 to get a string
    return new sun.misc.BASE64Encoder().encode(enc);
}

任何建议、想法都会帮助我弄清楚这里发生了什么。

这也是产生不同的结果:

    KeyStore keyStore = KeyStore.getInstance("JCEKS");
    keyStore.load(new FileInputStream((pathOfJKSfile)), password.toCharArray());
    Key key = keyStore.getKey(keyName, keyPass.toCharArray());
    byte[] raw = key.getEncoded();
    SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "PBEWithHmacSHA512AndAES_256");
    final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);

    final Cipher cipherEncrypt = Cipher.getInstance(ALGORITHM);
    cipherEncrypt.init(Cipher.ENCRYPT_MODE, secretKeySpec, paramSpec);

    final byte[] enc = cipherEncrypt.doFinal(messageBytes);
    System.out.println( new sun.misc.BASE64Encoder().encode(enc));

而且我知道 cipher.init() 使用“JceSecurity.RANDOM”来产生不同的结果。

【问题讨论】:

    标签: java encryption aes des


    【解决方案1】:
    • PBEWithHmacSHA512AndAES_256PBEWithMD5AndDES 这两种算法首先通过处理密码、盐和迭代计数(分别使用 HmacSHA512MD5)生成加密密钥,然后加密明文使用此键和CBC-mode 的文本(分别为AES-256DES)。初始化Cipher-instance 时,会生成CBC- 模式所需的伪随机initialization vector (IV)。

    • PBEWithHmacSHA512AndAES_256 的上下文中,IV 是使用最高优先级已安装提供程序的SecureRandom 实现生成的,至少对于Cipher#init() 中使用的方法代码(注意Cipher#init()-方法有几个重载,SecureRandom-instance 也可以显式传递)。 IE。每个Cipher-initialization 都会生成一个new(随机)IV,因此加密文本总是不同的,即使对于相同的纯文本也是如此。出于这个原因,您示例中的加密文本会在这种情况下发生变化。

    • PBEWithMD5AndDES 的上下文中,IV 由密码、盐、迭代次数(当然还有 MD5-hash-algorithm 本身)确定.因此,IV和密文在重复的情况下不会改变(前提是密码、盐、迭代次数等相同)。因此,您示例中的加密文本在此上下文中不会更改。

    • 在密码初始化期间生成新的随机 IV 对于 IV 的以下要求是有意义的:出于安全原因,CBC-mode 中的 IV(顺便说一句,这也适用于其他模式)may only be used once under the same key。此外,IV 必须是不可预测的。

    • PBEWithMD5AndDESdeprecated

    编辑:

    • 如今,IV 的使用已成为标准(出于安全原因)。可以在 Internet 上找到有关此主题的大量信息,例如here。下面我只介绍一些基本的东西。

    • 用于加密的 IV 必须以某种方式存储,因为它是解密所必需的。 IV 不必保密,因此它通常与加密数据连接(例如在加密数据之前)并与它们一起存储。在解密期间,两个部分都可以分开,因为 IV 的长度是已知的(AES 为 16 字节)。例如,对于加密方法中的连接,使用如下内容(让 ivenc 分别是具有 IV 和加密数据的字节数组):

      byte[] result = new byte[enc.length + iv.length];
      System.arraycopy(iv, 0, result, 0, iv.length);
      System.arraycopy(enc, 0, result, iv.length, enc.length);
      

      以及在解密方法中对应的对应项(请记住,AES 中 IV 的长度是 16 字节)。

    • 在加密方法中,IV 可以通过Cipher#getIV() 确定(这当然必须在调用Cipher#init() 之后发生)。

    • 在解密方法中,您必须将 IV 传递给 PBEParameterSpec-ctor(例如,让 iv 成为带有 IV 的字节数组):

      IvParameterSpec ivSpec = new IvParameterSpec(iv); 
      AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount, ivSpec);
      
    • IV 的生成也可以在Cipher-class 之外进行,参见例如Generating random IV for AES in Java。然后,您必须以与上述解密方法相同的方式在加密方法中传递该 IV。

    • 注意,与 IV 相关的一些要点必须考虑,例如使用没有 IV 的模式(例如 ECB),使用仅由 0-values 组成的 IV,使用可预测的 IV 或在同一密钥下多次使用 IV 等。总体上会大大降低安全性,请参见例如here!

    【讨论】:

    • 谢谢@Topaco。我知道 PBEWithMD5AndDES 已弃用。如果每次加密都会产生不同的结果,我该如何解密密码以供进一步使用。例如,属性文件包含加密密码,我将在我的应用程序中多次使用它。
    • 我已经扩展了我的答案,请参阅我的答案的编辑部分。
    • 非常感谢托帕科。我用你的建议解决了我的问题。祝你有美好的一天。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 2021-09-09
    • 2017-02-21
    • 2014-10-18
    • 1970-01-01
    相关资源
    最近更新 更多