/** * public static native boolean litEndInts2bn(int[], int, int, int) * Note: * This procedure directly writes the internal representation of BIGNUMs. * We do so as there is no direct interface based on Little Endian Integer Arrays. * Also note that the same representation is used in the Cordoba Java Implementation of BigIntegers, * whereof certain functionality is still being used. */ static jboolean NativeBN_litEndInts2bn(JNIEnv* env, jclass, jintArray arr, int len, jboolean neg, BIGNUM* ret) { if (!oneValidHandle(env, ret)) return JNI_FALSE; bn_check_top(ret); if (len > 0) { ScopedIntArrayRO scopedArray(env, arr); if (scopedArray.get() == NULL) { return JNI_FALSE; } STATIC_ASSERT(sizeof(BN_ULONG) == sizeof(jint), BN_ULONG_not_32_bit); const BN_ULONG* tmpInts = reinterpret_cast<const BN_ULONG*>(scopedArray.get()); if ((tmpInts != NULL) && (bn_wexpand(ret, len) != NULL)) { int i = len; do { i--; ret->d[i] = tmpInts[i]; } while (i > 0); ret->top = len; ret->neg = neg; // need to call this due to clear byte at top if avoiding // having the top bit set (-ve number) // Basically get rid of top zero ints: bn_correct_top(ret); return JNI_TRUE; } else { return JNI_FALSE; } } else { // (len = 0) means value = 0 and sign will be 0, too. ret->top = 0; return JNI_TRUE; } }
/** * public static native boolean twosComp2bn(byte[], int, int) */ static jboolean NativeBN_twosComp2bn(JNIEnv* env, jclass cls, jbyteArray arr, int bytesLen, BIGNUM* ret) { if (!oneValidHandle(env, ret)) return FALSE; jboolean success; unsigned char* tmpBytes; tmpBytes = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, arr, 0)); if (tmpBytes != NULL) { if ((tmpBytes[0] & 0X80) == 0) { // Positive value! // // We can use the existing BN implementation for unsigned big endian bytes: // success = (BN_bin2bn(tmpBytes, bytesLen, ret) != NULL); BN_set_negative(ret, FALSE); } else { // Negative value! // // We need to apply two's complement: // success = negBigEndianBytes2bn(env, cls, tmpBytes, bytesLen, ret); BN_set_negative(ret, TRUE); } (*env)->ReleasePrimitiveArrayCritical(env, arr, tmpBytes, JNI_ABORT); return success; } else return -1; // Error outside BN. mc FIXME: what to do in this case? Does JNI throw exception itself? }
extern "C" void Java_java_math_NativeBN_BN_1generate_1prime_1ex(JNIEnv* env, jclass, jlong ret, int bits, jboolean safe, jlong add, jlong rem, jlong cb) { if (!oneValidHandle(env, ret)) return; BN_generate_prime_ex(toBigNum(ret), bits, safe, toBigNum(add), toBigNum(rem), reinterpret_cast<BN_GENCB*>(cb)); throwExceptionIfNecessary(env); }
/** * public static native boolean litEndInts2bn(int[], int, int, int) * Note: * This procedure directly writes the internal representation of BIGNUMs. * We do so as there is no direct interface based on Little Endian Integer Arrays. * Also note that the same representation is used in the Cordoba Java Implementation of BigIntegers, * whereof certain functionality is still being used. */ static jboolean NativeBN_litEndInts2bn(JNIEnv* env, jclass cls, jintArray arr, int len, jboolean neg, BIGNUM* ret) { if (!oneValidHandle(env, ret)) return FALSE; bn_check_top(ret); if (len > 0) { BN_ULONG* tmpInts; // BN_ULONG is 4 Bytes on this system for sure, i.e. same as jint! tmpInts = (BN_ULONG*)((*env)->GetPrimitiveArrayCritical(env, arr, 0)); if ((tmpInts != NULL) && (bn_wexpand(ret, len) != NULL)) { int i = len; do { i--; ret->d[i] = tmpInts[i]; } while (i > 0); (*env)->ReleasePrimitiveArrayCritical(env, arr, tmpInts, JNI_ABORT); ret->top = len; ret->neg = neg; // need to call this due to clear byte at top if avoiding // having the top bit set (-ve number) // Basically get rid of top zero ints: bn_correct_top(ret); return TRUE; } else { if (tmpInts != NULL) (*env)->ReleasePrimitiveArrayCritical(env, arr, tmpInts, JNI_ABORT); return FALSE; } } else { // (len = 0) means value = 0 and sign will be 0, too. ret->top = 0; return TRUE; } }
static int NativeBN_BN_hex2bn(JNIEnv* env, jclass, BIGNUM* a, jstring str) { if (!oneValidHandle(env, a)) return -1; ScopedUtfChars chars(env, str); if (chars.c_str() == NULL) { return -1; } return BN_hex2bn(&a, chars.c_str()); }
extern "C" int Java_java_math_NativeBN_sign(JNIEnv* env, jclass, jlong a) { if (!oneValidHandle(env, a)) return -2; if (BN_is_zero(toBigNum(a))) { return 0; } else if (BN_is_negative(toBigNum(a))) { return -1; } return 1; }
/** * public static native int BN_hex2bn(int, java.lang.String) */ static int NativeBN_BN_hex2bn(JNIEnv* env, jclass cls, BIGNUM* a, jstring str) { if (!oneValidHandle(env, a)) return -1; char* tmpStr = (char*)(*env)->GetStringUTFChars(env, str, NULL); if (tmpStr != NULL) { int len = BN_hex2bn(&a, tmpStr); (*env)->ReleaseStringUTFChars(env, str, tmpStr); return len; // len == 0: Error } else return -1; // Error outside BN. }
extern "C" int Java_java_math_NativeBN_BN_1hex2bn(JNIEnv* env, jclass, jlong a0, jstring str) { if (!oneValidHandle(env, a0)) return -1; ScopedUtfChars chars(env, str); if (chars.c_str() == NULL) { return -1; } BIGNUM* a = toBigNum(a0); int result = BN_hex2bn(&a, chars.c_str()); throwExceptionIfNecessary(env); return result; }
extern "C" jstring Java_java_math_NativeBN_BN_1bn2hex(JNIEnv* env, jclass, jlong a) { if (!oneValidHandle(env, a)) return NULL; char* tmpStr = BN_bn2hex(toBigNum(a)); if (tmpStr == NULL) { return NULL; } char* retStr = leadingZerosTrimmed(tmpStr); jstring returnJString = env->NewStringUTF(retStr); OPENSSL_free(tmpStr); return returnJString; }
extern "C" void Java_java_math_NativeBN_BN_1bin2bn(JNIEnv* env, jclass, jbyteArray arr, int len, jboolean neg, jlong ret) { if (!oneValidHandle(env, ret)) return; ScopedByteArrayRO bytes(env, arr); if (bytes.get() == NULL) { return; } BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, toBigNum(ret)); if (!throwExceptionIfNecessary(env) && neg) { BN_set_negative(toBigNum(ret), true); } }
/** * public static native void modifyBit(int, int, int) */ static jboolean NativeBN_modifyBit(JNIEnv* env, jclass cls, BIGNUM* a, int n, int op) { // LOGD("NativeBN_BN_modifyBit"); if (!oneValidHandle(env, a)) return FALSE; switch (op) { case 1: return BN_set_bit(a, n); case 0: return BN_clear_bit(a, n); case -1: if (BN_is_bit_set(a, n)) return BN_clear_bit(a, n); else return BN_set_bit(a, n); } return FALSE; }
static jboolean NativeBN_BN_bin2bn(JNIEnv* env, jclass, jbyteArray arr, int len, jboolean neg, BIGNUM* ret) { if (!oneValidHandle(env, ret)) return JNI_FALSE; ScopedByteArrayRO bytes(env, arr); if (bytes.get() == NULL) { return -1; } jboolean success = (BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, ret) != NULL); if (success && neg) { BN_set_negative(ret, 1); } return success; }
/** * public static native java.lang.String BN_bn2hex(int) */ static jstring NativeBN_BN_bn2hex(JNIEnv* env, jclass cls, BIGNUM* a) { if (!oneValidHandle(env, a)) return NULL; char* tmpStr; char* retStr; tmpStr = BN_bn2hex(a); if (tmpStr != NULL) { retStr = leadingZerosTrimmed(tmpStr); jstring returnJString = ((*env)->NewStringUTF(env, (mcSignednessBull)retStr)); OPENSSL_free(tmpStr); return returnJString; } else return NULL; }
static jbyteArray NativeBN_BN_bn2bin(JNIEnv* env, jclass, BIGNUM* a) { if (!oneValidHandle(env, a)) return NULL; jbyteArray result = env->NewByteArray(BN_num_bytes(a)); if (result == NULL) { return NULL; } ScopedByteArrayRW bytes(env, result); if (bytes.get() == NULL) { return NULL; } BN_bn2bin(a, reinterpret_cast<unsigned char*>(bytes.get())); return result; }
static jstring NativeBN_BN_bn2dec(JNIEnv* env, jclass, BIGNUM* a) { if (!oneValidHandle(env, a)) return NULL; char* tmpStr; char* retStr; tmpStr = BN_bn2dec(a); if (tmpStr != NULL) { retStr = leadingZerosTrimmed(tmpStr); jstring returnJString = env->NewStringUTF(retStr); OPENSSL_free(tmpStr); return returnJString; } else return NULL; }
extern "C" jbyteArray Java_java_math_NativeBN_BN_1bn2bin(JNIEnv* env, jclass, jlong a0) { if (!oneValidHandle(env, a0)) return NULL; BIGNUM* a = toBigNum(a0); jbyteArray result = env->NewByteArray(BN_num_bytes(a)); if (result == NULL) { return NULL; } ScopedByteArrayRW bytes(env, result); if (bytes.get() == NULL) { return NULL; } BN_bn2bin(a, reinterpret_cast<unsigned char*>(bytes.get())); return result; }
/** * public static native boolean BN_bin2bn(byte[], int, int, int) */ static jboolean NativeBN_BN_bin2bn(JNIEnv* env, jclass cls, jbyteArray arr, int len, jboolean neg, BIGNUM* ret) { if (!oneValidHandle(env, ret)) return FALSE; jboolean success; unsigned char * tmpBytes; tmpBytes = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, arr, 0)); if (tmpBytes != NULL) { success = (BN_bin2bn(tmpBytes, len, ret) != NULL); if (neg) { BN_set_negative(ret, 1); } (*env)->ReleasePrimitiveArrayCritical(env, arr, tmpBytes, JNI_ABORT); return success; } else return -1; // Error outside BN. mc FIXME: what to do in this case? Does JNI throw exception itself? }
/** * public static native long longInt(int) */ static long long NativeBN_longInt(JNIEnv* env, jclass cls, BIGNUM* a) { if (!oneValidHandle(env, a)) return -1; bn_check_top(a); int intLen = a->top; BN_ULONG* d = a->d; switch (intLen) { case 0: return 0; case 1: if (!a->neg) return d[0] & 0X00000000FFFFFFFFLL; else return -(d[0] & 0X00000000FFFFFFFFLL); default: if (!a->neg) return ((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL); else return -(((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL)); } }
/** * public static native byte[] BN_bn2bin(int, byte[]) */ static jbyteArray NativeBN_BN_bn2bin(JNIEnv* env, jclass cls, BIGNUM* a, jbyteArray to) { if (!oneValidHandle(env, a)) return NULL; jbyteArray returnJBytes = to; unsigned char * tmpBytes; int len, byteCnt; byteCnt = BN_num_bytes(a); // FIXME: Currently ignoring array passed in to: returnJBytes = (*env)->NewByteArray(env, byteCnt); // FIXME: is it neccessary to check for returnJBytes != NULL? tmpBytes = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, returnJBytes, NULL)); if (tmpBytes != NULL) { len = BN_bn2bin(a, tmpBytes); (*env)->ReleasePrimitiveArrayCritical(env, returnJBytes, tmpBytes, 0); return returnJBytes; } else return NULL; }
/** * public static native int putULongInt(int, long, int) */ static jboolean NativeBN_putULongInt(JNIEnv* env, jclass cls, BIGNUM* a, unsigned long long dw, jboolean neg) { if (!oneValidHandle(env, a)) return FALSE; unsigned int hi = dw >> 32; // This shifts without sign extension. int lo = (int)dw; // This truncates implicitely. // cf. litEndInts2bn: bn_check_top(a); if (bn_wexpand(a, 2) != NULL) { a->d[0] = lo; a->d[1] = hi; a->top = 2; a->neg = neg; bn_correct_top(a); return TRUE; } else return FALSE; }
extern "C" void Java_java_math_NativeBN_putULongInt(JNIEnv* env, jclass, jlong a0, unsigned long long dw, jboolean neg) { if (!oneValidHandle(env, a0)) return; unsigned int hi = dw >> 32; // This shifts without sign extension. int lo = (int)dw; // This truncates implicitly. // cf. litEndInts2bn: BIGNUM* a = toBigNum(a0); bn_check_top(a); if (bn_wexpand(a, 2) != NULL) { a->d[0] = lo; a->d[1] = hi; a->top = 2; a->neg = neg; bn_correct_top(a); } else { throwExceptionIfNecessary(env); } }
/** * public static native int bitLength(int) */ static int NativeBN_bitLength(JNIEnv* env, jclass cls, BIGNUM* a) { // We rely on: (BN_BITS2 == 32), i.e. BN_ULONG is unsigned int and has 4 bytes: // if (!oneValidHandle(env, a)) return FALSE; bn_check_top(a); int intLen = a->top; if (intLen == 0) return 0; BN_ULONG* d = a->d; int i = intLen - 1; BN_ULONG msd = d[i]; // most significant digit if (a->neg) { // Handle negative values correctly: // i.e. decrement the msd if all other digits are 0: // while ((i > 0) && (d[i] != 0)) { i--; } do { i--; } while (!((i < 0) || (d[i] != 0))); if (i < 0) msd--; // Only if all lower significant digits are 0 we decrement the most significant one. } return (intLen - 1) * 32 + BN_num_bits_word(msd); }
static void NativeBN_putULongInt(JNIEnv* env, jclass, jlong a0, jlong java_dw, jboolean neg) { if (!oneValidHandle(env, a0)) return; uint64_t dw = java_dw; // cf. litEndInts2bn: BIGNUM* a = toBigNum(a0); bn_check_top(a); if (bn_wexpand(a, 8/BN_BYTES) != NULL) { #ifdef __LP64__ a->d[0] = dw; #else unsigned int hi = dw >> 32; // This shifts without sign extension. int lo = (int)dw; // This truncates implicitly. a->d[0] = lo; a->d[1] = hi; #endif a->top = 8 / BN_BYTES; a->neg = neg; bn_correct_top(a); } else {
/** * public static native int[] bn2litEndInts(int, int[]) * cf. litEndInts2bn */ static jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass cls, BIGNUM* a, jintArray to) { if (!oneValidHandle(env, a)) return NULL; jintArray returnJInts = to; bn_check_top(a); int len = a->top; if (len > 0) { // FIXME: Currently ignoring array passed in to: returnJInts = (*env)->NewIntArray(env, len); // FIXME: is it neccessary to check for returnJBytes != NULL? BN_ULONG* tmpInts = (BN_ULONG*)((*env)->GetPrimitiveArrayCritical(env, returnJInts, NULL)); if (tmpInts != NULL) { int i = len; do { i--; tmpInts[i] = a->d[i]; } while (i > 0); (*env)->ReleasePrimitiveArrayCritical(env, returnJInts, tmpInts, 0); return returnJInts; } else return NULL; } else { // value = 0 return NULL; // Client should not call when sign = 0! } }
static jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass, BIGNUM* a) { if (!oneValidHandle(env, a)) return NULL; bn_check_top(a); int len = a->top; if (len == 0) { return NULL; } jintArray result = env->NewIntArray(len); if (result == NULL) { return NULL; } ScopedIntArrayRW ints(env, result); if (ints.get() == NULL) { return NULL; } BN_ULONG* ulongs = reinterpret_cast<BN_ULONG*>(ints.get()); if (ulongs == NULL) { return NULL; } int i = len; do { i--; ulongs[i] = a->d[i]; } while (i > 0); return result; }
extern "C" long long Java_java_math_NativeBN_longInt(JNIEnv* env, jclass, jlong a0) { if (!oneValidHandle(env, a0)) return -1; BIGNUM* a = toBigNum(a0); bn_check_top(a); int intLen = a->top; BN_ULONG* d = a->d; switch (intLen) { case 0: return 0; case 1: if (!a->neg) { return d[0] & 0X00000000FFFFFFFFLL; } else { return -(d[0] & 0X00000000FFFFFFFFLL); } default: if (!a->neg) { return ((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL); } else { return -(((long long)d[1] << 32) | (d[0] & 0XFFFFFFFFLL)); } } }
static jboolean NativeBN_twosComp2bn(JNIEnv* env, jclass cls, jbyteArray arr, int bytesLen, BIGNUM* ret) { if (!oneValidHandle(env, ret)) return JNI_FALSE; ScopedByteArrayRO bytes(env, arr); if (bytes.get() == NULL) { return -1; } jboolean success; const unsigned char* s = reinterpret_cast<const unsigned char*>(bytes.get()); if ((bytes[0] & 0X80) == 0) { // Positive value! // // We can use the existing BN implementation for unsigned big endian bytes: // success = (BN_bin2bn(s, bytesLen, ret) != NULL); BN_set_negative(ret, JNI_FALSE); } else { // Negative value! // // We need to apply two's complement: // success = negBigEndianBytes2bn(env, cls, s, bytesLen, ret); BN_set_negative(ret, JNI_TRUE); } return success; }
extern "C" void Java_java_math_NativeBN_twosComp2bn(JNIEnv* env, jclass cls, jbyteArray arr, int bytesLen, jlong ret0) { if (!oneValidHandle(env, ret0)) return; BIGNUM* ret = toBigNum(ret0); ScopedByteArrayRO bytes(env, arr); if (bytes.get() == NULL) { return; } const unsigned char* s = reinterpret_cast<const unsigned char*>(bytes.get()); if ((bytes[0] & 0X80) == 0) { // Positive value! // // We can use the existing BN implementation for unsigned big endian bytes: // BN_bin2bn(s, bytesLen, ret); BN_set_negative(ret, false); } else { // Negative value! // // We need to apply two's complement: // negBigEndianBytes2bn(env, cls, s, bytesLen, ret0); BN_set_negative(ret, true); } throwExceptionIfNecessary(env); }
static void NativeBN_BN_free(JNIEnv* env, jclass, jlong a) { if (!oneValidHandle(env, a)) return; BN_free(toBigNum(a)); }
static int twoValidHandles(JNIEnv* env, jlong a, jlong b) { if (!oneValidHandle(env, a)) return JNI_FALSE; return isValidHandle(env, b, "Mandatory handle (second) passed as null"); }