blob: 5e111d75573b7351859ea0147a46a824415d3841 [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
17/*
18 * Native glue for Java class org.openssl.NativeBN
19 */
20
Elliott Hughesabf945f2010-06-03 19:55:20 -070021#define LOG_TAG "NativeBN"
22
Elliott Hughes99c59bf2010-05-17 16:22:04 -070023#include "JNIHelp.h"
Elliott Hughese22935d2010-08-12 17:27:27 -070024#include "JniConstants.h"
Elliott Hughes99c59bf2010-05-17 16:22:04 -070025#include "ScopedPrimitiveArray.h"
Elliott Hughes05960872010-05-26 17:45:07 -070026#include "ScopedUtfChars.h"
Elliott Hughesaba7ce62010-10-18 15:42:37 -070027#include "StaticAssert.h"
Elliott Hughes63710432010-06-11 12:58:06 -070028#include "UniquePtr.h"
Elliott Hughes99c59bf2010-05-17 16:22:04 -070029#include "jni.h"
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080030#include <openssl/bn.h>
Elliott Hughes99c59bf2010-05-17 16:22:04 -070031#include <openssl/crypto.h>
32#include <openssl/err.h>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080033#include <stdio.h>
34
Elliott Hughes63710432010-06-11 12:58:06 -070035struct BN_CTX_Deleter {
36 void operator()(BN_CTX* p) const {
37 BN_CTX_free(p);
38 }
39};
40typedef UniquePtr<BN_CTX, BN_CTX_Deleter> Unique_BN_CTX;
41
Elliott Hughesacce5ff2010-08-13 16:14:21 -070042static int isValidHandle (JNIEnv* env, void* handle, const char* message) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080043 if (handle == NULL) {
Elliott Hughesda4f31d2010-01-28 13:43:39 -080044 jniThrowNullPointerException(env, message);
Elliott Hughes99c59bf2010-05-17 16:22:04 -070045 return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080046 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -070047 return JNI_TRUE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080048}
49
50static int oneValidHandle (JNIEnv* env, void* a)
51{
52 return isValidHandle(env, a, "Mandatory handle (first) passed as null");
53}
54
Elliott Hughesacce5ff2010-08-13 16:14:21 -070055static int twoValidHandles (JNIEnv* env, void* a, void* b)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080056{
Elliott Hughes99c59bf2010-05-17 16:22:04 -070057 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080058 return isValidHandle(env, b, "Mandatory handle (second) passed as null");
59}
60
Elliott Hughesacce5ff2010-08-13 16:14:21 -070061static int threeValidHandles (JNIEnv* env, void* a, void* b, void* c)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080062{
Elliott Hughes99c59bf2010-05-17 16:22:04 -070063 if (!twoValidHandles(env, a, b)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080064 return isValidHandle(env, c, "Mandatory handle (third) passed as null");
65}
66
Elliott Hughesacce5ff2010-08-13 16:14:21 -070067static int fourValidHandles (JNIEnv* env, void* a, void* b, void* c, void* d)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080068{
Elliott Hughes99c59bf2010-05-17 16:22:04 -070069 if (!threeValidHandles(env, a, b, c)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080070 return isValidHandle(env, d, "Mandatory handle (fourth) passed as null");
71}
72
Brian Carlstromec2f5932010-05-07 16:58:16 -070073static unsigned long NativeBN_ERR_get_error(JNIEnv*, jclass) {
74 return ERR_get_error();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080075}
76
Brian Carlstromec2f5932010-05-07 16:58:16 -070077static jstring NativeBN_ERR_error_string(JNIEnv* env, jclass, unsigned long e) {
78 char* errStr = ERR_error_string(e, NULL);
79 return env->NewStringUTF(errStr);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080080}
81
Brian Carlstromec2f5932010-05-07 16:58:16 -070082static BIGNUM* NativeBN_BN_new(JNIEnv*, jclass) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080083 return BN_new();
84}
85
Brian Carlstromec2f5932010-05-07 16:58:16 -070086static void NativeBN_BN_free(JNIEnv* env, jclass, BIGNUM* a) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080087 if (!oneValidHandle(env, a)) return;
88 BN_free(a);
89}
90
Brian Carlstromec2f5932010-05-07 16:58:16 -070091static int NativeBN_BN_cmp(JNIEnv* env, jclass, BIGNUM* a, BIGNUM* b) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080092 if (!twoValidHandles(env, a, b)) return 1;
93 return BN_cmp(a, b);
94}
95
Brian Carlstromec2f5932010-05-07 16:58:16 -070096static jboolean NativeBN_BN_copy(JNIEnv* env, jclass, BIGNUM* to, BIGNUM* from) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -070097 if (!twoValidHandles(env, to, from)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080098 return (BN_copy(to, from) != NULL);
99}
100
Brian Carlstromec2f5932010-05-07 16:58:16 -0700101static jboolean NativeBN_putULongInt(JNIEnv* env, jclass, BIGNUM* a, unsigned long long dw, jboolean neg) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700102 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800103 unsigned int hi = dw >> 32; // This shifts without sign extension.
104 int lo = (int)dw; // This truncates implicitely.
105
106 // cf. litEndInts2bn:
107 bn_check_top(a);
108 if (bn_wexpand(a, 2) != NULL) {
109 a->d[0] = lo;
110 a->d[1] = hi;
111 a->top = 2;
112 a->neg = neg;
113 bn_correct_top(a);
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700114 return JNI_TRUE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800115 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700116 else return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800117}
118
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800119static jboolean NativeBN_putLongInt(JNIEnv* env, jclass cls, BIGNUM* a, long long dw) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700120 if (dw >= 0) return NativeBN_putULongInt(env, cls, a, dw, JNI_FALSE);
121 else return NativeBN_putULongInt(env, cls, a, -dw, JNI_TRUE);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800122}
123
Brian Carlstromec2f5932010-05-07 16:58:16 -0700124static int NativeBN_BN_dec2bn(JNIEnv* env, jclass, BIGNUM* a, jstring str) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800125 if (!oneValidHandle(env, a)) return -1;
Elliott Hughes05960872010-05-26 17:45:07 -0700126 ScopedUtfChars chars(env, str);
127 if (chars.c_str() == NULL) {
128 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800129 }
Elliott Hughes05960872010-05-26 17:45:07 -0700130 return BN_dec2bn(&a, chars.c_str());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800131}
132
Brian Carlstromec2f5932010-05-07 16:58:16 -0700133static int NativeBN_BN_hex2bn(JNIEnv* env, jclass, BIGNUM* a, jstring str) {
Elliott Hughes05960872010-05-26 17:45:07 -0700134 if (!oneValidHandle(env, a)) return -1;
135 ScopedUtfChars chars(env, str);
136 if (chars.c_str() == NULL) {
137 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800138 }
Elliott Hughes05960872010-05-26 17:45:07 -0700139 return BN_hex2bn(&a, chars.c_str());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800140}
141
Brian Carlstromec2f5932010-05-07 16:58:16 -0700142static jboolean NativeBN_BN_bin2bn(JNIEnv* env, jclass, jbyteArray arr, int len, jboolean neg, BIGNUM* ret) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700143 if (!oneValidHandle(env, ret)) return JNI_FALSE;
Elliott Hughesebca53a2010-05-20 20:54:45 -0700144 ScopedByteArrayRO bytes(env, arr);
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700145 if (bytes.get() == NULL) {
146 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800147 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700148 jboolean success = (BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, ret) != NULL);
149 if (success && neg) {
150 BN_set_negative(ret, 1);
151 }
152 return success;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800153}
154
155/**
156 * public static native boolean litEndInts2bn(int[], int, int, int)
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700157 * Note:
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800158 * This procedure directly writes the internal representation of BIGNUMs.
159 * We do so as there is no direct interface based on Little Endian Integer Arrays.
160 * Also note that the same representation is used in the Cordoba Java Implementation of BigIntegers,
161 * whereof certain functionality is still being used.
162 */
Brian Carlstromec2f5932010-05-07 16:58:16 -0700163static jboolean NativeBN_litEndInts2bn(JNIEnv* env, jclass, jintArray arr, int len, jboolean neg, BIGNUM* ret) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700164 if (!oneValidHandle(env, ret)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800165 bn_check_top(ret);
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700166 if (len > 0) {
Elliott Hughesebca53a2010-05-20 20:54:45 -0700167 ScopedIntArrayRO scopedArray(env, arr);
Elliott Hughes64101122010-07-12 09:53:54 -0700168 if (scopedArray.get() == NULL) {
169 return JNI_FALSE;
170 }
171
Elliott Hughesaba7ce62010-10-18 15:42:37 -0700172 STATIC_ASSERT(sizeof(BN_ULONG) == sizeof(jint), BN_ULONG_not_32_bit);
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700173 const BN_ULONG* tmpInts = reinterpret_cast<const BN_ULONG*>(scopedArray.get());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800174 if ((tmpInts != NULL) && (bn_wexpand(ret, len) != NULL)) {
175 int i = len; do { i--; ret->d[i] = tmpInts[i]; } while (i > 0);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800176 ret->top = len;
177 ret->neg = neg;
178 // need to call this due to clear byte at top if avoiding
179 // having the top bit set (-ve number)
180 // Basically get rid of top zero ints:
181 bn_correct_top(ret);
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700182 return JNI_TRUE;
183 } else {
184 return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800185 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700186 } else { // (len = 0) means value = 0 and sign will be 0, too.
187 ret->top = 0;
188 return JNI_TRUE;
189 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800190}
191
192
193#define BYTES2INT(bytes, k) \
194 ( (bytes[k + 3] & 0xFF) \
195 | (bytes[k + 2] & 0xFF) << 8 \
196 | (bytes[k + 1] & 0xFF) << 16 \
197 | (bytes[k + 0] & 0xFF) << 24 )
198
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700199static jboolean negBigEndianBytes2bn(JNIEnv*, jclass, const unsigned char* bytes, int bytesLen, BIGNUM* ret) {
Elliott Hughesaba7ce62010-10-18 15:42:37 -0700200 // We rely on: (BN_BITS2 == 32), i.e. BN_ULONG is unsigned int and has 4 bytes:
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800201 bn_check_top(ret);
Elliott Hughesaba7ce62010-10-18 15:42:37 -0700202 // FIXME: assert bytesLen > 0
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700203 int intLen = (bytesLen + 3) / 4;
204 int firstNonzeroDigit = -2;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800205 if (bn_wexpand(ret, intLen) != NULL) {
206 BN_ULONG* d = ret->d;
207 BN_ULONG di;
208 ret->top = intLen;
209 int highBytes = bytesLen % 4;
210 int k = bytesLen;
211 // Put bytes to the int array starting from the end of the byte array
212 int i = 0;
213 while (k > highBytes) {
214 k -= 4;
215 di = BYTES2INT(bytes, k);
216 if (di != 0) {
217 d[i] = -di;
218 firstNonzeroDigit = i;
219 i++;
220 while (k > highBytes) {
221 k -= 4;
222 d[i] = ~BYTES2INT(bytes, k);
223 i++;
224 }
225 break;
226 } else {
227 d[i] = 0;
228 i++;
229 }
230 }
231 if (highBytes != 0) {
232 di = -1;
233 // Put the first bytes in the highest element of the int array
234 if (firstNonzeroDigit != -2) {
235 for (k = 0; k < highBytes; k++) {
236 di = (di << 8) | (bytes[k] & 0xFF);
237 }
238 d[i] = ~di;
239 } else {
240 for (k = 0; k < highBytes; k++) {
241 di = (di << 8) | (bytes[k] & 0xFF);
242 }
243 d[i] = -di;
244 }
245 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700246 return JNI_TRUE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800247 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700248 else return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800249}
250
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800251static jboolean NativeBN_twosComp2bn(JNIEnv* env, jclass cls, jbyteArray arr, int bytesLen, BIGNUM* ret) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700252 if (!oneValidHandle(env, ret)) return JNI_FALSE;
Elliott Hughesebca53a2010-05-20 20:54:45 -0700253 ScopedByteArrayRO bytes(env, arr);
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700254 if (bytes.get() == NULL) {
255 return -1;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800256 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700257 jboolean success;
258 const unsigned char* s = reinterpret_cast<const unsigned char*>(bytes.get());
259 if ((bytes[0] & 0X80) == 0) { // Positive value!
260 //
261 // We can use the existing BN implementation for unsigned big endian bytes:
262 //
263 success = (BN_bin2bn(s, bytesLen, ret) != NULL);
264 BN_set_negative(ret, JNI_FALSE);
265 } else { // Negative value!
266 //
267 // We need to apply two's complement:
268 //
269 success = negBigEndianBytes2bn(env, cls, s, bytesLen, ret);
270 BN_set_negative(ret, JNI_TRUE);
271 }
272 return success;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800273}
274
Brian Carlstromec2f5932010-05-07 16:58:16 -0700275static long long NativeBN_longInt(JNIEnv* env, jclass, BIGNUM* a) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800276 if (!oneValidHandle(env, a)) return -1;
277 bn_check_top(a);
278 int intLen = a->top;
279 BN_ULONG* d = a->d;
280 switch (intLen) {
281 case 0:
282 return 0;
283 case 1:
284 if (!a->neg) return d[0] & 0X00000000FFFFFFFFLL;
285 else return -(d[0] & 0X00000000FFFFFFFFLL);
286 default:
287 if (!a->neg) return ((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL);
288 else return -(((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL));
289 }
290}
291
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800292static char* leadingZerosTrimmed(char* s) {
293 char* p = s;
294 if (*p == '-') {
295 p++;
296 while ((*p == '0') && (*(p + 1) != 0)) { p++; }
297 p--;
298 *p = '-';
299 } else {
300 while ((*p == '0') && (*(p + 1) != 0)) { p++; }
301 }
302 return p;
303}
304
Brian Carlstromec2f5932010-05-07 16:58:16 -0700305static jstring NativeBN_BN_bn2dec(JNIEnv* env, jclass, BIGNUM* a) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800306 if (!oneValidHandle(env, a)) return NULL;
307 char* tmpStr;
308 char* retStr;
309 tmpStr = BN_bn2dec(a);
310 if (tmpStr != NULL) {
311 retStr = leadingZerosTrimmed(tmpStr);
Brian Carlstromec2f5932010-05-07 16:58:16 -0700312 jstring returnJString = env->NewStringUTF(retStr);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800313 OPENSSL_free(tmpStr);
314 return returnJString;
315 }
316 else return NULL;
317}
318
Brian Carlstromec2f5932010-05-07 16:58:16 -0700319static jstring NativeBN_BN_bn2hex(JNIEnv* env, jclass, BIGNUM* a) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800320 if (!oneValidHandle(env, a)) return NULL;
321 char* tmpStr;
322 char* retStr;
323 tmpStr = BN_bn2hex(a);
324 if (tmpStr != NULL) {
325 retStr = leadingZerosTrimmed(tmpStr);
Brian Carlstromec2f5932010-05-07 16:58:16 -0700326 jstring returnJString = env->NewStringUTF(retStr);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800327 OPENSSL_free(tmpStr);
328 return returnJString;
329 }
330 else return NULL;
331}
332
Elliott Hughes4e216322010-05-18 15:06:16 -0700333static jbyteArray NativeBN_BN_bn2bin(JNIEnv* env, jclass, BIGNUM* a) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800334 if (!oneValidHandle(env, a)) return NULL;
Elliott Hughes4e216322010-05-18 15:06:16 -0700335 jbyteArray result = env->NewByteArray(BN_num_bytes(a));
336 if (result == NULL) {
337 return NULL;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800338 }
Elliott Hughesebca53a2010-05-20 20:54:45 -0700339 ScopedByteArrayRW bytes(env, result);
340 if (bytes.get() == NULL) {
Elliott Hughes4e216322010-05-18 15:06:16 -0700341 return NULL;
342 }
Elliott Hughesebca53a2010-05-20 20:54:45 -0700343 BN_bn2bin(a, reinterpret_cast<unsigned char*>(bytes.get()));
Elliott Hughes4e216322010-05-18 15:06:16 -0700344 return result;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800345}
346
Elliott Hughes4e216322010-05-18 15:06:16 -0700347static jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass, BIGNUM* a) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800348 if (!oneValidHandle(env, a)) return NULL;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800349 bn_check_top(a);
350 int len = a->top;
Elliott Hughes4e216322010-05-18 15:06:16 -0700351 if (len == 0) {
352 return NULL;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800353 }
Elliott Hughes4e216322010-05-18 15:06:16 -0700354 jintArray result = env->NewIntArray(len);
355 if (result == NULL) {
356 return NULL;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800357 }
Elliott Hughesebca53a2010-05-20 20:54:45 -0700358 ScopedIntArrayRW ints(env, result);
Elliott Hughes64101122010-07-12 09:53:54 -0700359 if (ints.get() == NULL) {
360 return NULL;
361 }
Elliott Hughesebca53a2010-05-20 20:54:45 -0700362 BN_ULONG* ulongs = reinterpret_cast<BN_ULONG*>(ints.get());
363 if (ulongs == NULL) {
Elliott Hughes4e216322010-05-18 15:06:16 -0700364 return NULL;
365 }
Elliott Hughesebca53a2010-05-20 20:54:45 -0700366 int i = len; do { i--; ulongs[i] = a->d[i]; } while (i > 0);
Elliott Hughes4e216322010-05-18 15:06:16 -0700367 return result;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800368}
369
Brian Carlstromec2f5932010-05-07 16:58:16 -0700370static int NativeBN_sign(JNIEnv* env, jclass, BIGNUM* a) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800371 if (!oneValidHandle(env, a)) return -2;
372 if (BN_is_zero(a)) return 0;
373 else if (BN_is_negative(a)) return -1;
374 else return 1;
375}
376
Brian Carlstromec2f5932010-05-07 16:58:16 -0700377static void NativeBN_BN_set_negative(JNIEnv* env, jclass, BIGNUM* b, int n) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800378 if (!oneValidHandle(env, b)) return;
379 BN_set_negative(b, n);
380}
381
Brian Carlstromec2f5932010-05-07 16:58:16 -0700382static int NativeBN_bitLength(JNIEnv* env, jclass, BIGNUM* a) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800383// We rely on: (BN_BITS2 == 32), i.e. BN_ULONG is unsigned int and has 4 bytes:
384//
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700385 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800386 bn_check_top(a);
387 int intLen = a->top;
388 if (intLen == 0) return 0;
389 BN_ULONG* d = a->d;
390 int i = intLen - 1;
391 BN_ULONG msd = d[i]; // most significant digit
392 if (a->neg) {
393 // Handle negative values correctly:
394 // i.e. decrement the msd if all other digits are 0:
395 // while ((i > 0) && (d[i] != 0)) { i--; }
396 do { i--; } while (!((i < 0) || (d[i] != 0)));
397 if (i < 0) msd--; // Only if all lower significant digits are 0 we decrement the most significant one.
398 }
399 return (intLen - 1) * 32 + BN_num_bits_word(msd);
400}
401
Brian Carlstromec2f5932010-05-07 16:58:16 -0700402static jboolean NativeBN_BN_is_bit_set(JNIEnv* env, jclass, BIGNUM* a, int n) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700403 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800404 return (jboolean)BN_is_bit_set(a, n);
405}
406
Brian Carlstromec2f5932010-05-07 16:58:16 -0700407static jboolean NativeBN_modifyBit(JNIEnv* env, jclass, BIGNUM* a, int n, int op) {
Steve Blockce1396e2011-12-20 16:25:45 +0000408// ALOGD("NativeBN_BN_modifyBit");
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700409 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800410 switch (op) {
411 case 1: return BN_set_bit(a, n);
412 case 0: return BN_clear_bit(a, n);
413 case -1:
414 if (BN_is_bit_set(a, n)) return BN_clear_bit(a, n);
415 else return BN_set_bit(a, n);
416 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700417 return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800418}
419
Brian Carlstromec2f5932010-05-07 16:58:16 -0700420static jboolean NativeBN_BN_shift(JNIEnv* env, jclass, BIGNUM* r, BIGNUM* a, int n) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700421 if (!twoValidHandles(env, r, a)) return JNI_FALSE;
Elliott Hughes13d47bd2010-02-03 15:23:07 -0800422 return (n >= 0) ? BN_lshift(r, a, n) : BN_rshift(r, a, -n);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800423}
424
Elliott Hughesacce5ff2010-08-13 16:14:21 -0700425static jboolean NativeBN_BN_add_word(JNIEnv* env, jclass, BIGNUM* a, BN_ULONG w) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700426 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800427 return BN_add_word(a, w);
428}
429
Elliott Hughesacce5ff2010-08-13 16:14:21 -0700430static jboolean NativeBN_BN_sub_word(JNIEnv* env, jclass, BIGNUM* a, BN_ULONG w) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700431 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800432 return BN_sub_word(a, w);
433}
434
Elliott Hughesacce5ff2010-08-13 16:14:21 -0700435static jboolean NativeBN_BN_mul_word(JNIEnv* env, jclass, BIGNUM* a, BN_ULONG w) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700436 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800437 return BN_mul_word(a, w);
438}
439
Elliott Hughesacce5ff2010-08-13 16:14:21 -0700440static BN_ULONG NativeBN_BN_div_word(JNIEnv* env, jclass, BIGNUM* a, BN_ULONG w) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700441 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800442 return BN_div_word(a, w);
443}
444
Elliott Hughesacce5ff2010-08-13 16:14:21 -0700445static BN_ULONG NativeBN_BN_mod_word(JNIEnv* env, jclass, BIGNUM* a, BN_ULONG w) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700446 if (!oneValidHandle(env, a)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800447 return BN_mod_word(a, w);
448}
449
Brian Carlstromec2f5932010-05-07 16:58:16 -0700450static jboolean NativeBN_BN_add(JNIEnv* env, jclass, BIGNUM* r, BIGNUM* a, BIGNUM* b) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700451 if (!threeValidHandles(env, r, a, b)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800452 return BN_add(r, a, b);
453}
454
Brian Carlstromec2f5932010-05-07 16:58:16 -0700455static jboolean NativeBN_BN_sub(JNIEnv* env, jclass, BIGNUM* r, BIGNUM* a, BIGNUM* b) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700456 if (!threeValidHandles(env, r, a, b)) return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800457 return BN_sub(r, a, b);
458}
459
Elliott Hughes63710432010-06-11 12:58:06 -0700460static jboolean NativeBN_BN_gcd(JNIEnv* env, jclass, BIGNUM* r, BIGNUM* a, BIGNUM* b) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700461 if (!threeValidHandles(env, r, a, b)) return JNI_FALSE;
Elliott Hughes63710432010-06-11 12:58:06 -0700462 Unique_BN_CTX ctx(BN_CTX_new());
463 return BN_gcd(r, a, b, ctx.get());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800464}
465
Elliott Hughes63710432010-06-11 12:58:06 -0700466static jboolean NativeBN_BN_mul(JNIEnv* env, jclass, BIGNUM* r, BIGNUM* a, BIGNUM* b) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700467 if (!threeValidHandles(env, r, a, b)) return JNI_FALSE;
Elliott Hughes63710432010-06-11 12:58:06 -0700468 Unique_BN_CTX ctx(BN_CTX_new());
469 return BN_mul(r, a, b, ctx.get());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800470}
471
Elliott Hughes63710432010-06-11 12:58:06 -0700472static jboolean NativeBN_BN_exp(JNIEnv* env, jclass, BIGNUM* r, BIGNUM* a, BIGNUM* p) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700473 if (!threeValidHandles(env, r, a, p)) return JNI_FALSE;
Elliott Hughes63710432010-06-11 12:58:06 -0700474 Unique_BN_CTX ctx(BN_CTX_new());
475 return BN_exp(r, a, p, ctx.get());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800476}
477
Elliott Hughes63710432010-06-11 12:58:06 -0700478static jboolean NativeBN_BN_div(JNIEnv* env, jclass, BIGNUM* dv, BIGNUM* rem, BIGNUM* m, BIGNUM* d) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700479 if (!fourValidHandles(env, (rem ? rem : dv), (dv ? dv : rem), m, d)) return JNI_FALSE;
Elliott Hughes63710432010-06-11 12:58:06 -0700480 Unique_BN_CTX ctx(BN_CTX_new());
481 return BN_div(dv, rem, m, d, ctx.get());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800482}
483
Elliott Hughes63710432010-06-11 12:58:06 -0700484static jboolean NativeBN_BN_nnmod(JNIEnv* env, jclass, BIGNUM* r, BIGNUM* a, BIGNUM* m) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700485 if (!threeValidHandles(env, r, a, m)) return JNI_FALSE;
Elliott Hughes63710432010-06-11 12:58:06 -0700486 Unique_BN_CTX ctx(BN_CTX_new());
487 return BN_nnmod(r, a, m, ctx.get());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800488}
489
Elliott Hughes63710432010-06-11 12:58:06 -0700490static jboolean NativeBN_BN_mod_exp(JNIEnv* env, jclass, BIGNUM* r, BIGNUM* a, BIGNUM* p, BIGNUM* m) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700491 if (!fourValidHandles(env, r, a, p, m)) return JNI_FALSE;
Elliott Hughes63710432010-06-11 12:58:06 -0700492 Unique_BN_CTX ctx(BN_CTX_new());
493 return BN_mod_exp(r, a, p, m, ctx.get());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800494}
495
Elliott Hughes63710432010-06-11 12:58:06 -0700496static jboolean NativeBN_BN_mod_inverse(JNIEnv* env, jclass, BIGNUM* ret, BIGNUM* a, BIGNUM* n) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700497 if (!threeValidHandles(env, ret, a, n)) return JNI_FALSE;
Elliott Hughes63710432010-06-11 12:58:06 -0700498 Unique_BN_CTX ctx(BN_CTX_new());
499 return (BN_mod_inverse(ret, a, n, ctx.get()) != NULL);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800500}
501
Brian Carlstromec2f5932010-05-07 16:58:16 -0700502static jboolean NativeBN_BN_generate_prime_ex(JNIEnv* env, jclass, BIGNUM* ret, int bits, jboolean safe,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800503 BIGNUM* add, BIGNUM* rem, jint cb) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700504 if (!oneValidHandle(env, ret)) return JNI_FALSE;
Elliott Hughes583ce472010-07-22 10:23:42 -0700505 return BN_generate_prime_ex(ret, bits, safe, add, rem, reinterpret_cast<BN_GENCB*>(cb));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800506}
507
Elliott Hughes63710432010-06-11 12:58:06 -0700508static jboolean NativeBN_BN_is_prime_ex(JNIEnv* env, jclass, BIGNUM* p, int nchecks, jint cb) {
Elliott Hughes99c59bf2010-05-17 16:22:04 -0700509 if (!oneValidHandle(env, p)) return JNI_FALSE;
Elliott Hughes63710432010-06-11 12:58:06 -0700510 Unique_BN_CTX ctx(BN_CTX_new());
Elliott Hughes583ce472010-07-22 10:23:42 -0700511 return BN_is_prime_ex(p, nchecks, ctx.get(), reinterpret_cast<BN_GENCB*>(cb));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800512}
513
Elliott Hughes63710432010-06-11 12:58:06 -0700514static JNINativeMethod gMethods[] = {
Elliott Hughese22935d2010-08-12 17:27:27 -0700515 NATIVE_METHOD(NativeBN, BN_add, "(III)Z"),
516 NATIVE_METHOD(NativeBN, BN_add_word, "(II)Z"),
517 NATIVE_METHOD(NativeBN, BN_bin2bn, "([BIZI)Z"),
518 NATIVE_METHOD(NativeBN, BN_bn2bin, "(I)[B"),
519 NATIVE_METHOD(NativeBN, BN_bn2dec, "(I)Ljava/lang/String;"),
520 NATIVE_METHOD(NativeBN, BN_bn2hex, "(I)Ljava/lang/String;"),
521 NATIVE_METHOD(NativeBN, BN_cmp, "(II)I"),
522 NATIVE_METHOD(NativeBN, BN_copy, "(II)Z"),
523 NATIVE_METHOD(NativeBN, BN_dec2bn, "(ILjava/lang/String;)I"),
524 NATIVE_METHOD(NativeBN, BN_div, "(IIII)Z"),
525 NATIVE_METHOD(NativeBN, BN_div_word, "(II)I"),
526 NATIVE_METHOD(NativeBN, BN_exp, "(III)Z"),
527 NATIVE_METHOD(NativeBN, BN_free, "(I)V"),
528 NATIVE_METHOD(NativeBN, BN_gcd, "(III)Z"),
529 NATIVE_METHOD(NativeBN, BN_generate_prime_ex, "(IIZIII)Z"),
530 NATIVE_METHOD(NativeBN, BN_hex2bn, "(ILjava/lang/String;)I"),
531 NATIVE_METHOD(NativeBN, BN_is_bit_set, "(II)Z"),
532 NATIVE_METHOD(NativeBN, BN_is_prime_ex, "(III)Z"),
533 NATIVE_METHOD(NativeBN, BN_mod_exp, "(IIII)Z"),
534 NATIVE_METHOD(NativeBN, BN_mod_inverse, "(III)Z"),
535 NATIVE_METHOD(NativeBN, BN_mod_word, "(II)I"),
536 NATIVE_METHOD(NativeBN, BN_mul, "(III)Z"),
537 NATIVE_METHOD(NativeBN, BN_mul_word, "(II)Z"),
538 NATIVE_METHOD(NativeBN, BN_new, "()I"),
539 NATIVE_METHOD(NativeBN, BN_nnmod, "(III)Z"),
540 NATIVE_METHOD(NativeBN, BN_set_negative, "(II)V"),
541 NATIVE_METHOD(NativeBN, BN_shift, "(III)Z"),
542 NATIVE_METHOD(NativeBN, BN_sub, "(III)Z"),
543 NATIVE_METHOD(NativeBN, BN_sub_word, "(II)Z"),
544 NATIVE_METHOD(NativeBN, ERR_error_string, "(I)Ljava/lang/String;"),
545 NATIVE_METHOD(NativeBN, ERR_get_error, "()I"),
546 NATIVE_METHOD(NativeBN, bitLength, "(I)I"),
547 NATIVE_METHOD(NativeBN, bn2litEndInts, "(I)[I"),
548 NATIVE_METHOD(NativeBN, litEndInts2bn, "([IIZI)Z"),
549 NATIVE_METHOD(NativeBN, longInt, "(I)J"),
550 NATIVE_METHOD(NativeBN, modifyBit, "(III)Z"),
551 NATIVE_METHOD(NativeBN, putLongInt, "(IJ)Z"),
552 NATIVE_METHOD(NativeBN, putULongInt, "(IJZ)Z"),
553 NATIVE_METHOD(NativeBN, sign, "(I)I"),
554 NATIVE_METHOD(NativeBN, twosComp2bn, "([BII)Z"),
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800555};
Elliott Hughes7cd67602012-05-03 17:21:04 -0700556void register_java_math_NativeBN(JNIEnv* env) {
557 jniRegisterNativeMethods(env, "java/math/NativeBN", gMethods, NELEM(gMethods));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800558}