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