Securing Data wtih OpenSSL and Ruby: Part One 1
For the most part Ruby has fantastic APIs. While there is an occasional wart here and there (I”m speaking to you DateTime). In general, it doesn’t suck. The OpenSSL bindings for Ruby are no exception.
Bob, meet Alice
To begin our cultural learnings of OpenSSL and Ruby, let’s take a look at source repository for the interpreter. In the samples directory are some nice examples how the bindings work. It seems that some of the original code examples were never migrated from the RubyPKI project, but thats ok, you can still access them here.
The OpenSSL Digest Class
One of the most common things you’ll most likely need is to create a digest of a string of data. We can do this using by instantiating a Digest class then invoking the hexdigest method.
irb(main):001:0> require 'openssl'
=> true
irb(main):002:0> @sha1 = OpenSSL::Digest::SHA1.new("fooooo")
=> 58c00efa9bed725721b29f4b5f7864f0f191cad5
irb(main):003:0> @sha1.hexdigest
=> "58c00efa9bed725721b29f4b5f7864f0f191cad5"
irb(main):005:0>Simple enough. But what is the deal with ‘digest’ versus ‘openssl/digest’? According to the ‘digest’ module is only used for backwards compatibility, so use the openssl version when possible.
Available Digest Algorithms
According to the source, the Digest algorithms available are dependent upon the version of OpenSSL compiled with Ruby.
module OpenSSL
class Digest
alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1)
if OPENSSL_VERSION_NUMBER > 0x00908000
alg += %w(SHA224 SHA256 SHA384 SHA512)
end
...Excel Series Decoder in Ruby
A co-worker of mine was writing a little script to parse an excel file that contained various network addresses and run various test cases against it. He was stumped on the algorithm how to decoded excel headers to specific indexes. While at first glance this looks like a simple problem, it ended up being more difficult than we thought. My co-worker approached the problem using a procedural approach, this ended up yielding a few nasty loops…far from elegant. The end result ended up being rather easy once the approach was modified to use recursion.
My Solution
require 'test/unit'
def to_excel(i)
case i
when 0
return ''
when 1..26
return ('A'..'Z').to_a.at(i - 1)
else
q, r = (i - 1).div(26), (i - 1) % 26
return "#{to_excel(q)}#{to_excel(r + 1)}"
end
end
class ExcelNumberSeriesTest < Test::Unit::TestCase
def test_simple
assert_equal 'A', to_excel(1)
assert_equal '', to_excel(0)
assert_equal 'Z', to_excel(26)
end
def test_doubles
assert_equal 'AA', to_excel(27)
assert_equal 'AB', to_excel(28)
assert_equal 'AZ', to_excel(52)
end
endCompiling Erlang Applications with Rake
The irony of Rake is that Ruby really doesn’t need it. This is not to say it isn’t useful to Ruby projects, quite the contrary. Where Rake shines is in building software for applications that require byte code and object code, such as Java or C centric projects.
One such language requiring byte code compilation is Erlang. The design of the runtime environment used by Erlang should be familiar to most Java or C# developers. Erlang uses a byte code compiler (erlc) and various application meta-data files (.app, .rel, .config). For my development work I use Erlide, the Eclipse based Erlang IDE. The standard project layout for an application created in Erlide is:
- project
- ebin
- include
- src
When creating a Rake file for Erlang projects, I ran into a few problems with compiling the source into the separate ebin directory. Namely, dependencies where not being constructed as desired yielding a full rebuild every time I ran the build script! In the following example I dynamically create the file rules so that the bytecode (.beam) files will only be recompiled if the source (.erl) file is changed.
require 'rake'
require 'rake/clean'
CLEAN.include(['ebin/*.beam', '*.dump'])
SRC = FileList['src/**/*.erl']
BEAM = []
SRC.each do |fn|
BEAM << dest = File.join('ebin', File.basename(fn).ext('beam'))
file dest do
sh "erlc -o ebin #{fn}"
end
end
namespace :erlang do
desc "staring ermail"
task :run => [:compile] do
sh("erl -noshell -pa ebin -s my_mod start")
end
desc "run tests"
task :test => BEAM do
sh("erl -noshell -s test_my_mod test -s init stop")
end
end
task :default => [:compile]
task :start => ['erlang:run']
task :compile => BEAMJava vs Ruby
Forgive me, as this will most likely spark deep seeded hatred from those forced to navigate the deep dark world of Java development. I have managed to break free from it for sometime now, enjoying my Ruby bliss of block passing and metaclasses. Just when I thought I was out, they pull me back in. They, being work. Why can’t we all develop with a language so pointed and terse.
The Java Version
StringBuffer subType = new StringBuffer();
for (String token : tokens) {
// pretty print the tag
char[] c = token.replaceAll("flag", "").toCharArray();
// make first char upper case
if (c.length > 0)
c[0] = Character.toUpperCase(c[0]);
subType.append(c);
}The Prettier, More Compact, Ruby Version
tokens.collect {|t| t.sub(/flag/, '').capitalize }.joinI can hear the snide remarks right now…save them. There are plenty more examples where that came from.
Deploying Java Applications with Capistrano
Capistrano 2, the fantastic sequel to the already superb Rails deployment framework, is an excellent solution to the otherwise mundane task of deploying Java applications.
Network security restrictions prohibit me from using the typically SCM -> Production server configuration. Next, I ran into a few problems uploading Jar files using the put command. Luckily Alex Gorbatchev, posted an example of how to use SFTP within a Capistrano deployment recipe.
I used his idea and adapted my rails recipe using SFTP deployment.
namespace :deploy do
task :update_code do
on_rollback { run "rm -rf #{release_path}" }
run "mkdir #{release_path}"
files = Dir.glob('lib/*.jar') + Dir.glob('dist/*.jar')
execute_on_servers(options) do |servers|
servers.each do |server|
files.each do |path|
logger.info "uploading #{File.basename(path)} to #{server}"
sftp = sessions[server].sftp
sftp.connect unless sftp.state == :open
sftp.put_file path, File.join(current_path, File.basename(path))
logger.debug "done uploading #{File.basename(path)} to #{server}"
end
end
end
finalize_update
end
end
