blob: 78cc69a345f6c1e48fcf05e85832882f1dab0b44 [file] [log] [blame]
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001/*
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
Elliott Hughesabf945f2010-06-03 19:55:20 -070017#define LOG_TAG "NativeBN"
18
Elliott Hughes99c59bf2010-05-17 16:22:04 -070019#include "JNIHelp.h"
Elliott Hughese22935d2010-08-12 17:27:27 -070020#include "JniConstants.h"
Elliott Hughes66e740b2013-04-24 12:35:12 -070021#include "JniException.h"
Elliott Hughes99c59bf2010-05-17 16:22:04 -070022#include "ScopedPrimitiveArray.h"
Elliott Hughes05960872010-05-26 17:45:07 -070023#include "ScopedUtfChars.h"
Elliott Hughes63710432010-06-11 12:58:06 -070024#include "UniquePtr.h"
Elliott Hughes99c59bf2010-05-17 16:22:04 -070025#include "jni.h"
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080026#include <openssl/bn.h>
Elliott Hughes99c59bf2010-05-17 16:22:04 -070027#include <openssl/crypto.h>
28#include <openssl/err.h>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080029#include <stdio.h>
30
Elliott Hughes63710432010-06-11 12:58:06 -070031struct BN_CTX_Deleter {
Elliott Hughes66e740b2013-04-24 12:35:12 -070032 void operator()(BN_CTX* p) const {
33 BN_CTX_free(p);
34 }
Elliott Hughes63710432010-06-11 12:58:06 -070035};
36typedef UniquePtr<BN_CTX, BN_CTX_Deleter> Unique_BN_CTX;
37
Elliott Hughesa125dde2013-04-22 17:02:28 -070038static BIGNUM* toBigNum(jlong address) {
39 return reinterpret_cast<BIGNUM*>(static_cast<uintptr_t>(address));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080040}
41
Elliott Hughes66e740b2013-04-24 12:35:12 -070042static 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}
Elliott Hughesa125dde2013-04-22 17:02:28 -070061
62static 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;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080068}
69
Elliott Hughesa125dde2013-04-22 17:02:28 -070070static int oneValidHandle(JNIEnv* env, jlong a) {
71 return isValidHandle(env, a, "Mandatory handle (first) passed as null");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080072}
73
Elliott Hughesa125dde2013-04-22 17:02:28 -070074static 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");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080077}
78
Elliott Hughesa125dde2013-04-22 17:02:28 -070079static 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
84static 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");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080087}
88
Elliott Hughes66e740b2013-04-24 12:35:12 -070089static 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;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080093}
94
Elliott Hughesa125dde2013-04-22 17:02:28 -070095static void NativeBN_BN_free(JNIEnv* env, jclass, jlong a) {
96 if (!oneValidHandle(env, a)) return;
97 BN_free(toBigNum(a));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080098}
99
Elliott Hughesa125dde2013-04-22 17:02:28 -0700100static 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));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800103}
104
Elliott Hughes66e740b2013-04-24 12:35:12 -0700105static 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);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800109}
110
Elliott Hughes66e740b2013-04-24 12:35:12 -0700111static void NativeBN_putULongInt(JNIEnv* env, jclass, jlong a0, unsigned long long dw, jboolean neg) {
112 if (!oneValidHandle(env, a0)) return;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800113 unsigned int hi = dw >> 32; // This shifts without sign extension.
Elliott Hughesa125dde2013-04-22 17:02:28 -0700114 int lo = (int)dw; // This truncates implicitly.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800115
116 // cf. litEndInts2bn:
Elliott Hughesa125dde2013-04-22 17:02:28 -0700117 BIGNUM* a = toBigNum(a0);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800118 bn_check_top(a);
Elliott Hughes66e740b2013-04-24 12:35:12 -0700119 if (bn_wexpand(a, 2) != NULL) {
120 a->d[0] = lo;
121 a->d[1] = hi;
122 a->top = 2;
123 a->neg = neg;
124 bn_correct_top(a);
125 } else {
126 throwExceptionIfNecessary(env);
127 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800128}
129
Elliott Hughes66e740b2013-04-24 12:35:12 -0700130static void NativeBN_putLongInt(JNIEnv* env, jclass cls, jlong a, long long dw) {
Elliott Hughesa125dde2013-04-22 17:02:28 -0700131 if (dw >= 0) {
Elliott Hughes66e740b2013-04-24 12:35:12 -0700132 NativeBN_putULongInt(env, cls, a, dw, JNI_FALSE);
Elliott Hughesa125dde2013-04-22 17:02:28 -0700133 } else {
Elliott Hughes66e740b2013-04-24 12:35:12 -0700134 NativeBN_putULongInt(env, cls, a, -dw, JNI_TRUE);
Elliott Hughesa125dde2013-04-22 17:02:28 -0700135 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800136}
137
Elliott Hughesa125dde2013-04-22 17:02:28 -0700138static int NativeBN_BN_dec2bn(JNIEnv* env, jclass, jlong a0, jstring str) {
139 if (!oneValidHandle(env, a0)) return -1;
140 ScopedUtfChars chars(env, str);
141 if (chars.c_str() == NULL) {
142 return -1;
143 }
144 BIGNUM* a = toBigNum(a0);
Elliott Hughes66e740b2013-04-24 12:35:12 -0700145 int result = BN_dec2bn(&a, chars.c_str());
146 throwExceptionIfNecessary(env);
147 return result;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800148}
149
Elliott Hughesa125dde2013-04-22 17:02:28 -0700150static int NativeBN_BN_hex2bn(JNIEnv* env, jclass, jlong a0, jstring str) {
151 if (!oneValidHandle(env, a0)) return -1;
152 ScopedUtfChars chars(env, str);
153 if (chars.c_str() == NULL) {
154 return -1;
155 }
156 BIGNUM* a = toBigNum(a0);
Elliott Hughes66e740b2013-04-24 12:35:12 -0700157 int result = BN_hex2bn(&a, chars.c_str());
158 throwExceptionIfNecessary(env);
159 return result;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800160}
161
Elliott Hughes66e740b2013-04-24 12:35:12 -0700162static void NativeBN_BN_bin2bn(JNIEnv* env, jclass, jbyteArray arr, int len, jboolean neg, jlong ret) {
163 if (!oneValidHandle(env, ret)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700164 ScopedByteArrayRO bytes(env, arr);
165 if (bytes.get() == NULL) {
Elliott Hughes66e740b2013-04-24 12:35:12 -0700166 return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700167 }
Elliott Hughes66e740b2013-04-24 12:35:12 -0700168 BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, toBigNum(ret));
169 if (!throwExceptionIfNecessary(env) && neg) {
170 BN_set_negative(toBigNum(ret), true);
Elliott Hughesa125dde2013-04-22 17:02:28 -0700171 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800172}
173
174/**
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700175 * Note:
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800176 * This procedure directly writes the internal representation of BIGNUMs.
177 * We do so as there is no direct interface based on Little Endian Integer Arrays.
178 * Also note that the same representation is used in the Cordoba Java Implementation of BigIntegers,
179 * whereof certain functionality is still being used.
180 */
Elliott Hughes66e740b2013-04-24 12:35:12 -0700181static void NativeBN_litEndInts2bn(JNIEnv* env, jclass, jintArray arr, int len, jboolean neg, jlong ret0) {
182 if (!oneValidHandle(env, ret0)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700183 BIGNUM* ret = toBigNum(ret0);
184 bn_check_top(ret);
185 if (len > 0) {
186 ScopedIntArrayRO scopedArray(env, arr);
187 if (scopedArray.get() == NULL) {
Elliott Hughes66e740b2013-04-24 12:35:12 -0700188 return;
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700189 }
Elliott Hughesa125dde2013-04-22 17:02:28 -0700190
Elliott Hughes55c4a2d2013-09-06 18:53:22 -0700191 static_assert(sizeof(BN_ULONG) == sizeof(jint), "BN_ULONG is not 32-bit!");
Elliott Hughesa125dde2013-04-22 17:02:28 -0700192 const BN_ULONG* tmpInts = reinterpret_cast<const BN_ULONG*>(scopedArray.get());
193 if ((tmpInts != NULL) && (bn_wexpand(ret, len) != NULL)) {
194 int i = len; do { i--; ret->d[i] = tmpInts[i]; } while (i > 0);
195 ret->top = len;
196 ret->neg = neg;
197 // need to call this due to clear byte at top if avoiding
198 // having the top bit set (-ve number)
199 // Basically get rid of top zero ints:
200 bn_correct_top(ret);
Elliott Hughesa125dde2013-04-22 17:02:28 -0700201 } else {
Elliott Hughes66e740b2013-04-24 12:35:12 -0700202 throwExceptionIfNecessary(env);
Elliott Hughesa125dde2013-04-22 17:02:28 -0700203 }
204 } else { // (len = 0) means value = 0 and sign will be 0, too.
205 ret->top = 0;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700206 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800207}
208
209
210#define BYTES2INT(bytes, k) \
Elliott Hughesa125dde2013-04-22 17:02:28 -0700211 ((bytes[k + 3] & 0xff) | (bytes[k + 2] & 0xff) << 8 | (bytes[k + 1] & 0xff) << 16 | (bytes[k + 0] & 0xff) << 24)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800212
Elliott Hughes66e740b2013-04-24 12:35:12 -0700213static void negBigEndianBytes2bn(JNIEnv*, jclass, const unsigned char* bytes, int bytesLen, jlong ret0) {
Elliott Hughesa125dde2013-04-22 17:02:28 -0700214 BIGNUM* ret = toBigNum(ret0);
215
216 // We rely on: (BN_BITS2 == 32), i.e. BN_ULONG is unsigned int and has 4 bytes:
217 bn_check_top(ret);
218 // FIXME: assert bytesLen > 0
219 int intLen = (bytesLen + 3) / 4;
220 int firstNonzeroDigit = -2;
221 if (bn_wexpand(ret, intLen) != NULL) {
222 BN_ULONG* d = ret->d;
223 BN_ULONG di;
224 ret->top = intLen;
225 int highBytes = bytesLen % 4;
226 int k = bytesLen;
227 // Put bytes to the int array starting from the end of the byte array
228 int i = 0;
229 while (k > highBytes) {
230 k -= 4;
231 di = BYTES2INT(bytes, k);
232 if (di != 0) {
233 d[i] = -di;
234 firstNonzeroDigit = i;
235 i++;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800236 while (k > highBytes) {
Elliott Hughesa125dde2013-04-22 17:02:28 -0700237 k -= 4;
238 d[i] = ~BYTES2INT(bytes, k);
239 i++;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800240 }
Elliott Hughesa125dde2013-04-22 17:02:28 -0700241 break;
242 } else {
243 d[i] = 0;
244 i++;
245 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800246 }
Elliott Hughesa125dde2013-04-22 17:02:28 -0700247 if (highBytes != 0) {
248 di = -1;
249 // Put the first bytes in the highest element of the int array
250 if (firstNonzeroDigit != -2) {
251 for (k = 0; k < highBytes; k++) {
252 di = (di << 8) | (bytes[k] & 0xFF);
253 }
254 d[i] = ~di;
255 } else {
256 for (k = 0; k < highBytes; k++) {
257 di = (di << 8) | (bytes[k] & 0xFF);
258 }
259 d[i] = -di;
260 }
261 }
Elliott Hughesa125dde2013-04-22 17:02:28 -0700262 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800263}
264
Elliott Hughes66e740b2013-04-24 12:35:12 -0700265static void NativeBN_twosComp2bn(JNIEnv* env, jclass cls, jbyteArray arr, int bytesLen, jlong ret0) {
266 if (!oneValidHandle(env, ret0)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700267 BIGNUM* ret = toBigNum(ret0);
268
269 ScopedByteArrayRO bytes(env, arr);
270 if (bytes.get() == NULL) {
Elliott Hughes66e740b2013-04-24 12:35:12 -0700271 return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700272 }
Elliott Hughesa125dde2013-04-22 17:02:28 -0700273 const unsigned char* s = reinterpret_cast<const unsigned char*>(bytes.get());
274 if ((bytes[0] & 0X80) == 0) { // Positive value!
275 //
276 // We can use the existing BN implementation for unsigned big endian bytes:
277 //
Elliott Hughes66e740b2013-04-24 12:35:12 -0700278 BN_bin2bn(s, bytesLen, ret);
279 BN_set_negative(ret, false);
Elliott Hughesa125dde2013-04-22 17:02:28 -0700280 } else { // Negative value!
281 //
282 // We need to apply two's complement:
283 //
Elliott Hughes66e740b2013-04-24 12:35:12 -0700284 negBigEndianBytes2bn(env, cls, s, bytesLen, ret0);
285 BN_set_negative(ret, true);
Elliott Hughesa125dde2013-04-22 17:02:28 -0700286 }
Elliott Hughes66e740b2013-04-24 12:35:12 -0700287 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800288}
289
Elliott Hughesa125dde2013-04-22 17:02:28 -0700290static long long NativeBN_longInt(JNIEnv* env, jclass, jlong a0) {
291 if (!oneValidHandle(env, a0)) return -1;
292 BIGNUM* a = toBigNum(a0);
293 bn_check_top(a);
294 int intLen = a->top;
295 BN_ULONG* d = a->d;
296 switch (intLen) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800297 case 0:
Elliott Hughesa125dde2013-04-22 17:02:28 -0700298 return 0;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800299 case 1:
Elliott Hughesa125dde2013-04-22 17:02:28 -0700300 if (!a->neg) {
301 return d[0] & 0X00000000FFFFFFFFLL;
302 } else {
303 return -(d[0] & 0X00000000FFFFFFFFLL);
304 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800305 default:
Elliott Hughesa125dde2013-04-22 17:02:28 -0700306 if (!a->neg) {
307 return ((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL);
308 } else {
309 return -(((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL));
310 }
311 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800312}
313
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800314static char* leadingZerosTrimmed(char* s) {
315 char* p = s;
316 if (*p == '-') {
317 p++;
318 while ((*p == '0') && (*(p + 1) != 0)) { p++; }
319 p--;
320 *p = '-';
321 } else {
322 while ((*p == '0') && (*(p + 1) != 0)) { p++; }
323 }
324 return p;
325}
326
Elliott Hughesa125dde2013-04-22 17:02:28 -0700327static jstring NativeBN_BN_bn2dec(JNIEnv* env, jclass, jlong a) {
328 if (!oneValidHandle(env, a)) return NULL;
329 char* tmpStr = BN_bn2dec(toBigNum(a));
330 if (tmpStr == NULL) {
331 return NULL;
332 }
333 char* retStr = leadingZerosTrimmed(tmpStr);
334 jstring returnJString = env->NewStringUTF(retStr);
335 OPENSSL_free(tmpStr);
336 return returnJString;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800337}
338
Elliott Hughesa125dde2013-04-22 17:02:28 -0700339static jstring NativeBN_BN_bn2hex(JNIEnv* env, jclass, jlong a) {
340 if (!oneValidHandle(env, a)) return NULL;
341 char* tmpStr = BN_bn2hex(toBigNum(a));
342 if (tmpStr == NULL) {
343 return NULL;
344 }
345 char* retStr = leadingZerosTrimmed(tmpStr);
346 jstring returnJString = env->NewStringUTF(retStr);
347 OPENSSL_free(tmpStr);
348 return returnJString;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800349}
350
Elliott Hughesa125dde2013-04-22 17:02:28 -0700351static jbyteArray NativeBN_BN_bn2bin(JNIEnv* env, jclass, jlong a0) {
352 if (!oneValidHandle(env, a0)) return NULL;
353 BIGNUM* a = toBigNum(a0);
354 jbyteArray result = env->NewByteArray(BN_num_bytes(a));
355 if (result == NULL) {
356 return NULL;
357 }
358 ScopedByteArrayRW bytes(env, result);
359 if (bytes.get() == NULL) {
360 return NULL;
361 }
362 BN_bn2bin(a, reinterpret_cast<unsigned char*>(bytes.get()));
363 return result;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800364}
365
Elliott Hughesa125dde2013-04-22 17:02:28 -0700366static jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass, jlong a0) {
367 if (!oneValidHandle(env, a0)) return NULL;
368 BIGNUM* a = toBigNum(a0);
369 bn_check_top(a);
370 int len = a->top;
371 if (len == 0) {
372 return NULL;
373 }
374 jintArray result = env->NewIntArray(len);
375 if (result == NULL) {
376 return NULL;
377 }
378 ScopedIntArrayRW ints(env, result);
379 if (ints.get() == NULL) {
380 return NULL;
381 }
382 BN_ULONG* ulongs = reinterpret_cast<BN_ULONG*>(ints.get());
383 if (ulongs == NULL) {
384 return NULL;
385 }
386 int i = len; do { i--; ulongs[i] = a->d[i]; } while (i > 0);
387 return result;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800388}
389
Elliott Hughesa125dde2013-04-22 17:02:28 -0700390static int NativeBN_sign(JNIEnv* env, jclass, jlong a) {
391 if (!oneValidHandle(env, a)) return -2;
392 if (BN_is_zero(toBigNum(a))) {
393 return 0;
394 } else if (BN_is_negative(toBigNum(a))) {
395 return -1;
396 }
397 return 1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800398}
399
Elliott Hughesa125dde2013-04-22 17:02:28 -0700400static void NativeBN_BN_set_negative(JNIEnv* env, jclass, jlong b, int n) {
401 if (!oneValidHandle(env, b)) return;
402 BN_set_negative(toBigNum(b), n);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800403}
404
Elliott Hughesa125dde2013-04-22 17:02:28 -0700405static int NativeBN_bitLength(JNIEnv* env, jclass, jlong a0) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800406// We rely on: (BN_BITS2 == 32), i.e. BN_ULONG is unsigned int and has 4 bytes:
407//
Elliott Hughesa125dde2013-04-22 17:02:28 -0700408 if (!oneValidHandle(env, a0)) return JNI_FALSE;
409 BIGNUM* a = toBigNum(a0);
410 bn_check_top(a);
411 int intLen = a->top;
412 if (intLen == 0) return 0;
413 BN_ULONG* d = a->d;
414 int i = intLen - 1;
415 BN_ULONG msd = d[i]; // most significant digit
416 if (a->neg) {
417 // Handle negative values correctly:
418 // i.e. decrement the msd if all other digits are 0:
419 // while ((i > 0) && (d[i] != 0)) { i--; }
420 do { i--; } while (!((i < 0) || (d[i] != 0)));
421 if (i < 0) msd--; // Only if all lower significant digits are 0 we decrement the most significant one.
422 }
423 return (intLen - 1) * 32 + BN_num_bits_word(msd);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800424}
425
Elliott Hughesa125dde2013-04-22 17:02:28 -0700426static jboolean NativeBN_BN_is_bit_set(JNIEnv* env, jclass, jlong a, int n) {
427 if (!oneValidHandle(env, a)) return JNI_FALSE;
428 return BN_is_bit_set(toBigNum(a), n);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800429}
430
Elliott Hughes66e740b2013-04-24 12:35:12 -0700431static void NativeBN_BN_shift(JNIEnv* env, jclass, jlong r, jlong a, int n) {
432 if (!twoValidHandles(env, r, a)) return;
433 if (n >= 0) {
434 BN_lshift(toBigNum(r), toBigNum(a), n);
435 } else {
436 BN_rshift(toBigNum(r), toBigNum(a), -n);
437 }
438 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800439}
440
Elliott Hughes66e740b2013-04-24 12:35:12 -0700441static void NativeBN_BN_add_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
442 if (!oneValidHandle(env, a)) return;
443 BN_add_word(toBigNum(a), w);
444 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800445}
446
Elliott Hughes66e740b2013-04-24 12:35:12 -0700447static void NativeBN_BN_mul_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
448 if (!oneValidHandle(env, a)) return;
449 BN_mul_word(toBigNum(a), w);
450 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800451}
452
Elliott Hughesa125dde2013-04-22 17:02:28 -0700453static BN_ULONG NativeBN_BN_mod_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
Elliott Hughes66e740b2013-04-24 12:35:12 -0700454 if (!oneValidHandle(env, a)) return 0;
455 int result = BN_mod_word(toBigNum(a), w);
456 throwExceptionIfNecessary(env);
457 return result;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800458}
459
Elliott Hughes66e740b2013-04-24 12:35:12 -0700460static void NativeBN_BN_add(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
461 if (!threeValidHandles(env, r, a, b)) return;
462 BN_add(toBigNum(r), toBigNum(a), toBigNum(b));
463 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800464}
465
Elliott Hughes66e740b2013-04-24 12:35:12 -0700466static void NativeBN_BN_sub(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
467 if (!threeValidHandles(env, r, a, b)) return;
468 BN_sub(toBigNum(r), toBigNum(a), toBigNum(b));
469 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800470}
471
Elliott Hughes66e740b2013-04-24 12:35:12 -0700472static void NativeBN_BN_gcd(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
473 if (!threeValidHandles(env, r, a, b)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700474 Unique_BN_CTX ctx(BN_CTX_new());
Elliott Hughes66e740b2013-04-24 12:35:12 -0700475 BN_gcd(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get());
476 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800477}
478
Elliott Hughes66e740b2013-04-24 12:35:12 -0700479static void NativeBN_BN_mul(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
480 if (!threeValidHandles(env, r, a, b)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700481 Unique_BN_CTX ctx(BN_CTX_new());
Elliott Hughes66e740b2013-04-24 12:35:12 -0700482 BN_mul(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get());
483 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800484}
485
Elliott Hughes66e740b2013-04-24 12:35:12 -0700486static void NativeBN_BN_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p) {
487 if (!threeValidHandles(env, r, a, p)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700488 Unique_BN_CTX ctx(BN_CTX_new());
Elliott Hughes66e740b2013-04-24 12:35:12 -0700489 BN_exp(toBigNum(r), toBigNum(a), toBigNum(p), ctx.get());
490 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800491}
492
Elliott Hughes66e740b2013-04-24 12:35:12 -0700493static void NativeBN_BN_div(JNIEnv* env, jclass, jlong dv, jlong rem, jlong m, jlong d) {
494 if (!fourValidHandles(env, (rem ? rem : dv), (dv ? dv : rem), m, d)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700495 Unique_BN_CTX ctx(BN_CTX_new());
Elliott Hughes66e740b2013-04-24 12:35:12 -0700496 BN_div(toBigNum(dv), toBigNum(rem), toBigNum(m), toBigNum(d), ctx.get());
497 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800498}
499
Elliott Hughes66e740b2013-04-24 12:35:12 -0700500static void NativeBN_BN_nnmod(JNIEnv* env, jclass, jlong r, jlong a, jlong m) {
501 if (!threeValidHandles(env, r, a, m)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700502 Unique_BN_CTX ctx(BN_CTX_new());
Elliott Hughes66e740b2013-04-24 12:35:12 -0700503 BN_nnmod(toBigNum(r), toBigNum(a), toBigNum(m), ctx.get());
504 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800505}
506
Elliott Hughes66e740b2013-04-24 12:35:12 -0700507static void NativeBN_BN_mod_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p, jlong m) {
508 if (!fourValidHandles(env, r, a, p, m)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700509 Unique_BN_CTX ctx(BN_CTX_new());
Elliott Hughes66e740b2013-04-24 12:35:12 -0700510 BN_mod_exp(toBigNum(r), toBigNum(a), toBigNum(p), toBigNum(m), ctx.get());
511 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800512}
513
Elliott Hughes66e740b2013-04-24 12:35:12 -0700514static void NativeBN_BN_mod_inverse(JNIEnv* env, jclass, jlong ret, jlong a, jlong n) {
515 if (!threeValidHandles(env, ret, a, n)) return;
Elliott Hughesa125dde2013-04-22 17:02:28 -0700516 Unique_BN_CTX ctx(BN_CTX_new());
Elliott Hughes66e740b2013-04-24 12:35:12 -0700517 BN_mod_inverse(toBigNum(ret), toBigNum(a), toBigNum(n), ctx.get());
518 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800519}
520
Elliott Hughes66e740b2013-04-24 12:35:12 -0700521static void NativeBN_BN_generate_prime_ex(JNIEnv* env, jclass, jlong ret, int bits,
522 jboolean safe, jlong add, jlong rem, jlong cb) {
523 if (!oneValidHandle(env, ret)) return;
524 BN_generate_prime_ex(toBigNum(ret), bits, safe, toBigNum(add), toBigNum(rem),
525 reinterpret_cast<BN_GENCB*>(cb));
526 throwExceptionIfNecessary(env);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800527}
528
Chris Dearman0a08bbe2013-05-29 19:50:42 -0700529static jboolean NativeBN_BN_is_prime_ex(JNIEnv* env, jclass, jlong p, int nchecks, jlong cb) {
Elliott Hughesa125dde2013-04-22 17:02:28 -0700530 if (!oneValidHandle(env, p)) return JNI_FALSE;
531 Unique_BN_CTX ctx(BN_CTX_new());
Chris Dearman0a08bbe2013-05-29 19:50:42 -0700532 return BN_is_prime_ex(toBigNum(p), nchecks, ctx.get(), reinterpret_cast<BN_GENCB*>(cb));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800533}
534
Elliott Hughes63710432010-06-11 12:58:06 -0700535static JNINativeMethod gMethods[] = {
Elliott Hughes66e740b2013-04-24 12:35:12 -0700536 NATIVE_METHOD(NativeBN, BN_add, "(JJJ)V"),
537 NATIVE_METHOD(NativeBN, BN_add_word, "(JI)V"),
538 NATIVE_METHOD(NativeBN, BN_bin2bn, "([BIZJ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700539 NATIVE_METHOD(NativeBN, BN_bn2bin, "(J)[B"),
540 NATIVE_METHOD(NativeBN, BN_bn2dec, "(J)Ljava/lang/String;"),
541 NATIVE_METHOD(NativeBN, BN_bn2hex, "(J)Ljava/lang/String;"),
542 NATIVE_METHOD(NativeBN, BN_cmp, "(JJ)I"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700543 NATIVE_METHOD(NativeBN, BN_copy, "(JJ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700544 NATIVE_METHOD(NativeBN, BN_dec2bn, "(JLjava/lang/String;)I"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700545 NATIVE_METHOD(NativeBN, BN_div, "(JJJJ)V"),
546 NATIVE_METHOD(NativeBN, BN_exp, "(JJJ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700547 NATIVE_METHOD(NativeBN, BN_free, "(J)V"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700548 NATIVE_METHOD(NativeBN, BN_gcd, "(JJJ)V"),
549 NATIVE_METHOD(NativeBN, BN_generate_prime_ex, "(JIZJJJ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700550 NATIVE_METHOD(NativeBN, BN_hex2bn, "(JLjava/lang/String;)I"),
551 NATIVE_METHOD(NativeBN, BN_is_bit_set, "(JI)Z"),
552 NATIVE_METHOD(NativeBN, BN_is_prime_ex, "(JIJ)Z"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700553 NATIVE_METHOD(NativeBN, BN_mod_exp, "(JJJJ)V"),
554 NATIVE_METHOD(NativeBN, BN_mod_inverse, "(JJJ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700555 NATIVE_METHOD(NativeBN, BN_mod_word, "(JI)I"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700556 NATIVE_METHOD(NativeBN, BN_mul, "(JJJ)V"),
557 NATIVE_METHOD(NativeBN, BN_mul_word, "(JI)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700558 NATIVE_METHOD(NativeBN, BN_new, "()J"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700559 NATIVE_METHOD(NativeBN, BN_nnmod, "(JJJ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700560 NATIVE_METHOD(NativeBN, BN_set_negative, "(JI)V"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700561 NATIVE_METHOD(NativeBN, BN_shift, "(JJI)V"),
562 NATIVE_METHOD(NativeBN, BN_sub, "(JJJ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700563 NATIVE_METHOD(NativeBN, bitLength, "(J)I"),
564 NATIVE_METHOD(NativeBN, bn2litEndInts, "(J)[I"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700565 NATIVE_METHOD(NativeBN, litEndInts2bn, "([IIZJ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700566 NATIVE_METHOD(NativeBN, longInt, "(J)J"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700567 NATIVE_METHOD(NativeBN, putLongInt, "(JJ)V"),
568 NATIVE_METHOD(NativeBN, putULongInt, "(JJZ)V"),
Elliott Hughesa125dde2013-04-22 17:02:28 -0700569 NATIVE_METHOD(NativeBN, sign, "(J)I"),
Elliott Hughes66e740b2013-04-24 12:35:12 -0700570 NATIVE_METHOD(NativeBN, twosComp2bn, "([BIJ)V"),
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800571};
Elliott Hughes7cd67602012-05-03 17:21:04 -0700572void register_java_math_NativeBN(JNIEnv* env) {
573 jniRegisterNativeMethods(env, "java/math/NativeBN", gMethods, NELEM(gMethods));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800574}