I am having trouble figuring out how to use OpenSSL::Cipher to decrypt data.
I keep getting this error:
Unhandled exception: EVP_CipherFinal_ex: Unknown or no error (OpenSSL::Cipher::Error)
from ../../../../../snap/crystal/397/share/crystal/src/openssl/cipher.cr:70:7 in 'final'
from src/crystal_encryption.cr:39:12 in 'decrypt'
from src/crystal_encryption.cr:57:18 in '__crystal_main'
from ../../../../../snap/crystal/397/share/crystal/src/crystal/main.cr:105:5 in 'main_user_code'
from ../../../../../snap/crystal/397/share/crystal/src/crystal/main.cr:91:7 in 'main'
from ../../../../../snap/crystal/397/share/crystal/src/crystal/main.cr:114:3 in 'main'
from __libc_start_main
from _start
from ???
I would really appreciate it if someone could spare some time to look at the code and let me know what I am doing wrong.
@aravindavk,
A single instance of Cipher works because some state is being kept between encryption/decryption. Notably, it breaks if you do the encryption/decryption independently.
To demonstrate this I have separated the encryption/decryption into separate files that writes/reads the encrypted data to a file.
@jwoertink,
I noticed that you are using “aes-256-cbc” in your code, and that does indeed work whereas the “aes-256-gcm” that I was using does not. And yeah, looks like those missing methods are required for gcm.
The main difference between gcm and cbc as far as I understand is that gcm does data integrity checks and cbc does not.
Switching my example to use cbc the effect of data corruption can be seen like this:
A single instance of Cipher works because some state is being kept between encryption/decryption. Notably, it breaks if you do the encryption/decryption independently.
Totally makes sense. They should not depend on each other.
I don’t know anything about cryptography, or encryption. So I can’t say that my was is a good way of doing, but it works for what I needed (for now). It seems like the Crystal Crypto stuff needs a lot of love. I’m finding a few instances where there’s some missing areas like the Crystal version of ecdsa, elliptic and rsa. So if you find a better way to handle this, then I’m all ears!
Yeah, the crypto stuff is a bit rough compared to the rest of Crystal.
I do wish there were a simple to use API for encryption built in, something like this.
text = "secret stuff..."
key, salt = Crypto::PBKDF2.key_derivation "password" #(optional) provide salt : Bytes
encrypted_bytes = text.bytes.encrypt key #(optional), algorithm: Crypto::AES256CBC
# encrypted_text, iv = ... (maybe return the iv, but I think I would prefer it to just be baked in to the result)
decrypted_bytes = encrypted_bytes.decrypt key #(optional), provide the algorithm
decrypted_text = decrypted_bytes.to_s
I don’t know, just would be nice if crypto was easy to use and hard to get wrong by default instead of the other way around. Also good examples in the documentation would be great.
Guess I will use cbc for now so I can get on with finishing this application.
I also broke my teeth a bit with the crypto in Crystal. But the std is rather well provided at low level. I just published this shard to simplify the Crypto in Crystal: https://github.com/Nicolab/crystal-crypt