# HG changeset patch # User Alessio Caiazza # Date 1265135655 -3600 # Node ID f5924ad9dd2468be630970716c72208034b5dc18 # Parent 58bc392e043d88964ec859866d7022c89c65a3a3 Full yubico-c wrapping. Some basic RDoc. gemspec externalized. rake task for documentation. diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 .hgignore --- a/.hgignore Sat Jan 30 19:10:11 2010 +0100 +++ b/.hgignore Tue Feb 02 19:34:15 2010 +0100 @@ -15,6 +15,7 @@ *.framework *.pbxuser *.gem +Makefile syntax: regexp .*\#.*\#$ \ No newline at end of file diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE Tue Feb 02 19:34:15 2010 +0100 @@ -0,0 +1,34 @@ +RubyRuby --- Ruby wrapper for low-level Yubikey OTP functions. + +Written by Alessio Caiazza . +Copyright (c) 2010 Alessio Caiazza +All rights reserved. + +The core library is written by Simon Josefsson . +Copyright (c) 2006, 2007, 2008, 2009 Yubico AB +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 Rakefile --- a/Rakefile Sat Jan 30 19:10:11 2010 +0100 +++ b/Rakefile Tue Feb 02 19:34:15 2010 +0100 @@ -2,25 +2,11 @@ require 'rubygems/gem_runner' require 'rake/gempackagetask' +require 'rake/rdoctask' -spec = Gem::Specification.new do |s| - s.name = 'YubiRuby' - s.version = '0.0.1' - s.author = 'Alessio \"nolith\" Caiazza' - s.email = 'nolith@abisso.org' - s.homepage = 'http://abisso.org' - s.platform = Gem::Platform::RUBY - s.summary = 'Yubikey integration' - s.files = FileList["{tests,lib,docs,ext}/**/*"].exclude("rdoc").to_a - s.require_paths = ['lib', 'ext'] - s.autorequire = 'yubiruby' - s.test_file = 'tests/ts_yubiruby.rb' - s.has_rdoc = true - s.extra_rdoc_files = ['README'] - s.extensions = ['ext/extconf.rb'] -end +load 'yubiruby.gemspec' -Rake::GemPackageTask.new(spec) do |pkg| +Rake::GemPackageTask.new($spec) do |pkg| pkg.need_tar = true end @@ -38,4 +24,40 @@ # $LOAD_PATH.unshift(path) # end require spec.test_file -end \ No newline at end of file +end + +# Rake RDocTask with all of the options stubbed out. +Rake::RDocTask.new(:rdoc) do |rd| +# rd.external # run the rdoc process as an external shell +# rd.main = "name" # 'name' will be the initial page displayed + rd.rdoc_dir = "doc" # set the output directory + rd.rdoc_files = FileList["{lib}/**/*"] + ['ext/libyubikey.c'] # List of files to include in the rdoc generation +# rd.template = "html" # Name of the template to be used by rdoc +# rd.title = "" # Title of the RDoc documentation +# rd.options << "--accessor accessorname[,..]" # comma separated list of additional class methods that should be treated like 'attr_reader' and friends. +# rd.options << "--all" # include all methods (not just public) in the output +# rd.options << "--charset charset" # specifies HTML character-set +# rd.options << "--debug" # displays lots on internal stuff +# rd.options << "--diagram" # Generate diagrams showing modules and classes using dot. +# rd.options << "--exclude pattern" # do not process files or directories matching pattern unless they're explicitly included +# rd.options << "--extension new=old" # Treat files ending with .new as if they ended with .old +# rd.options << "--fileboxes" # classes are put in boxes which represents files, where these classes reside. +# rd.options << "--force-update" # forces to scan all sources even if newer than the flag file. +# rd.options << "--fmt format name" # set the output formatter (html, chm, ri, xml) +# rd.options << "--image-format gif/png/jpg/jpeg" # Sets output image format for diagrams. Default is png. +# rd.options << "--include dir[,dir...]" # set (or add to) the list of directories to be searched. +# rd.options << "--inline-source" # Show method source code inline, rather than via a popup link +# rd.options << "--line-numbers" # Include line numbers in the source code +# rd.options << "--merge" # when creating ri output, merge processed classes into previously documented classes of the name name +# rd.options << "--one-file" # put all the output into a single file +# rd.options << "--opname name" # Set the 'name' of the output. Has no effect for HTML format. +# rd.options << "--promiscuous" # Show module/class in the files page. +# rd.options << "--quiet" # don't show progress as we parse +# rd.options << "--ri" # generate output for use by 'ri.' local +# rd.options << "--ri-site" # generate output for use by 'ri.' sitewide +# rd.options << "--ri-system" # generate output for use by 'ri.' system wide, for Ruby installs. +# rd.options << "--show-hash" # A name of the form #name in a comment is a possible hyperlink to an instance method name. When displayed, the '#' is removed unless this option is specified +# rd.options << "--style stylesheet url" # specifies the URL of a separate stylesheet. +# rd.options << "--tab-width n" # Set the width of tab characters (default 8) +# rd.options << "--webcvs url" # Specify a URL for linking to a web frontend to CVS. + end \ No newline at end of file diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 ext/extconf.rb --- a/ext/extconf.rb Sat Jan 30 19:10:11 2010 +0100 +++ b/ext/extconf.rb Tue Feb 02 19:34:15 2010 +0100 @@ -1,3 +1,14 @@ require 'mkmf' #dir_config("libyubikey") +if ARGV.include?('-h') + abort <<-EOF +Usage: #{$PROGRAM_NAME} [options] + +Options: + -d debug mode + -h print this help +EOF +end + +$CFLAGS << " -DNDEBUG" unless ARGV.include?('-d') create_makefile('libyubikey') \ No newline at end of file diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 ext/libyubikey.c --- a/ext/libyubikey.c Sat Jan 30 19:10:11 2010 +0100 +++ b/ext/libyubikey.c Tue Feb 02 19:34:15 2010 +0100 @@ -1,7 +1,37 @@ +/* libyubikey.c --- Ruby wrapper for low-level Yubikey OTP functions. + * + * Written by Alessio Caiazza . + * Copyright (c) 2010 Alessio Caiazza + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include #include #include "yubikey.h" -//#include "ykmodhex.c" #define MODHEX_SING_ENCODE "encode" #define MODHEX_SING_DECODE "decode" @@ -11,10 +41,19 @@ static VALUE mYubiRuby; static VALUE mModHex; +static VALUE cYubikey; /* ModHex */ -static VALUE modhex_sing_encode(VALUE self, VALUE obj) { + +/* + * call-seq: + * YubyRuby::ModHex.encode(obj) -> "modhex string" + * + * Encodes obj.to_str into a modhex string. + */ +static VALUE modhex_sing_encode(VALUE self, VALUE obj) +{ VALUE str = StringValue(obj); int src_size = RSTRING(str)->len; char *dst = (char*) malloc((2*src_size+1)*sizeof(char)); @@ -27,13 +66,30 @@ return rb_str_new2(dst); } -static VALUE modhex_encode(VALUE self) { +/* + * call-seq: + * str.modhex_encode -> "modhex string" + * + * Invokes YubyRuby::ModHex.encode on +self+. + */ +static VALUE modhex_encode(VALUE self) +{ ID method = rb_intern(MODHEX_SING_ENCODE); return rb_funcall(mModHex, method, 1, self); } -static VALUE modhex_sing_decode(VALUE self, VALUE obj) { +/* + * call-seq: + * YubyRuby::ModHex.decode(obj) -> "string" + * + * Decodes obj.to_str into a string. + * + * No validatition of format in provided, use YubyRuby::ModHex.modhex? + * for checking. + */ +static VALUE modhex_sing_decode(VALUE self, VALUE obj) +{ VALUE str = StringValue(obj); int src_size = RSTRING(str)->len; char *dst = (char*) malloc(((src_size/2)+1)*sizeof(char)); @@ -45,13 +101,27 @@ return rb_str_new2(dst); } -static VALUE modhex_decode(VALUE self) { +/* + * call-seq: + * str.modhec_decode -> "string" + * + * Invokes YubyRuby::ModHex.decode on +self+. + */ +static VALUE modhex_decode(VALUE self) +{ ID method = rb_intern(MODHEX_SING_DECODE); return rb_funcall(mModHex, method, 1, self); } -static VALUE modhex_sing_is_modhex(VALUE self, VALUE obj) { +/* + * call-seq: + * YubyRuby::ModHex.modhex?(obj) -> true or false + * + * Checks if obj.to_str is a valid modhex string. + */ +static VALUE modhex_sing_is_modhex(VALUE self, VALUE obj) +{ VALUE str = StringValue(obj); if (yubikey_modhex_p(RSTRING(str)->ptr) != 0) return Qtrue; @@ -59,25 +129,406 @@ return Qfalse; } -static VALUE modhex_is_modhex(VALUE self) { +/* + * call-seq: + * str.modhex? -> true or false + * + * Invokes YubyRuby::ModHex.modhex? on +self+ + */ +static VALUE modhex_is_modhex(VALUE self) +{ ID method = rb_intern(MODHEX_VALID); return rb_funcall(mModHex, method, 1, self); } /* ModHex END */ +/* Yubikey */ + +typedef struct { + uint8_t key[YUBIKEY_KEY_SIZE]; + yubikey_token_t token; +} yubikey_data; + +static void yubikey_free(void *p) +{ + free(((yubikey_data*)p)->token); + free(p); +} + +// allocate space for internal structures +static VALUE yubikey_alloc(VALUE klass) +{ + yubikey_data* data; + VALUE obj; + + data = (yubikey_data*) malloc(sizeof(yubikey_data)); + data->token = (yubikey_token_t)malloc(sizeof(yubikey_token_st)); + + obj = Data_Wrap_Struct(klass, 0, yubikey_free, data); + + return obj; +} + +/* call-seq: + * yubikey.key = "hex string" + * + * Sets the AES key to the hex string. + */ +static VALUE yubikey_set_key(VALUE self, VALUE key) +{ + yubikey_data* data; + + Data_Get_Struct(self, yubikey_data, data); + VALUE sKey = StringValue(key); + + if (sKey == Qnil) + rb_raise(rb_eTypeError, "wrong parameter type."); + + if (RSTRING(sKey)->len == YUBIKEY_KEY_SIZE*2) { + /* Hex */ + if (yubikey_hex_p(RSTRING(sKey)->ptr) == 0) + rb_raise(rb_eTypeError, "not an HEX string."); //TODO:ArgumentError + char* buff = (char*) malloc(sizeof(char)*(YUBIKEY_KEY_SIZE +1)); + yubikey_hex_decode( buff, RSTRING(sKey)->ptr, YUBIKEY_KEY_SIZE ); + MEMCPY(&data->key, buff, uint8_t, YUBIKEY_KEY_SIZE); + } + + return key; +} + +/* call-seq: + * yubikey.key -> "hex string" + * + * Gets the AES key as an hex string. + */ +static VALUE yubikey_get_key(VALUE self) +{ + yubikey_data* data; + + Data_Get_Struct(self, yubikey_data, data); + + char key[YUBIKEY_KEY_SIZE*2 + 1]; + char* buff = (char*) malloc(sizeof(char)*(YUBIKEY_KEY_SIZE +1)); + MEMCPY(buff, &data->key, uint8_t, YUBIKEY_KEY_SIZE); + buff[YUBIKEY_KEY_SIZE] = '\0'; + + yubikey_hex_encode( key, buff, YUBIKEY_KEY_SIZE ); + + return rb_str_new2(key); +} + +/* call-seq: + * Yubikey.new(aes_key) -> new_yubikey + * + * Creates a yubikey parser whith +aes_key+ ad AES key. + * + * +aes_key+ musb be encoded with YubiRuby::HEX.encode. + */ +static VALUE yubikey_initialize(VALUE self, VALUE key) +{ + yubikey_data* data; + + Data_Get_Struct(self, yubikey_data, data); + + yubikey_set_key(self, key); + + return self; +} + +static VALUE yubikey_init_copy(VALUE copy, VALUE orig) +{ + yubikey_data *t_orig, *t_copy; + + if (copy == orig) + return copy; + + if (TYPE(orig) != T_DATA || + RDATA(orig)->dfree != (RUBY_DATA_FUNC)yubikey_free) { + rb_raise(rb_eTypeError, "wrong argument type."); + } + + Data_Get_Struct(orig, yubikey_data, t_orig); + Data_Get_Struct(copy, yubikey_data, t_copy); + MEMCPY(&t_copy->key, &t_orig->key, uint8_t, YUBIKEY_KEY_SIZE); + MEMCPY(t_copy->token, t_orig->token, yubikey_token_st, 1); + + return copy; +} + +/* call-seq: + * yubikey.parse(otp) -> true or false + * + * Checks the +otp+ for a valid SSO. + */ +static VALUE yubikey_check(VALUE self, VALUE otp) +{ + yubikey_data *data; + + VALUE str = StringValue(otp); + if (str == Qnil) + rb_raise(rb_eTypeError, "wrong argument type."); + + int start = RSTRING(str)->len - 32; + + if (start < 0) + rb_raise(rb_eTypeError, "OTP too short."); //Argument error + + Data_Get_Struct(self, yubikey_data, data); + +#ifndef NDEBUG + /* Debug. */ + char *buff = (char*)malloc(YUBIKEY_KEY_SIZE+1); + yubikey_modhex_decode ((char*)buff, + (RSTRING(str)->ptr+start), + YUBIKEY_KEY_SIZE); + printf ("Input:\n"); + printf (" token: %s\n", (RSTRING(str)->ptr+start)); + + { + size_t i; + printf (" "); + for (i = 0; i < YUBIKEY_KEY_SIZE; i++) + printf ("%02x ", buff[i] & 0xFF); + printf ("\n"); + } + + printf (" aeskey: %s\n", RSTRING(yubikey_get_key(self))->ptr); + + { + size_t i; + printf (" "); + for (i = 0; i < YUBIKEY_KEY_SIZE; i++) + printf ("%02x ", data->key[i] & 0xFF); + printf ("\n"); + } +#endif + + /* Decrypt TOKEN using KEY and store output in OUT structure. Note + that there is no error checking whether the output data is valid or + not, use yubikey_check_* for that. */ + yubikey_parse ((uint8_t*)(RSTRING(str)->ptr+start), data->key, data->token); + +#ifndef NDEBUG + printf ("Output:\n"); + { + size_t i; + printf (" "); + for (i = 0; i < YUBIKEY_BLOCK_SIZE; i++) + printf ("%02x ", ((uint8_t*)data->token)[i] & 0xFF); + printf ("\n"); + } + + yubikey_token_st tok = *data->token; + printf ("\nStruct:\n"); + /* Debug */ + { + size_t i; + printf (" uid: "); + for (i = 0; i < YUBIKEY_UID_SIZE; i++) + printf ("%02x ", data->token->uid[i] & 0xFF); + printf ("\n"); + } + printf (" counter: %d (0x%04x)\n", tok.ctr, tok.ctr); + printf (" timestamp (low): %d (0x%04x)\n", tok.tstpl, tok.tstpl); + printf (" timestamp (high): %d (0x%02x)\n", tok.tstph, tok.tstph); + printf (" session use: %d (0x%02x)\n", tok.use, tok.use); + printf (" random: %d (0x%02x)\n", tok.rnd, tok.rnd); + printf (" crc: %d (0x%04x)\n", tok.crc, tok.crc); + + printf ("\nDerived:\n"); + printf (" cleaned counter: %d (0x%04x)\n", + yubikey_counter (tok.ctr), yubikey_counter (tok.ctr)); + yubikey_modhex_encode ((char*)buff, (char*)tok.uid, YUBIKEY_UID_SIZE); + printf (" modhex uid: %s\n", buff); + printf (" triggered by caps lock: %s\n", + yubikey_capslock(tok.ctr) ? "yes" : "no"); + printf (" crc: %04X\n", yubikey_crc16 ((void*)&tok, YUBIKEY_KEY_SIZE)); + + printf (" crc check: "); + if (yubikey_crc_ok_p ((uint8_t*)&tok)) + printf("ok\n"); + else + printf ("fail\n"); +#endif + if (yubikey_crc_ok_p ((uint8_t*)data->token)) + return Qtrue; + else + return Qfalse; +} + +/* call-seq: + * yubikey.to_str -> String + * + * Gets the decoded token as hex string representation. + */ +static VALUE yubikey_to_str(VALUE self) +{ + size_t i; + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + VALUE ary = rb_ary_new2(YUBIKEY_BLOCK_SIZE); + for (i = 0; i < YUBIKEY_BLOCK_SIZE; i++) { + VALUE num = INT2FIX(((uint8_t*)data->token)[i]); + //invoke .to_s 16 on each number + rb_ary_store(ary, i, rb_funcall(num, rb_intern("to_s"), 1, INT2FIX(16) )); + } + + return rb_funcall(ary, rb_intern("join"), 0); +} + +/* call-seq: + * yubikey.uid -> "hex string" + * + * Gets the decoded token UID field as hex string representation. + */ +static VALUE yubikey_get_uid(VALUE self) +{ + VALUE out = yubikey_to_str(self); + + // *2 becaouse of hex + return rb_str_new(RSTRING(out)->ptr, YUBIKEY_UID_SIZE*2 ); +} + +/* call-seq: + * yubikey.counter -> Fixnum + * + * Gets the decoded token counter field. + */ +static VALUE yubikey_get_counter(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + return INT2FIX(yubikey_counter(data->token->ctr)); +} + +/* call-seq: + * yubikey.triggered_by_capslock? -> true or false + * + */ +static VALUE yubikey_get_triggered_by_capslock(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + if (yubikey_capslock(data->token->ctr)) + return Qtrue; + else + return Qfalse; +} + +static VALUE yubikey_get_tsl(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + return INT2FIX(data->token->tstpl); +} + +static VALUE yubikey_get_tsh(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + return INT2FIX(data->token->tstph); +} + +static VALUE yubikey_get_session(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + return INT2FIX(data->token->use); +} + +static VALUE yubikey_get_random(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + return INT2FIX(data->token->rnd); +} + +static VALUE yubikey_get_crc(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + return INT2FIX(data->token->crc); +} + +static VALUE yubikey_calc_crc(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + return INT2FIX(yubikey_crc16 ((void*)data->token, YUBIKEY_KEY_SIZE)); +} + +static VALUE yubikey_check_crc(VALUE self) +{ + yubikey_data *data; + Data_Get_Struct(self, yubikey_data, data); + + if (yubikey_crc_ok_p ((uint8_t*)data->token)) + return Qtrue; + else + return Qfalse; +} +/* Yubikey END */ + +/* Implementation of Yubikey OTP functions. + * This Module may be used to interact with a Yubikey + */ void Init_libyubikey() { mYubiRuby = rb_define_module("YubiRuby"); + /* ModHex string encoder/decoder + * + * The YubiKey uses a special data encoding format known as "modhex" rather + * than normal hex encoding or base64 encoding. + * Modhex is similar to hex encoding but with a different encoding alphabet. + * The reason is to achieve a keyboard layout independent encoding. + * + * The String class in extended with this module. + */ mModHex = rb_define_module_under(mYubiRuby, "ModHex"); - rb_define_singleton_method(mModHex, MODHEX_SING_ENCODE, modhex_sing_encode, 1); - rb_define_method(mModHex, MODHEX_ENCODE, modhex_encode, 0); - rb_define_singleton_method(mModHex, MODHEX_SING_DECODE, modhex_sing_decode, 1); - rb_define_method(mModHex, MODHEX_DECODE, modhex_decode, 0); - rb_define_singleton_method(mModHex, MODHEX_VALID, modhex_sing_is_modhex, 1); - rb_define_method(mModHex, MODHEX_VALID, modhex_is_modhex, 0); + rb_define_singleton_method(mModHex, "encode", modhex_sing_encode, 1); + rb_define_method(mModHex, "modhex_encode", modhex_encode, 0); + rb_define_singleton_method(mModHex, "decode", modhex_sing_decode, 1); + rb_define_method(mModHex, "modhex_decode", modhex_decode, 0); + rb_define_singleton_method(mModHex, "modhex?", modhex_sing_is_modhex, 1); + rb_define_method(mModHex, "modhex?", modhex_is_modhex, 0); + /* lists of allowed char in MODHEX enconding */ rb_define_const(mModHex, "MODHEX_MAP", rb_str_new2(YUBIKEY_MODHEX_MAP)); //extends String with ModHex rb_include_module(rb_cString, mModHex); + + /* Prototypes for low-level Yubikey OTP functions. + * + */ + cYubikey = rb_define_class_under(mYubiRuby, "Yubikey", rb_cObject); + rb_define_alloc_func(cYubikey, yubikey_alloc); + rb_define_method(cYubikey, "initialize", yubikey_initialize, 1); + rb_define_method(cYubikey, "initialize_copy", yubikey_init_copy, 1); + /* CRC value for a valid token */ + rb_define_const(cYubikey, "CRC_OK_RESIDUE", INT2FIX(YUBIKEY_CRC_OK_RESIDUE)); + rb_define_method(cYubikey, "key", yubikey_get_key, 0); + rb_define_method(cYubikey, "key=", yubikey_set_key, 1); + rb_define_method(cYubikey, "parse", yubikey_check, 1); + rb_define_method(cYubikey, "to_str", yubikey_to_str, 0); + rb_define_alias(cYubikey, "to_s", "to_str"); + rb_define_method(cYubikey, "uid", yubikey_get_uid, 0); + rb_define_method(cYubikey, "counter", yubikey_get_counter, 0); + rb_define_method(cYubikey, "triggered_by_capslock?", yubikey_get_triggered_by_capslock, 0); + rb_define_method(cYubikey, "timestamp_low", yubikey_get_tsl, 0); + rb_define_method(cYubikey, "timestamp_high", yubikey_get_tsh, 0); + rb_define_method(cYubikey, "session", yubikey_get_session, 0); + rb_define_method(cYubikey, "random", yubikey_get_random, 0); + rb_define_method(cYubikey, "crc", yubikey_get_crc, 0); + rb_define_method(cYubikey, "crc_residue", yubikey_calc_crc, 0); + rb_define_method(cYubikey, "crc?", yubikey_check_crc, 0); } \ No newline at end of file diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 ext/ykaes.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ext/ykaes.c Tue Feb 02 19:34:15 2010 +0100 @@ -0,0 +1,214 @@ +/* ykaes.c --- Implementation of AES-128. + * + * Copyright (c) 2006, 2007, 2008, 2009 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "yubikey.h" + +#define NUMBER_OF_ROUNDS 10 + +static const uint8_t RC[] = + { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 }; + +static const uint8_t rijndael_sbox[] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +static const uint8_t rijndael_inv_sbox[] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +static inline uint8_t +xtime (uint8_t b) +{ + return (b & 0x80) ? ((b << 1) ^ 0x1b) : (b << 1); +} + +void +yubikey_aes_decrypt (uint8_t * state, const uint8_t * key) +{ + uint8_t i, j, round_key[0x10]; + uint8_t a02x, a13x; + uint8_t a02xx, a13xx; + uint8_t k1, k2; + + memcpy (round_key, key, sizeof (round_key)); + for (i = 0; i < NUMBER_OF_ROUNDS; i++) + { + round_key[0] ^= RC[i]; + + round_key[0] ^= rijndael_sbox[round_key[13]]; + round_key[1] ^= rijndael_sbox[round_key[14]]; + round_key[2] ^= rijndael_sbox[round_key[15]]; + round_key[3] ^= rijndael_sbox[round_key[12]]; + + for (j = 4; j < 16; j++) + round_key[j] ^= round_key[j - 4]; + } + for (i = 0; i < 0x10; i++) + state[i] ^= round_key[i]; + + for (i = 1; i <= NUMBER_OF_ROUNDS; i++) + { + // inv_byte_sub_shift_row(); + + /* First row: 0 shift, 0 4 8 12 */ + state[0] = rijndael_inv_sbox[state[0]]; + state[4] = rijndael_inv_sbox[state[4]]; + state[8] = rijndael_inv_sbox[state[8]]; + state[12] = rijndael_inv_sbox[state[12]]; + + /* Second row: -1 shift, 1 5 9 13 */ + j = state[13]; + state[13] = rijndael_inv_sbox[state[9]]; + state[9] = rijndael_inv_sbox[state[5]]; + state[5] = rijndael_inv_sbox[state[1]]; + state[1] = rijndael_inv_sbox[j]; + + /* Third row: -2 shift, 2 6 10 14 */ + j = state[2]; + state[2] = rijndael_inv_sbox[state[10]]; + state[10] = rijndael_inv_sbox[j]; + j = state[6]; + state[6] = rijndael_inv_sbox[state[14]]; + state[14] = rijndael_inv_sbox[j]; + + /* Fourth row: -3 shift, 3 7 11 15 */ + j = state[3]; + state[3] = rijndael_inv_sbox[state[7]]; + state[7] = rijndael_inv_sbox[state[11]]; + state[11] = rijndael_inv_sbox[state[15]]; + state[15] = rijndael_inv_sbox[j]; + +// get_inv_round_key(i); + + for (j = 15; j > 3; j--) + round_key[j] ^= round_key[j - 4]; + + round_key[0] ^= + (RC[NUMBER_OF_ROUNDS - i] ^ rijndael_sbox[round_key[13]]); + + round_key[1] ^= rijndael_sbox[round_key[14]]; + round_key[2] ^= rijndael_sbox[round_key[15]]; + round_key[3] ^= rijndael_sbox[round_key[12]]; + + for (j = 0; j < 16; j++) + state[j] ^= round_key[j]; + if (i != NUMBER_OF_ROUNDS) + { + + //inv_mix_column(); + + for (j = 0; j < 16; j += 4) + { + k1 = state[j] ^ state[j + 2]; + a02x = xtime (k1); + k2 = state[j + 1] ^ state[j + 3]; + a13x = xtime (k2); + + k1 ^= (k2 ^ xtime (state[j + 1] ^ state[j + 2])); + k2 = k1; + + a02xx = xtime (a02x); + a13xx = xtime (a13x); + + k1 ^= (xtime (a02xx ^ a13xx) ^ a02xx); + k2 ^= (xtime (a02xx ^ a13xx) ^ a13xx); + + state[j] ^= (k1 ^ a02x); + state[j + 1] ^= k2; + state[j + 2] ^= (k1 ^ a13x); + state[j + 3] ^= (k2 ^ a02x ^ a13x); + } + } + + } +} diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 ext/ykcrc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ext/ykcrc.c Tue Feb 02 19:34:15 2010 +0100 @@ -0,0 +1,54 @@ +/* ykcrc.c --- Implementation of Yubikey CRC-16 function. + * + * Written by Simon Josefsson . + * Copyright (c) 2006, 2007, 2008, 2009 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "yubikey.h" + +uint16_t +yubikey_crc16 (const uint8_t *buf, size_t buf_size) +{ + uint16_t m_crc = 0xffff; + + while (buf_size--) + { + int i, j; + m_crc ^= (uint8_t) * buf++ & 0xFF; + for (i = 0; i < 8; i++) + { + j = m_crc & 1; + m_crc >>= 1; + if (j) + m_crc ^= 0x8408; + } + } + + return m_crc; +} diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 ext/ykhex.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ext/ykhex.c Tue Feb 02 19:34:15 2010 +0100 @@ -0,0 +1,86 @@ +/* ykhex.c --- Implementation of hex encoding/decoding + * + * Written by Simon Josefsson . + * Copyright (c) 2006, 2007, 2008, 2009 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "yubikey.h" + +#include + +static const char trans[] = "0123456789abcdef"; + +void +yubikey_hex_encode (char *dst, const char *src, size_t srcSize) +{ + while (srcSize--) + { + *dst++ = trans[(*src >> 4) & 0xf]; + *dst++ = trans[*src++ & 0xf]; + } + + *dst = '\0'; +} + +void +yubikey_hex_decode (char *dst, const char *src, size_t dstSize) +{ + char b; + bool flag = false; + char *p1; + + for (; *src && dstSize > 0; src++) + { + if ((p1 = strchr (trans, *src)) == NULL) + b = 0; + else + b = (char) (p1 - trans); + + if ((flag = !flag)) + *dst = b; + else + { + *dst = (*dst << 4) | b; + dst++; + dstSize--; + } + } + while (dstSize--) + *dst++ = 0; +} + +int +yubikey_hex_p (const char *str) +{ + for (; *str; str++) + if (strchr (trans, *str) == NULL) + return 0; + + return 1; +} diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 ext/ykparse.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ext/ykparse.c Tue Feb 02 19:34:15 2010 +0100 @@ -0,0 +1,45 @@ +/* ykparse.c --- Implementation of Yubikey token parser. + * + * Written by Simon Josefsson . + * Copyright (c) 2006, 2007, 2008, 2009 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "yubikey.h" + +#include +#include + +void +yubikey_parse (const uint8_t token[32], + const uint8_t key[16], yubikey_token_t out) +{ + memset (out, 0, sizeof (*out)); + yubikey_modhex_decode ((void *) out, (char *) token, sizeof (*out)); + yubikey_aes_decrypt ((void *) out, key); +} diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 lib/hex.rb --- a/lib/hex.rb Sat Jan 30 19:10:11 2010 +0100 +++ b/lib/hex.rb Tue Feb 02 19:34:15 2010 +0100 @@ -1,14 +1,70 @@ +# Author:: Alessio Caiazza (mailto:nolith@abisso.org) +# Copyright:: Copyright (c) 2010 Alessio Caiazza +# License:: New BSD License - http://www.opensource.org/licenses/bsd-license.php +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + module YubiRuby + # Hex string encoder/decoder + # + # You may consider extending String with YubiRuby::HEX + # class String + # include YubiRuby::HEX + # end + # + # "foo bar".hex_encode #=> "666f6f20626172" + # "666f6f20626172".hex_decode #=> "foo bar" module HEX + + # call-seq: + # YubiRuby::HEX.encode("string") -> "hex string" + # + # Encodes obj.to_str into an hex string. + # def self.encode( obj ) s = obj.to_str s.unpack('U'*s.length).collect {|x| x.to_s 16}.join end + # call-seq: + # hex_encode -> "hex string" + # + # Invokes YubiRuby::HEX.encode on +self+. def hex_encode HEX.encode(self) end + # call-seq: + # YubiRuby::HEX.decode("hex string") -> "string" or "" + # + # Decodes obj.to_str into a string. + # + # An hex string length must be pair, if not an + # empty string is returned. def self.decode( obj ) s = obj.to_str dec = "" @@ -19,12 +75,12 @@ return dec end + # call-seq: + # hex_decode -> "string" + # + # Invokes YubiRuby::HEX.decode on +self+. def hex_decode HEX.decode(self) end end end - -#class String -# include YubiRuby::HEX -#end diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 lib/yubiruby.rb --- a/lib/yubiruby.rb Sat Jan 30 19:10:11 2010 +0100 +++ b/lib/yubiruby.rb Tue Feb 02 19:34:15 2010 +0100 @@ -1,3 +1,32 @@ +# Author:: Alessio Caiazza (mailto:nolith@abisso.org) +# Copyright:: Copyright (c) 2010 Alessio Caiazza +# License:: New BSD License - http://www.opensource.org/licenses/bsd-license.php +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + require 'libyubikey' require 'hex' diff -r 58bc392e043d88964ec859866d7022c89c65a3a3 -r f5924ad9dd2468be630970716c72208034b5dc18 yubiruby.gemspec --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yubiruby.gemspec Tue Feb 02 19:34:15 2010 +0100 @@ -0,0 +1,51 @@ +$spec = Gem::Specification.new do |s| + s.name = 'YubiRuby' + s.version = '0.0.1' + s.author = 'Alessio \"nolith\" Caiazza' + s.email = 'nolith@abisso.org' + s.homepage = 'http://bitbucket.org/nolith/yubiruby/' + s.platform = Gem::Platform::RUBY + s.summary = "Yubikey integration - Based on Prototypes for low-level Yubikey OTP functions witten " + + " by Simon Josefsson .\nCopyright (c) 2006, 2007, 2008, 2009 Yubico AB" + s.description = <<-EOF +Yubikey integration - + +Includes Prototypes for low-level Yubikey OTP functions +witten by Simon Josefsson . +Copyright (c) 2006, 2007, 2008, 2009 Yubico AB +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +EOF + s.files = FileList["{tests,lib,docs,bin}/**/*"].exclude("rdoc").to_a + + FileList["ext/*.{c,h}"] + ['ext/extconf.rb'] + s.require_paths = ['lib', 'ext'] + s.bindir = 'bin' + s.autorequire = 'yubiruby' + s.test_file = 'tests/ts_yubiruby.rb' + s.has_rdoc = true + s.extra_rdoc_files = ['README'] + s.extensions = ['ext/extconf.rb'] +end \ No newline at end of file