大家好,我有 Java 代码,它为我生成三重 DES 加密代码,现在我正在尝试使用 crypto-js 在 JavaScript 上使用它,但两个代码都提供不同的密钥我不知道为什么以及如何获得相同的密钥这是我的代码
public String _encrypt(String message) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
System.out.println(bytesToHex(keyBytes));
SecretKey key = new SecretKeySpec(keyBytes, "TripleDES");
Cipher cipher = Cipher.getInstance("TripleDES");
cipher.init(Cipher.ENCRYPT_MODE,key);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);
System.out.println(bytesToHex(buf));
byte [] base64Bytes = Base64.encodeBase64(buf);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
public static String bytesToHex(byte[] in) {
final StringBuilder builder = new StringBuilder();
for(byte b : in) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
public String _decrypt(String encryptedText) throws Exception {
byte[] message = Base64.decodeBase64(encryptedText.getBytes("utf-8"));
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher decipher = Cipher.getInstance("DESede");
decipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
和我的 java 脚本代码如下
key = CryptoJS.SHA1(key);
console.log(key.toString());
var iv = String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0);
var ivHex = CryptoJS.enc.Hex.parse(iv);
var options = {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: ivHex
};
var encrypted = CryptoJS.TripleDES.encrypt(pt, key, options);
var encryptedBase64 = encrypted.toString();
console.log(encryptedBase64);
var ct = {
ciphertext: CryptoJS.enc.Base64.parse(encryptedBase64)
};
var decrypted = CryptoJS.TripleDES.decrypt(ct, key, options);
console.log(decrypted.toString(CryptoJS.enc.Utf8));
密钥 ="3AD5485E60A4FECD" 消息="文本加密">
encrypted 从 java chKL5NVtBXesEKfNIokpdw==
加密从javascript chKL5NVtBXeTFwswp882Vw==
谁能帮助我或给我简要的知识为什么会发生这种情况。
这两个代码存在多个差异:
-
您可能正在使用不同的操作模式。Java正在使用ECB,JS正在使用CBC。
始终使用完全限定的密码字符串。
Cipher.getInstance("TripleDES");
可能会导致不同的密码,具体取决于默认安全提供程序。它最有可能导致"TripleDES/ECB/PKCS5Padding"
,但并非必须如此。如果它发生变化,您将失去不同 JVM 之间的兼容性。供参考:Java 默认加密/AES 行为此外,PKCS#5 填充和PKCS#7 填充在所有意图和用途上都是相等的。
-
您的密钥可能不同。SHA-1 哈希的输出为 20 个字节,但完整的 3DES 密钥长度为 24 个字节。
Arrays.copyOf(digestOfPassword, 24);
用 0x00 字节值填充剩余的 4 个字节。在CryptoJS中,你直接将短键传递到encrypt
函数中。您需要用 0x00 个字节填充剩余的字节。由于CryptoJS在WordArray
中处理二进制数据,这可以通过以下方式完成:key = CryptoJS.SHA1(key); key.sigBytes += 4; // 32 bit more marked key.words.push(0); // 32 bit of zeros
-
你的静脉注射很奇怪。这可能很容易:
var ivHex = CryptoJS.enc.Hex.parse('0000000000000000'); // 8 bytes
这可以用于测试,但在生产中,IV必须是不可预测的(阅读:随机)。不要使用静态 IV,因为这会使密码具有确定性,因此在语义上不安全。观察密文的攻击者可以确定之前发送相同消息前缀的时间。IV不是秘密的,因此您可以将其与密文一起发送。通常,它只是在密文前面加上并在解密之前切掉。
我建议你扔掉这段代码(只提供 80 位的安全性并使用糟糕的默认值)并使用一个库,例如 RNCryptor。
安全注意事项
切勿使用欧洲央行模式。它是确定性的,因此在语义上不安全。您至少应该使用随机模式,如 CBC 或 CTR。最好对密文进行身份验证,以便不可能进行填充预言机攻击等攻击。这可以通过 GCM 或 EAX 等经过身份验证的模式或先加密 MAC 方案来完成。
现在不要使用三重DES。即使您使用 192 位的最大密钥大小,它最多也只能提供 112 位的安全性。如果使用较短的密钥大小,则它仅提供 56 或 57 位安全性。AES会更快(处理器具有特殊的AES-NI指令集),并且使用128位的最低密钥大小甚至更安全。3DES 的最大密文大小也有实际限制。请参阅 3DES 和 AES 的安全性比较。