The Crystal Programming Language Forum

Simple Encrypt + Decrypt?

I come from Laravel background where the following interface exists (docs if you really want to see more):

# example value make by `php artisan key:generate`
# ENV["APL_KEY"] = "base64:dTOymAUpqvF/2tOxnQdakYHuL66HlmkElovGwumCiPE="

struct SimpleEncrypt
  def initialize(
    @key : String = ENV["APP_KEY"], 
    @cypher = AES128)
  end

  def encrypt (data : String) : String
    # encrypts the string
  end

  def decrypt (data : String) : String
    # decrypts the string
  end
end

e = SimpleEncrypt.new()
value = "any string"
encrypted_value = e.encrypt(value)
value2 = e.decrypt(encrypted_value)
puts value2 == value
# true

I couldn’t find anything in the standard library or http://crystalshards.xyz/ for this, but I did find things suited for adjacent topics like password hashing, SSL, certificates, MD5/SHA.

I think this would make a great STD or shard, but I don’t know the primitives for doing this myself.

I found https://github.com/dscottboggs/crypher, maybe its code would be useful

https://github.com/didactic-drunk/sodium.cr seems good candidate for your use-case. Especially the example https://github.com/didactic-drunk/sodium.cr#secret-key-encryption

You can check my simple cli app:
https://github.com/Geo-7/openssl_sample

Hello,

# Encrypt *data*
  def cipher_encrypt(data) : IO::Memory
    cipher = OpenSSL::Cipher.new("aes-256-cbc")
    cipher.encrypt
    cipher.key = App.cfg.cipher_key
    cipher.iv = App.cfg.cipher_iv
    cipher.update data
    encrypted = cipher.final

    IO::Memory.new(encrypted)
  end

  # Decrypt *data*
  def cipher_decrypt(data) : IO::Memory
    cipher = OpenSSL::Cipher.new("aes-256-cbc")
    cipher.decrypt
    cipher.key = App.cfg.cipher_key
    cipher.iv = App.cfg.cipher_iv
    cipher.update data
    decrypted = cipher.final

    IO::Memory.new(decrypted)
  end

App.cfg.cipher_* should be replaced (or assigned).

These methods return IO::Memory. Use to_s to get value in String (cipher_encrypt("hello").to_s)

2 Likes

AES encrypt

Forget my example above. I made a more practical and reliable shard : https://github.com/Nicolab/crystal-crypt.

require "crypt"
require "crypt/crypter"
require "crypt/random"

data = "super secret data"
secret = Crypt.random_string(32)
crypter = Crypt::Crypter.new(secret)

# Data encrypted
encrypted = crypter.encrypt(data)

# Data decrypted
decrypted_bytes = crypter.decrypt(encrypted)

# Decrypted data (Bytes)
puts decrypted_bytes

# Convert Bytes to String
puts String.new(decrypted_bytes)

Generate a password:

require "crypt"
require "crypt/bcrypt"

password = Crypt.create_bcrypt_password("super secret")
# => $2a$10$rI4xRiuAN2fyiKwynO6PPuorfuoM4L2PVv6hlnVJEmNLjqcibAfHq

password.verify("wrong secret") # => false
password.verify("super secret") # => true
1 Like

A shard is not necessary for Bcrypt, it is easy enough with the stdlib.
For OpenSSL, I can agree not so much. I hope the API will be revisited and more type safe after the 1.0.