大家好我有java代码为我生成三重加密代码现在我试图在javascript上使用crypto-js,但两个代码提供不同的键我不知道为什么以及如何获得相同的密钥在这里是我的代码
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));
key =“3ad5485e60a4fecd” 消息= “textToEncrypt”
加密来自java chKL5NVtBXesEKfNIokpdw ==
加密来自javascript chKL5NVtBXeTFwswp882Vw ==
任何人都可以帮助我,或者让我简要了解为什么会这样。
答案 0 :(得分:1)
这两个代码有很多不同之处:
您可能正在使用不同的modes of operation。 Java正在使用ECB而JS正在使用CBC。
始终使用完全限定的密码字符串。
Cipher.getInstance("TripleDES");
可能会导致不同的密码,具体取决于默认的安全提供程序。它最有可能导致"TripleDES/ECB/PKCS5Padding"
,但不一定如此。如果它发生变化,您将失去不同JVM之间的兼容性。供参考:Java default Crypto/AES behavior
此外,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
你的IV很奇怪。这可能很容易:
var ivHex = CryptoJS.enc.Hex.parse('0000000000000000'); // 8 bytes
这可以用于测试,但在生产中,IV必须是不可预测的(读取:随机)。不要使用静态IV,因为这会使密码具有确定性,因此在语义上不安全。观察密文的攻击者可以确定何时发送相同的消息前缀。 IV不是秘密,因此您可以将其与密文一起发送。通常,它只是在密文之前加上密码并在解密前切掉。
我建议您丢弃此代码(仅提供80位安全性并使用错误的默认值)并使用一个库,例如RNCryptor。
绝不使用ECB mode 。它是确定性的,因此在语义上不安全。您应该至少使用CBC或CTR等随机模式。最好对您的密文进行身份验证,以便像padding oracle attack这样的攻击是不可能的。这可以使用经过身份验证的模式(如GCM或EAX)或encrypt-then-MAC方案来完成。
现在不要使用Triple DES。即使你使用192位的最大密钥大小,它也只能提供112位的安全性。如果使用较短的密钥大小,则它仅提供56或57位的安全性。 AES会更快(处理器具有特殊的AES-NI指令集),并且具有128位的最低密钥大小更加安全。使用3DES对最大密文大小也有实际限制。请参阅Security comparison of 3DES and AES。