Thursday, December 20, 2007

AES encryption and decryption in Ruby

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

Thursday, December 6, 2007

Assigning values to has_many through relationships

I found out the hard way today that you can't directly assign values to a has_many :through relationship like you can with a has_and_belongs_to_many relationship. First let me explain the two approaches for many to many relationships if you're not sure what they are.

Say you have a "group", and groups can have any number of accounts. Accounts can also belong to any number of groups. You can accomplish this two ways. First, create a join table called accounts_groups, with no id, and two primary keys, account_id and group_id. Then simply put this one line in the group class
has_and_belongs_to_many :accounts

and this in the account class
has_and_belongs_to_many :groups

The downside of this approach is that you can't have additional information about the association (like number_of_logins, etc.). If you don't need additional information about the association, I think has_and_belongs_to_many (habtm) is the better approach (less code, less complicated), even though this seems to have fallen out of favor in the Rails community.

If you do need information in the association, or you just want to use the Rails community's preferred approach, first create a join table named memberships, with a primary key id, account_id, and group_id. Then add a class named Membership:
class Membership < ActiveRecord::Base
belongs_to :account
belongs_to :node
end

Add this to your group class:
has_many :memberships
has_many :accounts, :through => :memberships

And this is your account class:
has_many :memberships
has_many :groups, :through => :memberships

One downside of has_many :through is that you can't assign directly to the relationship. For the above example, say you had an array of accounts that you want to assign to a group. You can't code
@group.accounts = array

But you can with habtm You can also assign an array of id's to a has_and_belongs_to_many relationship by using relationship_ids = array. Note that it's the singular form of the relationship in the name of the function. One more reason to use habtm.

BUT I found a really good function to allow you to assign values to has_many through relationships at the Grinding Rails blog (http://tuples.us/2007/05/09/metaprogramming-has_many-through-accessors/). It's really useful when using has_many through relationships.

Sunday, December 2, 2007

Formatting Ruby and HTML code for blog posting

I just found a better way to format code for blogs. Read my blog post Better way to format code for blog posts to see how. I'll leave the old way here, in case you want to still use this way.

Posting Ruby and HTML that looks good here on Blogspot can be a pain. But I found a ruby gem called Syntax that will format Ruby code to look right on web pages. It can also do the same thing for HTML/XML. I found out about this at http://blog.wolfman.com/articles/2006/05/26/howto-format-ruby-code-for-blogs. To install it, just type:
gem install syntax

at the command prompt. Then add this to your CSS declaration.
pre {
background-color: #f1f1f3;
color: #112;
padding: 5px;
font-family:"bitstream vera sans mono",monaco,"lucida console","courier new",courier,serif;
font-size: 0.9em;
overflow: auto;
margin: 4px 0px;
width: 95%;
}



/* Syntax highlighting */
pre .normal {}
pre .comment { color: #005; font-style: italic; }
pre .keyword { color: #A00; font-weight: bold; }
pre .method { color: #077; }
pre .class { color: #074; }
pre .module { color: #050; }
pre .punct { color: #447; font-weight: bold; }
pre .symbol { color: #099; }
pre .string { color: #944; background: #FFE; }
pre .char { color: #F07; }
pre .ident { color: #004; }
pre .constant { color: #07F; }
pre .regex { color: #B66; background: #FEF; }
pre .number { color: #F99; }
pre .attribute { color: #5bb; }
pre .global { color: #7FB; }
pre .expr { color: #227; }
pre .escape { color: #277; }

For blogspot, just click Template, and Edit HTML.

I wrote up a Ruby script using this gem for Windows that will read Ruby code from the clipboard in Windows, format it for HTML, and paste the HTML back to the clipboard. For some later Ruby versions you'll need to run "gem install win32-clipboard". Here is the code:
require 'syntax/convertors/html'
require 'Win32API'
require 'win32/clipboard'
include Win32

in_data = Clipboard.data
convertor = Syntax::Convertors::HTML.for_syntax "ruby"
code_html = convertor.convert(in_data)
Clipboard.set_data(code_html)
And I also wrote one for formatting HTML or XML code. Notice that the only thing different is the for_syntax line.
require 'syntax/convertors/html'
require 'Win32API'
require 'win32/clipboard'
include Win32

in_data = Clipboard.data
convertor = Syntax::Convertors::HTML.for_syntax "xml"
code_html = convertor.convert(in_data)
Clipboard.set_data(code_html)


For other OSes, here is code that will read a file "input.rb" and convert it to HTML in the file output.html:
require 'syntax/convertors/html'

in_data = File.read('input.rb')
convertor = Syntax::Convertors::HTML.for_syntax "ruby"
code_html = convertor.convert(in_data)
File.open('output.html', 'w') {|f| f << code_html }

And here is the code to convert HTML or XML from the file input.html into output.html:
require 'syntax/convertors/html'

in_data = File.read('input.html')
convertor = Syntax::Convertors::HTML.for_syntax "xml"
code_html = convertor.convert(in_data)
File.open('output.html', 'w') {|f| f << code_html }


The only complaint is that sometimes line breaks are displayed on the web page in your code in Internet Explorer when there shouldn't be. The scroll bars show up, but it won't scroll over to the right for more than one word. This is more of an IE specific issue though, it displays fine in Firefox.