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