如何使用 CryptoJS 加密和使用 Rust Magic Crypt 解密

How to encrypt with CryptoJS and decrypt with Rust Magic Crypt

我正在尝试使用 Javascript 的 CryptoJS 加密消息,如下所示:

const encrypted_payload = CryptoJS.AES.encrypt("Hello, world!", "magickey");
console.log(enrypted_payload.toString());

... 然后使用 Rust 的 Magic Crypt 库解密,像这样:

#[macro_use] extern crate magic_crypt;
use magic_crypt::MagicCryptTrait;

fn main() {
    let message = r#"U2FsdGVkX1+anrxRX8UNTJ8ur9LIf6n2YcmbmDqPSls="#;

    let mc = new_magic_crypt!("magickey", 256);

    let result = mc.decrypt_base64_to_string(&message)
        .expect("Could not decrypt base64 to string");
    
    println!("{}", result)
}

Rust 的 Cargo.toml 文件包括:

[dependencies]
magic-crypt = "3.1.6"

编译失败。错误语句是DecryptError(BlockModeError).

如果在 CryptoJS 中,密钥作为字符串传递,那么它会被解释为密码,并且 key/IV 是使用特殊的派生函数 (EVP_BytesToKey) 派生的。要直接将密钥作为密钥处理,必须将其作为 WordArray.
传递 在 Rust 代码中,密码似乎只是简单地散列(例如 AES-128 的 MD5,AES-256 的 SHA256),这是非常不安全的(尽管我不是 Rust 专家,可能会忽略一些东西)。
无论如何,这会导致密钥不兼容。一种可能性是使用 Rust 密钥的散列作为 CryptoJS 中的 WordArray:

示例:来自 magic_crypt 文档,here:

use magic_crypt::MagicCryptTrait;
let mc = new_magic_crypt!("magickey", 256);
let base64 = mc.encrypt_str_to_base64("http://magiclen.org");
assert_eq!("DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=", base64);
assert_eq!("http://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap());

magic_crypt 从密码内部派生出一个 32 字节的密钥作为 SHA256 散列。那么用CryptoJS加密就是:

var key = CryptoJS.SHA256("magickey");
var ciphertext = "DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=";
var iv = CryptoJS.enc.Base64.parse("AAAAAAAAAAAAAAAAAAAAAA==")
var decrypted = CryptoJS.AES.decrypt(ciphertext, key, {iv: iv});

console.log(decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

这两个代码都应用具有零 IV 和 PKCS7 填充的 CBC 模式。请注意,静态 IV 是不安全的,只能用于测试。

另一个方向类似,例如使用 CryptoJS 加密从 Rust 示例生成密文(假设相同的密钥、IV 和明文):

var key = CryptoJS.SHA256("magickey");
var plaintext = "http://magiclen.org";
var iv = CryptoJS.enc.Base64.parse("AAAAAAAAAAAAAAAAAAAAAA==")
var ciphertext = CryptoJS.AES.encrypt(plaintext, key, {iv: iv});

console.log(ciphertext.toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>