这是Java中加密的最佳/安全方法吗?

Ben*_*193 1 java security aes

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

这是输出:

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

这是代码:

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);      
  }
}
Run Code Online (Sandbox Code Playgroud)

Art*_* B. 5

不,这段代码非常可怕:

  • 您的密钥已修复,然后一个字符串,然后进行哈希处理.这看起来像你key实际上应该是一个密码.单个哈希不足以从密码派生密钥.您需要使用强大的散列方案,如PBKDF2,bcrypt,scrypt和Argon2.一定要使用高成本因子/迭代计数.选择成本是很常见的,因此单次迭代至少需要100ms.了解更多:如何安全地散列密码?

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

  • ECB模式非常糟糕.它是确定性的,因此在语义上不安全.您应该至少使用 CBC CTR等随机模式.

  • 如果没有身份验证,您就有可能无法检测到(密文)对密文的修改.最好对您的密文进行身份验证,以便无法进行填充oracle攻击等攻击.这可以通过GCM或EAX等经过身份验证的模式来完成,也可以通过具有强哈希函数(如SHA-256)的HMAC 进行加密 - 然后 - MAC方案来完成.

由于这些问题,您应该使用库.试试JNCryptor这个库.


The*_*ini 5

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

  • 除非您另行指定,否则您在ECB模式下使用AES .无论底层的密码是什么,ECB模式都是不安全的.有许多安全模式,但通常人们实现CBC模式,这是通过将您更改Algo为"AES/CBC/PKCS5Padding"(实际上是PKCS7填充,Java只是不知道更好)来实现的.然后,您需要通过SecureRandom()选择IV来加密这种方式.这个OWASP示例似乎是正确的(仅供参考 - 在网络上找到的99%的实现在某处都存在安全问题).
  • key不是密钥,而是将密码转换为密钥.你不应该硬编码,但我认为你这样做只是为了证明概念.在任何情况下,问题是使用诸如SHA-1之类的散列函数将密码转换为密钥不是一个好的决定,因为密码往往具有低熵并且可以强制使用.因此,在将密码转换为密钥时,您应该使用专用于抵抗暴力的功能.这些功能包括pbkdf2,bcrypt,scrypt和argon2.有关更多信息,Troy Hunt(一个.Net人)在这种情况下很好地概述了使用SHA-1(或SHA2系列中的任何东西)之类的问题.

另外要记住的是,加密通常不会提供消息完整性.这意味着,仅仅因为您加密了数据并不意味着有人无法对其进行修改,并且您的软件仍然会解密修改后的数据,而不会意识到它已被修改.如果您需要知道您的数据未被修改,那么您将需要添加类似HMAC的内容,否则您将需要切换到GCM等操作模式.

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