Permalink
Browse files

readme and spec

  • Loading branch information...
1 parent 864826a commit 8469516d1bbed38008875f9af439637ef0337898 Nate Wiger committed Jan 20, 2010
Showing with 145 additions and 73 deletions.
  1. +52 −13 README.rdoc
  2. +1 −1 ext/extconf.rb
  3. +47 −43 ext/fast_aes.c
  4. +4 −12 ext/fast_aes.h
  5. +1 −1 fast-aes.gemspec
  6. BIN spec/.fast_aes_spec.rb.swp
  7. +0 −3 spec/fast_aes_spec.rb
  8. +40 −0 test/benchmark.rb
View
@@ -1,32 +1,69 @@
= FastAES - Fast AES implementation for Ruby in C
-This is a lightweight, fast implementation of AES (the US government's Advanced Encryption Standard)
-written in C for speed. You can read more on the {Wikipedia AES Page}[http://en.wikipedia.org/wiki/Advanced_Encryption_Standard].
-The algorithm itself was extracted from the open source Netcat clone {sbd}[http://www.cycom.se/dl/sbd]
-(AES support by Christophe Devine).
+This is a lightweight, fast implementation of AES (the US government's Advanced Encryption Standard,
+aka "Rijndael"), written in C for speed. You can read more on the {Wikipedia AES Page}[http://en.wikipedia.org/wiki/Advanced_Encryption_Standard].
+The algorithm itself was extracted from work by Christophe Devine for the open source Netcat clone
+{sbd}[http://www.cycom.se/dl/sbd]. According to the community, this is
+{one of the best performing AES implementations available}[http://www.derkeiler.com/Newsgroups/sci.crypt/2003-07/0162.html]:
-This library supports a subset of AES functionality, specifically:
+ >> With some exceptions your code performs better than all others in
+ >> enc[ryption]/dec[ryption]. Do you have an explanation of that fact? Thanks.
+ >
+ > Well, I've tried to make the code as simple and straightforward as
+ > possible; I also used a few basic tricks, like loop unrolling.
-* 128, 192, and 256-bit ciphers only
+Since this library wraps the Christophe's implementation, it supports a subset of AES, specifically:
+
+* 128, 192, and 256-bit ciphers
* Cipher Block Chaining (CBC) mode only
+* Data is auto-padded at 16-bit boundaries
+
+You can read specifics about AES-CBC in the IPSec-related {RFC 3602}[http://www.rfc-archive.org/getrfc.php?rfc=3602]
+
+=== Other Ruby AES gems
+
+I couldn't find any that worked worth a crap. The {ruby-aes}[http://rubyforge.org/projects/ruby-aes/]
+project has Ruby 1.9 bugs that have been open over _two_ _years_ now, {crypt/rijndael}[http://crypt.rubyforge.org/rijndael.html]
+doesn't work on Ruby 1.9 and is *SLOOOOOOW* (as it's written in Ruby), and some people even report getting
+{different encryption results from different libraries}[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/228214].
-You can read specifics about AES-CBC in the IPSec-related {RFC3602}[http://www.rfc-archive.org/getrfc.php?rfc=3602]
+So I grabbed some C reference code, wrapped a Ruby interface around it, and voíla.
+
+C'mon people, it's not that hard. It's called Google. In my day, you had to actually *WRITE* the code.
== Installation
gem install gemcutter
gem install fast-aes
-
+
== Example
- require 'fast_aes' # note underscore
+Simple encryption/decryption:
+
+ require 'fast-aes'
aes = FastAES.new(key) # can be 128, 192, or 256 bits
-
+
text = "Hey there"
- data = aes.encrypt(text, text.length)
- puts aes.decrypt(data, data.length) # "Hey there"
+ data = aes.encrypt(text)
+ puts aes.decrypt(data) # "Hey there"
+
+== Why FastAES
+
+=== SSL vs AES
+
+I'm going to guess you're using Ruby with Rails, which means you're doing 90+% web development.
+If you need security, SSL is the obvious choice.
+
+There will probably come a time, however, when you need a couple backend servers to talk, maybe
+job servers, or an admin interface, or whatever. Maybe even a simple chat server.
+
+You can use SSL for this if you want it to be time-consuming to setup, painful to maintain, and
+slow. Or you can use an alternative, such as AES. Setting up an SSH tunnel is another good
+alternative.
+
+There are other alternatives, but many of these are either (a) cracked or (b) covered by patents.
== Special Note
@@ -38,7 +75,9 @@ library.
== Author
-Copyright (c) 2009 {Nate Wiger}[http://nate.wiger.org]. All Rights Reserved. Released under the MIT License.
+AES C reference code by Christophe Devine. Thanks Christophe.
+
+This gem copyright (c) 2010 {Nate Wiger}[http://nate.wiger.org]. Released under the MIT License.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use,
View
@@ -2,7 +2,7 @@
require 'mkmf'
# Give it a name
-extension_name = 'fast_aes'
+extension_name = 'fast-aes'
# The destination
dir_config(extension_name)
View
@@ -18,6 +18,12 @@
/* Global boolean */
int fast_aes_do_gen_tables = 1;
+/* Old school. Oh yeah */
+#ifndef RSTRING_PTR
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
+#endif
+
/* Ruby buckets */
VALUE rb_cFastAES;
@@ -27,41 +33,41 @@ void Init_fast_aes()
rb_define_alloc_func(rb_cFastAES, fast_aes_alloc);
rb_define_method(rb_cFastAES, "initialize", fast_aes_initialize, 1);
- rb_define_method(rb_cFastAES, "encrypt", fast_aes_encrypt, 2);
- rb_define_method(rb_cFastAES, "decrypt", fast_aes_decrypt, 2);
+ rb_define_method(rb_cFastAES, "encrypt", fast_aes_encrypt, 1);
+ rb_define_method(rb_cFastAES, "decrypt", fast_aes_decrypt, 1);
rb_define_method(rb_cFastAES, "key", fast_aes_key, 0);
}
VALUE fast_aes_key(VALUE self)
{
- /* get our "self" data structure (eg, member vars) */
+ /* get our "self" data structure (eg, member vars) */
fast_aes_t* fast_aes;
- Data_Get_Struct(self, fast_aes_t, fast_aes);
+ Data_Get_Struct(self, fast_aes_t, fast_aes);
VALUE new_str = rb_str_new(fast_aes->key, fast_aes->key_bits/8);
return new_str;
}
VALUE fast_aes_alloc(VALUE klass)
{
- /* Initialize our structs */
- fast_aes_t *fast_aes = malloc(sizeof(fast_aes_t));
+ /* Initialize our structs */
+ fast_aes_t *fast_aes = malloc(sizeof(fast_aes_t));
- /* Clear out memory */
- memset(fast_aes->key, 0, sizeof(fast_aes->key));
- memset(fast_aes->erk, 0, sizeof(fast_aes->erk));
- memset(fast_aes->drk, 0, sizeof(fast_aes->drk));
+ /* Clear out memory */
+ memset(fast_aes->key, 0, sizeof(fast_aes->key));
+ memset(fast_aes->erk, 0, sizeof(fast_aes->erk));
+ memset(fast_aes->drk, 0, sizeof(fast_aes->drk));
memset(fast_aes->initial_erk, 0, sizeof(fast_aes->initial_erk));
- memset(fast_aes->initial_drk, 0, sizeof(fast_aes->initial_drk));
+ memset(fast_aes->initial_drk, 0, sizeof(fast_aes->initial_drk));
- return Data_Wrap_Struct(klass, fast_aes_mark, fast_aes_free, fast_aes);
+ return Data_Wrap_Struct(klass, fast_aes_mark, fast_aes_free, fast_aes);
}
VALUE fast_aes_initialize(VALUE self, VALUE key)
{
- /* get our "self" data structure (eg, member vars) */
+ /* get our "self" data structure (eg, member vars) */
fast_aes_t* fast_aes;
- Data_Get_Struct(self, fast_aes_t, fast_aes);
- char error_mesg[350];
+ Data_Get_Struct(self, fast_aes_t, fast_aes);
+ char error_mesg[350];
int key_bits;
char* key_data = StringValuePtr(key);
@@ -90,15 +96,15 @@ VALUE fast_aes_initialize(VALUE self, VALUE key)
/*printf("AES key=%s, bits=%d\n", fast_aes->key, fast_aes->key_bits);*/
break;
default:
- sprintf(error_mesg, "AES key must be 128, 192, or 256 bits in length (got %d): %s", key_bits, key_data);
+ sprintf(error_mesg, "AES key must be 128, 192, or 256 bits in length (got %d): %s", key_bits, key_data);
rb_raise(rb_eArgError, error_mesg);
return Qnil;
}
- if (fast_aes_initialize_state(fast_aes)) {
+ if (fast_aes_initialize_state(fast_aes)) {
rb_raise(rb_eRuntimeError, "Failed to initialize AES internal state");
return Qnil;
- }
+ }
return Qtrue;
}
@@ -108,30 +114,29 @@ void fast_aes_module_shutdown( fast_aes_t* fast_aes )
void fast_aes_mark( fast_aes_t* fast_aes )
{
- //rb_gc_mark(??);
- //should we mark each member here?
+ //rb_gc_mark(??);
+ //should we mark each member here?
}
void fast_aes_free( fast_aes_t* fast_aes )
{
- fast_aes_module_shutdown(fast_aes);
- free(fast_aes);
+ fast_aes_module_shutdown(fast_aes);
+ free(fast_aes);
}
VALUE fast_aes_encrypt(
VALUE self,
- VALUE DataIn,
- VALUE BytesIn
+ VALUE buffer
)
{
- /* get our "self" data structure (eg, member vars) */
+ /* get our "self" data structure (eg, member vars) */
fast_aes_t* fast_aes;
- Data_Get_Struct(self, fast_aes_t, fast_aes);
+ Data_Get_Struct(self, fast_aes_t, fast_aes);
- char* pDataIn = StringValuePtr(DataIn);
- int uiNumBytesIn = NUM2INT(BytesIn);
+ char* pDataIn = StringValuePtr(buffer);
+ int uiNumBytesIn = RSTRING_LEN(buffer);
char* pDataOut = malloc((uiNumBytesIn + 15) & -16); /* auto-malloc min size in 16-byte increments */
- // printf("input='%s' (length=%d)\n", pDataIn, uiNumBytesIn);
+ // printf("input='%s' (length=%d)\n", pDataIn, uiNumBytesIn);
/*size_t* puiNumBytesOut*/
unsigned char *pRead, *pWrite;
@@ -147,10 +152,10 @@ VALUE fast_aes_encrypt(
/* set the state back to the start to allow for correct encryption
* everytime we are passed data to encrypt
*/
- if (fast_aes_reinitialize_state(fast_aes)) {
+ if (fast_aes_reinitialize_state(fast_aes)) {
rb_raise(rb_eRuntimeError, "Failed to reinitialize AES internal state");
return Qnil;
- }
+ }
//printf( "using key %s to AES %d bits\n", (char*)m_key, strlen((char*)m_key)*8 );
@@ -163,7 +168,7 @@ VALUE fast_aes_encrypt(
fast_aes_encrypt_block(fast_aes, pRead, pWrite);
pRead += 16; pWrite += 16;
uiNumBytesIn -= 16;
- puiNumBytesOut += 16;
+ puiNumBytesOut += 16;
}
/*//////////////////////////////////////////////////////////////////////////
@@ -179,7 +184,7 @@ VALUE fast_aes_encrypt(
// printf("temp='%s'; pWrite='%s'\n", temp, pWrite);
fast_aes_encrypt_block(fast_aes, temp, pWrite);
// printf("temp='%s'; pWrite='%s'\n", temp, pWrite);
- puiNumBytesOut += 16;
+ puiNumBytesOut += 16;
}
/* return the encrypted string */
@@ -190,16 +195,15 @@ VALUE fast_aes_encrypt(
VALUE fast_aes_decrypt(
VALUE self,
- VALUE DataIn,
- VALUE BytesIn
+ VALUE buffer
)
{
- /* get our "self" data structure (eg, member vars) */
+ /* get our "self" data structure (eg, member vars) */
fast_aes_t* fast_aes;
- Data_Get_Struct(self, fast_aes_t, fast_aes);
+ Data_Get_Struct(self, fast_aes_t, fast_aes);
- char* pDataIn = StringValuePtr(DataIn);
- int uiNumBytesIn = NUM2INT(BytesIn);
+ char* pDataIn = StringValuePtr(buffer);
+ int uiNumBytesIn = RSTRING_LEN(buffer);
char* pDataOut = malloc((uiNumBytesIn + 15) & -16); /* auto-malloc min size in 16-byte increments */
pDataOut = malloc(uiNumBytesIn + 15);
@@ -215,10 +219,10 @@ VALUE fast_aes_decrypt(
// set the state back to the start to allow for correct decryption
// everytime we are passed data to decrypt
- if (fast_aes_reinitialize_state(fast_aes)) {
+ if (fast_aes_reinitialize_state(fast_aes)) {
rb_raise(rb_eRuntimeError, "Failed to reinitialize AES internal state");
return Qnil;
- }
+ }
//printf( "using key %s to AES %d bits\n", (char*)m_key, strlen((char*)m_key)*8 );
////////////////////////////////////////////////////////////////////////////
@@ -230,7 +234,7 @@ VALUE fast_aes_decrypt(
fast_aes_decrypt_block(fast_aes, pRead, pWrite);
pRead += 16; pWrite += 16;
uiNumBytesIn -= 16;
- puiNumBytesOut += 16;
+ puiNumBytesOut += 16;
}
////////////////////////////////////////////////////////////////////////////
@@ -243,7 +247,7 @@ VALUE fast_aes_decrypt(
memset(temp, 0, sizeof(temp)); /* pad with 0's */
memcpy(temp, pRead, uiNumBytesIn);
fast_aes_decrypt_block(fast_aes, temp, pWrite);
- puiNumBytesOut += 16;
+ puiNumBytesOut += 16;
}
/* return the decrypted string */
View
@@ -28,11 +28,11 @@ typedef struct {
/* Encryption Round Keys */
unsigned int erk[64];
- unsigned int initial_erk[64];
+ unsigned int initial_erk[64];
/* Decryption Round Keys */
unsigned int drk[64];
- unsigned int initial_drk[64];
+ unsigned int initial_drk[64];
/* Number of rounds. */
int nr;
@@ -52,17 +52,9 @@ void fast_aes_free(fast_aes_t* fast_aes_config);
void fast_aes_module_shutdown(fast_aes_t* fast_aes_config);
/* and actual, bonafide encryption */
-VALUE fast_aes_encrypt(
- VALUE self,
- VALUE DataIn,
- VALUE BytesIn
-);
+VALUE fast_aes_encrypt(VALUE self, VALUE buffer);
-VALUE fast_aes_decrypt(
- VALUE self,
- VALUE DataIn,
- VALUE BytesIn
-);
+VALUE fast_aes_decrypt(VALUE self, VALUE buffer);
void fast_aes_encrypt_block(fast_aes_t* fast_aes, unsigned char input[16], unsigned char output[16]);
void fast_aes_decrypt_block(fast_aes_t* fast_aes, unsigned char input[16], unsigned char output[16]);
View
@@ -3,7 +3,7 @@ spec = Gem::Specification.new do |s|
s.version = '0.1.0'
s.summary = "Fast AES implementation in C. Works with Ruby 1.8 and 1.9"
s.description = s.summary
- s.files = Dir['lib/**/*.rb'] + Dir['spec/**/*.rb']
+ s.files = Dir['ext/**/*.{rb,c,h}'] + Dir['spec/**/*.rb'] + Dir['test/**/*.rb']
s.require_path = 'lib'
s.has_rdoc = true
s.rubyforge_project = 'fast-aes'
View
Binary file not shown.
View
@@ -1,9 +1,6 @@
-$LOAD_PATH.unshift "#{File.dirname(__FILE__)}"
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../ext/#{RUBY_PLATFORM}"
-require 'bit_field'
-
describe 'FastAES' do
before :all do
puts "building extension..."
Oops, something went wrong.

0 comments on commit 8469516

Please sign in to comment.