【发布时间】:2021-09-27 04:31:28
【问题描述】:
我之前有一个关于在 Java 中实现加密和使用 CryptoJS 解密的问题已回答 here。在那个问题的 cmets 中,有人建议我实现某种密钥派生函数,而不是直接使用“秘密”。我的 CheckMarx 报告中也建议使用盐来使加密更加安全。这就是我从 Java 端加密的方式,连接 myKey 和 salt 的字节:
package aes;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AesEncryption {
private static SecretKeySpec secretKey;
private static byte[] key;
public static void setKey(String myKey) {
MessageDigest sha = null;
try {
byte[] salt = generateSalt(16);
key = Bytes.concat(myKey.getBytes(), salt);
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKey = new SecretKeySpec(key, "AES");
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static String encrypt(String strToEncrypt, String secret) {
try {
setKey(secret);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
}
catch (Exception e)
{
System.out.println("Error while encrypting: " + e.toString());
}
return null;
}
private static byte[] generateSalt(int length) {
Random r = new SecureRandom();
byte[] salt = new byte[length];
r.nextBytes(salt);
return salt;
}
}
我现在遇到的麻烦是如何使用新添加的盐正确解密。这是从 JavaScript 端调用的解密函数:
aesDecrypt: (encryptedValue, aesSecret) => {
var sha1Hash = CryptoJS.SHA1(aesSecret)
var secretAesKey = CryptoJS.lib.WordArray.create(sha1Hash.words.slice(0, 16 / 4));
var bytes = CryptoJS.AES.decrypt(encryptedValue, secretAesKey, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
var originalValue = bytes.toString(CryptoJS.enc.Utf8);
return originalValue
}
既然添加了盐,我如何才能从字节数组中仅导出 secretAesKey?
【问题讨论】:
-
你必须使用相同的盐
-
在有效载荷中传递盐是常见的事情吗? @g00se
-
为什么不使用专为此目的设计的可靠的密钥派生函数,如 PBKDF2。这比摘要更安全(即使使用盐)。此外,SHA1 和 ECB 也不是安全的选择。
-
你可以在网上找到很多例子,例如Java/SCEE。该解决方案除了使用 PBKDF2 之外,还使用了一种与随机 IV/nonce 相结合的安全模式。
-
CryptoJS 不支持 GCM 模式。但是该链接提供了跨平台实现,也适用于 JavaScript 和各种 JavaScript 库(SJCL、WebCrypto API、NodeJS)。 here。如果你想使用 CryptoJS,你必须将模式更改为例如加拿大广播公司。然后必须由您自己实施身份验证(例如使用 MAC)。
标签: javascript java encryption aes