Encryption in Crystal lang


How do I do encryption in Crystal? I want to encrypt say a hash type or a named tuple containing some information, and then add it as a cookie value. I need to be able to read this encrypted value back and decrypt it to original hash type. Is this possible?

Thank you so much for all the help.


Check out OpenSSL::Cipher https://crystal-lang.org/api/0.18.7/OpenSSL/Cipher.html


@redcodefinal Just a heads up that link is for a quite old version of the Crystal docs.


oops my bad, I just googled OpenSSL Cipher Crystal API and thats what came up.


@Blacksmoke16 Wait I’m missing something here, I went through the API docs on latest and couldn’t find Cipher any more, but I know it’s still there because I recently used it in a program I was writing. It’s still there in the src.


Your question consists of two problems -

  1. serialize your hash to some string or binary stream, (and deserialize back)
  2. encrypt it (and decrypt back)

If I would need to do it, I’ll do something like this:

require "yaml"
require "monocypher"

def encrypt(object, secret)
  plaintext = object.to_yaml.to_slice
  ciphertext = Bytes.new(plaintext.size + Crypto::OVERHEAD_SYMMETRIC)
  Crypto.encrypt(key: secret, input: plaintext, output: ciphertext)
  cookiestring = ciphertext.hexstring

def decrypt(text, secret)
  ciphertext = text.hexbytes
  raise "ciphertext too short" if ciphertext.size < Crypto::OVERHEAD_SYMMETRIC
  result = Bytes.new(ciphertext.size - Crypto::OVERHEAD_SYMMETRIC)
  unless Crypto.decrypt(key: secret, input: ciphertext, output: result)
    raise "ciphertext is corrupt"
  hash1 = YAML.parse(String.new(result))

secret = Crypto::SymmetricKey.new # this will generate a key from system random source
puts "secret key is #{secret}"

hash = {"1" => [1, 2, 3], 2 => "test"}
cookiestring = encrypt(hash, secret)
puts "encrypted message: #{cookiestring}"
puts "decrypted message: #{decrypt(cookiestring, secret)}"

using my monocypher bindings shard and untyped serialization to YAML (it is limited to simple types, but maybe it’s ok for a cookie).

Maybe you should better use OpenSSL or LibSodium bindings for encryption, and typed serialization (using e.g. YAML::Serializable) for serialization.


@redcodefinal Looks like that file isnt’t required in the docs_main file nor the openssl.cr file, thus is missing from the docs. Could prob make an issue for it as it’s prob not intentional it’s not there now.


Posted - https://github.com/crystal-lang/crystal/issues/7770


Thanks everyone. I was aware of OpenSSL::Cipher, however, as has been pointed out that wasn’t available in the new documentation.

I did not know about monocypher. Thank you @konovod. Will look into that. I appreciate the example you gave. That would be very helpful.