peoj
Hi folks,
I’m attempting to port this JS code into its Erlang/Elixir equivalent:
const key = "mysecretkey";
function decryptString(encryptedString) {
const algorithm = 'aes256';
const decipher = crypto.createDecipher(algorithm, key);
return decipher.update(encryptedString, 'hex', 'utf8') +
decipher.final('utf8');
}
This is as far as I have gotten so far in E land:
iex> key = "mysecretkey"
iex> encrypted_text = "myencryptedtext-changed-for-this-example"
iex> :crypto.crypto_one_time(:aes_256_ecb, key, encrypted_text, encrypt: false)
** (ErlangError) Erlang error: {:badarg, {'api_ng.c', 143}, 'Bad key size'}
(crypto 4.8.3) :crypto.ng_crypto_one_time_nif(:aes_256_ecb, "mysecretkey", "", "myencryptedtext-changed-for-this-example", false, :undefined)
Clearly the precise example I’ve given will never work since I’ve redacted both the key and encrypted text. However the error message I’ve included above is the real thing.
Does anyone know what I’m missing?
Trending in Questions
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app?
Looking for hints regarding:
Addi...
New
Kia ora,
We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
Hi all, I wanted to ask how the community is dealing with post-release steps.
Today we have Ecto migrations, which make sure that the db...
New
Hello,
I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 10 of 16 Posts
hauleth
AES256 require key to be exactly 32 byte long, your key is 11 bytes, 21 bytes too short. JS code probably does some padding to achieve what you want.
However:
For gods sake, do not use this code. Burry it in the dessert, and wear gloves. After that burn all your clothes.
Jokes aside - this is terrible way to do cryptography and encrypt data. Just don’t do it that way. If you have “AES” written in your code, then you are probably vulnerable. It is even hard to list what is wrong there:
This is nowhere to be even considered to be a remotely reasonable implementation. It is just insecure.
peoj
Thanks for the suggestion and for the wisdom re the code. Yes I’m aware it’s flawed (actually I’m porting it in order to eventually remove it).
f0rest8
Not sure what you’re specific encryption needs are, but if you’re going to implement encryption in Elixir then you might want to consider using the enacl library.
If you have simpler needs depending on your use case, i.e. transparent database field encryption with Ecto (symmetric), then you can look at a library like cloak/cloak_ecto.
Hope it helps
peoj
I got a bit closer by trimming the key to the suggested length, thank you.
Unfortunately I’m clearly doing something else wrong too because the returned value is quite clearly not cleartext ;).
Any further hints on where to look? As you can probably already tell I’m fairly lacking in knowledge in this area!
mattbaker
I like crypto! And I like puzzles, and I had a suspicion Node was doing something silly, so I chased this a bit. I’ll say two things right off the bat:
First, this would be confusing to anyone. Node made some choices that favored ease of use, and sacrificed clarity (and security!) in the process. Node is doing things hidden from you that you couldn’t possibly have known about without knowing exactly what to search for. With a little experience with cryptography concepts it’s not bad, but if you’re new to this stuff (and you mentioned you are) this is really hard to solve without help.
Second, @hauleth is right that a revamp of how you encrypt things is warranted, but we don’t always have the luxury of doing that with legacy data! Best practices here do not solve the problem in front of you. For what it’s worth, I don’t think you’re encrypting in ECB in Node, I think you’re actually using CBC.
With all that said, to make any progress there are some things to figure out before we can decrypt the data Node is producing in Elixir.
Question 1: what block cipher mode is Node using?
You specified
aes256in your JS code andaes_256_ecbin Elixir. The string “aes256” doesn’t really tell us the whole story, because encryption is not just about which encryption algorithm is being used, it’s also about how each block of data is operated on during the encryption or decryption process. You’ve selected “ECB” (electronic code book) but there are others, like “CBC” (cipher block chaining). You really need to know which one is being used if you want to decrypt your data.If you head down the rabbit hole far enough with the Node docs you’ll see that
aes256value you’re passing is from a list of ciphers provided by OpenSSL. Unfortunately, the stringaes256doesn’t tell us the block mode.I couldn’t find a clear explanation of what
aes256truly maps to so I just ranopenssl enc -aes256to see what would happen. The first thing you’ll see isSo, that makes me think when you say “aes256” in your code in Node it’s really a shortcut for aes-256-cbc.
That means the first thing you have wrong is the algorithm, instead of ECB you should be using
:aes_256_cbc.Question 2: But if it’s CBC, what’s the initialization vector?
This wikipedia page talks a bit about block cipher modes. The primary thing to notice is the difference between ECB and CBC mode. You could also google other resources explaining block cipher modes that might be more clear than that wikipedia page.
If you look at the pictures describing how ECB works, you’ll see decryption needs two inputs: the key and some ciphertext (aka encrypted data).
You’ll also see that CBC expects three inputs. The key, the ciphertext, and something called an “initialization vector” (IV) to get things started.
Since you are (apparently) using CBC but not supplying an IV in your JS code, the only conclusion is that Node is generating an IV for you, and it must be doing it deterministically (not a great thing in the crypto world, one of the reasons the Node docs push people toward
createCipheriv).Luckily you’re not only one dealing with this. Here’s someone trying to solve the same problem in Ruby.
Summarizing the Stack Overflow post above: Node takes the “password” you provide (of any length) and uses that to produce an encryption key and an IV. So it turns out that not only is Node secretely making an IV for you, it’s also creating an encryption key that’s based on your “password” but not literally your password. In your example, the decryption key is not actually “mysecretkey” (no surprise, since it’s too short to be an encryption key!)
That’s all outlined in the Stack Overflow answer I linked to, which I recommend you read.
If we copy what they did in Ruby in Elixir, that process could look something like this:
And finally, encoding
Last but not least, your JS code makes me think that your encrypted data is probably being passed around encoded as base 16 (hex), for example are you providing something like “f07258ace89d16d847cb0ec520b19438” as input when you try to decrypt data?
If so, that means you need to decode the hex string before you try to decrypt it. You can use
Base.decode16!(encrypted_text, case: :lower)for this.Putting it all together
So, if I had to summarize, it’d be this: Node is trying to be helpful by hiding a bunch of things from you, and that works if you never have to decrypt something outside the Node ecosystem, but it’s a crappy design if you do. In their defense, the
createCipherfunction you’re using there has been deprecated in favor of a function that takes a true key (not a “password”) and an explicit IV value (you must generate it, they will not do it for you). I’m very happy they’ve deprecated the function you’re using.The good news is you can definitely re-create what Node did behind the scenes so that you can decrypt your data in Elixir.
First, here’s an example of some JS code that I’m guessing is close to your own. We can use it to generate test data.
That produces the following output:
So in Elixir our goal is to decrypt the string “686ca8793bf5e7317cfd451aa81b72cf” by mimicking Node. If we succeed then we know we’ve copied Node’s approach.
That prints out “hello world” on my machine.
I hope that helps you get unstuck and away from Node
If I had to suggest a new approach once you’re able to migrate off your legacy Node code:
aes_256_ecbbecause it’s easier. Something likeaes_256_cbcis fine as far as I know, and there are others.mindok
This has to be answer of the year!!! Awesome work.
emeryotopalik
Aren’t you supposed to be on vacation?
peoj
What an incredible answer. Thanks so much for helping and teaching me a thing or two along the way.
hauleth
Please, do not do that. Encryption without authentication is pointless as attacker can manipulate the plaintext without any problems (without knowing the plaintext):
So as you can see, I can change first letter from
AtoBwithout any problems. This is huge problem as you no longer can trust the cipher text.In short - do not use non-AEAD ciphers, never.
lud
The more I learn crypto, the more there is to learn
I know it is true for most domains but in that case it is almost overwhelming.