• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "NativeBN"
18 
19 #include "JNIHelp.h"
20 #include "JniConstants.h"
21 #include "JniException.h"
22 #include "ScopedPrimitiveArray.h"
23 #include "ScopedUtfChars.h"
24 #include "StaticAssert.h"
25 #include "UniquePtr.h"
26 #include "jni.h"
27 #include <openssl/bn.h>
28 #include <openssl/crypto.h>
29 #include <openssl/err.h>
30 #include <stdio.h>
31 
32 struct BN_CTX_Deleter {
operator ()BN_CTX_Deleter33   void operator()(BN_CTX* p) const {
34     BN_CTX_free(p);
35   }
36 };
37 typedef UniquePtr<BN_CTX, BN_CTX_Deleter> Unique_BN_CTX;
38 
toBigNum(jlong address)39 static BIGNUM* toBigNum(jlong address) {
40   return reinterpret_cast<BIGNUM*>(static_cast<uintptr_t>(address));
41 }
42 
throwExceptionIfNecessary(JNIEnv * env)43 static bool throwExceptionIfNecessary(JNIEnv* env) {
44   long error = ERR_get_error();
45   if (error == 0) {
46     return false;
47   }
48   char message[256];
49   ERR_error_string_n(error, message, sizeof(message));
50   int reason = ERR_GET_REASON(error);
51   if (reason == BN_R_DIV_BY_ZERO) {
52     jniThrowException(env, "java/lang/ArithmeticException", "BigInteger division by zero");
53   } else if (reason == BN_R_NO_INVERSE) {
54     jniThrowException(env, "java/lang/ArithmeticException", "BigInteger not invertible");
55   } else if (reason == ERR_R_MALLOC_FAILURE) {
56     jniThrowOutOfMemoryError(env, message);
57   } else {
58     jniThrowException(env, "java/lang/ArithmeticException", message);
59   }
60   return true;
61 }
62 
isValidHandle(JNIEnv * env,jlong handle,const char * message)63 static int isValidHandle(JNIEnv* env, jlong handle, const char* message) {
64   if (handle == 0) {
65     jniThrowNullPointerException(env, message);
66     return JNI_FALSE;
67   }
68   return JNI_TRUE;
69 }
70 
oneValidHandle(JNIEnv * env,jlong a)71 static int oneValidHandle(JNIEnv* env, jlong a) {
72   return isValidHandle(env, a, "Mandatory handle (first) passed as null");
73 }
74 
twoValidHandles(JNIEnv * env,jlong a,jlong b)75 static int twoValidHandles(JNIEnv* env, jlong a, jlong b) {
76   if (!oneValidHandle(env, a)) return JNI_FALSE;
77   return isValidHandle(env, b, "Mandatory handle (second) passed as null");
78 }
79 
threeValidHandles(JNIEnv * env,jlong a,jlong b,jlong c)80 static int threeValidHandles(JNIEnv* env, jlong a, jlong b, jlong c) {
81   if (!twoValidHandles(env, a, b)) return JNI_FALSE;
82   return isValidHandle(env, c, "Mandatory handle (third) passed as null");
83 }
84 
fourValidHandles(JNIEnv * env,jlong a,jlong b,jlong c,jlong d)85 static int fourValidHandles(JNIEnv* env, jlong a, jlong b, jlong c, jlong d) {
86   if (!threeValidHandles(env, a, b, c)) return JNI_FALSE;
87   return isValidHandle(env, d, "Mandatory handle (fourth) passed as null");
88 }
89 
NativeBN_BN_new(JNIEnv * env,jclass)90 static jlong NativeBN_BN_new(JNIEnv* env, jclass) {
91   jlong result = static_cast<jlong>(reinterpret_cast<uintptr_t>(BN_new()));
92   throwExceptionIfNecessary(env);
93   return result;
94 }
95 
NativeBN_BN_free(JNIEnv * env,jclass,jlong a)96 static void NativeBN_BN_free(JNIEnv* env, jclass, jlong a) {
97   if (!oneValidHandle(env, a)) return;
98   BN_free(toBigNum(a));
99 }
100 
NativeBN_BN_cmp(JNIEnv * env,jclass,jlong a,jlong b)101 static int NativeBN_BN_cmp(JNIEnv* env, jclass, jlong a, jlong b) {
102   if (!twoValidHandles(env, a, b)) return 1;
103   return BN_cmp(toBigNum(a), toBigNum(b));
104 }
105 
NativeBN_BN_copy(JNIEnv * env,jclass,jlong to,jlong from)106 static void NativeBN_BN_copy(JNIEnv* env, jclass, jlong to, jlong from) {
107   if (!twoValidHandles(env, to, from)) return;
108   BN_copy(toBigNum(to), toBigNum(from));
109   throwExceptionIfNecessary(env);
110 }
111 
NativeBN_putULongInt(JNIEnv * env,jclass,jlong a0,unsigned long long dw,jboolean neg)112 static void NativeBN_putULongInt(JNIEnv* env, jclass, jlong a0, unsigned long long dw, jboolean neg) {
113     if (!oneValidHandle(env, a0)) return;
114     unsigned int hi = dw >> 32; // This shifts without sign extension.
115     int lo = (int)dw; // This truncates implicitly.
116 
117     // cf. litEndInts2bn:
118     BIGNUM* a = toBigNum(a0);
119     bn_check_top(a);
120     if (bn_wexpand(a, 2) != NULL) {
121       a->d[0] = lo;
122       a->d[1] = hi;
123       a->top = 2;
124       a->neg = neg;
125       bn_correct_top(a);
126     } else {
127       throwExceptionIfNecessary(env);
128     }
129 }
130 
NativeBN_putLongInt(JNIEnv * env,jclass cls,jlong a,long long dw)131 static void NativeBN_putLongInt(JNIEnv* env, jclass cls, jlong a, long long dw) {
132   if (dw >= 0) {
133     NativeBN_putULongInt(env, cls, a, dw, JNI_FALSE);
134   } else {
135     NativeBN_putULongInt(env, cls, a, -dw, JNI_TRUE);
136   }
137 }
138 
NativeBN_BN_dec2bn(JNIEnv * env,jclass,jlong a0,jstring str)139 static int NativeBN_BN_dec2bn(JNIEnv* env, jclass, jlong a0, jstring str) {
140   if (!oneValidHandle(env, a0)) return -1;
141   ScopedUtfChars chars(env, str);
142   if (chars.c_str() == NULL) {
143     return -1;
144   }
145   BIGNUM* a = toBigNum(a0);
146   int result = BN_dec2bn(&a, chars.c_str());
147   throwExceptionIfNecessary(env);
148   return result;
149 }
150 
NativeBN_BN_hex2bn(JNIEnv * env,jclass,jlong a0,jstring str)151 static int NativeBN_BN_hex2bn(JNIEnv* env, jclass, jlong a0, jstring str) {
152   if (!oneValidHandle(env, a0)) return -1;
153   ScopedUtfChars chars(env, str);
154   if (chars.c_str() == NULL) {
155     return -1;
156   }
157   BIGNUM* a = toBigNum(a0);
158   int result = BN_hex2bn(&a, chars.c_str());
159   throwExceptionIfNecessary(env);
160   return result;
161 }
162 
NativeBN_BN_bin2bn(JNIEnv * env,jclass,jbyteArray arr,int len,jboolean neg,jlong ret)163 static void NativeBN_BN_bin2bn(JNIEnv* env, jclass, jbyteArray arr, int len, jboolean neg, jlong ret) {
164   if (!oneValidHandle(env, ret)) return;
165   ScopedByteArrayRO bytes(env, arr);
166   if (bytes.get() == NULL) {
167     return;
168   }
169   BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, toBigNum(ret));
170   if (!throwExceptionIfNecessary(env) && neg) {
171     BN_set_negative(toBigNum(ret), true);
172   }
173 }
174 
175 /**
176  * Note:
177  * This procedure directly writes the internal representation of BIGNUMs.
178  * We do so as there is no direct interface based on Little Endian Integer Arrays.
179  * Also note that the same representation is used in the Cordoba Java Implementation of BigIntegers,
180  *        whereof certain functionality is still being used.
181  */
NativeBN_litEndInts2bn(JNIEnv * env,jclass,jintArray arr,int len,jboolean neg,jlong ret0)182 static void NativeBN_litEndInts2bn(JNIEnv* env, jclass, jintArray arr, int len, jboolean neg, jlong ret0) {
183   if (!oneValidHandle(env, ret0)) return;
184   BIGNUM* ret = toBigNum(ret0);
185   bn_check_top(ret);
186   if (len > 0) {
187     ScopedIntArrayRO scopedArray(env, arr);
188     if (scopedArray.get() == NULL) {
189       return;
190     }
191 
192     STATIC_ASSERT(sizeof(BN_ULONG) == sizeof(jint), BN_ULONG_not_32_bit);
193     const BN_ULONG* tmpInts = reinterpret_cast<const BN_ULONG*>(scopedArray.get());
194     if ((tmpInts != NULL) && (bn_wexpand(ret, len) != NULL)) {
195       int i = len; do { i--; ret->d[i] = tmpInts[i]; } while (i > 0);
196       ret->top = len;
197       ret->neg = neg;
198       // need to call this due to clear byte at top if avoiding
199       // having the top bit set (-ve number)
200       // Basically get rid of top zero ints:
201       bn_correct_top(ret);
202     } else {
203       throwExceptionIfNecessary(env);
204     }
205   } else { // (len = 0) means value = 0 and sign will be 0, too.
206     ret->top = 0;
207   }
208 }
209 
210 
211 #define BYTES2INT(bytes, k) \
212     ((bytes[k + 3] & 0xff) | (bytes[k + 2] & 0xff) << 8 | (bytes[k + 1] & 0xff) << 16 | (bytes[k + 0] & 0xff) << 24)
213 
negBigEndianBytes2bn(JNIEnv *,jclass,const unsigned char * bytes,int bytesLen,jlong ret0)214 static void negBigEndianBytes2bn(JNIEnv*, jclass, const unsigned char* bytes, int bytesLen, jlong ret0) {
215   BIGNUM* ret = toBigNum(ret0);
216 
217   // We rely on: (BN_BITS2 == 32), i.e. BN_ULONG is unsigned int and has 4 bytes:
218   bn_check_top(ret);
219   // FIXME: assert bytesLen > 0
220   int intLen = (bytesLen + 3) / 4;
221   int firstNonzeroDigit = -2;
222   if (bn_wexpand(ret, intLen) != NULL) {
223     BN_ULONG* d = ret->d;
224     BN_ULONG di;
225     ret->top = intLen;
226     int highBytes = bytesLen % 4;
227     int k = bytesLen;
228     // Put bytes to the int array starting from the end of the byte array
229     int i = 0;
230     while (k > highBytes) {
231       k -= 4;
232       di = BYTES2INT(bytes, k);
233       if (di != 0) {
234         d[i] = -di;
235         firstNonzeroDigit = i;
236         i++;
237         while (k > highBytes) {
238           k -= 4;
239           d[i] = ~BYTES2INT(bytes, k);
240           i++;
241         }
242         break;
243       } else {
244         d[i] = 0;
245         i++;
246       }
247     }
248     if (highBytes != 0) {
249       di = -1;
250       // Put the first bytes in the highest element of the int array
251       if (firstNonzeroDigit != -2) {
252         for (k = 0; k < highBytes; k++) {
253           di = (di << 8) | (bytes[k] & 0xFF);
254         }
255         d[i] = ~di;
256       } else {
257         for (k = 0; k < highBytes; k++) {
258           di = (di << 8) | (bytes[k] & 0xFF);
259         }
260         d[i] = -di;
261       }
262     }
263   }
264 }
265 
NativeBN_twosComp2bn(JNIEnv * env,jclass cls,jbyteArray arr,int bytesLen,jlong ret0)266 static void NativeBN_twosComp2bn(JNIEnv* env, jclass cls, jbyteArray arr, int bytesLen, jlong ret0) {
267   if (!oneValidHandle(env, ret0)) return;
268   BIGNUM* ret = toBigNum(ret0);
269 
270   ScopedByteArrayRO bytes(env, arr);
271   if (bytes.get() == NULL) {
272     return;
273   }
274   const unsigned char* s = reinterpret_cast<const unsigned char*>(bytes.get());
275   if ((bytes[0] & 0X80) == 0) { // Positive value!
276     //
277     // We can use the existing BN implementation for unsigned big endian bytes:
278     //
279     BN_bin2bn(s, bytesLen, ret);
280     BN_set_negative(ret, false);
281   } else { // Negative value!
282     //
283     // We need to apply two's complement:
284     //
285     negBigEndianBytes2bn(env, cls, s, bytesLen, ret0);
286     BN_set_negative(ret, true);
287   }
288   throwExceptionIfNecessary(env);
289 }
290 
NativeBN_longInt(JNIEnv * env,jclass,jlong a0)291 static long long NativeBN_longInt(JNIEnv* env, jclass, jlong a0) {
292   if (!oneValidHandle(env, a0)) return -1;
293   BIGNUM* a = toBigNum(a0);
294   bn_check_top(a);
295   int intLen = a->top;
296   BN_ULONG* d = a->d;
297   switch (intLen) {
298     case 0:
299       return 0;
300     case 1:
301       if (!a->neg) {
302         return d[0] & 0X00000000FFFFFFFFLL;
303       } else {
304         return -(d[0] & 0X00000000FFFFFFFFLL);
305       }
306     default:
307       if (!a->neg) {
308         return ((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL);
309       } else {
310         return -(((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL));
311       }
312   }
313 }
314 
leadingZerosTrimmed(char * s)315 static char* leadingZerosTrimmed(char* s) {
316     char* p = s;
317     if (*p == '-') {
318         p++;
319         while ((*p == '0') && (*(p + 1) != 0)) { p++; }
320         p--;
321         *p = '-';
322     } else {
323         while ((*p == '0') && (*(p + 1) != 0)) { p++; }
324     }
325     return p;
326 }
327 
NativeBN_BN_bn2dec(JNIEnv * env,jclass,jlong a)328 static jstring NativeBN_BN_bn2dec(JNIEnv* env, jclass, jlong a) {
329   if (!oneValidHandle(env, a)) return NULL;
330   char* tmpStr = BN_bn2dec(toBigNum(a));
331   if (tmpStr == NULL) {
332     return NULL;
333   }
334   char* retStr = leadingZerosTrimmed(tmpStr);
335   jstring returnJString = env->NewStringUTF(retStr);
336   OPENSSL_free(tmpStr);
337   return returnJString;
338 }
339 
NativeBN_BN_bn2hex(JNIEnv * env,jclass,jlong a)340 static jstring NativeBN_BN_bn2hex(JNIEnv* env, jclass, jlong a) {
341   if (!oneValidHandle(env, a)) return NULL;
342   char* tmpStr = BN_bn2hex(toBigNum(a));
343   if (tmpStr == NULL) {
344     return NULL;
345   }
346   char* retStr = leadingZerosTrimmed(tmpStr);
347   jstring returnJString = env->NewStringUTF(retStr);
348   OPENSSL_free(tmpStr);
349   return returnJString;
350 }
351 
NativeBN_BN_bn2bin(JNIEnv * env,jclass,jlong a0)352 static jbyteArray NativeBN_BN_bn2bin(JNIEnv* env, jclass, jlong a0) {
353   if (!oneValidHandle(env, a0)) return NULL;
354   BIGNUM* a = toBigNum(a0);
355   jbyteArray result = env->NewByteArray(BN_num_bytes(a));
356   if (result == NULL) {
357     return NULL;
358   }
359   ScopedByteArrayRW bytes(env, result);
360   if (bytes.get() == NULL) {
361     return NULL;
362   }
363   BN_bn2bin(a, reinterpret_cast<unsigned char*>(bytes.get()));
364   return result;
365 }
366 
NativeBN_bn2litEndInts(JNIEnv * env,jclass,jlong a0)367 static jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass, jlong a0) {
368   if (!oneValidHandle(env, a0)) return NULL;
369   BIGNUM* a = toBigNum(a0);
370   bn_check_top(a);
371   int len = a->top;
372   if (len == 0) {
373     return NULL;
374   }
375   jintArray result = env->NewIntArray(len);
376   if (result == NULL) {
377     return NULL;
378   }
379   ScopedIntArrayRW ints(env, result);
380   if (ints.get() == NULL) {
381     return NULL;
382   }
383   BN_ULONG* ulongs = reinterpret_cast<BN_ULONG*>(ints.get());
384   if (ulongs == NULL) {
385     return NULL;
386   }
387   int i = len; do { i--; ulongs[i] = a->d[i]; } while (i > 0);
388   return result;
389 }
390 
NativeBN_sign(JNIEnv * env,jclass,jlong a)391 static int NativeBN_sign(JNIEnv* env, jclass, jlong a) {
392   if (!oneValidHandle(env, a)) return -2;
393   if (BN_is_zero(toBigNum(a))) {
394       return 0;
395   } else if (BN_is_negative(toBigNum(a))) {
396     return -1;
397   }
398   return 1;
399 }
400 
NativeBN_BN_set_negative(JNIEnv * env,jclass,jlong b,int n)401 static void NativeBN_BN_set_negative(JNIEnv* env, jclass, jlong b, int n) {
402   if (!oneValidHandle(env, b)) return;
403   BN_set_negative(toBigNum(b), n);
404 }
405 
NativeBN_bitLength(JNIEnv * env,jclass,jlong a0)406 static int NativeBN_bitLength(JNIEnv* env, jclass, jlong a0) {
407 // We rely on: (BN_BITS2 == 32), i.e. BN_ULONG is unsigned int and has 4 bytes:
408 //
409   if (!oneValidHandle(env, a0)) return JNI_FALSE;
410   BIGNUM* a = toBigNum(a0);
411   bn_check_top(a);
412   int intLen = a->top;
413   if (intLen == 0) return 0;
414   BN_ULONG* d = a->d;
415   int i = intLen - 1;
416   BN_ULONG msd = d[i]; // most significant digit
417   if (a->neg) {
418     // Handle negative values correctly:
419     // i.e. decrement the msd if all other digits are 0:
420     // while ((i > 0) && (d[i] != 0)) { i--; }
421     do { i--; } while (!((i < 0) || (d[i] != 0)));
422     if (i < 0) msd--; // Only if all lower significant digits are 0 we decrement the most significant one.
423   }
424   return (intLen - 1) * 32 + BN_num_bits_word(msd);
425 }
426 
NativeBN_BN_is_bit_set(JNIEnv * env,jclass,jlong a,int n)427 static jboolean NativeBN_BN_is_bit_set(JNIEnv* env, jclass, jlong a, int n) {
428   if (!oneValidHandle(env, a)) return JNI_FALSE;
429   return BN_is_bit_set(toBigNum(a), n);
430 }
431 
NativeBN_BN_shift(JNIEnv * env,jclass,jlong r,jlong a,int n)432 static void NativeBN_BN_shift(JNIEnv* env, jclass, jlong r, jlong a, int n) {
433   if (!twoValidHandles(env, r, a)) return;
434   if (n >= 0) {
435     BN_lshift(toBigNum(r), toBigNum(a), n);
436   } else {
437     BN_rshift(toBigNum(r), toBigNum(a), -n);
438   }
439   throwExceptionIfNecessary(env);
440 }
441 
NativeBN_BN_add_word(JNIEnv * env,jclass,jlong a,BN_ULONG w)442 static void NativeBN_BN_add_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
443   if (!oneValidHandle(env, a)) return;
444   BN_add_word(toBigNum(a), w);
445   throwExceptionIfNecessary(env);
446 }
447 
NativeBN_BN_mul_word(JNIEnv * env,jclass,jlong a,BN_ULONG w)448 static void NativeBN_BN_mul_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
449   if (!oneValidHandle(env, a)) return;
450   BN_mul_word(toBigNum(a), w);
451   throwExceptionIfNecessary(env);
452 }
453 
NativeBN_BN_mod_word(JNIEnv * env,jclass,jlong a,BN_ULONG w)454 static BN_ULONG NativeBN_BN_mod_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
455   if (!oneValidHandle(env, a)) return 0;
456   int result = BN_mod_word(toBigNum(a), w);
457   throwExceptionIfNecessary(env);
458   return result;
459 }
460 
NativeBN_BN_add(JNIEnv * env,jclass,jlong r,jlong a,jlong b)461 static void NativeBN_BN_add(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
462   if (!threeValidHandles(env, r, a, b)) return;
463   BN_add(toBigNum(r), toBigNum(a), toBigNum(b));
464   throwExceptionIfNecessary(env);
465 }
466 
NativeBN_BN_sub(JNIEnv * env,jclass,jlong r,jlong a,jlong b)467 static void NativeBN_BN_sub(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
468   if (!threeValidHandles(env, r, a, b)) return;
469   BN_sub(toBigNum(r), toBigNum(a), toBigNum(b));
470   throwExceptionIfNecessary(env);
471 }
472 
NativeBN_BN_gcd(JNIEnv * env,jclass,jlong r,jlong a,jlong b)473 static void NativeBN_BN_gcd(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
474   if (!threeValidHandles(env, r, a, b)) return;
475   Unique_BN_CTX ctx(BN_CTX_new());
476   BN_gcd(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get());
477   throwExceptionIfNecessary(env);
478 }
479 
NativeBN_BN_mul(JNIEnv * env,jclass,jlong r,jlong a,jlong b)480 static void NativeBN_BN_mul(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
481   if (!threeValidHandles(env, r, a, b)) return;
482   Unique_BN_CTX ctx(BN_CTX_new());
483   BN_mul(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get());
484   throwExceptionIfNecessary(env);
485 }
486 
NativeBN_BN_exp(JNIEnv * env,jclass,jlong r,jlong a,jlong p)487 static void NativeBN_BN_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p) {
488   if (!threeValidHandles(env, r, a, p)) return;
489   Unique_BN_CTX ctx(BN_CTX_new());
490   BN_exp(toBigNum(r), toBigNum(a), toBigNum(p), ctx.get());
491   throwExceptionIfNecessary(env);
492 }
493 
NativeBN_BN_div(JNIEnv * env,jclass,jlong dv,jlong rem,jlong m,jlong d)494 static void NativeBN_BN_div(JNIEnv* env, jclass, jlong dv, jlong rem, jlong m, jlong d) {
495   if (!fourValidHandles(env, (rem ? rem : dv), (dv ? dv : rem), m, d)) return;
496   Unique_BN_CTX ctx(BN_CTX_new());
497   BN_div(toBigNum(dv), toBigNum(rem), toBigNum(m), toBigNum(d), ctx.get());
498   throwExceptionIfNecessary(env);
499 }
500 
NativeBN_BN_nnmod(JNIEnv * env,jclass,jlong r,jlong a,jlong m)501 static void NativeBN_BN_nnmod(JNIEnv* env, jclass, jlong r, jlong a, jlong m) {
502   if (!threeValidHandles(env, r, a, m)) return;
503   Unique_BN_CTX ctx(BN_CTX_new());
504   BN_nnmod(toBigNum(r), toBigNum(a), toBigNum(m), ctx.get());
505   throwExceptionIfNecessary(env);
506 }
507 
NativeBN_BN_mod_exp(JNIEnv * env,jclass,jlong r,jlong a,jlong p,jlong m)508 static void NativeBN_BN_mod_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p, jlong m) {
509   if (!fourValidHandles(env, r, a, p, m)) return;
510   Unique_BN_CTX ctx(BN_CTX_new());
511   BN_mod_exp(toBigNum(r), toBigNum(a), toBigNum(p), toBigNum(m), ctx.get());
512   throwExceptionIfNecessary(env);
513 }
514 
NativeBN_BN_mod_inverse(JNIEnv * env,jclass,jlong ret,jlong a,jlong n)515 static void NativeBN_BN_mod_inverse(JNIEnv* env, jclass, jlong ret, jlong a, jlong n) {
516   if (!threeValidHandles(env, ret, a, n)) return;
517   Unique_BN_CTX ctx(BN_CTX_new());
518   BN_mod_inverse(toBigNum(ret), toBigNum(a), toBigNum(n), ctx.get());
519   throwExceptionIfNecessary(env);
520 }
521 
NativeBN_BN_generate_prime_ex(JNIEnv * env,jclass,jlong ret,int bits,jboolean safe,jlong add,jlong rem,jlong cb)522 static void NativeBN_BN_generate_prime_ex(JNIEnv* env, jclass, jlong ret, int bits,
523                                           jboolean safe, jlong add, jlong rem, jlong cb) {
524   if (!oneValidHandle(env, ret)) return;
525   BN_generate_prime_ex(toBigNum(ret), bits, safe, toBigNum(add), toBigNum(rem),
526                        reinterpret_cast<BN_GENCB*>(cb));
527   throwExceptionIfNecessary(env);
528 }
529 
NativeBN_BN_is_prime_ex(JNIEnv * env,jclass,jlong p,int nchecks,jlong cb)530 static jboolean NativeBN_BN_is_prime_ex(JNIEnv* env, jclass, jlong p, int nchecks, jlong cb) {
531   if (!oneValidHandle(env, p)) return JNI_FALSE;
532   Unique_BN_CTX ctx(BN_CTX_new());
533   return BN_is_prime_ex(toBigNum(p), nchecks, ctx.get(), reinterpret_cast<BN_GENCB*>(cb));
534 }
535 
536 static JNINativeMethod gMethods[] = {
537    NATIVE_METHOD(NativeBN, BN_add, "(JJJ)V"),
538    NATIVE_METHOD(NativeBN, BN_add_word, "(JI)V"),
539    NATIVE_METHOD(NativeBN, BN_bin2bn, "([BIZJ)V"),
540    NATIVE_METHOD(NativeBN, BN_bn2bin, "(J)[B"),
541    NATIVE_METHOD(NativeBN, BN_bn2dec, "(J)Ljava/lang/String;"),
542    NATIVE_METHOD(NativeBN, BN_bn2hex, "(J)Ljava/lang/String;"),
543    NATIVE_METHOD(NativeBN, BN_cmp, "(JJ)I"),
544    NATIVE_METHOD(NativeBN, BN_copy, "(JJ)V"),
545    NATIVE_METHOD(NativeBN, BN_dec2bn, "(JLjava/lang/String;)I"),
546    NATIVE_METHOD(NativeBN, BN_div, "(JJJJ)V"),
547    NATIVE_METHOD(NativeBN, BN_exp, "(JJJ)V"),
548    NATIVE_METHOD(NativeBN, BN_free, "(J)V"),
549    NATIVE_METHOD(NativeBN, BN_gcd, "(JJJ)V"),
550    NATIVE_METHOD(NativeBN, BN_generate_prime_ex, "(JIZJJJ)V"),
551    NATIVE_METHOD(NativeBN, BN_hex2bn, "(JLjava/lang/String;)I"),
552    NATIVE_METHOD(NativeBN, BN_is_bit_set, "(JI)Z"),
553    NATIVE_METHOD(NativeBN, BN_is_prime_ex, "(JIJ)Z"),
554    NATIVE_METHOD(NativeBN, BN_mod_exp, "(JJJJ)V"),
555    NATIVE_METHOD(NativeBN, BN_mod_inverse, "(JJJ)V"),
556    NATIVE_METHOD(NativeBN, BN_mod_word, "(JI)I"),
557    NATIVE_METHOD(NativeBN, BN_mul, "(JJJ)V"),
558    NATIVE_METHOD(NativeBN, BN_mul_word, "(JI)V"),
559    NATIVE_METHOD(NativeBN, BN_new, "()J"),
560    NATIVE_METHOD(NativeBN, BN_nnmod, "(JJJ)V"),
561    NATIVE_METHOD(NativeBN, BN_set_negative, "(JI)V"),
562    NATIVE_METHOD(NativeBN, BN_shift, "(JJI)V"),
563    NATIVE_METHOD(NativeBN, BN_sub, "(JJJ)V"),
564    NATIVE_METHOD(NativeBN, bitLength, "(J)I"),
565    NATIVE_METHOD(NativeBN, bn2litEndInts, "(J)[I"),
566    NATIVE_METHOD(NativeBN, litEndInts2bn, "([IIZJ)V"),
567    NATIVE_METHOD(NativeBN, longInt, "(J)J"),
568    NATIVE_METHOD(NativeBN, putLongInt, "(JJ)V"),
569    NATIVE_METHOD(NativeBN, putULongInt, "(JJZ)V"),
570    NATIVE_METHOD(NativeBN, sign, "(J)I"),
571    NATIVE_METHOD(NativeBN, twosComp2bn, "([BIJ)V"),
572 };
register_java_math_NativeBN(JNIEnv * env)573 void register_java_math_NativeBN(JNIEnv* env) {
574     jniRegisterNativeMethods(env, "java/math/NativeBN", gMethods, NELEM(gMethods));
575 }
576