【问题标题】:Is this the best/secure method for encryption in Java?这是Java加密的最佳/安全方法吗?
【发布时间】:2017-08-23 10:11:13
【问题描述】:

我是安全方面的新手,我想知道我是否可以让我的程序变得更好,比如更改或添加一些东西以使其更好(更安全)
(我对程序输出有疑问)

这是输出:

Encrypted Message: +g@þóv«5Ùû`ž   
keybyte: [B@71e7a66b   
Original string: Message   
Original string (Hex): [B@2ac1fdc4

代码如下:

public class AES {

  public static void main(String ... args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
    final String Algo="AES";
    String key = "aaaaaaaaaaaaaaaa";
    byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);

    MessageDigest sha= MessageDigest.getInstance("SHA-1"); 
    keyBytes=sha.digest(keyBytes);
    keyBytes=Arrays.copyOf(keyBytes, 16);

    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, Algo);
    Cipher cipher = Cipher.getInstance(Algo);
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
    byte[] ciphertext = cipher.doFinal("Message".getBytes());
    System.out.println("Encrypted Message: " +new String(ciphertext));

    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    byte[] original = cipher.doFinal(ciphertext);
    String originalString = new String(original);
    System.out.println("keybyte: "+keyBytes);
    System.out.println("Original string: " + originalString + "\nOriginal string (Hex): " +original);      
  }
}

【问题讨论】:

  • “更好”是什么意思?
  • 使加密/解密更安全(我应该使用 keyGenerator 代替吗?)

标签: java security aes


【解决方案1】:

您的实现至少存在两个问题:

  • 除非您另外指定,否则您将在 ECB mode 中使用 AES。无论引擎盖下的密码是什么,ECB 模式都不安全。有许多安全模式,但通常人们实现 CBC 模式,这是通过将您的 Algo 更改为“AES/CBC/PKCS5Padding”来实现的(这实际上是 PKCS7 填充,Java 只是不知道更好)。然后,您需要通过 SecureRandom() 选择一个 IV 来加密。这个OWASP example 似乎做得对(仅供参考——您会在网络上找到的 99% 的实现在某处存在安全问题)。
  • 您的key 不是密钥,而是正在变成密钥的密码。您不应该对此进行硬编码,但我认为您这样做只是为了概念证明。在任何情况下,问题在于使用诸如 SHA-1 之类的哈希函数将密码转换为密钥不是一个好的决定,因为密码往往具有低熵并且可以被暴力破解。因此,在将密码转换为密钥时,您应该使用专门用于抵抗暴力破解的功能。此类函数包括 pbkdf2、bcrypt、scrypt 和 argon2。欲了解更多信息,Troy Hunt(.Net 专家)提供了good overview,说明在这种情况下使用 SHA-1(或 SHA2 系列中的任何东西)等问题。

要记住的另一件事是加密通常不提供消息完整性。这意味着仅仅因为您已加密数据并不意味着有人无法修改它,您的软件仍会解密修改后的数据而不会意识到它已被修改。如果您需要知道您的数据没有被修改,那么您需要添加诸如 HMAC 之类的东西,否则您需要切换到诸如 GCM 之类的操作模式。

最后,AES 是安全性的绝佳选择。但是你需要在正确的模式下使用它,你需要正确地实现它,你需要了解你是否需要的不仅仅是加密。

【讨论】:

  • 非常感谢您的所有时间和帮助。这对我来说是很多新信息。由于我刚开始学习安全性,我发现在我目前的水平上使用带有迭代的 Salt 更容易。我期待在下一个项目中使用您的提示。非常感谢
【解决方案2】:

不,这段代码很糟糕:

  • 您的 密钥是固定的,然后是一个经过哈希处理的字符串。在我看来,您的key 实际上应该是密码。单个哈希不足以从密码中派生密钥。您需要使用强散列方案,如 PBKDF2、bcrypt、scrypt 和 Argon2。确保使用高成本因数/迭代次数。通常选择成本以使单次迭代至少需要 100 毫秒。查看更多:How to securely hash passwords?

  • 始终使用完全限定的密码字符串。 Cipher.getInstance("AES"); 可能会产生不同的密码,具体取决于默认的安全提供程序。它最有可能导致"AES/ECB/PKCS5Padding",但并非必须如此。如果它发生变化,您将失去不同 JVM 之间的兼容性。供参考:Java default Crypto/AES behavior

  • ECB mode 很糟糕。它是确定性的,因此在语义上不安全。您至少应该使用CBCCTR 之类的随机模式。

  • 如果没有身份验证,您可能无法检测到对密文的(恶意)修改。最好对您的密文进行身份验证,以免像padding oracle attack 这样的攻击是不可能的。这可以通过 GCM 或 EAX 等经过身份验证的模式来完成,也可以通过具有强哈希函数(如 SHA-256)的 HMAC 使用 encrypt-then-MAC 方案来完成。

由于这些问题,您应该改用库。试试JNCryptorthis library

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多