1 /*
2 * 'OpenSSL for Ruby' project
3 * Copyright (C) 2001-2002 Technorama team <oss-ruby@technorama.net>
4 * All rights reserved.
5 */
6 /*
7 * This program is licensed under the same licence as Ruby.
8 * (See the file 'LICENCE'.)
9 */
10 /* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
11 #include "ossl.h"
12
13 #define NewBN(klass) \
14 TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
15 #define SetBN(obj, bn) do { \
16 if (!(bn)) { \
17 ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
18 } \
19 RTYPEDDATA_DATA(obj) = (bn); \
20 } while (0)
21
22 #define GetBN(obj, bn) do { \
23 TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
24 if (!(bn)) { \
25 ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
26 } \
27 } while (0)
28
29 static void
ossl_bn_free(void * ptr)30 ossl_bn_free(void *ptr)
31 {
32 BN_clear_free(ptr);
33 }
34
35 static const rb_data_type_t ossl_bn_type = {
36 "OpenSSL/BN",
37 {
38 0, ossl_bn_free,
39 },
40 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
41 };
42
43 /*
44 * Classes
45 */
46 VALUE cBN;
47
48 /* Document-class: OpenSSL::BNError
49 *
50 * Generic Error for all of OpenSSL::BN (big num)
51 */
52 VALUE eBNError;
53
54 /*
55 * Public
56 */
57 VALUE
ossl_bn_new(const BIGNUM * bn)58 ossl_bn_new(const BIGNUM *bn)
59 {
60 BIGNUM *newbn;
61 VALUE obj;
62
63 obj = NewBN(cBN);
64 newbn = bn ? BN_dup(bn) : BN_new();
65 if (!newbn) {
66 ossl_raise(eBNError, NULL);
67 }
68 SetBN(obj, newbn);
69
70 return obj;
71 }
72
73 static BIGNUM *
integer_to_bnptr(VALUE obj,BIGNUM * orig)74 integer_to_bnptr(VALUE obj, BIGNUM *orig)
75 {
76 BIGNUM *bn;
77
78 if (FIXNUM_P(obj)) {
79 long i;
80 unsigned char bin[sizeof(long)];
81 long n = FIX2LONG(obj);
82 unsigned long un = labs(n);
83
84 for (i = sizeof(long) - 1; 0 <= i; i--) {
85 bin[i] = un & 0xff;
86 un >>= 8;
87 }
88
89 bn = BN_bin2bn(bin, sizeof(bin), orig);
90 if (!bn)
91 ossl_raise(eBNError, "BN_bin2bn");
92 if (n < 0)
93 BN_set_negative(bn, 1);
94 }
95 else { /* assuming Bignum */
96 size_t len = rb_absint_size(obj, NULL);
97 unsigned char *bin;
98 VALUE buf;
99 int sign;
100
101 if (INT_MAX < len) {
102 rb_raise(eBNError, "bignum too long");
103 }
104 bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
105 sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
106
107 bn = BN_bin2bn(bin, (int)len, orig);
108 ALLOCV_END(buf);
109 if (!bn)
110 ossl_raise(eBNError, "BN_bin2bn");
111 if (sign < 0)
112 BN_set_negative(bn, 1);
113 }
114
115 return bn;
116 }
117
118 static VALUE
try_convert_to_bn(VALUE obj)119 try_convert_to_bn(VALUE obj)
120 {
121 BIGNUM *bn;
122 VALUE newobj = Qnil;
123
124 if (rb_obj_is_kind_of(obj, cBN))
125 return obj;
126 if (RB_INTEGER_TYPE_P(obj)) {
127 newobj = NewBN(cBN); /* Handle potential mem leaks */
128 bn = integer_to_bnptr(obj, NULL);
129 SetBN(newobj, bn);
130 }
131
132 return newobj;
133 }
134
135 BIGNUM *
ossl_bn_value_ptr(volatile VALUE * ptr)136 ossl_bn_value_ptr(volatile VALUE *ptr)
137 {
138 VALUE tmp;
139 BIGNUM *bn;
140
141 tmp = try_convert_to_bn(*ptr);
142 if (NIL_P(tmp))
143 ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
144 GetBN(tmp, bn);
145 *ptr = tmp;
146
147 return bn;
148 }
149
150 /*
151 * Private
152 */
153 /*
154 * BN_CTX - is used in more difficult math. ops
155 * (Why just 1? Because Ruby itself isn't thread safe,
156 * we don't need to care about threads)
157 */
158 BN_CTX *ossl_bn_ctx;
159
160 static VALUE
ossl_bn_alloc(VALUE klass)161 ossl_bn_alloc(VALUE klass)
162 {
163 BIGNUM *bn;
164 VALUE obj = NewBN(klass);
165
166 if (!(bn = BN_new())) {
167 ossl_raise(eBNError, NULL);
168 }
169 SetBN(obj, bn);
170
171 return obj;
172 }
173
174 /*
175 * call-seq:
176 * OpenSSL::BN.new => aBN
177 * OpenSSL::BN.new(bn) => aBN
178 * OpenSSL::BN.new(integer) => aBN
179 * OpenSSL::BN.new(string) => aBN
180 * OpenSSL::BN.new(string, 0 | 2 | 10 | 16) => aBN
181 *
182 * Construct a new OpenSSL BIGNUM object.
183 */
184 static VALUE
ossl_bn_initialize(int argc,VALUE * argv,VALUE self)185 ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
186 {
187 BIGNUM *bn;
188 VALUE str, bs;
189 int base = 10;
190 char *ptr;
191
192 if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
193 base = NUM2INT(bs);
194 }
195
196 if (RB_INTEGER_TYPE_P(str)) {
197 GetBN(self, bn);
198 integer_to_bnptr(str, bn);
199
200 return self;
201 }
202
203 if (RTEST(rb_obj_is_kind_of(str, cBN))) {
204 BIGNUM *other;
205
206 GetBN(self, bn);
207 GetBN(str, other); /* Safe - we checked kind_of? above */
208 if (!BN_copy(bn, other)) {
209 ossl_raise(eBNError, NULL);
210 }
211 return self;
212 }
213
214 GetBN(self, bn);
215 switch (base) {
216 case 0:
217 ptr = StringValuePtr(str);
218 if (!BN_mpi2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
219 ossl_raise(eBNError, NULL);
220 }
221 break;
222 case 2:
223 ptr = StringValuePtr(str);
224 if (!BN_bin2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
225 ossl_raise(eBNError, NULL);
226 }
227 break;
228 case 10:
229 if (!BN_dec2bn(&bn, StringValueCStr(str))) {
230 ossl_raise(eBNError, NULL);
231 }
232 break;
233 case 16:
234 if (!BN_hex2bn(&bn, StringValueCStr(str))) {
235 ossl_raise(eBNError, NULL);
236 }
237 break;
238 default:
239 ossl_raise(rb_eArgError, "invalid radix %d", base);
240 }
241 return self;
242 }
243
244 /*
245 * call-seq:
246 * bn.to_s => string
247 * bn.to_s(base) => string
248 *
249 * === Parameters
250 * * _base_ - Integer
251 * Valid values:
252 * * 0 - MPI
253 * * 2 - binary
254 * * 10 - the default
255 * * 16 - hex
256 */
257 static VALUE
ossl_bn_to_s(int argc,VALUE * argv,VALUE self)258 ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
259 {
260 BIGNUM *bn;
261 VALUE str, bs;
262 int base = 10, len;
263 char *buf;
264
265 if (rb_scan_args(argc, argv, "01", &bs) == 1) {
266 base = NUM2INT(bs);
267 }
268 GetBN(self, bn);
269 switch (base) {
270 case 0:
271 len = BN_bn2mpi(bn, NULL);
272 str = rb_str_new(0, len);
273 if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
274 ossl_raise(eBNError, NULL);
275 break;
276 case 2:
277 len = BN_num_bytes(bn);
278 str = rb_str_new(0, len);
279 if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
280 ossl_raise(eBNError, NULL);
281 break;
282 case 10:
283 if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
284 str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
285 break;
286 case 16:
287 if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
288 str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
289 break;
290 default:
291 ossl_raise(rb_eArgError, "invalid radix %d", base);
292 }
293
294 return str;
295 }
296
297 /*
298 * call-seq:
299 * bn.to_i => integer
300 */
301 static VALUE
ossl_bn_to_i(VALUE self)302 ossl_bn_to_i(VALUE self)
303 {
304 BIGNUM *bn;
305 char *txt;
306 VALUE num;
307
308 GetBN(self, bn);
309
310 if (!(txt = BN_bn2hex(bn))) {
311 ossl_raise(eBNError, NULL);
312 }
313 num = rb_cstr_to_inum(txt, 16, Qtrue);
314 OPENSSL_free(txt);
315
316 return num;
317 }
318
319 static VALUE
ossl_bn_to_bn(VALUE self)320 ossl_bn_to_bn(VALUE self)
321 {
322 return self;
323 }
324
325 static VALUE
ossl_bn_coerce(VALUE self,VALUE other)326 ossl_bn_coerce(VALUE self, VALUE other)
327 {
328 switch(TYPE(other)) {
329 case T_STRING:
330 self = ossl_bn_to_s(0, NULL, self);
331 break;
332 case T_FIXNUM:
333 case T_BIGNUM:
334 self = ossl_bn_to_i(self);
335 break;
336 default:
337 if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
338 ossl_raise(rb_eTypeError, "Don't know how to coerce");
339 }
340 }
341 return rb_assoc_new(other, self);
342 }
343
344 #define BIGNUM_BOOL1(func) \
345 static VALUE \
346 ossl_bn_##func(VALUE self) \
347 { \
348 BIGNUM *bn; \
349 GetBN(self, bn); \
350 if (BN_##func(bn)) { \
351 return Qtrue; \
352 } \
353 return Qfalse; \
354 }
355
356 /*
357 * Document-method: OpenSSL::BN#zero?
358 * call-seq:
359 * bn.zero? => true | false
360 */
361 BIGNUM_BOOL1(is_zero)
362
363 /*
364 * Document-method: OpenSSL::BN#one?
365 * call-seq:
366 * bn.one? => true | false
367 */
BIGNUM_BOOL1(is_one)368 BIGNUM_BOOL1(is_one)
369
370 /*
371 * Document-method: OpenSSL::BN#odd?
372 * call-seq:
373 * bn.odd? => true | false
374 */
375 BIGNUM_BOOL1(is_odd)
376
377 /*
378 * call-seq:
379 * bn.negative? => true | false
380 */
381 static VALUE
382 ossl_bn_is_negative(VALUE self)
383 {
384 BIGNUM *bn;
385
386 GetBN(self, bn);
387 if (BN_is_zero(bn))
388 return Qfalse;
389 return BN_is_negative(bn) ? Qtrue : Qfalse;
390 }
391
392 #define BIGNUM_1c(func) \
393 static VALUE \
394 ossl_bn_##func(VALUE self) \
395 { \
396 BIGNUM *bn, *result; \
397 VALUE obj; \
398 GetBN(self, bn); \
399 obj = NewBN(rb_obj_class(self)); \
400 if (!(result = BN_new())) { \
401 ossl_raise(eBNError, NULL); \
402 } \
403 if (!BN_##func(result, bn, ossl_bn_ctx)) { \
404 BN_free(result); \
405 ossl_raise(eBNError, NULL); \
406 } \
407 SetBN(obj, result); \
408 return obj; \
409 }
410
411 /*
412 * Document-method: OpenSSL::BN#sqr
413 * call-seq:
414 * bn.sqr => aBN
415 */
416 BIGNUM_1c(sqr)
417
418 #define BIGNUM_2(func) \
419 static VALUE \
420 ossl_bn_##func(VALUE self, VALUE other) \
421 { \
422 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
423 VALUE obj; \
424 GetBN(self, bn1); \
425 obj = NewBN(rb_obj_class(self)); \
426 if (!(result = BN_new())) { \
427 ossl_raise(eBNError, NULL); \
428 } \
429 if (!BN_##func(result, bn1, bn2)) { \
430 BN_free(result); \
431 ossl_raise(eBNError, NULL); \
432 } \
433 SetBN(obj, result); \
434 return obj; \
435 }
436
437 /*
438 * Document-method: OpenSSL::BN#+
439 * call-seq:
440 * bn + bn2 => aBN
441 */
BIGNUM_2(add)442 BIGNUM_2(add)
443
444 /*
445 * Document-method: OpenSSL::BN#-
446 * call-seq:
447 * bn - bn2 => aBN
448 */
449 BIGNUM_2(sub)
450
451 #define BIGNUM_2c(func) \
452 static VALUE \
453 ossl_bn_##func(VALUE self, VALUE other) \
454 { \
455 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
456 VALUE obj; \
457 GetBN(self, bn1); \
458 obj = NewBN(rb_obj_class(self)); \
459 if (!(result = BN_new())) { \
460 ossl_raise(eBNError, NULL); \
461 } \
462 if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) { \
463 BN_free(result); \
464 ossl_raise(eBNError, NULL); \
465 } \
466 SetBN(obj, result); \
467 return obj; \
468 }
469
470 /*
471 * Document-method: OpenSSL::BN#*
472 * call-seq:
473 * bn * bn2 => aBN
474 */
475 BIGNUM_2c(mul)
476
477 /*
478 * Document-method: OpenSSL::BN#%
479 * call-seq:
480 * bn % bn2 => aBN
481 */
482 BIGNUM_2c(mod)
483
484 /*
485 * Document-method: OpenSSL::BN#**
486 * call-seq:
487 * bn ** bn2 => aBN
488 */
489 BIGNUM_2c(exp)
490
491 /*
492 * Document-method: OpenSSL::BN#gcd
493 * call-seq:
494 * bn.gcd(bn2) => aBN
495 */
496 BIGNUM_2c(gcd)
497
498 /*
499 * Document-method: OpenSSL::BN#mod_sqr
500 * call-seq:
501 * bn.mod_sqr(bn2) => aBN
502 */
503 BIGNUM_2c(mod_sqr)
504
505 /*
506 * Document-method: OpenSSL::BN#mod_inverse
507 * call-seq:
508 * bn.mod_inverse(bn2) => aBN
509 */
510 BIGNUM_2c(mod_inverse)
511
512 /*
513 * call-seq:
514 * bn1 / bn2 => [result, remainder]
515 *
516 * Division of OpenSSL::BN instances
517 */
518 static VALUE
519 ossl_bn_div(VALUE self, VALUE other)
520 {
521 BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;
522 VALUE klass, obj1, obj2;
523
524 GetBN(self, bn1);
525
526 klass = rb_obj_class(self);
527 obj1 = NewBN(klass);
528 obj2 = NewBN(klass);
529 if (!(r1 = BN_new())) {
530 ossl_raise(eBNError, NULL);
531 }
532 if (!(r2 = BN_new())) {
533 BN_free(r1);
534 ossl_raise(eBNError, NULL);
535 }
536 if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
537 BN_free(r1);
538 BN_free(r2);
539 ossl_raise(eBNError, NULL);
540 }
541 SetBN(obj1, r1);
542 SetBN(obj2, r2);
543
544 return rb_ary_new3(2, obj1, obj2);
545 }
546
547 #define BIGNUM_3c(func) \
548 static VALUE \
549 ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
550 { \
551 BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
552 BIGNUM *bn3 = GetBNPtr(other2), *result; \
553 VALUE obj; \
554 GetBN(self, bn1); \
555 obj = NewBN(rb_obj_class(self)); \
556 if (!(result = BN_new())) { \
557 ossl_raise(eBNError, NULL); \
558 } \
559 if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) { \
560 BN_free(result); \
561 ossl_raise(eBNError, NULL); \
562 } \
563 SetBN(obj, result); \
564 return obj; \
565 }
566
567 /*
568 * Document-method: OpenSSL::BN#mod_add
569 * call-seq:
570 * bn.mod_add(bn1, bn2) -> aBN
571 */
572 BIGNUM_3c(mod_add)
573
574 /*
575 * Document-method: OpenSSL::BN#mod_sub
576 * call-seq:
577 * bn.mod_sub(bn1, bn2) -> aBN
578 */
BIGNUM_3c(mod_sub)579 BIGNUM_3c(mod_sub)
580
581 /*
582 * Document-method: OpenSSL::BN#mod_mul
583 * call-seq:
584 * bn.mod_mul(bn1, bn2) -> aBN
585 */
586 BIGNUM_3c(mod_mul)
587
588 /*
589 * Document-method: OpenSSL::BN#mod_exp
590 * call-seq:
591 * bn.mod_exp(bn1, bn2) -> aBN
592 */
593 BIGNUM_3c(mod_exp)
594
595 #define BIGNUM_BIT(func) \
596 static VALUE \
597 ossl_bn_##func(VALUE self, VALUE bit) \
598 { \
599 BIGNUM *bn; \
600 GetBN(self, bn); \
601 if (!BN_##func(bn, NUM2INT(bit))) { \
602 ossl_raise(eBNError, NULL); \
603 } \
604 return self; \
605 }
606
607 /*
608 * Document-method: OpenSSL::BN#set_bit!
609 * call-seq:
610 * bn.set_bit!(bit) -> self
611 */
612 BIGNUM_BIT(set_bit)
613
614 /*
615 * Document-method: OpenSSL::BN#clear_bit!
616 * call-seq:
617 * bn.clear_bit!(bit) -> self
618 */
619 BIGNUM_BIT(clear_bit)
620
621 /*
622 * Document-method: OpenSSL::BN#mask_bit!
623 * call-seq:
624 * bn.mask_bit!(bit) -> self
625 */
626 BIGNUM_BIT(mask_bits)
627
628 /*
629 * call-seq:
630 * bn.bit_set?(bit) => true | false
631 *
632 * Tests bit _bit_ in _bn_ and returns +true+ if set, +false+ if not set.
633 */
634 static VALUE
635 ossl_bn_is_bit_set(VALUE self, VALUE bit)
636 {
637 int b;
638 BIGNUM *bn;
639
640 b = NUM2INT(bit);
641 GetBN(self, bn);
642 if (BN_is_bit_set(bn, b)) {
643 return Qtrue;
644 }
645 return Qfalse;
646 }
647
648 #define BIGNUM_SHIFT(func) \
649 static VALUE \
650 ossl_bn_##func(VALUE self, VALUE bits) \
651 { \
652 BIGNUM *bn, *result; \
653 int b; \
654 VALUE obj; \
655 b = NUM2INT(bits); \
656 GetBN(self, bn); \
657 obj = NewBN(rb_obj_class(self)); \
658 if (!(result = BN_new())) { \
659 ossl_raise(eBNError, NULL); \
660 } \
661 if (!BN_##func(result, bn, b)) { \
662 BN_free(result); \
663 ossl_raise(eBNError, NULL); \
664 } \
665 SetBN(obj, result); \
666 return obj; \
667 }
668
669 /*
670 * Document-method: OpenSSL::BN#<<
671 * call-seq:
672 * bn << bits -> aBN
673 */
674 BIGNUM_SHIFT(lshift)
675
676 /*
677 * Document-method: OpenSSL::BN#>>
678 * call-seq:
679 * bn >> bits -> aBN
680 */
BIGNUM_SHIFT(rshift)681 BIGNUM_SHIFT(rshift)
682
683 #define BIGNUM_SELF_SHIFT(func) \
684 static VALUE \
685 ossl_bn_self_##func(VALUE self, VALUE bits) \
686 { \
687 BIGNUM *bn; \
688 int b; \
689 b = NUM2INT(bits); \
690 GetBN(self, bn); \
691 if (!BN_##func(bn, bn, b)) \
692 ossl_raise(eBNError, NULL); \
693 return self; \
694 }
695
696 /*
697 * Document-method: OpenSSL::BN#lshift!
698 * call-seq:
699 * bn.lshift!(bits) -> self
700 */
701 BIGNUM_SELF_SHIFT(lshift)
702
703 /*
704 * Document-method: OpenSSL::BN#rshift!
705 * call-seq:
706 * bn.rshift!(bits) -> self
707 */
708 BIGNUM_SELF_SHIFT(rshift)
709
710 #define BIGNUM_RAND(func) \
711 static VALUE \
712 ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \
713 { \
714 BIGNUM *result; \
715 int bottom = 0, top = 0, b; \
716 VALUE bits, fill, odd, obj; \
717 \
718 switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) { \
719 case 3: \
720 bottom = (odd == Qtrue) ? 1 : 0; \
721 /* FALLTHROUGH */ \
722 case 2: \
723 top = NUM2INT(fill); \
724 } \
725 b = NUM2INT(bits); \
726 obj = NewBN(klass); \
727 if (!(result = BN_new())) { \
728 ossl_raise(eBNError, NULL); \
729 } \
730 if (!BN_##func(result, b, top, bottom)) { \
731 BN_free(result); \
732 ossl_raise(eBNError, NULL); \
733 } \
734 SetBN(obj, result); \
735 return obj; \
736 }
737
738 /*
739 * Document-method: OpenSSL::BN.rand
740 * BN.rand(bits [, fill [, odd]]) -> aBN
741 */
742 BIGNUM_RAND(rand)
743
744 /*
745 * Document-method: OpenSSL::BN.pseudo_rand
746 * BN.pseudo_rand(bits [, fill [, odd]]) -> aBN
747 */
748 BIGNUM_RAND(pseudo_rand)
749
750 #define BIGNUM_RAND_RANGE(func) \
751 static VALUE \
752 ossl_bn_s_##func##_range(VALUE klass, VALUE range) \
753 { \
754 BIGNUM *bn = GetBNPtr(range), *result; \
755 VALUE obj = NewBN(klass); \
756 if (!(result = BN_new())) { \
757 ossl_raise(eBNError, NULL); \
758 } \
759 if (!BN_##func##_range(result, bn)) { \
760 BN_free(result); \
761 ossl_raise(eBNError, NULL); \
762 } \
763 SetBN(obj, result); \
764 return obj; \
765 }
766
767 /*
768 * Document-method: OpenSSL::BN.rand_range
769 * call-seq:
770 * BN.rand_range(range) -> aBN
771 *
772 */
773 BIGNUM_RAND_RANGE(rand)
774
775 /*
776 * Document-method: OpenSSL::BN.pseudo_rand_range
777 * call-seq:
778 * BN.pseudo_rand_range(range) -> aBN
779 *
780 */
781 BIGNUM_RAND_RANGE(pseudo_rand)
782
783 /*
784 * call-seq:
785 * BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn
786 *
787 * Generates a random prime number of bit length _bits_. If _safe_ is set to
788 * +true+, generates a safe prime. If _add_ is specified, generates a prime that
789 * fulfills condition <tt>p % add = rem</tt>.
790 *
791 * === Parameters
792 * * _bits_ - integer
793 * * _safe_ - boolean
794 * * _add_ - BN
795 * * _rem_ - BN
796 */
797 static VALUE
798 ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
799 {
800 BIGNUM *add = NULL, *rem = NULL, *result;
801 int safe = 1, num;
802 VALUE vnum, vsafe, vadd, vrem, obj;
803
804 rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem);
805
806 num = NUM2INT(vnum);
807
808 if (vsafe == Qfalse) {
809 safe = 0;
810 }
811 if (!NIL_P(vadd)) {
812 add = GetBNPtr(vadd);
813 rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
814 }
815 obj = NewBN(klass);
816 if (!(result = BN_new())) {
817 ossl_raise(eBNError, NULL);
818 }
819 if (!BN_generate_prime_ex(result, num, safe, add, rem, NULL)) {
820 BN_free(result);
821 ossl_raise(eBNError, NULL);
822 }
823 SetBN(obj, result);
824
825 return obj;
826 }
827
828 #define BIGNUM_NUM(func) \
829 static VALUE \
830 ossl_bn_##func(VALUE self) \
831 { \
832 BIGNUM *bn; \
833 GetBN(self, bn); \
834 return INT2NUM(BN_##func(bn)); \
835 }
836
837 /*
838 * Document-method: OpenSSL::BN#num_bytes
839 * call-seq:
840 * bn.num_bytes => integer
841 */
842 BIGNUM_NUM(num_bytes)
843
844 /*
845 * Document-method: OpenSSL::BN#num_bits
846 * call-seq:
847 * bn.num_bits => integer
848 */
BIGNUM_NUM(num_bits)849 BIGNUM_NUM(num_bits)
850
851 static VALUE
852 ossl_bn_copy(VALUE self, VALUE other)
853 {
854 BIGNUM *bn1, *bn2;
855
856 rb_check_frozen(self);
857
858 if (self == other) return self;
859
860 GetBN(self, bn1);
861 bn2 = GetBNPtr(other);
862
863 if (!BN_copy(bn1, bn2)) {
864 ossl_raise(eBNError, NULL);
865 }
866 return self;
867 }
868
869 /*
870 * call-seq:
871 * +bn -> aBN
872 */
873 static VALUE
ossl_bn_uplus(VALUE self)874 ossl_bn_uplus(VALUE self)
875 {
876 return self;
877 }
878
879 /*
880 * call-seq:
881 * -bn -> aBN
882 */
883 static VALUE
ossl_bn_uminus(VALUE self)884 ossl_bn_uminus(VALUE self)
885 {
886 VALUE obj;
887 BIGNUM *bn1, *bn2;
888
889 GetBN(self, bn1);
890 obj = NewBN(cBN);
891 bn2 = BN_dup(bn1);
892 if (!bn2)
893 ossl_raise(eBNError, "BN_dup");
894 SetBN(obj, bn2);
895 BN_set_negative(bn2, !BN_is_negative(bn2));
896
897 return obj;
898 }
899
900 #define BIGNUM_CMP(func) \
901 static VALUE \
902 ossl_bn_##func(VALUE self, VALUE other) \
903 { \
904 BIGNUM *bn1, *bn2 = GetBNPtr(other); \
905 GetBN(self, bn1); \
906 return INT2NUM(BN_##func(bn1, bn2)); \
907 }
908
909 /*
910 * Document-method: OpenSSL::BN#cmp
911 * call-seq:
912 * bn.cmp(bn2) => integer
913 */
914 /*
915 * Document-method: OpenSSL::BN#<=>
916 * call-seq:
917 * bn <=> bn2 => integer
918 */
919 BIGNUM_CMP(cmp)
920
921 /*
922 * Document-method: OpenSSL::BN#ucmp
923 * call-seq:
924 * bn.ucmp(bn2) => integer
925 */
BIGNUM_CMP(ucmp)926 BIGNUM_CMP(ucmp)
927
928 /*
929 * call-seq:
930 * bn == obj => true or false
931 *
932 * Returns +true+ only if _obj_ has the same value as _bn_. Contrast this
933 * with OpenSSL::BN#eql?, which requires obj to be OpenSSL::BN.
934 */
935 static VALUE
936 ossl_bn_eq(VALUE self, VALUE other)
937 {
938 BIGNUM *bn1, *bn2;
939
940 GetBN(self, bn1);
941 other = try_convert_to_bn(other);
942 if (NIL_P(other))
943 return Qfalse;
944 GetBN(other, bn2);
945
946 if (!BN_cmp(bn1, bn2)) {
947 return Qtrue;
948 }
949 return Qfalse;
950 }
951
952 /*
953 * call-seq:
954 * bn.eql?(obj) => true or false
955 *
956 * Returns <code>true</code> only if <i>obj</i> is a
957 * <code>OpenSSL::BN</code> with the same value as <i>bn</i>. Contrast this
958 * with OpenSSL::BN#==, which performs type conversions.
959 */
960 static VALUE
ossl_bn_eql(VALUE self,VALUE other)961 ossl_bn_eql(VALUE self, VALUE other)
962 {
963 BIGNUM *bn1, *bn2;
964
965 if (!rb_obj_is_kind_of(other, cBN))
966 return Qfalse;
967 GetBN(self, bn1);
968 GetBN(other, bn2);
969
970 return BN_cmp(bn1, bn2) ? Qfalse : Qtrue;
971 }
972
973 /*
974 * call-seq:
975 * bn.hash => Integer
976 *
977 * Returns a hash code for this object.
978 *
979 * See also Object#hash.
980 */
981 static VALUE
ossl_bn_hash(VALUE self)982 ossl_bn_hash(VALUE self)
983 {
984 BIGNUM *bn;
985 VALUE tmp, hash;
986 unsigned char *buf;
987 int len;
988
989 GetBN(self, bn);
990 len = BN_num_bytes(bn);
991 buf = ALLOCV(tmp, len);
992 if (BN_bn2bin(bn, buf) != len) {
993 ALLOCV_END(tmp);
994 ossl_raise(eBNError, "BN_bn2bin");
995 }
996
997 hash = ST2FIX(rb_memhash(buf, len));
998 ALLOCV_END(tmp);
999
1000 return hash;
1001 }
1002
1003 /*
1004 * call-seq:
1005 * bn.prime? => true | false
1006 * bn.prime?(checks) => true | false
1007 *
1008 * Performs a Miller-Rabin probabilistic primality test with _checks_
1009 * iterations. If _checks_ is not specified, a number of iterations is used
1010 * that yields a false positive rate of at most 2^-80 for random input.
1011 *
1012 * === Parameters
1013 * * _checks_ - integer
1014 */
1015 static VALUE
ossl_bn_is_prime(int argc,VALUE * argv,VALUE self)1016 ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
1017 {
1018 BIGNUM *bn;
1019 VALUE vchecks;
1020 int checks = BN_prime_checks;
1021
1022 if (rb_scan_args(argc, argv, "01", &vchecks) == 1) {
1023 checks = NUM2INT(vchecks);
1024 }
1025 GetBN(self, bn);
1026 switch (BN_is_prime_ex(bn, checks, ossl_bn_ctx, NULL)) {
1027 case 1:
1028 return Qtrue;
1029 case 0:
1030 return Qfalse;
1031 default:
1032 ossl_raise(eBNError, NULL);
1033 }
1034 /* not reachable */
1035 return Qnil;
1036 }
1037
1038 /*
1039 * call-seq:
1040 * bn.prime_fasttest? => true | false
1041 * bn.prime_fasttest?(checks) => true | false
1042 * bn.prime_fasttest?(checks, trial_div) => true | false
1043 *
1044 * Performs a Miller-Rabin primality test. This is same as #prime? except this
1045 * first attempts trial divisions with some small primes.
1046 *
1047 * === Parameters
1048 * * _checks_ - integer
1049 * * _trial_div_ - boolean
1050 */
1051 static VALUE
ossl_bn_is_prime_fasttest(int argc,VALUE * argv,VALUE self)1052 ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
1053 {
1054 BIGNUM *bn;
1055 VALUE vchecks, vtrivdiv;
1056 int checks = BN_prime_checks, do_trial_division = 1;
1057
1058 rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv);
1059
1060 if (!NIL_P(vchecks)) {
1061 checks = NUM2INT(vchecks);
1062 }
1063 GetBN(self, bn);
1064 /* handle true/false */
1065 if (vtrivdiv == Qfalse) {
1066 do_trial_division = 0;
1067 }
1068 switch (BN_is_prime_fasttest_ex(bn, checks, ossl_bn_ctx, do_trial_division, NULL)) {
1069 case 1:
1070 return Qtrue;
1071 case 0:
1072 return Qfalse;
1073 default:
1074 ossl_raise(eBNError, NULL);
1075 }
1076 /* not reachable */
1077 return Qnil;
1078 }
1079
1080 /*
1081 * INIT
1082 * (NOTE: ordering of methods is the same as in 'man bn')
1083 */
1084 void
Init_ossl_bn(void)1085 Init_ossl_bn(void)
1086 {
1087 #if 0
1088 mOSSL = rb_define_module("OpenSSL");
1089 eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
1090 #endif
1091
1092 if (!(ossl_bn_ctx = BN_CTX_new())) {
1093 ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
1094 }
1095
1096 eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError);
1097
1098 cBN = rb_define_class_under(mOSSL, "BN", rb_cObject);
1099
1100 rb_define_alloc_func(cBN, ossl_bn_alloc);
1101 rb_define_method(cBN, "initialize", ossl_bn_initialize, -1);
1102
1103 rb_define_method(cBN, "initialize_copy", ossl_bn_copy, 1);
1104 rb_define_method(cBN, "copy", ossl_bn_copy, 1);
1105
1106 /* swap (=coerce?) */
1107
1108 rb_define_method(cBN, "num_bytes", ossl_bn_num_bytes, 0);
1109 rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0);
1110 /* num_bits_word */
1111
1112 rb_define_method(cBN, "+@", ossl_bn_uplus, 0);
1113 rb_define_method(cBN, "-@", ossl_bn_uminus, 0);
1114
1115 rb_define_method(cBN, "+", ossl_bn_add, 1);
1116 rb_define_method(cBN, "-", ossl_bn_sub, 1);
1117 rb_define_method(cBN, "*", ossl_bn_mul, 1);
1118 rb_define_method(cBN, "sqr", ossl_bn_sqr, 0);
1119 rb_define_method(cBN, "/", ossl_bn_div, 1);
1120 rb_define_method(cBN, "%", ossl_bn_mod, 1);
1121 /* nnmod */
1122
1123 rb_define_method(cBN, "mod_add", ossl_bn_mod_add, 2);
1124 rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2);
1125 rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2);
1126 rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1);
1127 rb_define_method(cBN, "**", ossl_bn_exp, 1);
1128 rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2);
1129 rb_define_method(cBN, "gcd", ossl_bn_gcd, 1);
1130
1131 /* add_word
1132 * sub_word
1133 * mul_word
1134 * div_word
1135 * mod_word */
1136
1137 rb_define_method(cBN, "cmp", ossl_bn_cmp, 1);
1138 rb_define_alias(cBN, "<=>", "cmp");
1139 rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1);
1140 rb_define_method(cBN, "eql?", ossl_bn_eql, 1);
1141 rb_define_method(cBN, "hash", ossl_bn_hash, 0);
1142 rb_define_method(cBN, "==", ossl_bn_eq, 1);
1143 rb_define_alias(cBN, "===", "==");
1144 rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0);
1145 rb_define_method(cBN, "one?", ossl_bn_is_one, 0);
1146 /* is_word */
1147 rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0);
1148 rb_define_method(cBN, "negative?", ossl_bn_is_negative, 0);
1149
1150 /* zero
1151 * one
1152 * value_one - DON'T IMPL.
1153 * set_word
1154 * get_word */
1155
1156 rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1);
1157 rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1);
1158 rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1);
1159 rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1);
1160
1161 rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1);
1162 rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1);
1163 rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1);
1164
1165 rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1);
1166 rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1);
1167 rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1);
1168 rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1);
1169 rb_define_method(cBN, "<<", ossl_bn_lshift, 1);
1170 rb_define_method(cBN, ">>", ossl_bn_rshift, 1);
1171 rb_define_method(cBN, "lshift!", ossl_bn_self_lshift, 1);
1172 rb_define_method(cBN, "rshift!", ossl_bn_self_rshift, 1);
1173 /* lshift1 - DON'T IMPL. */
1174 /* rshift1 - DON'T IMPL. */
1175
1176 /*
1177 * bn2bin
1178 * bin2bn
1179 * bn2hex
1180 * bn2dec
1181 * hex2bn
1182 * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s
1183 * print - NOT IMPL.
1184 * print_fp - NOT IMPL.
1185 * bn2mpi
1186 * mpi2bn
1187 */
1188 rb_define_method(cBN, "to_s", ossl_bn_to_s, -1);
1189 rb_define_method(cBN, "to_i", ossl_bn_to_i, 0);
1190 rb_define_alias(cBN, "to_int", "to_i");
1191 rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0);
1192 rb_define_method(cBN, "coerce", ossl_bn_coerce, 1);
1193
1194 /*
1195 * TODO:
1196 * But how to: from_bin, from_mpi? PACK?
1197 * to_bin
1198 * to_mpi
1199 */
1200
1201 rb_define_method(cBN, "mod_inverse", ossl_bn_mod_inverse, 1);
1202
1203 /* RECiProcal
1204 * MONTgomery */
1205 }
1206