为什么AES产生不同的结果以及为什么DES不产生

时间:2019-03-21 12:07:48

标签: java encryption aes des

我正在尝试更改现有项目的加密算法。但是我有点困惑。当我使用“ 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”实现了不同的结果。

1 个答案:

答案 0 :(得分:2)

  • PBEWithHmacSHA512AndAES_256PBEWithMD5AndDES这两种算法首先通过处理密码,盐和迭代计数(使用HmacSHA512MD5来生成加密密钥。 ,然后使用此密钥和CBC-mode加密纯文本(分别使用AES-256DES)。初始化Cipher实例后,将生成CBC-模式所需的伪随机initialization vector(IV)。

  • PBEWithHmacSHA512AndAES_256的上下文中,至少使用{{3},使用最高安装优先级的提供程序的SecureRandom实现来生成IV。 }}-方法在代码中使用(请注意,Cipher#init()-方法有多个重载,并且SecureRandom-实例也可以显式传递)。即每次Cipher初始化时,都会生成 new (随机)IV,因此,即使对于相同的纯文本,加密的文本也始终是不同的。因此,示例中的加密文本会在这种情况下发生变化。

  • PBEWithMD5AndDES的上下文中,IV仅由密码,盐,迭代次数(当然还有MD5散列)确定。 -算法本身)。因此,IV和加密文本在重复的情况下不会更改(前提是密码,密码,迭代次数等相同)。因此,示例中的加密文本在这种情况下不会更改。

  • 在密码初始化期间生成新的随机IV对于IV的以下要求是有意义的:出于安全原因,CBC模式的IV(顺便说一句也适用) (其他模式)Cipher#init()。此外,IV必须是不可预测的。

  • PBEWithMD5AndDESmay only be used once under the same key

编辑:

  • 如今,出于安全考虑,IV的使用是标准的。在互联网上可以找到有关此主题的很多信息,例如deprecated。在下文中,我只会描述一些基本的东西。

  • 用于加密的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字节)。

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

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

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

  • 注意,关于IV,必须考虑一些要点,例如使用没有IV的模式(例如ECB),使用仅由0值组成的IV,使用可预测的IV或在同一密钥下多次使用IV等,通常会大大降低安全性,例如,请参见Generating random IV for AES in Java