1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17abf945fb9ce99d8c2769ac5b2691b2732fa59887Elliott Hughes#define LOG_TAG "NativeBN"
18abf945fb9ce99d8c2769ac5b2691b2732fa59887Elliott Hughes
1999c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes#include "JNIHelp.h"
20e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes#include "JniConstants.h"
2166e740b765384686ce87003608412e940ab5d489Elliott Hughes#include "JniException.h"
2299c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes#include "ScopedPrimitiveArray.h"
2305960876dff6a5b686821eed8f7ae7cef5af4f50Elliott Hughes#include "ScopedUtfChars.h"
2499c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes#include "jni.h"
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <openssl/bn.h>
2699c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes#include <openssl/crypto.h>
2799c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes#include <openssl/err.h>
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <stdio.h>
29b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan#include <algorithm>
30b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers#include <memory>
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3263710430c17f7c0a1e74b926cd21248fde8e9589Elliott Hughesstruct BN_CTX_Deleter {
3366e740b765384686ce87003608412e940ab5d489Elliott Hughes  void operator()(BN_CTX* p) const {
3466e740b765384686ce87003608412e940ab5d489Elliott Hughes    BN_CTX_free(p);
3566e740b765384686ce87003608412e940ab5d489Elliott Hughes  }
3663710430c17f7c0a1e74b926cd21248fde8e9589Elliott Hughes};
37b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogerstypedef std::unique_ptr<BN_CTX, BN_CTX_Deleter> Unique_BN_CTX;
3863710430c17f7c0a1e74b926cd21248fde8e9589Elliott Hughes
39a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic BIGNUM* toBigNum(jlong address) {
40a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return reinterpret_cast<BIGNUM*>(static_cast<uintptr_t>(address));
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
43ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjaminstatic void throwException(JNIEnv* env) {
4466e740b765384686ce87003608412e940ab5d489Elliott Hughes  long error = ERR_get_error();
45ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  // OpenSSL's error queue may contain multiple errors. Clean up after them.
46ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  ERR_clear_error();
47ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin
4866e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (error == 0) {
49ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    // An operation failed but did not push to the error queue. Throw a default
50ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    // exception.
51ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    jniThrowException(env, "java/lang/ArithmeticException", "Operation failed");
52ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    return;
5366e740b765384686ce87003608412e940ab5d489Elliott Hughes  }
54ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin
5566e740b765384686ce87003608412e940ab5d489Elliott Hughes  char message[256];
5666e740b765384686ce87003608412e940ab5d489Elliott Hughes  ERR_error_string_n(error, message, sizeof(message));
5766e740b765384686ce87003608412e940ab5d489Elliott Hughes  int reason = ERR_GET_REASON(error);
5866e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (reason == BN_R_DIV_BY_ZERO) {
5966e740b765384686ce87003608412e940ab5d489Elliott Hughes    jniThrowException(env, "java/lang/ArithmeticException", "BigInteger division by zero");
6066e740b765384686ce87003608412e940ab5d489Elliott Hughes  } else if (reason == BN_R_NO_INVERSE) {
6166e740b765384686ce87003608412e940ab5d489Elliott Hughes    jniThrowException(env, "java/lang/ArithmeticException", "BigInteger not invertible");
6266e740b765384686ce87003608412e940ab5d489Elliott Hughes  } else if (reason == ERR_R_MALLOC_FAILURE) {
6366e740b765384686ce87003608412e940ab5d489Elliott Hughes    jniThrowOutOfMemoryError(env, message);
6466e740b765384686ce87003608412e940ab5d489Elliott Hughes  } else {
6566e740b765384686ce87003608412e940ab5d489Elliott Hughes    jniThrowException(env, "java/lang/ArithmeticException", message);
6666e740b765384686ce87003608412e940ab5d489Elliott Hughes  }
6766e740b765384686ce87003608412e940ab5d489Elliott Hughes}
68a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
69a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int isValidHandle(JNIEnv* env, jlong handle, const char* message) {
70a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (handle == 0) {
71a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    jniThrowNullPointerException(env, message);
72a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return JNI_FALSE;
73a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
74a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return JNI_TRUE;
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
77a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int oneValidHandle(JNIEnv* env, jlong a) {
78a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return isValidHandle(env, a, "Mandatory handle (first) passed as null");
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
81a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int twoValidHandles(JNIEnv* env, jlong a, jlong b) {
82a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a)) return JNI_FALSE;
83a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return isValidHandle(env, b, "Mandatory handle (second) passed as null");
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
86a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int threeValidHandles(JNIEnv* env, jlong a, jlong b, jlong c) {
87a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!twoValidHandles(env, a, b)) return JNI_FALSE;
88a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return isValidHandle(env, c, "Mandatory handle (third) passed as null");
89a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
90a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
91a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int fourValidHandles(JNIEnv* env, jlong a, jlong b, jlong c, jlong d) {
92a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!threeValidHandles(env, a, b, c)) return JNI_FALSE;
93a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return isValidHandle(env, d, "Mandatory handle (fourth) passed as null");
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9666e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic jlong NativeBN_BN_new(JNIEnv* env, jclass) {
9766e740b765384686ce87003608412e940ab5d489Elliott Hughes  jlong result = static_cast<jlong>(reinterpret_cast<uintptr_t>(BN_new()));
98ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!result) {
99ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
100ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
10166e740b765384686ce87003608412e940ab5d489Elliott Hughes  return result;
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
10433fc9556dfda6298fcd7c119f68a7375e13cbed9Richard Uhlerstatic jlong NativeBN_getNativeFinalizer(JNIEnv*, jclass) {
10533fc9556dfda6298fcd7c119f68a7375e13cbed9Richard Uhler  return static_cast<jlong>(reinterpret_cast<uintptr_t>(&BN_free));
10633fc9556dfda6298fcd7c119f68a7375e13cbed9Richard Uhler}
10733fc9556dfda6298fcd7c119f68a7375e13cbed9Richard Uhler
108a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic void NativeBN_BN_free(JNIEnv* env, jclass, jlong a) {
109a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a)) return;
110a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BN_free(toBigNum(a));
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
113a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int NativeBN_BN_cmp(JNIEnv* env, jclass, jlong a, jlong b) {
114a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!twoValidHandles(env, a, b)) return 1;
115a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return BN_cmp(toBigNum(a), toBigNum(b));
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
11866e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_copy(JNIEnv* env, jclass, jlong to, jlong from) {
11966e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!twoValidHandles(env, to, from)) return;
120ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_copy(toBigNum(to), toBigNum(from))) {
121ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
122ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
125a961d0b42b313aae32f340d9bf7de18e638da2cbColin Crossstatic void NativeBN_putULongInt(JNIEnv* env, jclass, jlong a0, jlong java_dw, jboolean neg) {
1268383f343119f7a98cbe3b4a5bddc89038ac5c166Adam Langley  if (!oneValidHandle(env, a0)) return;
127a961d0b42b313aae32f340d9bf7de18e638da2cbColin Cross
1288383f343119f7a98cbe3b4a5bddc89038ac5c166Adam Langley  uint64_t dw = java_dw;
1298383f343119f7a98cbe3b4a5bddc89038ac5c166Adam Langley  BIGNUM* a = toBigNum(a0);
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
131571cc4d33f5fdbfdae8bf219854c211581fdc4b4David Benjamin  if (!BN_set_u64(a, dw)) {
132571cc4d33f5fdbfdae8bf219854c211581fdc4b4David Benjamin    throwException(env);
133571cc4d33f5fdbfdae8bf219854c211581fdc4b4David Benjamin    return;
1348383f343119f7a98cbe3b4a5bddc89038ac5c166Adam Langley  }
1358383f343119f7a98cbe3b4a5bddc89038ac5c166Adam Langley
1368383f343119f7a98cbe3b4a5bddc89038ac5c166Adam Langley  BN_set_negative(a, neg);
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
139a961d0b42b313aae32f340d9bf7de18e638da2cbColin Crossstatic void NativeBN_putLongInt(JNIEnv* env, jclass cls, jlong a, jlong dw) {
140a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (dw >= 0) {
14166e740b765384686ce87003608412e940ab5d489Elliott Hughes    NativeBN_putULongInt(env, cls, a, dw, JNI_FALSE);
142a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  } else {
14366e740b765384686ce87003608412e940ab5d489Elliott Hughes    NativeBN_putULongInt(env, cls, a, -dw, JNI_TRUE);
144a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
147a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int NativeBN_BN_dec2bn(JNIEnv* env, jclass, jlong a0, jstring str) {
148a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a0)) return -1;
149a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  ScopedUtfChars chars(env, str);
150a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (chars.c_str() == NULL) {
151a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return -1;
152a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
153a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BIGNUM* a = toBigNum(a0);
15466e740b765384686ce87003608412e940ab5d489Elliott Hughes  int result = BN_dec2bn(&a, chars.c_str());
155ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (result == 0) {
156ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
157ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
15866e740b765384686ce87003608412e940ab5d489Elliott Hughes  return result;
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
161a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int NativeBN_BN_hex2bn(JNIEnv* env, jclass, jlong a0, jstring str) {
162a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a0)) return -1;
163a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  ScopedUtfChars chars(env, str);
164a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (chars.c_str() == NULL) {
165a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return -1;
166a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
167a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BIGNUM* a = toBigNum(a0);
16866e740b765384686ce87003608412e940ab5d489Elliott Hughes  int result = BN_hex2bn(&a, chars.c_str());
169ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (result == 0) {
170ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
171ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
17266e740b765384686ce87003608412e940ab5d489Elliott Hughes  return result;
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17566e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_bin2bn(JNIEnv* env, jclass, jbyteArray arr, int len, jboolean neg, jlong ret) {
17666e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!oneValidHandle(env, ret)) return;
177a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  ScopedByteArrayRO bytes(env, arr);
178a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (bytes.get() == NULL) {
17966e740b765384686ce87003608412e940ab5d489Elliott Hughes    return;
180a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
181ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, toBigNum(ret))) {
182ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
183ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    return;
184a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
185ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin
186ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  BN_set_negative(toBigNum(ret), neg);
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18966e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_litEndInts2bn(JNIEnv* env, jclass, jintArray arr, int len, jboolean neg, jlong ret0) {
19066e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!oneValidHandle(env, ret0)) return;
191a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BIGNUM* ret = toBigNum(ret0);
192ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin
193b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  ScopedIntArrayRO scopedArray(env, arr);
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  if (scopedArray.get() == NULL) {
196b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    return;
197b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  }
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
199b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  // We can simply interpret the little-endian integer stream as a
200b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  // little-endian byte stream and use BN_le2bn.
201b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  const uint8_t* tmpBytes = reinterpret_cast<const uint8_t *>(scopedArray.get());
202b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  size_t numBytes = len * sizeof(int);
203a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
204b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  if (!BN_le2bn(tmpBytes, numBytes, ret)) {
205b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    throwException(env);
206ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
207ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin
208b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  BN_set_negative(ret, neg);
209a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
210a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
211b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloanstatic void NativeBN_twosComp2bn(JNIEnv* env, jclass, jbyteArray arr, int bytesLen, jlong ret0) {
21266e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!oneValidHandle(env, ret0)) return;
213a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BIGNUM* ret = toBigNum(ret0);
214a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
215a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  ScopedByteArrayRO bytes(env, arr);
216a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (bytes.get() == NULL) {
21766e740b765384686ce87003608412e940ab5d489Elliott Hughes    return;
218a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
219b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
220725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  if (bytesLen == 0) {
221725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    BN_zero(ret);
222725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    return;
223725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  }
224b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
225725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  const unsigned char* bytesTmp = reinterpret_cast<const unsigned char*>(bytes.get());
226b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
227725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  if (!BN_bin2bn(bytesTmp, bytesLen, ret)) {
228725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    throwException(env);
229725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    return;
230725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  }
231b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
232725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  // Use the high bit to determine the sign in twos-complement.
233725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  BN_set_negative(ret, (bytes[0] & 0x80) != 0);
234b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
235725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  if (BN_is_negative(ret)) {
236725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    // For negative values, BN_bin2bn doesn't interpret the twos-complement
237725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    // representation, so ret is now (- value - 2^N). We can use nnmod_pow2 to set
238725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    // ret to (-value).
239725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    if (!BN_nnmod_pow2(ret, ret, bytesLen * 8)) {
240b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan      throwException(env);
241b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan      return;
242b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    }
243725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan
244725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    // And now we correct the sign.
245725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    BN_set_negative(ret, 1);
246a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
247a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
248a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
249a961d0b42b313aae32f340d9bf7de18e638da2cbColin Crossstatic jlong NativeBN_longInt(JNIEnv* env, jclass, jlong a0) {
250a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a0)) return -1;
251a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BIGNUM* a = toBigNum(a0);
252b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  uint64_t word;
253a961d0b42b313aae32f340d9bf7de18e638da2cbColin Cross
254b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  if (BN_get_u64(a, &word)) {
255b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    return BN_is_negative(a) ? -((jlong) word) : word;
256b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  } else {
257b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    // This should be unreachable if our caller checks BigInt::twosCompFitsIntoBytes(8)
258b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    throwException(env);
259b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    return 0;
260a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic char* leadingZerosTrimmed(char* s) {
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    char* p = s;
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    if (*p == '-') {
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        p++;
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while ((*p == '0') && (*(p + 1) != 0)) { p++; }
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        p--;
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        *p = '-';
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    } else {
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while ((*p == '0') && (*(p + 1) != 0)) { p++; }
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    return p;
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
276a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic jstring NativeBN_BN_bn2dec(JNIEnv* env, jclass, jlong a) {
277a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a)) return NULL;
278a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  char* tmpStr = BN_bn2dec(toBigNum(a));
279a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (tmpStr == NULL) {
280ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
281a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return NULL;
282a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
283a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  char* retStr = leadingZerosTrimmed(tmpStr);
284a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  jstring returnJString = env->NewStringUTF(retStr);
285a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  OPENSSL_free(tmpStr);
286a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return returnJString;
287a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
288a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
289a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic jstring NativeBN_BN_bn2hex(JNIEnv* env, jclass, jlong a) {
290a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a)) return NULL;
291a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  char* tmpStr = BN_bn2hex(toBigNum(a));
292a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (tmpStr == NULL) {
293ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
294a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return NULL;
295a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
296a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  char* retStr = leadingZerosTrimmed(tmpStr);
297a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  jstring returnJString = env->NewStringUTF(retStr);
298a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  OPENSSL_free(tmpStr);
299a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return returnJString;
300a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
301a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
302a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic jbyteArray NativeBN_BN_bn2bin(JNIEnv* env, jclass, jlong a0) {
303a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a0)) return NULL;
304a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BIGNUM* a = toBigNum(a0);
305a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  jbyteArray result = env->NewByteArray(BN_num_bytes(a));
306a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (result == NULL) {
307a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return NULL;
308a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
309a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  ScopedByteArrayRW bytes(env, result);
310a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (bytes.get() == NULL) {
311a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return NULL;
312a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
313a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BN_bn2bin(a, reinterpret_cast<unsigned char*>(bytes.get()));
314a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return result;
315a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
316a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
317a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass, jlong a0) {
318a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a0)) return NULL;
319b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
320a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BIGNUM* a = toBigNum(a0);
321b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
322b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  // The number of integers we need is BN_num_bytes(a) / sizeof(int), rounded up
323b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  int intLen = (BN_num_bytes(a) + sizeof(int) - 1) / sizeof(int);
324b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
325b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  // Allocate our result with the JNI boilerplate
326b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  jintArray result = env->NewIntArray(intLen);
327b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
328a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (result == NULL) {
329b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    throwException(env);
330a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return NULL;
331a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
332b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
333a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  ScopedIntArrayRW ints(env, result);
334b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
335a961d0b42b313aae32f340d9bf7de18e638da2cbColin Cross  unsigned int* uints = reinterpret_cast<unsigned int*>(ints.get());
336a961d0b42b313aae32f340d9bf7de18e638da2cbColin Cross  if (uints == NULL) {
337b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    throwException(env);
338a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return NULL;
339a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
340b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
341b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  // We can simply interpret a little-endian byte stream as a little-endian integer stream.
342b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  if (!BN_bn2le_padded(reinterpret_cast<uint8_t*>(uints), intLen * sizeof(int), a)) {
343b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    throwException(env);
344b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    return NULL;
345b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  }
346b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
347a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return result;
348a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
349a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
350a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic int NativeBN_sign(JNIEnv* env, jclass, jlong a) {
351a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a)) return -2;
352a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (BN_is_zero(toBigNum(a))) {
353a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes      return 0;
354a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  } else if (BN_is_negative(toBigNum(a))) {
355a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes    return -1;
356a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  }
357a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  return 1;
358a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
359a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
360a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic void NativeBN_BN_set_negative(JNIEnv* env, jclass, jlong b, int n) {
361a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, b)) return;
362a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  BN_set_negative(toBigNum(b), n);
363a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes}
364a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes
365725aa55c317e0541a891d3be8d69892609340e6cRobert Sloanstatic int NativeBN_bitLength(JNIEnv* env, jclass, jlong a0) {
366725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  if (!oneValidHandle(env, a0)) return JNI_FALSE;
367725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  BIGNUM* a = toBigNum(a0);
368b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
369725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  // If a is not negative, we can use BN_num_bits directly.
370725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  if (!BN_is_negative(a)) {
371725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    return BN_num_bits(a);
372b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  }
373b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
374725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  // In the negative case, the number of bits in a is the same as the number of bits in |a|,
375725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  // except one less when |a| is a power of two.
376725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  BIGNUM positiveA;
377725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  BN_init(&positiveA);
378b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
379725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  if (!BN_copy(&positiveA, a)) {
380725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    BN_free(&positiveA);
381b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan    throwException(env);
382725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan    return -1;
383b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  }
384b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
385725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  BN_set_negative(&positiveA, false);
386725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  int numBits = BN_is_pow2(&positiveA) ? BN_num_bits(&positiveA) - 1 : BN_num_bits(&positiveA);
387b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
388725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  BN_free(&positiveA);
389725aa55c317e0541a891d3be8d69892609340e6cRobert Sloan  return numBits;
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
392a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic jboolean NativeBN_BN_is_bit_set(JNIEnv* env, jclass, jlong a, int n) {
393a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  if (!oneValidHandle(env, a)) return JNI_FALSE;
394b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan
395b23d3f2954007f4c24556cdb90b624d2e3b5748cRobert Sloan  // NOTE: this is only called in the positive case, so BN_is_bit_set is fine here.
396ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  return BN_is_bit_set(toBigNum(a), n) ? JNI_TRUE : JNI_FALSE;
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
39966e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_shift(JNIEnv* env, jclass, jlong r, jlong a, int n) {
40066e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!twoValidHandles(env, r, a)) return;
401ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  int ok;
40266e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (n >= 0) {
403ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    ok = BN_lshift(toBigNum(r), toBigNum(a), n);
40466e740b765384686ce87003608412e940ab5d489Elliott Hughes  } else {
405ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    ok = BN_rshift(toBigNum(r), toBigNum(a), -n);
406ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
407ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!ok) {
408ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
40966e740b765384686ce87003608412e940ab5d489Elliott Hughes  }
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41266e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_add_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
41366e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!oneValidHandle(env, a)) return;
414ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_add_word(toBigNum(a), w)) {
415ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
416ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41966e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_mul_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
42066e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!oneValidHandle(env, a)) return;
421ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_mul_word(toBigNum(a), w)) {
422ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
423ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
426a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughesstatic BN_ULONG NativeBN_BN_mod_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
42766e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!oneValidHandle(env, a)) return 0;
428ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  BN_ULONG result = BN_mod_word(toBigNum(a), w);
429ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (result == (BN_ULONG)-1) {
430ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
431ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
43266e740b765384686ce87003608412e940ab5d489Elliott Hughes  return result;
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
43566e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_add(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
43666e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!threeValidHandles(env, r, a, b)) return;
437ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_add(toBigNum(r), toBigNum(a), toBigNum(b))) {
438ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
439ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44266e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_sub(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
44366e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!threeValidHandles(env, r, a, b)) return;
444ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_sub(toBigNum(r), toBigNum(a), toBigNum(b))) {
445ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
446ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44966e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_gcd(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
45066e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!threeValidHandles(env, r, a, b)) return;
451a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  Unique_BN_CTX ctx(BN_CTX_new());
452ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_gcd(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get())) {
453ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
454ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
45766e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_mul(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
45866e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!threeValidHandles(env, r, a, b)) return;
459a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  Unique_BN_CTX ctx(BN_CTX_new());
460ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_mul(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get())) {
461ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
462ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46566e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p) {
46666e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!threeValidHandles(env, r, a, p)) return;
467a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  Unique_BN_CTX ctx(BN_CTX_new());
468ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_exp(toBigNum(r), toBigNum(a), toBigNum(p), ctx.get())) {
469ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
470ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
47366e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_div(JNIEnv* env, jclass, jlong dv, jlong rem, jlong m, jlong d) {
47466e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!fourValidHandles(env, (rem ? rem : dv), (dv ? dv : rem), m, d)) return;
475a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  Unique_BN_CTX ctx(BN_CTX_new());
476ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_div(toBigNum(dv), toBigNum(rem), toBigNum(m), toBigNum(d), ctx.get())) {
477ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
478ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48166e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_nnmod(JNIEnv* env, jclass, jlong r, jlong a, jlong m) {
48266e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!threeValidHandles(env, r, a, m)) return;
483a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  Unique_BN_CTX ctx(BN_CTX_new());
484ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_nnmod(toBigNum(r), toBigNum(a), toBigNum(m), ctx.get())) {
485ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
486ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48966e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_mod_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p, jlong m) {
49066e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!fourValidHandles(env, r, a, p, m)) return;
491a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  Unique_BN_CTX ctx(BN_CTX_new());
492ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_mod_exp(toBigNum(r), toBigNum(a), toBigNum(p), toBigNum(m), ctx.get())) {
493ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
494ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
49766e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_mod_inverse(JNIEnv* env, jclass, jlong ret, jlong a, jlong n) {
49866e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!threeValidHandles(env, ret, a, n)) return;
499a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  Unique_BN_CTX ctx(BN_CTX_new());
500ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_mod_inverse(toBigNum(ret), toBigNum(a), toBigNum(n), ctx.get())) {
501ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
502ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
50566e740b765384686ce87003608412e940ab5d489Elliott Hughesstatic void NativeBN_BN_generate_prime_ex(JNIEnv* env, jclass, jlong ret, int bits,
506ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin                                          jboolean safe, jlong add, jlong rem) {
50766e740b765384686ce87003608412e940ab5d489Elliott Hughes  if (!oneValidHandle(env, ret)) return;
508ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_generate_prime_ex(toBigNum(ret), bits, safe, toBigNum(add), toBigNum(rem),
509ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin                            NULL)) {
510ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
511ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
514ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjaminstatic jboolean NativeBN_BN_primality_test(JNIEnv* env, jclass, jlong candidate, int checks,
515ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin                                           jboolean do_trial_decryption) {
516ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!oneValidHandle(env, candidate)) return JNI_FALSE;
517a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes  Unique_BN_CTX ctx(BN_CTX_new());
518ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  int is_probably_prime;
519ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  if (!BN_primality_test(&is_probably_prime, toBigNum(candidate), checks, ctx.get(),
520ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin                         do_trial_decryption, NULL)) {
521ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    throwException(env);
522ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin    return JNI_FALSE;
523ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  }
524ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin  return is_probably_prime ? JNI_TRUE : JNI_FALSE;
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
52763710430c17f7c0a1e74b926cd21248fde8e9589Elliott Hughesstatic JNINativeMethod gMethods[] = {
52866e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_add, "(JJJ)V"),
52966e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_add_word, "(JI)V"),
53066e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_bin2bn, "([BIZJ)V"),
531a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_bn2bin, "(J)[B"),
532a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_bn2dec, "(J)Ljava/lang/String;"),
533a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_bn2hex, "(J)Ljava/lang/String;"),
534a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_cmp, "(JJ)I"),
53566e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_copy, "(JJ)V"),
536a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_dec2bn, "(JLjava/lang/String;)I"),
53766e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_div, "(JJJJ)V"),
53866e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_exp, "(JJJ)V"),
539a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_free, "(J)V"),
54066e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_gcd, "(JJJ)V"),
541ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin   NATIVE_METHOD(NativeBN, BN_generate_prime_ex, "(JIZJJ)V"),
542a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_hex2bn, "(JLjava/lang/String;)I"),
543a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_is_bit_set, "(JI)Z"),
544ef742f1823504e4166f678d2651cccf16e711b1eDavid Benjamin   NATIVE_METHOD(NativeBN, BN_primality_test, "(JIZ)Z"),
54566e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_mod_exp, "(JJJJ)V"),
54666e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_mod_inverse, "(JJJ)V"),
547a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_mod_word, "(JI)I"),
54866e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_mul, "(JJJ)V"),
54966e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_mul_word, "(JI)V"),
550a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_new, "()J"),
55166e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_nnmod, "(JJJ)V"),
552a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, BN_set_negative, "(JI)V"),
55366e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_shift, "(JJI)V"),
55466e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, BN_sub, "(JJJ)V"),
555a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, bitLength, "(J)I"),
556a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, bn2litEndInts, "(J)[I"),
55733fc9556dfda6298fcd7c119f68a7375e13cbed9Richard Uhler   NATIVE_METHOD(NativeBN, getNativeFinalizer, "()J"),
55866e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, litEndInts2bn, "([IIZJ)V"),
559a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, longInt, "(J)J"),
56066e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, putLongInt, "(JJ)V"),
56166e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, putULongInt, "(JJZ)V"),
562a125dded8ab0490d05e2fa9ec2e821ef1ae6facdElliott Hughes   NATIVE_METHOD(NativeBN, sign, "(J)I"),
56366e740b765384686ce87003608412e940ab5d489Elliott Hughes   NATIVE_METHOD(NativeBN, twosComp2bn, "([BIJ)V"),
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project};
5657cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughesvoid register_java_math_NativeBN(JNIEnv* env) {
5667cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughes    jniRegisterNativeMethods(env, "java/math/NativeBN", gMethods, NELEM(gMethods));
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
568