I will attempt this now with: elixir-node: An Elixir library for interacting with Node.js.
With the help of rustler you can use Rust to decrypt the AES key. I used the node.js example and was able to decode the encrypted AES key using Rust/Rustler:
use base64::prelude::*;
use rustler::{Env, NifResult};
use rsa::{RsaPrivateKey, Oaep, sha2::Sha256};
use rsa::pkcs8::DecodePrivateKey;
use rustler::types::binary::{Binary, OwnedBinary};
#[rustler::nif(schedule = "DirtyCpu")]
fn decrypt<'a>(env: Env<'a>, private_file_path: String, cipher_text: String) -> NifResult<Binary<'a>> {
let padding = Oaep::new::<Sha256>();
let content = std::fs::read_to_string(&private_file_path).unwrap();
let private_key = RsaPrivateKey::from_pkcs8_pem(&content).unwrap();
let enc_data = BASE64_STANDARD.decode(cipher_text).unwrap();
let dec_data = private_key.decrypt(padding, &enc_data).unwrap();
let mut result: OwnedBinary = OwnedBinary::new(dec_data.len()).unwrap();
result.as_mut_slice().copy_from_slice(&dec_data);
Ok(Binary::from_owned(result, env))
}
rustler::init!("Elixir.RCrypto");
Here is the output:
iex [09:40 :: 2] > RCrypto.decrypt("./private_unencrypted.pem", "hiHNE0AFZI6pn/Sbo0yPmbm37NQxuCc1rDxotfkeOHjjCO9BEVMtLQKfOE6w2/VQwISqJpAE0D9FlScvEdMgNjtbo5rNRutHFVF5xnvLsXyV228dxt5m8h+6k1LApk5TLOj97+fi4iiYq5Tr3n1E+4jpY0TTl30s/k0rhciOIy7HwFpaRWVSiOZFqx+PTYrJYcRot/DoArd4DLAdlbeoHcyoB4R0LV4DJRUmKwrcP/7J3njC1PpetGjgGiy5g/e/dKoxmcjjyhSwS7QeoCxBAF4ErHWHFfNOeNyCdwLmOtlLIa55nwGQ0Jyn0xp4WQj2xJqoHvCTcqbAxRtCJ5b5zA==")
"<some-key-data>"
iex [09:40 :: 3] >
Of course, the code is just a quick demo. Loading the key for each call should not be used at all.
This is very helpful.
I eventually used NodeJS : {:nodejs, "~> 2.0"} to call the encryption.js file provided in Meta’s examples.
works like a charm!
As an exercise, I have written a package that provides the missing function for decrypting the AES key using Rust. At the same time, I looked at the solution with Node-Server and compared it. I also wrote a small load testing that performs the decryption of the request and the encryption of the response.
The :observer delivers the expected results. While the dirty CPU rises to 100% in the Rust implementation, the work in the node implementation is performed by the started node server. With the Node implementation, data must be serialised via port. You can clearly see the increased IO usage, although the Erlang schedulers are hardly loaded. The Rust implementation is faster with a factor of 1.37. This can be explained by the fact that the node implementation calls the OpenSSL functions, which means that encryption/decryption is performed almost as quickly for large data. Only the serialisation has an impact.
The Rust implementation eliminates the need to manage additional node servers and reduces IO usage. You also gain a small speed advantage. The CPU usage is almost the same. The node server consume about 100%.
hi, just to confirm that your library works excellently, I’ve moved over from the NodeJS version to your rust version.
Thanks for this lib!























