YubiRuby 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|