AES encryption and decryption in Ruby is very simple, although I had a hard time finding documentation on how to do it. Ruby has a wrapper over OpenSSL, but I had trouble finding documentation on how to use OpenSSL as well. I found a pretty good piece of code at http://snippets.dzone.com/posts/show/576.
Using this and other information that I found, I created a module for encrypting and decrypting blocks of data. It isn't just limited to AES encryption and decryption, since OpenSSL supports many other types of encryption, but I only use it for AES 256. To get a list of the types of encryption that OpenSSL uses (and what the string would be that you pass in to my functions as cipher_type), open a command prompt, type openssl, then help, and the cipher types are listed under cipher-commands. The two types for AES 256 encryption are "AES-256-CBC" and "AES-256-ECB". Here is my module:
require 'openssl'
module AESCrypt
# Decrypts a block of data (encrypted_data) given an encryption key
# and an initialization vector (iv). Keys, iv's, and the data
# returned are all binary strings. Cipher_type should be
# "AES-256-CBC", "AES-256-ECB", or any of the cipher types
# supported by OpenSSL. Pass nil for the iv if the encryption type
# doesn't use iv's (like ECB).
#:return: => String
#:arg: encrypted_data => String
#:arg: key => String
#:arg: iv => String
#:arg: cipher_type => String
def AESCrypt.decrypt(encrypted_data, key, iv, cipher_type)
aes = OpenSSL::Cipher::Cipher.new(cipher_type)
aes.decrypt
aes.key = key
aes.iv = iv if iv != nil
aes.update(encrypted_data) + aes.final
end
# Encrypts a block of data given an encryption key and an
# initialization vector (iv). Keys, iv's, and the data returned
# are all binary strings. Cipher_type should be "AES-256-CBC",
# "AES-256-ECB", or any of the cipher types supported by OpenSSL.
# Pass nil for the iv if the encryption type doesn't use iv's (like
# ECB).
#:return: => String
#:arg: data => String
#:arg: key => String
#:arg: iv => String
#:arg: cipher_type => String
def AESCrypt.encrypt(data, key, iv, cipher_type)
aes = OpenSSL::Cipher::Cipher.new(cipher_type)
aes.encrypt
aes.key = key
aes.iv = iv if iv != nil
aes.update(data) + aes.final
end
end
11 comments:
great post, I am trying to get rails to do the encryption/decryption for me so i can just use the variable in the controller. It is easy to encrypt with a before_save filter, but how can we decrypt it after a select statement?
Well - if you are worried about decrypting just a single field, you can override the accessor methods.
def value=(val)
write_attribute(:value,encrypt(val))
end
def value
decrypt(read_attribute(:value))
end
Thanks a lot for this code. Really useful
When I try using this module, I always get the error "OpenSSL::CipherError: wrong final block length" when trying to decrypt. Example below:
AESCrypt.encrypt("tester","blahblahasdfasdfasdfasdfasdfasdf",nil,"AES-256-CBC")
AESCrypt.decrypt("}\206\213\237x?Kl\002x9?","blahblahasdfasdfasdfasdfasdfasdf",nil,"AES-256-CBC")
OpenSSL::CipherError: wrong final block length
I am pretty uninformed on this topic, so any help is greatly appreciated...
That's a nice script and it works for me as long as i run it in the terminal via irb on my mac. But when I try to implement this in my Rails App in /lib as a module and than call it from a Controller it returns things like "PG)??_Q?Ф???"
My code to run it looks like that:
class XY < ApplicationController
include Aescrypt
def index
puts Aescrypt.encrypt("Hehe", "Blalalalalalalalalalalalalalalalalalalalalalalalalal" , "jahdsfjhgdhjgdsjkhgjdfgajdhfhdagf", "AES-256-CBC")
end
end
in the terminal it returns
F???EMq??'?l%
do you have any idea?
Thx a lot.
The difference might be because your key and IV lengths are not correct. The second parameter is the key, which should be 32 bytes/characters long for AES-256. The text string that you have for that is longer than 32 characters. The third parameter is the IV (initialization vector) which should be 16 bytes/characters long, and what you are passing in is longer than 16 characters. Try to cut those two parameters down to 32 and 16 characters and see if you get the same results.
Hmm, it doesn't look like that this is the problem because as long as I run it outside the Rails env. it works fine and returns:
"\354\025#\300!\350'ZE\310\245I\2738\n-"
Inside Rails it doesn't work.
Thank you for the code...
Did you find a way to make it work inside rails?
This comment has been removed by the author.
great article!
how do i store encrypted string into database ?
I have:
Mysql::Error: Incorrect string value: '\xDF\xF0\xCF\xE7\x1A\xDB...' for column 'email' at row 1:
UPDATE `orders` SET `email` = '▀Ё╧ч\Z█n~╒q+eХ┤a╡' .....
What type of column it has to be ?
ok i found ... it has to be blob (:binary)
for mysql
Post a Comment