下面是Java脚本代码
var keySize = 256;
var ivSize = 128;
var iterations = 1000;
var message = "Hello World";
var password = "secret";
var ivSfmc = "4963b7334a46352623252955df21d7f3";
var saltSFmc = "e0cf1267f564b362";
var encryptedString = "";
function encrypt(msg, pass) {
salt = CryptoJS.enc.Hex.parse(saltSFmc);
iv = CryptoJS.enc.Hex.parse(ivSfmc);
var key = CryptoJS.PBKDF2(pass, salt, {
keySize: keySize / 32,
padding: CryptoJS.pad.Pkcs7,
iterations: iterations
});
var encrypted = CryptoJS.AES.encrypt(msg, key, {
iv: iv,
mode: CryptoJS.mode.CBC
});
encryptedString = encrypted.toString();
return encryptedString;
}
function decrypt(transitmessage, pass) {
iv = CryptoJS.enc.Hex.parse(ivSfmc);
salt = CryptoJS.enc.Hex.parse(saltSFmc);
var key = CryptoJS.PBKDF2(pass, salt, {
keySize: keySize / 32,
iterations: iterations
});
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
})
return decrypted;
}
var encrypted = encrypt(message, password);
var decrypted = decrypt(encryptedString, password);
输出
加密:ndLxNDM5BwSeqNfXAQ5P3g==
解密:你好世界
下面是Swift代码,多次交叉验证等效性,但结果仍然不同
import UIKit
import CryptoSwift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
do {
let password: [UInt8] = Array("secret".utf8)
let salt = Array(hex: "e0cf1267f564b362")
/* Generate a key from a `password`. Optional if you already have a key */
let key = try PKCS5.PBKDF2(
password: password,
salt: salt,
iterations: 1000,
keyLength: 32, /* AES-256 */
variant: .sha256
).calculate()
/* Generate random IV value. IV is public value. Either need to generate, or get it from elsewhere */
let iv = Array(hex: "4963b7334a46352623252955df21d7f3")
/* AES cryptor instance */
let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7)
/* Encrypt Data */
let inputData = Array("Hello World".utf8)
let encryptedBytes = try aes.encrypt(inputData)
let encryptedData = Data(encryptedBytes)
print(encryptedData.base64EncodedString())
/* Decrypt Data */
let decryptedBytes = try aes.decrypt(encryptedData.bytes)
let decryptedData = Data(decryptedBytes)
print(String(bytes: decryptedData, encoding: .utf8)!)
} catch ( let error) {
print(error)
}
}
}
输出
加密:n05I/Ub/GC/mzQRmlNTl7w==
解密:你好世界
由于两个级别的加密值不同,我无法解密从 CryptoJS 加密收到的字符串,经过大量试验后我仍然陷入困境,无法理解为什么存在差异,即使两端都使用了确切的值,任何帮助或建议将不胜感激。谢谢!
在这两个代码中应用了不同的摘要,这就是密文不同的原因(对于相同的输入数据:salt、IV、消息和密码):
在 CryptoJS 代码中,未明确指定 PBKDF2 的摘要,因此使用 CryptoJS 默认 SHA1。
在 Swift 代码中,PBKDF2 的摘要被显式指定为 SHA256(这也是 CryptoSwift 默认值)。
为了使密文相同,必须使用相同的摘要。
因此,在 CryptoJS 代码中,应用 SHA-256:
...
var key = CryptoJS.PBKDF2(pass, salt, {
keySize: keySize / 32,
iterations: iterations,
hasher: CryptoJS.algo.SHA256 // Fix, default: SHA1
});
...
var keySize = 256;
var ivSize = 128;
var iterations = 1000;
var message = "Hello World";
var password = "secret";
var ivSfmc = "4963b7334a46352623252955df21d7f3";
var saltSFmc = "e0cf1267f564b362";
var encryptedString = "";
function encrypt(msg, pass) {
var salt = CryptoJS.enc.Hex.parse(saltSFmc);
var iv = CryptoJS.enc.Hex.parse(ivSfmc);
var key = CryptoJS.PBKDF2(pass, salt, {
keySize: keySize / 32,
iterations: iterations,
hasher: CryptoJS.algo.SHA256 // Fix, default: SHA1
});
var encrypted = CryptoJS.AES.encrypt(msg, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7, // default
mode: CryptoJS.mode.CBC // default
});
encryptedString = encrypted.toString();
return encryptedString;
}
function decrypt(encrypted, pass) {
var iv = CryptoJS.enc.Hex.parse(ivSfmc);
var salt = CryptoJS.enc.Hex.parse(saltSFmc);
var key = CryptoJS.PBKDF2(pass, salt, {
keySize: keySize / 32,
iterations: iterations,
hasher: CryptoJS.algo.SHA256 // Fix, default: SHA1
});
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7, // default
mode: CryptoJS.mode.CBC // default
});
return decrypted;
}
var message = "Hello World"
var password = "secret";
var encrypted = encrypt(message, password);
var decrypted = decrypt(encrypted, password);
console.log(encryptedString.toString(CryptoJS.enc.Base64)); // for SHA256: n05I/Ub/GC/mzQRmlNTl7w==
// for SHA1, default: ndLxNDM5BwSeqNfXAQ5P3g==
console.log(decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
或者使用 Swift 代码 SHA1:
...
let key = try PKCS5.PBKDF2(
password: password,
salt: salt,
iterations: 1000,
keyLength: 32, /* AES-256 */
variant: .sha1 // Fix, default: SHA256
).calculate()
...
安全:
使用静态盐和 IV 是漏洞。通常,每次加密都会随机生成 salt 和 IV,与密文(例如 salt|iv|ciphertext)连接并发送到解密方。在那里,它们根据盐和 IV 的商定/已知长度进行分离(请记住,盐和 IV 不是秘密)。
尽管 SHA-1 已被破坏,但在 PBKDF2 的背景下,它并不被认为是不安全的(尽管如此,停止使用此摘要以使其从生态系统中消失是有意义的)。
对于 PBKDF2 来说,1000 次迭代计数通常太低。该值应设置得尽可能高,同时保持可接受的性能。