I'm attempting to encrypt a message using Javascript's CryptoJS like so:
const encrypted_payload = CryptoJS.AES.encrypt("Hello, world!", "magickey");
console.log(enrypted_payload.toString());
... and then decrypt using Rust's Magic Crypt Library, like so:
#[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)
}
The Cargo.toml
file for Rust includes:
[dependencies]
magic-crypt = "3.1.6"
This fails to compile. The error statement is DecryptError(BlockModeError)
.
If in CryptoJS the key is passed as a string, then it is interpreted as a password and the key/IV is derived using a special derivation function (EVP_BytesToKey
). To process the key directly as a key, it must be passed as a WordArray
.
In the Rust code the passwords seem to be simply hashed (e.g. MD5 for AES-128, SHA256 for AES-256), which is surprisingly insecure (though I'm not a Rust expert and may be overlooking something).
Anyway this results in incompatible keys. One possibility is to use the hash of the Rust key as WordArray
in CryptoJS:
Example: From the magic_crypt documentation, 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
internally derives a 32 bytes key as SHA256 hash from the password. Then the encryption with CryptoJS is:
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>
Both codes apply CBC mode with a zero IV and PKCS7 padding. Note that a static IV is insecure and should only be used for testings.
The other direction is analogous, e.g. encryption with CryptoJS generates the ciphertext from the Rust example (assuming the same key, IV and plaintext):
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>