YubiRuby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +0 -0
- data/bin/modhex +48 -0
- data/ext/extconf.rb +14 -0
- data/ext/libyubikey.c +534 -0
- data/ext/ykaes.c +214 -0
- data/ext/ykcrc.c +54 -0
- data/ext/ykhex.c +86 -0
- data/ext/ykmodhex.c +86 -0
- data/ext/ykparse.c +45 -0
- data/ext/yubikey.h +121 -0
- data/lib/hex.rb +86 -0
- data/lib/yubiruby.rb +36 -0
- data/tests/tc_modhex.rb +13 -0
- data/tests/ts_yubiruby.rb +6 -0
- metadata +100 -0
data/README
ADDED
File without changes
|
data/bin/modhex
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','ext')
|
4
|
+
|
5
|
+
require 'yubiruby'
|
6
|
+
|
7
|
+
if __FILE__ == $PROGRAM_NAME
|
8
|
+
if ARGV.length < 1
|
9
|
+
msg=<<-EOF
|
10
|
+
Usage: #{$PROGRAM_NAME} [-dh] <data>
|
11
|
+
|
12
|
+
Convert input DATA as specified and print output to STDOUT.
|
13
|
+
|
14
|
+
-d: Decode data (the default is to encode data).
|
15
|
+
-h: Use hex encoding for all non-modhex data.
|
16
|
+
DATA: string with data to encode
|
17
|
+
|
18
|
+
Examples:
|
19
|
+
|
20
|
+
ModHex encode ASCII-string \"test\":
|
21
|
+
#{$PROGRAM_NAME} test
|
22
|
+
|
23
|
+
Decode ModHex data \"ifhgieif\" into ASCII string:
|
24
|
+
#{$PROGRAM_NAME} -d ifhgieif
|
25
|
+
|
26
|
+
ModHex encode hex-encoded data \"b565716f\":
|
27
|
+
#{$PROGRAM_NAME} -h b565716f
|
28
|
+
|
29
|
+
Decode ModHex data \"nghgibhv\" and print hex-encode data:
|
30
|
+
#{$PROGRAM_NAME} -d -h nghgibhv
|
31
|
+
EOF
|
32
|
+
abort msg
|
33
|
+
end
|
34
|
+
|
35
|
+
hex = ARGV.include? "-h"
|
36
|
+
decode = ARGV.include? "-d"
|
37
|
+
data = ARGV.last
|
38
|
+
|
39
|
+
if decode
|
40
|
+
out = data.modhex_decode
|
41
|
+
out = YubiRuby::HEX.encode(out) if hex
|
42
|
+
puts out
|
43
|
+
else
|
44
|
+
data = YubiRuby::HEX.decode(data) if hex
|
45
|
+
puts data.modhex_encode
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
#dir_config("libyubikey")
|
3
|
+
if ARGV.include?('-h')
|
4
|
+
abort <<-EOF
|
5
|
+
Usage: #{$PROGRAM_NAME} [options]
|
6
|
+
|
7
|
+
Options:
|
8
|
+
-d debug mode
|
9
|
+
-h print this help
|
10
|
+
EOF
|
11
|
+
end
|
12
|
+
|
13
|
+
$CFLAGS << " -DNDEBUG" unless ARGV.include?('-d')
|
14
|
+
create_makefile('libyubikey')
|
data/ext/libyubikey.c
ADDED
@@ -0,0 +1,534 @@
|
|
1
|
+
/* libyubikey.c --- Ruby wrapper for low-level Yubikey OTP functions.
|
2
|
+
*
|
3
|
+
* Written by Alessio Caiazza <nolith@abisso.org>.
|
4
|
+
* Copyright (c) 2010 Alessio Caiazza
|
5
|
+
* All rights reserved.
|
6
|
+
*
|
7
|
+
* Redistribution and use in source and binary forms, with or without
|
8
|
+
* modification, are permitted provided that the following conditions are
|
9
|
+
* met:
|
10
|
+
*
|
11
|
+
* * Redistributions of source code must retain the above copyright
|
12
|
+
* notice, this list of conditions and the following disclaimer.
|
13
|
+
*
|
14
|
+
* * Redistributions in binary form must reproduce the above
|
15
|
+
* copyright notice, this list of conditions and the following
|
16
|
+
* disclaimer in the documentation and/or other materials provided
|
17
|
+
* with the distribution.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
20
|
+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
21
|
+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
22
|
+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
25
|
+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
26
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
27
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
28
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
*/
|
31
|
+
|
32
|
+
#include <ruby.h>
|
33
|
+
#include <stdlib.h>
|
34
|
+
#include "yubikey.h"
|
35
|
+
|
36
|
+
#define MODHEX_SING_ENCODE "encode"
|
37
|
+
#define MODHEX_SING_DECODE "decode"
|
38
|
+
#define MODHEX_ENCODE "modhex_encode"
|
39
|
+
#define MODHEX_DECODE "modhex_decode"
|
40
|
+
#define MODHEX_VALID "modhex?"
|
41
|
+
|
42
|
+
static VALUE mYubiRuby;
|
43
|
+
static VALUE mModHex;
|
44
|
+
static VALUE cYubikey;
|
45
|
+
|
46
|
+
|
47
|
+
/* ModHex */
|
48
|
+
|
49
|
+
/*
|
50
|
+
* call-seq:
|
51
|
+
* YubyRuby::ModHex.encode(obj) -> "modhex string"
|
52
|
+
*
|
53
|
+
* Encodes <tt>obj.to_str</tt> into a <tt>modhex string</tt>.
|
54
|
+
*/
|
55
|
+
static VALUE modhex_sing_encode(VALUE self, VALUE obj)
|
56
|
+
{
|
57
|
+
VALUE str = StringValue(obj);
|
58
|
+
int src_size = RSTRING(str)->len;
|
59
|
+
char *dst = (char*) malloc((2*src_size+1)*sizeof(char));
|
60
|
+
/* ModHex encode input string SRC of length SRCSIZE and put the zero
|
61
|
+
terminated output string in DST. The size of the output string DST
|
62
|
+
must be at least 2*SRCSIZE+1. The output string is always
|
63
|
+
2*SRCSIZE large plus the terminating zero. */
|
64
|
+
yubikey_modhex_encode(dst, RSTRING(str)->ptr, src_size);
|
65
|
+
|
66
|
+
return rb_str_new2(dst);
|
67
|
+
}
|
68
|
+
|
69
|
+
/*
|
70
|
+
* call-seq:
|
71
|
+
* str.modhex_encode -> "modhex string"
|
72
|
+
*
|
73
|
+
* Invokes YubyRuby::ModHex.encode on +self+.
|
74
|
+
*/
|
75
|
+
static VALUE modhex_encode(VALUE self)
|
76
|
+
{
|
77
|
+
ID method = rb_intern(MODHEX_SING_ENCODE);
|
78
|
+
|
79
|
+
return rb_funcall(mModHex, method, 1, self);
|
80
|
+
}
|
81
|
+
|
82
|
+
/*
|
83
|
+
* call-seq:
|
84
|
+
* YubyRuby::ModHex.decode(obj) -> "string"
|
85
|
+
*
|
86
|
+
* Decodes <tt>obj.to_str</tt> into a <tt>string</tt>.
|
87
|
+
*
|
88
|
+
* No validatition of format in provided, use YubyRuby::ModHex.modhex?
|
89
|
+
* for checking.
|
90
|
+
*/
|
91
|
+
static VALUE modhex_sing_decode(VALUE self, VALUE obj)
|
92
|
+
{
|
93
|
+
VALUE str = StringValue(obj);
|
94
|
+
int src_size = RSTRING(str)->len;
|
95
|
+
char *dst = (char*) malloc(((src_size/2)+1)*sizeof(char));
|
96
|
+
/* ModHex decode input string SRC of length DSTSIZE/2 into output
|
97
|
+
string DST. The output string DST is always DSTSIZE/2 large plus
|
98
|
+
the terminating zero. */
|
99
|
+
yubikey_modhex_decode(dst, RSTRING(str)->ptr, src_size);
|
100
|
+
|
101
|
+
return rb_str_new2(dst);
|
102
|
+
}
|
103
|
+
|
104
|
+
/*
|
105
|
+
* call-seq:
|
106
|
+
* str.modhec_decode -> "string"
|
107
|
+
*
|
108
|
+
* Invokes YubyRuby::ModHex.decode on +self+.
|
109
|
+
*/
|
110
|
+
static VALUE modhex_decode(VALUE self)
|
111
|
+
{
|
112
|
+
ID method = rb_intern(MODHEX_SING_DECODE);
|
113
|
+
|
114
|
+
return rb_funcall(mModHex, method, 1, self);
|
115
|
+
}
|
116
|
+
|
117
|
+
/*
|
118
|
+
* call-seq:
|
119
|
+
* YubyRuby::ModHex.modhex?(obj) -> true or false
|
120
|
+
*
|
121
|
+
* Checks if <tt>obj.to_str</tt> is a valid <tt>modhex string</tt>.
|
122
|
+
*/
|
123
|
+
static VALUE modhex_sing_is_modhex(VALUE self, VALUE obj)
|
124
|
+
{
|
125
|
+
VALUE str = StringValue(obj);
|
126
|
+
if (yubikey_modhex_p(RSTRING(str)->ptr) != 0)
|
127
|
+
return Qtrue;
|
128
|
+
else
|
129
|
+
return Qfalse;
|
130
|
+
}
|
131
|
+
|
132
|
+
/*
|
133
|
+
* call-seq:
|
134
|
+
* str.modhex? -> true or false
|
135
|
+
*
|
136
|
+
* Invokes YubyRuby::ModHex.modhex? on +self+
|
137
|
+
*/
|
138
|
+
static VALUE modhex_is_modhex(VALUE self)
|
139
|
+
{
|
140
|
+
ID method = rb_intern(MODHEX_VALID);
|
141
|
+
|
142
|
+
return rb_funcall(mModHex, method, 1, self);
|
143
|
+
}
|
144
|
+
/* ModHex END */
|
145
|
+
|
146
|
+
/* Yubikey */
|
147
|
+
|
148
|
+
typedef struct {
|
149
|
+
uint8_t key[YUBIKEY_KEY_SIZE];
|
150
|
+
yubikey_token_t token;
|
151
|
+
} yubikey_data;
|
152
|
+
|
153
|
+
static void yubikey_free(void *p)
|
154
|
+
{
|
155
|
+
free(((yubikey_data*)p)->token);
|
156
|
+
free(p);
|
157
|
+
}
|
158
|
+
|
159
|
+
// allocate space for internal structures
|
160
|
+
static VALUE yubikey_alloc(VALUE klass)
|
161
|
+
{
|
162
|
+
yubikey_data* data;
|
163
|
+
VALUE obj;
|
164
|
+
|
165
|
+
data = (yubikey_data*) malloc(sizeof(yubikey_data));
|
166
|
+
data->token = (yubikey_token_t)malloc(sizeof(yubikey_token_st));
|
167
|
+
|
168
|
+
obj = Data_Wrap_Struct(klass, 0, yubikey_free, data);
|
169
|
+
|
170
|
+
return obj;
|
171
|
+
}
|
172
|
+
|
173
|
+
/* call-seq:
|
174
|
+
* yubikey.key = "hex string"
|
175
|
+
*
|
176
|
+
* Sets the AES key to the <tt>hex string</tt>.
|
177
|
+
*/
|
178
|
+
static VALUE yubikey_set_key(VALUE self, VALUE key)
|
179
|
+
{
|
180
|
+
yubikey_data* data;
|
181
|
+
|
182
|
+
Data_Get_Struct(self, yubikey_data, data);
|
183
|
+
VALUE sKey = StringValue(key);
|
184
|
+
|
185
|
+
if (sKey == Qnil)
|
186
|
+
rb_raise(rb_eTypeError, "wrong parameter type.");
|
187
|
+
|
188
|
+
if (RSTRING(sKey)->len == YUBIKEY_KEY_SIZE*2) {
|
189
|
+
/* Hex */
|
190
|
+
if (yubikey_hex_p(RSTRING(sKey)->ptr) == 0)
|
191
|
+
rb_raise(rb_eTypeError, "not an HEX string."); //TODO:ArgumentError
|
192
|
+
char* buff = (char*) malloc(sizeof(char)*(YUBIKEY_KEY_SIZE +1));
|
193
|
+
yubikey_hex_decode( buff, RSTRING(sKey)->ptr, YUBIKEY_KEY_SIZE );
|
194
|
+
MEMCPY(&data->key, buff, uint8_t, YUBIKEY_KEY_SIZE);
|
195
|
+
}
|
196
|
+
|
197
|
+
return key;
|
198
|
+
}
|
199
|
+
|
200
|
+
/* call-seq:
|
201
|
+
* yubikey.key -> "hex string"
|
202
|
+
*
|
203
|
+
* Gets the AES key as an hex string.
|
204
|
+
*/
|
205
|
+
static VALUE yubikey_get_key(VALUE self)
|
206
|
+
{
|
207
|
+
yubikey_data* data;
|
208
|
+
|
209
|
+
Data_Get_Struct(self, yubikey_data, data);
|
210
|
+
|
211
|
+
char key[YUBIKEY_KEY_SIZE*2 + 1];
|
212
|
+
char* buff = (char*) malloc(sizeof(char)*(YUBIKEY_KEY_SIZE +1));
|
213
|
+
MEMCPY(buff, &data->key, uint8_t, YUBIKEY_KEY_SIZE);
|
214
|
+
buff[YUBIKEY_KEY_SIZE] = '\0';
|
215
|
+
|
216
|
+
yubikey_hex_encode( key, buff, YUBIKEY_KEY_SIZE );
|
217
|
+
|
218
|
+
return rb_str_new2(key);
|
219
|
+
}
|
220
|
+
|
221
|
+
/* call-seq:
|
222
|
+
* Yubikey.new(aes_key) -> new_yubikey
|
223
|
+
*
|
224
|
+
* Creates a yubikey parser whith +aes_key+ ad AES key.
|
225
|
+
*
|
226
|
+
* +aes_key+ musb be encoded with YubiRuby::HEX.encode.
|
227
|
+
*/
|
228
|
+
static VALUE yubikey_initialize(VALUE self, VALUE key)
|
229
|
+
{
|
230
|
+
yubikey_data* data;
|
231
|
+
|
232
|
+
Data_Get_Struct(self, yubikey_data, data);
|
233
|
+
|
234
|
+
yubikey_set_key(self, key);
|
235
|
+
|
236
|
+
return self;
|
237
|
+
}
|
238
|
+
|
239
|
+
static VALUE yubikey_init_copy(VALUE copy, VALUE orig)
|
240
|
+
{
|
241
|
+
yubikey_data *t_orig, *t_copy;
|
242
|
+
|
243
|
+
if (copy == orig)
|
244
|
+
return copy;
|
245
|
+
|
246
|
+
if (TYPE(orig) != T_DATA ||
|
247
|
+
RDATA(orig)->dfree != (RUBY_DATA_FUNC)yubikey_free) {
|
248
|
+
rb_raise(rb_eTypeError, "wrong argument type.");
|
249
|
+
}
|
250
|
+
|
251
|
+
Data_Get_Struct(orig, yubikey_data, t_orig);
|
252
|
+
Data_Get_Struct(copy, yubikey_data, t_copy);
|
253
|
+
MEMCPY(&t_copy->key, &t_orig->key, uint8_t, YUBIKEY_KEY_SIZE);
|
254
|
+
MEMCPY(t_copy->token, t_orig->token, yubikey_token_st, 1);
|
255
|
+
|
256
|
+
return copy;
|
257
|
+
}
|
258
|
+
|
259
|
+
/* call-seq:
|
260
|
+
* yubikey.parse(otp) -> true or false
|
261
|
+
*
|
262
|
+
* Checks the +otp+ for a valid SSO.
|
263
|
+
*/
|
264
|
+
static VALUE yubikey_check(VALUE self, VALUE otp)
|
265
|
+
{
|
266
|
+
yubikey_data *data;
|
267
|
+
|
268
|
+
VALUE str = StringValue(otp);
|
269
|
+
if (str == Qnil)
|
270
|
+
rb_raise(rb_eTypeError, "wrong argument type.");
|
271
|
+
|
272
|
+
int start = RSTRING(str)->len - 32;
|
273
|
+
|
274
|
+
if (start < 0)
|
275
|
+
rb_raise(rb_eTypeError, "OTP too short."); //Argument error
|
276
|
+
|
277
|
+
Data_Get_Struct(self, yubikey_data, data);
|
278
|
+
|
279
|
+
#ifndef NDEBUG
|
280
|
+
/* Debug. */
|
281
|
+
char *buff = (char*)malloc(YUBIKEY_KEY_SIZE+1);
|
282
|
+
yubikey_modhex_decode ((char*)buff,
|
283
|
+
(RSTRING(str)->ptr+start),
|
284
|
+
YUBIKEY_KEY_SIZE);
|
285
|
+
printf ("Input:\n");
|
286
|
+
printf (" token: %s\n", (RSTRING(str)->ptr+start));
|
287
|
+
|
288
|
+
{
|
289
|
+
size_t i;
|
290
|
+
printf (" ");
|
291
|
+
for (i = 0; i < YUBIKEY_KEY_SIZE; i++)
|
292
|
+
printf ("%02x ", buff[i] & 0xFF);
|
293
|
+
printf ("\n");
|
294
|
+
}
|
295
|
+
|
296
|
+
printf (" aeskey: %s\n", RSTRING(yubikey_get_key(self))->ptr);
|
297
|
+
|
298
|
+
{
|
299
|
+
size_t i;
|
300
|
+
printf (" ");
|
301
|
+
for (i = 0; i < YUBIKEY_KEY_SIZE; i++)
|
302
|
+
printf ("%02x ", data->key[i] & 0xFF);
|
303
|
+
printf ("\n");
|
304
|
+
}
|
305
|
+
#endif
|
306
|
+
|
307
|
+
/* Decrypt TOKEN using KEY and store output in OUT structure. Note
|
308
|
+
that there is no error checking whether the output data is valid or
|
309
|
+
not, use yubikey_check_* for that. */
|
310
|
+
yubikey_parse ((uint8_t*)(RSTRING(str)->ptr+start), data->key, data->token);
|
311
|
+
|
312
|
+
#ifndef NDEBUG
|
313
|
+
printf ("Output:\n");
|
314
|
+
{
|
315
|
+
size_t i;
|
316
|
+
printf (" ");
|
317
|
+
for (i = 0; i < YUBIKEY_BLOCK_SIZE; i++)
|
318
|
+
printf ("%02x ", ((uint8_t*)data->token)[i] & 0xFF);
|
319
|
+
printf ("\n");
|
320
|
+
}
|
321
|
+
|
322
|
+
yubikey_token_st tok = *data->token;
|
323
|
+
printf ("\nStruct:\n");
|
324
|
+
/* Debug */
|
325
|
+
{
|
326
|
+
size_t i;
|
327
|
+
printf (" uid: ");
|
328
|
+
for (i = 0; i < YUBIKEY_UID_SIZE; i++)
|
329
|
+
printf ("%02x ", data->token->uid[i] & 0xFF);
|
330
|
+
printf ("\n");
|
331
|
+
}
|
332
|
+
printf (" counter: %d (0x%04x)\n", tok.ctr, tok.ctr);
|
333
|
+
printf (" timestamp (low): %d (0x%04x)\n", tok.tstpl, tok.tstpl);
|
334
|
+
printf (" timestamp (high): %d (0x%02x)\n", tok.tstph, tok.tstph);
|
335
|
+
printf (" session use: %d (0x%02x)\n", tok.use, tok.use);
|
336
|
+
printf (" random: %d (0x%02x)\n", tok.rnd, tok.rnd);
|
337
|
+
printf (" crc: %d (0x%04x)\n", tok.crc, tok.crc);
|
338
|
+
|
339
|
+
printf ("\nDerived:\n");
|
340
|
+
printf (" cleaned counter: %d (0x%04x)\n",
|
341
|
+
yubikey_counter (tok.ctr), yubikey_counter (tok.ctr));
|
342
|
+
yubikey_modhex_encode ((char*)buff, (char*)tok.uid, YUBIKEY_UID_SIZE);
|
343
|
+
printf (" modhex uid: %s\n", buff);
|
344
|
+
printf (" triggered by caps lock: %s\n",
|
345
|
+
yubikey_capslock(tok.ctr) ? "yes" : "no");
|
346
|
+
printf (" crc: %04X\n", yubikey_crc16 ((void*)&tok, YUBIKEY_KEY_SIZE));
|
347
|
+
|
348
|
+
printf (" crc check: ");
|
349
|
+
if (yubikey_crc_ok_p ((uint8_t*)&tok))
|
350
|
+
printf("ok\n");
|
351
|
+
else
|
352
|
+
printf ("fail\n");
|
353
|
+
#endif
|
354
|
+
if (yubikey_crc_ok_p ((uint8_t*)data->token))
|
355
|
+
return Qtrue;
|
356
|
+
else
|
357
|
+
return Qfalse;
|
358
|
+
}
|
359
|
+
|
360
|
+
/* call-seq:
|
361
|
+
* yubikey.to_str -> String
|
362
|
+
*
|
363
|
+
* Gets the decoded token as <tt>hex string</tt> representation.
|
364
|
+
*/
|
365
|
+
static VALUE yubikey_to_str(VALUE self)
|
366
|
+
{
|
367
|
+
size_t i;
|
368
|
+
yubikey_data *data;
|
369
|
+
Data_Get_Struct(self, yubikey_data, data);
|
370
|
+
|
371
|
+
VALUE ary = rb_ary_new2(YUBIKEY_BLOCK_SIZE);
|
372
|
+
for (i = 0; i < YUBIKEY_BLOCK_SIZE; i++) {
|
373
|
+
VALUE num = INT2FIX(((uint8_t*)data->token)[i]);
|
374
|
+
//invoke .to_s 16 on each number
|
375
|
+
rb_ary_store(ary, i, rb_funcall(num, rb_intern("to_s"), 1, INT2FIX(16) ));
|
376
|
+
}
|
377
|
+
|
378
|
+
return rb_funcall(ary, rb_intern("join"), 0);
|
379
|
+
}
|
380
|
+
|
381
|
+
/* call-seq:
|
382
|
+
* yubikey.uid -> "hex string"
|
383
|
+
*
|
384
|
+
* Gets the decoded token UID field as <tt>hex string</tt> representation.
|
385
|
+
*/
|
386
|
+
static VALUE yubikey_get_uid(VALUE self)
|
387
|
+
{
|
388
|
+
VALUE out = yubikey_to_str(self);
|
389
|
+
|
390
|
+
// *2 becaouse of hex
|
391
|
+
return rb_str_new(RSTRING(out)->ptr, YUBIKEY_UID_SIZE*2 );
|
392
|
+
}
|
393
|
+
|
394
|
+
/* call-seq:
|
395
|
+
* yubikey.counter -> Fixnum
|
396
|
+
*
|
397
|
+
* Gets the decoded token counter field.
|
398
|
+
*/
|
399
|
+
static VALUE yubikey_get_counter(VALUE self)
|
400
|
+
{
|
401
|
+
yubikey_data *data;
|
402
|
+
Data_Get_Struct(self, yubikey_data, data);
|
403
|
+
|
404
|
+
return INT2FIX(yubikey_counter(data->token->ctr));
|
405
|
+
}
|
406
|
+
|
407
|
+
/* call-seq:
|
408
|
+
* yubikey.triggered_by_capslock? -> true or false
|
409
|
+
*
|
410
|
+
*/
|
411
|
+
static VALUE yubikey_get_triggered_by_capslock(VALUE self)
|
412
|
+
{
|
413
|
+
yubikey_data *data;
|
414
|
+
Data_Get_Struct(self, yubikey_data, data);
|
415
|
+
|
416
|
+
if (yubikey_capslock(data->token->ctr))
|
417
|
+
return Qtrue;
|
418
|
+
else
|
419
|
+
return Qfalse;
|
420
|
+
}
|
421
|
+
|
422
|
+
static VALUE yubikey_get_tsl(VALUE self)
|
423
|
+
{
|
424
|
+
yubikey_data *data;
|
425
|
+
Data_Get_Struct(self, yubikey_data, data);
|
426
|
+
|
427
|
+
return INT2FIX(data->token->tstpl);
|
428
|
+
}
|
429
|
+
|
430
|
+
static VALUE yubikey_get_tsh(VALUE self)
|
431
|
+
{
|
432
|
+
yubikey_data *data;
|
433
|
+
Data_Get_Struct(self, yubikey_data, data);
|
434
|
+
|
435
|
+
return INT2FIX(data->token->tstph);
|
436
|
+
}
|
437
|
+
|
438
|
+
static VALUE yubikey_get_session(VALUE self)
|
439
|
+
{
|
440
|
+
yubikey_data *data;
|
441
|
+
Data_Get_Struct(self, yubikey_data, data);
|
442
|
+
|
443
|
+
return INT2FIX(data->token->use);
|
444
|
+
}
|
445
|
+
|
446
|
+
static VALUE yubikey_get_random(VALUE self)
|
447
|
+
{
|
448
|
+
yubikey_data *data;
|
449
|
+
Data_Get_Struct(self, yubikey_data, data);
|
450
|
+
|
451
|
+
return INT2FIX(data->token->rnd);
|
452
|
+
}
|
453
|
+
|
454
|
+
static VALUE yubikey_get_crc(VALUE self)
|
455
|
+
{
|
456
|
+
yubikey_data *data;
|
457
|
+
Data_Get_Struct(self, yubikey_data, data);
|
458
|
+
|
459
|
+
return INT2FIX(data->token->crc);
|
460
|
+
}
|
461
|
+
|
462
|
+
static VALUE yubikey_calc_crc(VALUE self)
|
463
|
+
{
|
464
|
+
yubikey_data *data;
|
465
|
+
Data_Get_Struct(self, yubikey_data, data);
|
466
|
+
|
467
|
+
return INT2FIX(yubikey_crc16 ((void*)data->token, YUBIKEY_KEY_SIZE));
|
468
|
+
}
|
469
|
+
|
470
|
+
static VALUE yubikey_check_crc(VALUE self)
|
471
|
+
{
|
472
|
+
yubikey_data *data;
|
473
|
+
Data_Get_Struct(self, yubikey_data, data);
|
474
|
+
|
475
|
+
if (yubikey_crc_ok_p ((uint8_t*)data->token))
|
476
|
+
return Qtrue;
|
477
|
+
else
|
478
|
+
return Qfalse;
|
479
|
+
}
|
480
|
+
/* Yubikey END */
|
481
|
+
|
482
|
+
/* Implementation of Yubikey OTP functions.
|
483
|
+
* This Module may be used to interact with a Yubikey
|
484
|
+
*/
|
485
|
+
void Init_libyubikey() {
|
486
|
+
mYubiRuby = rb_define_module("YubiRuby");
|
487
|
+
|
488
|
+
/* ModHex string encoder/decoder
|
489
|
+
*
|
490
|
+
* The YubiKey uses a special data encoding format known as "modhex" rather
|
491
|
+
* than normal hex encoding or base64 encoding.
|
492
|
+
* Modhex is similar to hex encoding but with a different encoding alphabet.
|
493
|
+
* The reason is to achieve a keyboard layout independent encoding.
|
494
|
+
*
|
495
|
+
* The String class in extended with this module.
|
496
|
+
*/
|
497
|
+
mModHex = rb_define_module_under(mYubiRuby, "ModHex");
|
498
|
+
rb_define_singleton_method(mModHex, "encode", modhex_sing_encode, 1);
|
499
|
+
rb_define_method(mModHex, "modhex_encode", modhex_encode, 0);
|
500
|
+
rb_define_singleton_method(mModHex, "decode", modhex_sing_decode, 1);
|
501
|
+
rb_define_method(mModHex, "modhex_decode", modhex_decode, 0);
|
502
|
+
rb_define_singleton_method(mModHex, "modhex?", modhex_sing_is_modhex, 1);
|
503
|
+
rb_define_method(mModHex, "modhex?", modhex_is_modhex, 0);
|
504
|
+
/* lists of allowed char in MODHEX enconding */
|
505
|
+
rb_define_const(mModHex, "MODHEX_MAP", rb_str_new2(YUBIKEY_MODHEX_MAP));
|
506
|
+
|
507
|
+
//extends String with ModHex
|
508
|
+
rb_include_module(rb_cString, mModHex);
|
509
|
+
|
510
|
+
/* Prototypes for low-level Yubikey OTP functions.
|
511
|
+
*
|
512
|
+
*/
|
513
|
+
cYubikey = rb_define_class_under(mYubiRuby, "Yubikey", rb_cObject);
|
514
|
+
rb_define_alloc_func(cYubikey, yubikey_alloc);
|
515
|
+
rb_define_method(cYubikey, "initialize", yubikey_initialize, 1);
|
516
|
+
rb_define_method(cYubikey, "initialize_copy", yubikey_init_copy, 1);
|
517
|
+
/* CRC value for a valid token */
|
518
|
+
rb_define_const(cYubikey, "CRC_OK_RESIDUE", INT2FIX(YUBIKEY_CRC_OK_RESIDUE));
|
519
|
+
rb_define_method(cYubikey, "key", yubikey_get_key, 0);
|
520
|
+
rb_define_method(cYubikey, "key=", yubikey_set_key, 1);
|
521
|
+
rb_define_method(cYubikey, "parse", yubikey_check, 1);
|
522
|
+
rb_define_method(cYubikey, "to_str", yubikey_to_str, 0);
|
523
|
+
rb_define_alias(cYubikey, "to_s", "to_str");
|
524
|
+
rb_define_method(cYubikey, "uid", yubikey_get_uid, 0);
|
525
|
+
rb_define_method(cYubikey, "counter", yubikey_get_counter, 0);
|
526
|
+
rb_define_method(cYubikey, "triggered_by_capslock?", yubikey_get_triggered_by_capslock, 0);
|
527
|
+
rb_define_method(cYubikey, "timestamp_low", yubikey_get_tsl, 0);
|
528
|
+
rb_define_method(cYubikey, "timestamp_high", yubikey_get_tsh, 0);
|
529
|
+
rb_define_method(cYubikey, "session", yubikey_get_session, 0);
|
530
|
+
rb_define_method(cYubikey, "random", yubikey_get_random, 0);
|
531
|
+
rb_define_method(cYubikey, "crc", yubikey_get_crc, 0);
|
532
|
+
rb_define_method(cYubikey, "crc_residue", yubikey_calc_crc, 0);
|
533
|
+
rb_define_method(cYubikey, "crc?", yubikey_check_crc, 0);
|
534
|
+
}
|