http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/com/intel/chimera/cipher/OpensslNative.c ---------------------------------------------------------------------- diff --git a/src/main/native/com/intel/chimera/cipher/OpensslNative.c b/src/main/native/com/intel/chimera/cipher/OpensslNative.c deleted file mode 100644 index 4f87866..0000000 --- a/src/main/native/com/intel/chimera/cipher/OpensslNative.c +++ /dev/null @@ -1,467 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "com_intel_chimera.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "OpensslNative.h" - -#ifdef UNIX -static EVP_CIPHER_CTX * (*dlsym_EVP_CIPHER_CTX_new)(void); -static void (*dlsym_EVP_CIPHER_CTX_free)(EVP_CIPHER_CTX *); -static int (*dlsym_EVP_CIPHER_CTX_cleanup)(EVP_CIPHER_CTX *); -static void (*dlsym_EVP_CIPHER_CTX_init)(EVP_CIPHER_CTX *); -static int (*dlsym_EVP_CIPHER_CTX_set_padding)(EVP_CIPHER_CTX *, int); -static int (*dlsym_EVP_CipherInit_ex)(EVP_CIPHER_CTX *, const EVP_CIPHER *, \ - ENGINE *, const unsigned char *, const unsigned char *, int); -static int (*dlsym_EVP_CipherUpdate)(EVP_CIPHER_CTX *, unsigned char *, \ - int *, const unsigned char *, int); -static int (*dlsym_EVP_CipherFinal_ex)(EVP_CIPHER_CTX *, unsigned char *, int *); -static EVP_CIPHER * (*dlsym_EVP_aes_256_ctr)(void); -static EVP_CIPHER * (*dlsym_EVP_aes_192_ctr)(void); -static EVP_CIPHER * (*dlsym_EVP_aes_128_ctr)(void); -static EVP_CIPHER * (*dlsym_EVP_aes_256_cbc)(void); -static EVP_CIPHER * (*dlsym_EVP_aes_192_cbc)(void); -static EVP_CIPHER * (*dlsym_EVP_aes_128_cbc)(void); -static void *openssl; -#endif - -#ifdef WINDOWS -typedef EVP_CIPHER_CTX * (__cdecl *__dlsym_EVP_CIPHER_CTX_new)(void); -typedef void (__cdecl *__dlsym_EVP_CIPHER_CTX_free)(EVP_CIPHER_CTX *); -typedef int (__cdecl *__dlsym_EVP_CIPHER_CTX_cleanup)(EVP_CIPHER_CTX *); -typedef void (__cdecl *__dlsym_EVP_CIPHER_CTX_init)(EVP_CIPHER_CTX *); -typedef int (__cdecl *__dlsym_EVP_CIPHER_CTX_set_padding)(EVP_CIPHER_CTX *, int); -typedef int (__cdecl *__dlsym_EVP_CipherInit_ex)(EVP_CIPHER_CTX *, \ - const EVP_CIPHER *, ENGINE *, const unsigned char *, \ - const unsigned char *, int); -typedef int (__cdecl *__dlsym_EVP_CipherUpdate)(EVP_CIPHER_CTX *, \ - unsigned char *, int *, const unsigned char *, int); -typedef int (__cdecl *__dlsym_EVP_CipherFinal_ex)(EVP_CIPHER_CTX *, \ - unsigned char *, int *); -typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_256_ctr)(void); -typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_192_ctr)(void); -typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_128_ctr)(void); -typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_256_cbc)(void); -typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_192_cbc)(void); -typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_128_cbc)(void); -static __dlsym_EVP_CIPHER_CTX_new dlsym_EVP_CIPHER_CTX_new; -static __dlsym_EVP_CIPHER_CTX_free dlsym_EVP_CIPHER_CTX_free; -static __dlsym_EVP_CIPHER_CTX_cleanup dlsym_EVP_CIPHER_CTX_cleanup; -static __dlsym_EVP_CIPHER_CTX_init dlsym_EVP_CIPHER_CTX_init; -static __dlsym_EVP_CIPHER_CTX_set_padding dlsym_EVP_CIPHER_CTX_set_padding; -static __dlsym_EVP_CipherInit_ex dlsym_EVP_CipherInit_ex; -static __dlsym_EVP_CipherUpdate dlsym_EVP_CipherUpdate; -static __dlsym_EVP_CipherFinal_ex dlsym_EVP_CipherFinal_ex; -static __dlsym_EVP_aes_256_ctr dlsym_EVP_aes_256_ctr; -static __dlsym_EVP_aes_192_ctr dlsym_EVP_aes_192_ctr; -static __dlsym_EVP_aes_128_ctr dlsym_EVP_aes_128_ctr; -static __dlsym_EVP_aes_256_cbc dlsym_EVP_aes_256_cbc; -static __dlsym_EVP_aes_192_cbc dlsym_EVP_aes_192_cbc; -static __dlsym_EVP_aes_128_cbc dlsym_EVP_aes_128_cbc; -static HMODULE openssl; -#endif - -static void loadAes(JNIEnv *env) -{ -#ifdef UNIX - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_256_ctr, env, openssl, "EVP_aes_256_ctr"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_192_ctr, env, openssl, "EVP_aes_192_ctr"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_128_ctr, env, openssl, "EVP_aes_128_ctr"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_256_cbc, env, openssl, "EVP_aes_256_cbc"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_192_cbc, env, openssl, "EVP_aes_192_cbc"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_128_cbc, env, openssl, "EVP_aes_128_cbc"); -#endif - -#ifdef WINDOWS - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_256_ctr, dlsym_EVP_aes_256_ctr, \ - env, openssl, "EVP_aes_256_ctr"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_192_ctr, dlsym_EVP_aes_192_ctr, \ - env, openssl, "EVP_aes_192_ctr"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_128_ctr, dlsym_EVP_aes_128_ctr, \ - env, openssl, "EVP_aes_128_ctr"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_256_cbc, dlsym_EVP_aes_256_cbc, \ - env, openssl, "EVP_aes_256_cbc"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_192_cbc, dlsym_EVP_aes_192_cbc, \ - env, openssl, "EVP_aes_192_cbc"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_128_cbc, dlsym_EVP_aes_128_cbc, \ - env, openssl, "EVP_aes_128_cbc"); -#endif -} - -JNIEXPORT void JNICALL Java_com_intel_chimera_cipher_OpensslNative_initIDs - (JNIEnv *env, jclass clazz) -{ - char msg[1000]; -#ifdef UNIX - openssl = dlopen(CHIMERA_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL); -#endif - -#ifdef WINDOWS - openssl = LoadLibrary(CHIMERA_OPENSSL_LIBRARY); -#endif - - if (!openssl) { - snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", CHIMERA_OPENSSL_LIBRARY, \ - dlerror()); - THROW(env, "java/lang/UnsatisfiedLinkError", msg); - return; - } - -#ifdef UNIX - dlerror(); // Clear any existing error - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_new, env, openssl, \ - "EVP_CIPHER_CTX_new"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_free, env, openssl, \ - "EVP_CIPHER_CTX_free"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_cleanup, env, openssl, \ - "EVP_CIPHER_CTX_cleanup"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_init, env, openssl, \ - "EVP_CIPHER_CTX_init"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_set_padding, env, openssl, \ - "EVP_CIPHER_CTX_set_padding"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherInit_ex, env, openssl, \ - "EVP_CipherInit_ex"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherUpdate, env, openssl, \ - "EVP_CipherUpdate"); - LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherFinal_ex, env, openssl, \ - "EVP_CipherFinal_ex"); -#endif - -#ifdef WINDOWS - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_new, dlsym_EVP_CIPHER_CTX_new, \ - env, openssl, "EVP_CIPHER_CTX_new"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_free, dlsym_EVP_CIPHER_CTX_free, \ - env, openssl, "EVP_CIPHER_CTX_free"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_cleanup, \ - dlsym_EVP_CIPHER_CTX_cleanup, env, - openssl, "EVP_CIPHER_CTX_cleanup"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_init, dlsym_EVP_CIPHER_CTX_init, \ - env, openssl, "EVP_CIPHER_CTX_init"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_set_padding, \ - dlsym_EVP_CIPHER_CTX_set_padding, env, \ - openssl, "EVP_CIPHER_CTX_set_padding"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CipherInit_ex, dlsym_EVP_CipherInit_ex, \ - env, openssl, "EVP_CipherInit_ex"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CipherUpdate, dlsym_EVP_CipherUpdate, \ - env, openssl, "EVP_CipherUpdate"); - LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CipherFinal_ex, dlsym_EVP_CipherFinal_ex, \ - env, openssl, "EVP_CipherFinal_ex"); -#endif - - loadAes(env); - jthrowable jthr = (*env)->ExceptionOccurred(env); - if (jthr) { - (*env)->DeleteLocalRef(env, jthr); - THROW(env, "java/lang/UnsatisfiedLinkError", \ - "Cannot find AES-CTR support, is your version of Openssl new enough?"); - return; - } -} - -JNIEXPORT jlong JNICALL Java_com_intel_chimera_cipher_OpensslNative_initContext - (JNIEnv *env, jclass clazz, jint alg, jint padding) -{ - if (alg != AES_CTR && alg != AES_CBC) { - THROW(env, "java/security/NoSuchAlgorithmException", NULL); - return (jlong)0; - } - if (!(alg == AES_CTR && padding == NOPADDING) - && !(alg == AES_CBC && (padding == NOPADDING|| padding == PKCS5PADDING))) { - THROW(env, "javax/crypto/NoSuchPaddingException", NULL); - return (jlong)0; - } - - if (dlsym_EVP_aes_256_ctr == NULL || - dlsym_EVP_aes_192_ctr == NULL || dlsym_EVP_aes_128_ctr == NULL) { - THROW(env, "java/security/NoSuchAlgorithmException", \ - "Doesn't support AES CTR."); - return (jlong)0; - } - - if (dlsym_EVP_aes_256_cbc == NULL || - dlsym_EVP_aes_192_cbc == NULL || dlsym_EVP_aes_128_cbc == NULL) { - THROW(env, "java/security/NoSuchAlgorithmException", \ - "Doesn't support AES CBC."); - return (jlong)0; - } - - // Create and initialize a EVP_CIPHER_CTX - EVP_CIPHER_CTX *context = dlsym_EVP_CIPHER_CTX_new(); - if (!context) { - THROW(env, "java/lang/OutOfMemoryError", NULL); - return (jlong)0; - } - - return JLONG(context); -} - -// Only supports AES-CTR and AES-CBC currently -static EVP_CIPHER * getEvpCipher(int alg, int keyLen) -{ - EVP_CIPHER *cipher = NULL; - if (alg == AES_CTR) { - if (keyLen == KEY_LENGTH_256) { - cipher = dlsym_EVP_aes_256_ctr(); - } else if (keyLen == KEY_LENGTH_192) { - cipher = dlsym_EVP_aes_192_ctr(); - } else if (keyLen == KEY_LENGTH_128) { - cipher = dlsym_EVP_aes_128_ctr(); - } - } else if (alg == AES_CBC) { - if (keyLen == KEY_LENGTH_256) { - cipher = dlsym_EVP_aes_256_cbc(); - } else if (keyLen == KEY_LENGTH_192) { - cipher = dlsym_EVP_aes_192_cbc(); - } else if (keyLen == KEY_LENGTH_128) { - cipher = dlsym_EVP_aes_128_cbc(); - } - } - return cipher; -} - -JNIEXPORT jlong JNICALL Java_com_intel_chimera_cipher_OpensslNative_init - (JNIEnv *env, jclass clazz, jlong ctx, jint mode, jint alg, jint padding, - jbyteArray key, jbyteArray iv) -{ - int jKeyLen = (*env)->GetArrayLength(env, key); - int jIvLen = (*env)->GetArrayLength(env, iv); - if (jKeyLen != KEY_LENGTH_128 && jKeyLen != KEY_LENGTH_192 - && jKeyLen != KEY_LENGTH_256) { - THROW(env, "java/security/InvalidKeyException", "Invalid key length."); - return (jlong)0; - } - if (jIvLen != IV_LENGTH) { - THROW(env, "java/security/InvalidAlgorithmParameterException", "Wrong IV length."); - return (jlong)0; - } - - EVP_CIPHER_CTX *context = CONTEXT(ctx); - if (context == 0) { - // Create and initialize a EVP_CIPHER_CTX - context = dlsym_EVP_CIPHER_CTX_new(); - if (!context) { - THROW(env, "java/lang/OutOfMemoryError", NULL); - return (jlong)0; - } - } - - jbyte *jKey = (*env)->GetByteArrayElements(env, key, NULL); - if (jKey == NULL) { - THROW(env, "java/lang/InternalError", "Cannot get bytes array for key."); - return (jlong)0; - } - jbyte *jIv = (*env)->GetByteArrayElements(env, iv, NULL); - if (jIv == NULL) { - (*env)->ReleaseByteArrayElements(env, key, jKey, 0); - THROW(env, "java/lang/InternalError", "Cannot get bytes array for iv."); - return (jlong)0; - } - - if (!(alg == AES_CTR || alg == AES_CBC)) { - THROW(env, "java/security/NoSuchAlgorithmException", "The algorithm is not supported."); - return (jlong)0; - } - - int rc = dlsym_EVP_CipherInit_ex(context, getEvpCipher(alg, jKeyLen), \ - NULL, (unsigned char *)jKey, (unsigned char *)jIv, mode == ENCRYPT_MODE); - (*env)->ReleaseByteArrayElements(env, key, jKey, 0); - (*env)->ReleaseByteArrayElements(env, iv, jIv, 0); - if (rc == 0) { - dlsym_EVP_CIPHER_CTX_cleanup(context); - THROW(env, "java/lang/InternalError", "Error in EVP_CipherInit_ex."); - return (jlong)0; - } - - if (padding == NOPADDING) { - dlsym_EVP_CIPHER_CTX_set_padding(context, 0); - } else if (padding == PKCS5PADDING) { - dlsym_EVP_CIPHER_CTX_set_padding(context, 1); - } - - return JLONG(context); -} - -// https://www.openssl.org/docs/crypto/EVP_EncryptInit.html -static int check_update_max_output_len(EVP_CIPHER_CTX *context, int input_len, - int max_output_len) -{ - if (context->flags & EVP_CIPH_NO_PADDING) { - if (max_output_len >= input_len) { - return 1; - } - return 0; - } else { - int b = context->cipher->block_size; - if (context->encrypt) { - if (max_output_len >= input_len + b - 1) { - return 1; - } - } else { - if (max_output_len >= input_len + b) { - return 1; - } - } - - return 0; - } -} - -JNIEXPORT jint JNICALL Java_com_intel_chimera_cipher_OpensslNative_update - (JNIEnv *env, jclass clazz, jlong ctx, jobject input, jint input_offset, - jint input_len, jobject output, jint output_offset, jint max_output_len) -{ - EVP_CIPHER_CTX *context = CONTEXT(ctx); - if (!check_update_max_output_len(context, input_len, max_output_len)) { - THROW(env, "javax/crypto/ShortBufferException", \ - "Output buffer is not sufficient."); - return 0; - } - unsigned char *input_bytes = (*env)->GetDirectBufferAddress(env, input); - unsigned char *output_bytes = (*env)->GetDirectBufferAddress(env, output); - if (input_bytes == NULL || output_bytes == NULL) { - THROW(env, "java/lang/InternalError", "Cannot get buffer address."); - return 0; - } - input_bytes = input_bytes + input_offset; - output_bytes = output_bytes + output_offset; - - int output_len = 0; - if (!dlsym_EVP_CipherUpdate(context, output_bytes, &output_len, \ - input_bytes, input_len)) { - dlsym_EVP_CIPHER_CTX_cleanup(context); - THROW(env, "java/lang/InternalError", "Error in EVP_CipherUpdate."); - return 0; - } - return output_len; -} - -JNIEXPORT jint JNICALL Java_com_intel_chimera_cipher_OpensslNative_updateByteArray - (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray input, jint input_offset, - jint input_len, jbyteArray output, jint output_offset, jint max_output_len) -{ - EVP_CIPHER_CTX *context = CONTEXT(ctx); - if (!check_update_max_output_len(context, input_len, max_output_len)) { - THROW(env, "javax/crypto/ShortBufferException", \ - "Output buffer is not sufficient."); - return 0; - } - unsigned char *input_bytes = (unsigned char *) (*env)->GetByteArrayElements(env, input, 0); - unsigned char *output_bytes = (unsigned char *) (*env)->GetByteArrayElements(env, output, 0); - if (input_bytes == NULL || output_bytes == NULL) { - THROW(env, "java/lang/InternalError", "Cannot get buffer address."); - return 0; - } - - int output_len = 0; - int rc = dlsym_EVP_CipherUpdate(context, output_bytes + output_offset, &output_len, \ - input_bytes + input_offset, input_len); - - (*env)->ReleaseByteArrayElements(env, input, (jbyte *) input_bytes, 0); - (*env)->ReleaseByteArrayElements(env, output, (jbyte *) output_bytes, 0); - - if (rc == 0) { - dlsym_EVP_CIPHER_CTX_cleanup(context); - THROW(env, "java/lang/InternalError", "Error in EVP_CipherUpdate."); - return 0; - } - return output_len; -} - -// https://www.openssl.org/docs/crypto/EVP_EncryptInit.html -static int check_doFinal_max_output_len(EVP_CIPHER_CTX *context, - int max_output_len) -{ - if (context->flags & EVP_CIPH_NO_PADDING) { - return 1; - } else { - int b = context->cipher->block_size; - if (max_output_len >= b) { - return 1; - } - - return 0; - } -} - -JNIEXPORT jint JNICALL Java_com_intel_chimera_cipher_OpensslNative_doFinal - (JNIEnv *env, jclass clazz, jlong ctx, jobject output, jint offset, - jint max_output_len) -{ - EVP_CIPHER_CTX *context = CONTEXT(ctx); - if (!check_doFinal_max_output_len(context, max_output_len)) { - THROW(env, "javax/crypto/ShortBufferException", \ - "Output buffer is not sufficient."); - return 0; - } - unsigned char *output_bytes = (*env)->GetDirectBufferAddress(env, output); - if (output_bytes == NULL) { - THROW(env, "java/lang/InternalError", "Cannot get buffer address."); - return 0; - } - output_bytes = output_bytes + offset; - - int output_len = 0; - if (!dlsym_EVP_CipherFinal_ex(context, output_bytes, &output_len)) { - dlsym_EVP_CIPHER_CTX_cleanup(context); - THROW(env, "java/lang/InternalError", "Error in EVP_CipherFinal_ex."); - return 0; - } - return output_len; -} - -JNIEXPORT jint JNICALL Java_com_intel_chimera_cipher_OpensslNative_doFinalByteArray - (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray output, jint offset, - jint max_output_len) -{ - EVP_CIPHER_CTX *context = CONTEXT(ctx); - if (!check_doFinal_max_output_len(context, max_output_len)) { - THROW(env, "javax/crypto/ShortBufferException", \ - "Output buffer is not sufficient."); - return 0; - } - unsigned char *output_bytes = (unsigned char *) (*env)->GetByteArrayElements(env, output, 0); - if (output_bytes == NULL) { - THROW(env, "java/lang/InternalError", "Cannot get buffer address."); - return 0; - } - - int output_len = 0; - int rc = dlsym_EVP_CipherFinal_ex(context, output_bytes + offset, &output_len); - - (*env)->ReleaseByteArrayElements(env, output, (jbyte *) output_bytes, 0); - - if (rc == 0) { - dlsym_EVP_CIPHER_CTX_cleanup(context); - THROW(env, "java/lang/InternalError", "Error in EVP_CipherFinal_ex."); - return 0; - } - return output_len; -} - -JNIEXPORT void JNICALL Java_com_intel_chimera_cipher_OpensslNative_clean - (JNIEnv *env, jclass clazz, jlong ctx) -{ - EVP_CIPHER_CTX *context = CONTEXT(ctx); - if (context) { - dlsym_EVP_CIPHER_CTX_free(context); - } -}
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/com/intel/chimera/com_intel_chimera.h ---------------------------------------------------------------------- diff --git a/src/main/native/com/intel/chimera/com_intel_chimera.h b/src/main/native/com/intel/chimera/com_intel_chimera.h deleted file mode 100644 index 1eb979e..0000000 --- a/src/main/native/com/intel/chimera/com_intel_chimera.h +++ /dev/null @@ -1,228 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This file includes some common utilities - * for all native code used in chimera. - */ - -#if !defined COM_INTEL_CHIMERA_H -#define COM_INTEL_CHIMERA_H - -#if defined(_WIN32) -#undef UNIX -#define WINDOWS -#else -#undef WINDOWS -#define UNIX -#endif - -/* A helper macro to 'throw' a java exception. */ -#define THROW(env, exception_name, message) \ - { \ - jclass ecls = (*env)->FindClass(env, exception_name); \ - if (ecls) { \ - (*env)->ThrowNew(env, ecls, message); \ - (*env)->DeleteLocalRef(env, ecls); \ - } \ - } - -/* Helper macro to return if an exception is pending */ -#define PASS_EXCEPTIONS(env) \ - { \ - if ((*env)->ExceptionCheck(env)) return; \ - } - -#define PASS_EXCEPTIONS_GOTO(env, target) \ - { \ - if ((*env)->ExceptionCheck(env)) goto target; \ - } - -#define PASS_EXCEPTIONS_RET(env, ret) \ - { \ - if ((*env)->ExceptionCheck(env)) return (ret); \ - } - -/** - * Unix definitions - */ -#ifdef UNIX -#include <config.h> -#include <dlfcn.h> -#include <jni.h> - -/** - * A helper function to dlsym a 'symbol' from a given library-handle. - * - * @param env jni handle to report contingencies. - * @param handle handle to the dlopen'ed library. - * @param symbol symbol to load. - * @return returns the address where the symbol is loaded in memory, - * <code>NULL</code> on error. - */ -static __attribute__ ((unused)) -void *do_dlsym(JNIEnv *env, void *handle, const char *symbol) { - if (!env || !handle || !symbol) { - THROW(env, "java/lang/InternalError", NULL); - return NULL; - } - char *error = NULL; - void *func_ptr = dlsym(handle, symbol); - if ((error = dlerror()) != NULL) { - THROW(env, "java/lang/UnsatisfiedLinkError", symbol); - return NULL; - } - return func_ptr; -} - -/* A helper macro to dlsym the requisite dynamic symbol and bail-out on error. */ -#define LOAD_DYNAMIC_SYMBOL(func_ptr, env, handle, symbol) \ - if ((func_ptr = do_dlsym(env, handle, symbol)) == NULL) { \ - return; \ - } -#endif -// Unix part end - - -/** - * Windows definitions - */ -#ifdef WINDOWS - -/* Force using Unicode throughout the code */ -#ifndef UNICODE -#define UNICODE -#endif - -/* Microsoft C Compiler does not support the C99 inline keyword */ -#ifndef __cplusplus -#define inline __inline; -#endif // _cplusplus - -/* Optimization macros supported by GCC but for which there is no - direct equivalent in the Microsoft C compiler */ -#define likely(_c) (_c) -#define unlikely(_c) (_c) - -/* Disable certain warnings in the native CRC32 code. */ -#pragma warning(disable:4018) // Signed/unsigned mismatch. -#pragma warning(disable:4244) // Possible loss of data in conversion. -#pragma warning(disable:4267) // Possible loss of data. -#pragma warning(disable:4996) // Use of deprecated function. - -#include <Windows.h> -#include <stdio.h> -#include <jni.h> - -#define snprintf(a, b ,c, d) _snprintf_s((a), (b), _TRUNCATE, (c), (d)) - -/* A helper macro to dlsym the requisite dynamic symbol and bail-out on error. */ -#define LOAD_DYNAMIC_SYMBOL(func_type, func_ptr, env, handle, symbol) \ - if ((func_ptr = (func_type) do_dlsym(env, handle, symbol)) == NULL) { \ - return; \ - } - -/** - * A helper function to dynamic load a 'symbol' from a given library-handle. - * - * @param env jni handle to report contingencies. - * @param handle handle to the dynamic library. - * @param symbol symbol to load. - * @return returns the address where the symbol is loaded in memory, - * <code>NULL</code> on error. - */ -static FARPROC WINAPI do_dlsym(JNIEnv *env, HMODULE handle, LPCSTR symbol) { - DWORD dwErrorCode = ERROR_SUCCESS; - FARPROC func_ptr = NULL; - - if (!env || !handle || !symbol) { - THROW(env, "java/lang/InternalError", NULL); - return NULL; - } - - func_ptr = GetProcAddress(handle, symbol); - if (func_ptr == NULL) - { - THROW(env, "java/lang/UnsatisfiedLinkError", symbol); - } - return func_ptr; -} -#endif -// Windows part end - - -#define LOCK_CLASS(env, clazz, classname) \ - if ((*env)->MonitorEnter(env, clazz) != 0) { \ - char exception_msg[128]; \ - snprintf(exception_msg, 128, "Failed to lock %s", classname); \ - THROW(env, "java/lang/InternalError", exception_msg); \ - } - -#define UNLOCK_CLASS(env, clazz, classname) \ - if ((*env)->MonitorExit(env, clazz) != 0) { \ - char exception_msg[128]; \ - snprintf(exception_msg, 128, "Failed to unlock %s", classname); \ - THROW(env, "java/lang/InternalError", exception_msg); \ - } - -#define RETRY_ON_EINTR(ret, expr) do { \ - ret = expr; \ -} while ((ret == -1) && (errno == EINTR)); - -#ifdef UNIX -#include <dlfcn.h> -#include "config.h" -#endif - -#ifdef WINDOWS -#include "winutils.h" -#endif - -#include <openssl/aes.h> -#include <openssl/evp.h> -#include <openssl/err.h> - -/** - * A helper macro to convert the java 'context-handle' - * to a EVP_CIPHER_CTX pointer. - */ -#define CONTEXT(context) ((EVP_CIPHER_CTX*)((ptrdiff_t)(context))) - -/** - * A helper macro to convert the EVP_CIPHER_CTX pointer to the - * java 'context-handle'. - */ -#define JLONG(context) ((jlong)((ptrdiff_t)(context))) - -#define KEY_LENGTH_128 16 -#define KEY_LENGTH_192 24 -#define KEY_LENGTH_256 32 -#define IV_LENGTH 16 - -#define ENCRYPT_MODE 1 -#define DECRYPT_MODE 0 - -/** Currently only support AES/CTR/NoPadding. */ -#define AES_CTR 0 -#define AES_CBC 1 -#define NOPADDING 0 -#define PKCS5PADDING 1 - -#endif - -//vim: sw=2: ts=2: et http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/com/intel/chimera/exception.c ---------------------------------------------------------------------- diff --git a/src/main/native/com/intel/chimera/exception.c b/src/main/native/com/intel/chimera/exception.c deleted file mode 100644 index fc072e8..0000000 --- a/src/main/native/com/intel/chimera/exception.c +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "exception.h" - -#include <jni.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -jthrowable newExceptionV(JNIEnv* env, const char *name, - const char *fmt, va_list ap) -{ - int need; - char buf[1], *msg = NULL; - va_list ap2; - jstring jstr = NULL; - jthrowable jthr; - jclass clazz; - jmethodID excCtor; - - va_copy(ap2, ap); - clazz = (*env)->FindClass(env, name); - if (!clazz) { - jthr = (*env)->ExceptionOccurred(env); - (*env)->ExceptionClear(env); - goto done; - } - excCtor = (*env)->GetMethodID(env, - clazz, "<init>", "(Ljava/lang/String;)V"); - if (!excCtor) { - jthr = (*env)->ExceptionOccurred(env); - (*env)->ExceptionClear(env); - goto done; - } - need = vsnprintf(buf, sizeof(buf), fmt, ap); - if (need < 0) { - fmt = "vsnprintf error"; - need = strlen(fmt); - } - msg = malloc(need + 1); - vsnprintf(msg, need + 1, fmt, ap2); - jstr = (*env)->NewStringUTF(env, msg); - if (!jstr) { - jthr = (*env)->ExceptionOccurred(env); - (*env)->ExceptionClear(env); - goto done; - } - jthr = (*env)->NewObject(env, clazz, excCtor, jstr); - if (!jthr) { - jthr = (*env)->ExceptionOccurred(env); - (*env)->ExceptionClear(env); - goto done; - } - -done: - free(msg); - va_end(ap2); - (*env)->DeleteLocalRef(env, jstr); - return jthr; -} - -jthrowable newException(JNIEnv* env, const char *name, const char *fmt, ...) -{ - va_list ap; - jthrowable jthr; - - va_start(ap, fmt); - jthr = newExceptionV(env, name, fmt, ap); - va_end(ap); - return jthr; -} - -jthrowable newRuntimeException(JNIEnv* env, const char *fmt, ...) -{ - va_list ap; - jthrowable jthr; - - va_start(ap, fmt); - jthr = newExceptionV(env, "java/lang/RuntimeException", fmt, ap); - va_end(ap); - return jthr; -} - -jthrowable newIOException(JNIEnv* env, const char *fmt, ...) -{ - va_list ap; - jthrowable jthr; - - va_start(ap, fmt); - jthr = newExceptionV(env, "java/io/IOException", fmt, ap); - va_end(ap); - return jthr; -} - -const char* terror(int errnum) -{ - -#if defined(__sun) -// MT-Safe under Solaris which doesn't support sys_errlist/sys_nerr - return strerror(errnum); -#else - if ((errnum < 0) || (errnum >= sys_nerr)) { - return "unknown error."; - } - return sys_errlist[errnum]; -#endif -} - http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/com/intel/chimera/exception.h ---------------------------------------------------------------------- diff --git a/src/main/native/com/intel/chimera/exception.h b/src/main/native/com/intel/chimera/exception.h deleted file mode 100644 index eace346..0000000 --- a/src/main/native/com/intel/chimera/exception.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef CHIMERA_NATIVE_SRC_EXCEPTION_H -#define CHIMERA_NATIVE_SRC_EXCEPTION_H - -#include <jni.h> /* for jthrowable */ -#include <stdarg.h> /* for va_list */ -#include "com_intel_chimera.h" - -#ifdef WINDOWS -/* - * gcc-style type-checked format arguments are not supported on Windows, so just - * stub this macro. - */ -#define TYPE_CHECKED_PRINTF_FORMAT(formatArg, varArgs) -# else -/* Use gcc type-checked format arguments. */ -#define TYPE_CHECKED_PRINTF_FORMAT(formatArg, varArgs) \ - __attribute__((format(printf, formatArg, varArgs))) -#endif - -/** - * Create a new Exception. - * - * No exceptions will be pending on return. - * - * @param env The JNI environment - * @param name full name of the Java exception class - * @param fmt printf-style format string - * @param ap printf-style arguments - * - * @return The RuntimeException - */ -jthrowable newExceptionV(JNIEnv* env, const char *name, - const char *fmt, va_list ap); - -/** - * Create a new Exception. - * - * No exceptions will be pending on return. - * - * @param env The JNI environment - * @param name full name of the Java exception class - * @param fmt printf-style format string - * @param ... printf-style arguments - * - * @return The RuntimeException - */ -jthrowable newException(JNIEnv* env, const char *name, const char *fmt, ...) - TYPE_CHECKED_PRINTF_FORMAT(3, 4); - -/** - * Create a new RuntimeException. - * - * No exceptions will be pending on return. - * - * @param env The JNI environment - * @param fmt printf-style format string - * @param ... printf-style arguments - * - * @return The RuntimeException - */ -jthrowable newRuntimeException(JNIEnv* env, const char *fmt, ...) - TYPE_CHECKED_PRINTF_FORMAT(2, 3); - -/** - * Create a new IOException. - * - * No exceptions will be pending on return. - * - * @param env The JNI environment - * @param fmt printf-style format string - * @param ... printf-style arguments - * - * @return The IOException, or another exception if we failed - * to create the NativeIOException. - */ -jthrowable newIOException(JNIEnv* env, const char *fmt, ...) - TYPE_CHECKED_PRINTF_FORMAT(2, 3); - -/** - * Thread-safe strerror alternative. - * - * @param errnum Error number. - * @return Statically allocated error string. - */ -const char* terror(int errnum); - -#undef TYPE_CHECKED_PRINTF_FORMAT -#endif http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/com/intel/chimera/random/OpensslSecureRandomNative.c ---------------------------------------------------------------------- diff --git a/src/main/native/com/intel/chimera/random/OpensslSecureRandomNative.c b/src/main/native/com/intel/chimera/random/OpensslSecureRandomNative.c deleted file mode 100644 index 96a4fc7..0000000 --- a/src/main/native/com/intel/chimera/random/OpensslSecureRandomNative.c +++ /dev/null @@ -1,335 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "com_intel_chimera_random.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef UNIX -#include <pthread.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <sys/types.h> -#endif - -#ifdef WINDOWS -#include <windows.h> -#endif - -#include "OpensslSecureRandomNative.h" - -#ifdef UNIX -static void * (*dlsym_CRYPTO_malloc) (int, const char *, int); -static void (*dlsym_CRYPTO_free) (void *); -static int (*dlsym_CRYPTO_num_locks) (void); -static void (*dlsym_CRYPTO_set_locking_callback) (void (*)()); -static void (*dlsym_CRYPTO_set_id_callback) (unsigned long (*)()); -static void (*dlsym_ENGINE_load_rdrand) (void); -static ENGINE * (*dlsym_ENGINE_by_id) (const char *); -static int (*dlsym_ENGINE_init) (ENGINE *); -static int (*dlsym_ENGINE_set_default) (ENGINE *, unsigned int); -static int (*dlsym_ENGINE_finish) (ENGINE *); -static int (*dlsym_ENGINE_free) (ENGINE *); -static void (*dlsym_ENGINE_cleanup) (void); -static int (*dlsym_RAND_bytes) (unsigned char *, int); -static unsigned long (*dlsym_ERR_get_error) (void); -#endif - -#ifdef WINDOWS -typedef void * (__cdecl *__dlsym_CRYPTO_malloc) (int, const char *, int); -typedef void (__cdecl *__dlsym_CRYPTO_free) (void *); -typedef int (__cdecl *__dlsym_CRYPTO_num_locks) (void); -typedef void (__cdecl *__dlsym_CRYPTO_set_locking_callback) \ - (void (*)(int, int, char *, int); -typedef void (__cdecl *__dlsym_ENGINE_load_rdrand) (void); -typedef ENGINE * (__cdecl *__dlsym_ENGINE_by_id) (const char *); -typedef int (__cdecl *__dlsym_ENGINE_init) (ENGINE *); -typedef int (__cdecl *__dlsym_ENGINE_set_default) (ENGINE *, unsigned int); -typedef int (__cdecl *__dlsym_ENGINE_finish) (ENGINE *); -typedef int (__cdecl *__dlsym_ENGINE_free) (ENGINE *); -typedef void (__cdecl *__dlsym_ENGINE_cleanup) (void); -typedef int (__cdecl *__dlsym_RAND_bytes) (unsigned char *, int); -typedef unsigned long (__cdecl *__dlsym_ERR_get_error) (void); -static __dlsym_CRYPTO_malloc dlsym_CRYPTO_malloc; -static __dlsym_CRYPTO_free dlsym_CRYPTO_free; -static __dlsym_CRYPTO_num_locks dlsym_CRYPTO_num_locks; -static __dlsym_CRYPTO_set_locking_callback dlsym_CRYPTO_set_locking_callback; -static __dlsym_ENGINE_load_rdrand dlsym_ENGINE_load_rdrand; -static __dlsym_ENGINE_by_id dlsym_ENGINE_by_id; -static __dlsym_ENGINE_init dlsym_ENGINE_init; -static __dlsym_ENGINE_set_default dlsym_ENGINE_set_default; -static __dlsym_ENGINE_finish dlsym_ENGINE_finish; -static __dlsym_ENGINE_free dlsym_ENGINE_free; -static __dlsym_ENGINE_cleanup dlsym_ENGINE_cleanup; -static __dlsym_RAND_bytes dlsym_RAND_bytes; -static __dlsym_ERR_get_error dlsym_ERR_get_error; -#endif - -static ENGINE * openssl_rand_init(void); -static void openssl_rand_clean(ENGINE *eng, int clean_locks); -static int openssl_rand_bytes(unsigned char *buf, int num); - -JNIEXPORT void JNICALL Java_com_intel_chimera_random_OpensslSecureRandomNative_initSR - (JNIEnv *env, jclass clazz) -{ - char msg[1000]; -#ifdef UNIX - void *openssl = dlopen(CHIMERA_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL); -#endif - -#ifdef WINDOWS - HMODULE openssl = LoadLibrary(CHIMERA_OPENSSL_LIBRARY); -#endif - - if (!openssl) { - snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", CHIMERA_OPENSSL_LIBRARY, \ - dlerror()); - THROW(env, "java/lang/UnsatisfiedLinkError", msg); - return; - } - -#ifdef UNIX - dlerror(); // Clear any existing error - LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_malloc, env, openssl, "CRYPTO_malloc"); - LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_free, env, openssl, "CRYPTO_free"); - LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_num_locks, env, openssl, "CRYPTO_num_locks"); - LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_set_locking_callback, \ - env, openssl, "CRYPTO_set_locking_callback"); - LOAD_DYNAMIC_SYMBOL(dlsym_CRYPTO_set_id_callback, env, \ - openssl, "CRYPTO_set_id_callback"); - LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_load_rdrand, env, \ - openssl, "ENGINE_load_rdrand"); - LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_by_id, env, openssl, "ENGINE_by_id"); - LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_init, env, openssl, "ENGINE_init"); - LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_set_default, env, \ - openssl, "ENGINE_set_default"); - LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_finish, env, openssl, "ENGINE_finish"); - LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_free, env, openssl, "ENGINE_free"); - LOAD_DYNAMIC_SYMBOL(dlsym_ENGINE_cleanup, env, openssl, "ENGINE_cleanup"); - LOAD_DYNAMIC_SYMBOL(dlsym_RAND_bytes, env, openssl, "RAND_bytes"); - LOAD_DYNAMIC_SYMBOL(dlsym_ERR_get_error, env, openssl, "ERR_get_error"); -#endif - -#ifdef WINDOWS - LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_malloc, dlsym_CRYPTO_malloc, \ - env, openssl, "CRYPTO_malloc"); - LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_free, dlsym_CRYPTO_free, \ - env, openssl, "CRYPTO_free"); - LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_num_locks, dlsym_CRYPTO_num_locks, \ - env, openssl, "CRYPTO_num_locks"); - LOAD_DYNAMIC_SYMBOL(__dlsym_CRYPTO_set_locking_callback, \ - dlsym_CRYPTO_set_locking_callback, \ - env, openssl, "CRYPTO_set_locking_callback"); - LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_load_rdrand, dlsym_ENGINE_load_rdrand, \ - env, openssl, "ENGINE_load_rdrand"); - LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_by_id, dlsym_ENGINE_by_id, \ - env, openssl, "ENGINE_by_id"); - LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_init, dlsym_ENGINE_init, \ - env, openssl, "ENGINE_init"); - LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_set_default, dlsym_ENGINE_set_default, \ - env, openssl, "ENGINE_set_default"); - LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_finish, dlsym_ENGINE_finish, \ - env, openssl, "ENGINE_finish"); - LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_free, dlsym_ENGINE_free, \ - env, openssl, "ENGINE_free"); - LOAD_DYNAMIC_SYMBOL(__dlsym_ENGINE_cleanup, dlsym_ENGINE_cleanup, \ - env, openssl, "ENGINE_cleanup"); - LOAD_DYNAMIC_SYMBOL(__dlsym_RAND_bytes, dlsym_RAND_bytes, \ - env, openssl, "RAND_bytes"); - LOAD_DYNAMIC_SYMBOL(__dlsym_ERR_get_error, dlsym_ERR_get_error, \ - env, openssl, "ERR_get_error"); -#endif - - openssl_rand_init(); -} - -JNIEXPORT jboolean JNICALL Java_com_intel_chimera_random_OpensslSecureRandomNative_nextRandBytes___3B - (JNIEnv *env, jobject object, jbyteArray bytes) -{ - if (NULL == bytes) { - THROW(env, "java/lang/NullPointerException", "Buffer cannot be null."); - return JNI_FALSE; - } - jbyte *b = (*env)->GetByteArrayElements(env, bytes, NULL); - if (NULL == b) { - THROW(env, "java/lang/InternalError", "Cannot get bytes array."); - return JNI_FALSE; - } - int b_len = (*env)->GetArrayLength(env, bytes); - int ret = openssl_rand_bytes((unsigned char *)b, b_len); - (*env)->ReleaseByteArrayElements(env, bytes, b, 0); - - if (1 != ret) { - return JNI_FALSE; - } - return JNI_TRUE; -} - -/** - * To ensure thread safety for random number generators, we need to call - * CRYPTO_set_locking_callback. - * http://wiki.openssl.org/index.php/Random_Numbers - * Example: crypto/threads/mttest.c - */ - -#ifdef WINDOWS -static void windows_locking_callback(int mode, int type, char *file, int line); -static HANDLE *lock_cs; - -static void locks_setup(void) -{ - int i; - lock_cs = dlsym_CRYPTO_malloc(dlsym_CRYPTO_num_locks() * sizeof(HANDLE), \ - __FILE__, __LINE__); - - for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) { - lock_cs[i] = CreateMutex(NULL, FALSE, NULL); - } - dlsym_CRYPTO_set_locking_callback((void (*)(int, int, char *, int)) \ - windows_locking_callback); - /* id callback defined */ -} - -static void locks_cleanup(void) -{ - int i; - dlsym_CRYPTO_set_locking_callback(NULL); - - for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) { - CloseHandle(lock_cs[i]); - } - dlsym_CRYPTO_free(lock_cs); -} - -static void windows_locking_callback(int mode, int type, char *file, int line) -{ - UNUSED(file), UNUSED(line); - - if (mode & CRYPTO_LOCK) { - WaitForSingleObject(lock_cs[type], INFINITE); - } else { - ReleaseMutex(lock_cs[type]); - } -} -#endif /* WINDOWS */ - -#ifdef UNIX -static void pthreads_locking_callback(int mode, int type, char *file, int line); -static unsigned long pthreads_thread_id(void); -static pthread_mutex_t *lock_cs; - -static void locks_setup(void) -{ - int i; - lock_cs = dlsym_CRYPTO_malloc(dlsym_CRYPTO_num_locks() * \ - sizeof(pthread_mutex_t), __FILE__, __LINE__); - - for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) { - pthread_mutex_init(&(lock_cs[i]), NULL); - } - - dlsym_CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id); - dlsym_CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback); -} - -static void locks_cleanup(void) -{ - int i; - dlsym_CRYPTO_set_locking_callback(NULL); - - for (i = 0; i < dlsym_CRYPTO_num_locks(); i++) { - pthread_mutex_destroy(&(lock_cs[i])); - } - - dlsym_CRYPTO_free(lock_cs); -} - -static void pthreads_locking_callback(int mode, int type, char *file, int line) -{ - UNUSED(file), UNUSED(line); - - if (mode & CRYPTO_LOCK) { - pthread_mutex_lock(&(lock_cs[type])); - } else { - pthread_mutex_unlock(&(lock_cs[type])); - } -} - -static unsigned long pthreads_thread_id(void) -{ - return (unsigned long)syscall(SYS_gettid); -} - -#endif /* UNIX */ - -/** - * If using an Intel chipset with RDRAND, the high-performance hardware - * random number generator will be used. - */ -static ENGINE * openssl_rand_init(void) -{ - locks_setup(); - - dlsym_ENGINE_load_rdrand(); - ENGINE *eng = dlsym_ENGINE_by_id("rdrand"); - - int ret = -1; - do { - if (NULL == eng) { - break; - } - - int rc = dlsym_ENGINE_init(eng); - if (0 == rc) { - break; - } - - rc = dlsym_ENGINE_set_default(eng, ENGINE_METHOD_RAND); - if (0 == rc) { - break; - } - - ret = 0; - } while(0); - - if (ret == -1) { - openssl_rand_clean(eng, 0); - } - - return eng; -} - -static void openssl_rand_clean(ENGINE *eng, int clean_locks) -{ - if (NULL != eng) { - dlsym_ENGINE_finish(eng); - dlsym_ENGINE_free(eng); - } - - dlsym_ENGINE_cleanup(); - if (clean_locks) { - locks_cleanup(); - } -} - -static int openssl_rand_bytes(unsigned char *buf, int num) -{ - return dlsym_RAND_bytes(buf, num); -} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/com/intel/chimera/random/com_intel_chimera_random.h ---------------------------------------------------------------------- diff --git a/src/main/native/com/intel/chimera/random/com_intel_chimera_random.h b/src/main/native/com/intel/chimera/random/com_intel_chimera_random.h deleted file mode 100644 index b011cde..0000000 --- a/src/main/native/com/intel/chimera/random/com_intel_chimera_random.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COM_INTEL_CHIMERA_RANDOM_H -#define COM_INTEL_CHIMERA_RANDOM_H - -#include "com_intel_chimera.h" - -#ifdef UNIX -#include <dlfcn.h> -#include "config.h" -#endif - -#ifdef WINDOWS -#include "winutils.h" -#endif - -#define UNUSED(x) ((void)(x)) - -#include <openssl/crypto.h> -#include <openssl/engine.h> -#include <openssl/rand.h> -#include <openssl/err.h> - -#endif //COM_INTEL_CHIMERA_RANDOM_H http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/org/apache/commons/crypto/cipher/OpensslNative.c ---------------------------------------------------------------------- diff --git a/src/main/native/org/apache/commons/crypto/cipher/OpensslNative.c b/src/main/native/org/apache/commons/crypto/cipher/OpensslNative.c new file mode 100644 index 0000000..552babd --- /dev/null +++ b/src/main/native/org/apache/commons/crypto/cipher/OpensslNative.c @@ -0,0 +1,467 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "org_apache_commons_crypto.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "OpensslNative.h" + +#ifdef UNIX +static EVP_CIPHER_CTX * (*dlsym_EVP_CIPHER_CTX_new)(void); +static void (*dlsym_EVP_CIPHER_CTX_free)(EVP_CIPHER_CTX *); +static int (*dlsym_EVP_CIPHER_CTX_cleanup)(EVP_CIPHER_CTX *); +static void (*dlsym_EVP_CIPHER_CTX_init)(EVP_CIPHER_CTX *); +static int (*dlsym_EVP_CIPHER_CTX_set_padding)(EVP_CIPHER_CTX *, int); +static int (*dlsym_EVP_CipherInit_ex)(EVP_CIPHER_CTX *, const EVP_CIPHER *, \ + ENGINE *, const unsigned char *, const unsigned char *, int); +static int (*dlsym_EVP_CipherUpdate)(EVP_CIPHER_CTX *, unsigned char *, \ + int *, const unsigned char *, int); +static int (*dlsym_EVP_CipherFinal_ex)(EVP_CIPHER_CTX *, unsigned char *, int *); +static EVP_CIPHER * (*dlsym_EVP_aes_256_ctr)(void); +static EVP_CIPHER * (*dlsym_EVP_aes_192_ctr)(void); +static EVP_CIPHER * (*dlsym_EVP_aes_128_ctr)(void); +static EVP_CIPHER * (*dlsym_EVP_aes_256_cbc)(void); +static EVP_CIPHER * (*dlsym_EVP_aes_192_cbc)(void); +static EVP_CIPHER * (*dlsym_EVP_aes_128_cbc)(void); +static void *openssl; +#endif + +#ifdef WINDOWS +typedef EVP_CIPHER_CTX * (__cdecl *__dlsym_EVP_CIPHER_CTX_new)(void); +typedef void (__cdecl *__dlsym_EVP_CIPHER_CTX_free)(EVP_CIPHER_CTX *); +typedef int (__cdecl *__dlsym_EVP_CIPHER_CTX_cleanup)(EVP_CIPHER_CTX *); +typedef void (__cdecl *__dlsym_EVP_CIPHER_CTX_init)(EVP_CIPHER_CTX *); +typedef int (__cdecl *__dlsym_EVP_CIPHER_CTX_set_padding)(EVP_CIPHER_CTX *, int); +typedef int (__cdecl *__dlsym_EVP_CipherInit_ex)(EVP_CIPHER_CTX *, \ + const EVP_CIPHER *, ENGINE *, const unsigned char *, \ + const unsigned char *, int); +typedef int (__cdecl *__dlsym_EVP_CipherUpdate)(EVP_CIPHER_CTX *, \ + unsigned char *, int *, const unsigned char *, int); +typedef int (__cdecl *__dlsym_EVP_CipherFinal_ex)(EVP_CIPHER_CTX *, \ + unsigned char *, int *); +typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_256_ctr)(void); +typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_192_ctr)(void); +typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_128_ctr)(void); +typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_256_cbc)(void); +typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_192_cbc)(void); +typedef EVP_CIPHER * (__cdecl *__dlsym_EVP_aes_128_cbc)(void); +static __dlsym_EVP_CIPHER_CTX_new dlsym_EVP_CIPHER_CTX_new; +static __dlsym_EVP_CIPHER_CTX_free dlsym_EVP_CIPHER_CTX_free; +static __dlsym_EVP_CIPHER_CTX_cleanup dlsym_EVP_CIPHER_CTX_cleanup; +static __dlsym_EVP_CIPHER_CTX_init dlsym_EVP_CIPHER_CTX_init; +static __dlsym_EVP_CIPHER_CTX_set_padding dlsym_EVP_CIPHER_CTX_set_padding; +static __dlsym_EVP_CipherInit_ex dlsym_EVP_CipherInit_ex; +static __dlsym_EVP_CipherUpdate dlsym_EVP_CipherUpdate; +static __dlsym_EVP_CipherFinal_ex dlsym_EVP_CipherFinal_ex; +static __dlsym_EVP_aes_256_ctr dlsym_EVP_aes_256_ctr; +static __dlsym_EVP_aes_192_ctr dlsym_EVP_aes_192_ctr; +static __dlsym_EVP_aes_128_ctr dlsym_EVP_aes_128_ctr; +static __dlsym_EVP_aes_256_cbc dlsym_EVP_aes_256_cbc; +static __dlsym_EVP_aes_192_cbc dlsym_EVP_aes_192_cbc; +static __dlsym_EVP_aes_128_cbc dlsym_EVP_aes_128_cbc; +static HMODULE openssl; +#endif + +static void loadAes(JNIEnv *env) +{ +#ifdef UNIX + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_256_ctr, env, openssl, "EVP_aes_256_ctr"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_192_ctr, env, openssl, "EVP_aes_192_ctr"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_128_ctr, env, openssl, "EVP_aes_128_ctr"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_256_cbc, env, openssl, "EVP_aes_256_cbc"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_192_cbc, env, openssl, "EVP_aes_192_cbc"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_aes_128_cbc, env, openssl, "EVP_aes_128_cbc"); +#endif + +#ifdef WINDOWS + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_256_ctr, dlsym_EVP_aes_256_ctr, \ + env, openssl, "EVP_aes_256_ctr"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_192_ctr, dlsym_EVP_aes_192_ctr, \ + env, openssl, "EVP_aes_192_ctr"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_128_ctr, dlsym_EVP_aes_128_ctr, \ + env, openssl, "EVP_aes_128_ctr"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_256_cbc, dlsym_EVP_aes_256_cbc, \ + env, openssl, "EVP_aes_256_cbc"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_192_cbc, dlsym_EVP_aes_192_cbc, \ + env, openssl, "EVP_aes_192_cbc"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_aes_128_cbc, dlsym_EVP_aes_128_cbc, \ + env, openssl, "EVP_aes_128_cbc"); +#endif +} + +JNIEXPORT void JNICALL Java_org_apache_commons_crypto_cipher_OpensslNative_initIDs + (JNIEnv *env, jclass clazz) +{ + char msg[1000]; +#ifdef UNIX + openssl = dlopen(CHIMERA_OPENSSL_LIBRARY, RTLD_LAZY | RTLD_GLOBAL); +#endif + +#ifdef WINDOWS + openssl = LoadLibrary(CHIMERA_OPENSSL_LIBRARY); +#endif + + if (!openssl) { + snprintf(msg, sizeof(msg), "Cannot load %s (%s)!", CHIMERA_OPENSSL_LIBRARY, \ + dlerror()); + THROW(env, "java/lang/UnsatisfiedLinkError", msg); + return; + } + +#ifdef UNIX + dlerror(); // Clear any existing error + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_new, env, openssl, \ + "EVP_CIPHER_CTX_new"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_free, env, openssl, \ + "EVP_CIPHER_CTX_free"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_cleanup, env, openssl, \ + "EVP_CIPHER_CTX_cleanup"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_init, env, openssl, \ + "EVP_CIPHER_CTX_init"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CIPHER_CTX_set_padding, env, openssl, \ + "EVP_CIPHER_CTX_set_padding"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherInit_ex, env, openssl, \ + "EVP_CipherInit_ex"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherUpdate, env, openssl, \ + "EVP_CipherUpdate"); + LOAD_DYNAMIC_SYMBOL(dlsym_EVP_CipherFinal_ex, env, openssl, \ + "EVP_CipherFinal_ex"); +#endif + +#ifdef WINDOWS + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_new, dlsym_EVP_CIPHER_CTX_new, \ + env, openssl, "EVP_CIPHER_CTX_new"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_free, dlsym_EVP_CIPHER_CTX_free, \ + env, openssl, "EVP_CIPHER_CTX_free"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_cleanup, \ + dlsym_EVP_CIPHER_CTX_cleanup, env, + openssl, "EVP_CIPHER_CTX_cleanup"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_init, dlsym_EVP_CIPHER_CTX_init, \ + env, openssl, "EVP_CIPHER_CTX_init"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CIPHER_CTX_set_padding, \ + dlsym_EVP_CIPHER_CTX_set_padding, env, \ + openssl, "EVP_CIPHER_CTX_set_padding"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CipherInit_ex, dlsym_EVP_CipherInit_ex, \ + env, openssl, "EVP_CipherInit_ex"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CipherUpdate, dlsym_EVP_CipherUpdate, \ + env, openssl, "EVP_CipherUpdate"); + LOAD_DYNAMIC_SYMBOL(__dlsym_EVP_CipherFinal_ex, dlsym_EVP_CipherFinal_ex, \ + env, openssl, "EVP_CipherFinal_ex"); +#endif + + loadAes(env); + jthrowable jthr = (*env)->ExceptionOccurred(env); + if (jthr) { + (*env)->DeleteLocalRef(env, jthr); + THROW(env, "java/lang/UnsatisfiedLinkError", \ + "Cannot find AES-CTR support, is your version of Openssl new enough?"); + return; + } +} + +JNIEXPORT jlong JNICALL Java_org_apache_commons_crypto_cipher_OpensslNative_initContext + (JNIEnv *env, jclass clazz, jint alg, jint padding) +{ + if (alg != AES_CTR && alg != AES_CBC) { + THROW(env, "java/security/NoSuchAlgorithmException", NULL); + return (jlong)0; + } + if (!(alg == AES_CTR && padding == NOPADDING) + && !(alg == AES_CBC && (padding == NOPADDING|| padding == PKCS5PADDING))) { + THROW(env, "javax/crypto/NoSuchPaddingException", NULL); + return (jlong)0; + } + + if (dlsym_EVP_aes_256_ctr == NULL || + dlsym_EVP_aes_192_ctr == NULL || dlsym_EVP_aes_128_ctr == NULL) { + THROW(env, "java/security/NoSuchAlgorithmException", \ + "Doesn't support AES CTR."); + return (jlong)0; + } + + if (dlsym_EVP_aes_256_cbc == NULL || + dlsym_EVP_aes_192_cbc == NULL || dlsym_EVP_aes_128_cbc == NULL) { + THROW(env, "java/security/NoSuchAlgorithmException", \ + "Doesn't support AES CBC."); + return (jlong)0; + } + + // Create and initialize a EVP_CIPHER_CTX + EVP_CIPHER_CTX *context = dlsym_EVP_CIPHER_CTX_new(); + if (!context) { + THROW(env, "java/lang/OutOfMemoryError", NULL); + return (jlong)0; + } + + return JLONG(context); +} + +// Only supports AES-CTR and AES-CBC currently +static EVP_CIPHER * getEvpCipher(int alg, int keyLen) +{ + EVP_CIPHER *cipher = NULL; + if (alg == AES_CTR) { + if (keyLen == KEY_LENGTH_256) { + cipher = dlsym_EVP_aes_256_ctr(); + } else if (keyLen == KEY_LENGTH_192) { + cipher = dlsym_EVP_aes_192_ctr(); + } else if (keyLen == KEY_LENGTH_128) { + cipher = dlsym_EVP_aes_128_ctr(); + } + } else if (alg == AES_CBC) { + if (keyLen == KEY_LENGTH_256) { + cipher = dlsym_EVP_aes_256_cbc(); + } else if (keyLen == KEY_LENGTH_192) { + cipher = dlsym_EVP_aes_192_cbc(); + } else if (keyLen == KEY_LENGTH_128) { + cipher = dlsym_EVP_aes_128_cbc(); + } + } + return cipher; +} + +JNIEXPORT jlong JNICALL Java_org_apache_commons_crypto_cipher_OpensslNative_init + (JNIEnv *env, jclass clazz, jlong ctx, jint mode, jint alg, jint padding, + jbyteArray key, jbyteArray iv) +{ + int jKeyLen = (*env)->GetArrayLength(env, key); + int jIvLen = (*env)->GetArrayLength(env, iv); + if (jKeyLen != KEY_LENGTH_128 && jKeyLen != KEY_LENGTH_192 + && jKeyLen != KEY_LENGTH_256) { + THROW(env, "java/security/InvalidKeyException", "Invalid key length."); + return (jlong)0; + } + if (jIvLen != IV_LENGTH) { + THROW(env, "java/security/InvalidAlgorithmParameterException", "Wrong IV length."); + return (jlong)0; + } + + EVP_CIPHER_CTX *context = CONTEXT(ctx); + if (context == 0) { + // Create and initialize a EVP_CIPHER_CTX + context = dlsym_EVP_CIPHER_CTX_new(); + if (!context) { + THROW(env, "java/lang/OutOfMemoryError", NULL); + return (jlong)0; + } + } + + jbyte *jKey = (*env)->GetByteArrayElements(env, key, NULL); + if (jKey == NULL) { + THROW(env, "java/lang/InternalError", "Cannot get bytes array for key."); + return (jlong)0; + } + jbyte *jIv = (*env)->GetByteArrayElements(env, iv, NULL); + if (jIv == NULL) { + (*env)->ReleaseByteArrayElements(env, key, jKey, 0); + THROW(env, "java/lang/InternalError", "Cannot get bytes array for iv."); + return (jlong)0; + } + + if (!(alg == AES_CTR || alg == AES_CBC)) { + THROW(env, "java/security/NoSuchAlgorithmException", "The algorithm is not supported."); + return (jlong)0; + } + + int rc = dlsym_EVP_CipherInit_ex(context, getEvpCipher(alg, jKeyLen), \ + NULL, (unsigned char *)jKey, (unsigned char *)jIv, mode == ENCRYPT_MODE); + (*env)->ReleaseByteArrayElements(env, key, jKey, 0); + (*env)->ReleaseByteArrayElements(env, iv, jIv, 0); + if (rc == 0) { + dlsym_EVP_CIPHER_CTX_cleanup(context); + THROW(env, "java/lang/InternalError", "Error in EVP_CipherInit_ex."); + return (jlong)0; + } + + if (padding == NOPADDING) { + dlsym_EVP_CIPHER_CTX_set_padding(context, 0); + } else if (padding == PKCS5PADDING) { + dlsym_EVP_CIPHER_CTX_set_padding(context, 1); + } + + return JLONG(context); +} + +// https://www.openssl.org/docs/crypto/EVP_EncryptInit.html +static int check_update_max_output_len(EVP_CIPHER_CTX *context, int input_len, + int max_output_len) +{ + if (context->flags & EVP_CIPH_NO_PADDING) { + if (max_output_len >= input_len) { + return 1; + } + return 0; + } else { + int b = context->cipher->block_size; + if (context->encrypt) { + if (max_output_len >= input_len + b - 1) { + return 1; + } + } else { + if (max_output_len >= input_len + b) { + return 1; + } + } + + return 0; + } +} + +JNIEXPORT jint JNICALL Java_org_apache_commons_crypto_cipher_OpensslNative_update + (JNIEnv *env, jclass clazz, jlong ctx, jobject input, jint input_offset, + jint input_len, jobject output, jint output_offset, jint max_output_len) +{ + EVP_CIPHER_CTX *context = CONTEXT(ctx); + if (!check_update_max_output_len(context, input_len, max_output_len)) { + THROW(env, "javax/crypto/ShortBufferException", \ + "Output buffer is not sufficient."); + return 0; + } + unsigned char *input_bytes = (*env)->GetDirectBufferAddress(env, input); + unsigned char *output_bytes = (*env)->GetDirectBufferAddress(env, output); + if (input_bytes == NULL || output_bytes == NULL) { + THROW(env, "java/lang/InternalError", "Cannot get buffer address."); + return 0; + } + input_bytes = input_bytes + input_offset; + output_bytes = output_bytes + output_offset; + + int output_len = 0; + if (!dlsym_EVP_CipherUpdate(context, output_bytes, &output_len, \ + input_bytes, input_len)) { + dlsym_EVP_CIPHER_CTX_cleanup(context); + THROW(env, "java/lang/InternalError", "Error in EVP_CipherUpdate."); + return 0; + } + return output_len; +} + +JNIEXPORT jint JNICALL Java_org_apache_commons_crypto_cipher_OpensslNative_updateByteArray + (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray input, jint input_offset, + jint input_len, jbyteArray output, jint output_offset, jint max_output_len) +{ + EVP_CIPHER_CTX *context = CONTEXT(ctx); + if (!check_update_max_output_len(context, input_len, max_output_len)) { + THROW(env, "javax/crypto/ShortBufferException", \ + "Output buffer is not sufficient."); + return 0; + } + unsigned char *input_bytes = (unsigned char *) (*env)->GetByteArrayElements(env, input, 0); + unsigned char *output_bytes = (unsigned char *) (*env)->GetByteArrayElements(env, output, 0); + if (input_bytes == NULL || output_bytes == NULL) { + THROW(env, "java/lang/InternalError", "Cannot get buffer address."); + return 0; + } + + int output_len = 0; + int rc = dlsym_EVP_CipherUpdate(context, output_bytes + output_offset, &output_len, \ + input_bytes + input_offset, input_len); + + (*env)->ReleaseByteArrayElements(env, input, (jbyte *) input_bytes, 0); + (*env)->ReleaseByteArrayElements(env, output, (jbyte *) output_bytes, 0); + + if (rc == 0) { + dlsym_EVP_CIPHER_CTX_cleanup(context); + THROW(env, "java/lang/InternalError", "Error in EVP_CipherUpdate."); + return 0; + } + return output_len; +} + +// https://www.openssl.org/docs/crypto/EVP_EncryptInit.html +static int check_doFinal_max_output_len(EVP_CIPHER_CTX *context, + int max_output_len) +{ + if (context->flags & EVP_CIPH_NO_PADDING) { + return 1; + } else { + int b = context->cipher->block_size; + if (max_output_len >= b) { + return 1; + } + + return 0; + } +} + +JNIEXPORT jint JNICALL Java_org_apache_commons_crypto_cipher_OpensslNative_doFinal + (JNIEnv *env, jclass clazz, jlong ctx, jobject output, jint offset, + jint max_output_len) +{ + EVP_CIPHER_CTX *context = CONTEXT(ctx); + if (!check_doFinal_max_output_len(context, max_output_len)) { + THROW(env, "javax/crypto/ShortBufferException", \ + "Output buffer is not sufficient."); + return 0; + } + unsigned char *output_bytes = (*env)->GetDirectBufferAddress(env, output); + if (output_bytes == NULL) { + THROW(env, "java/lang/InternalError", "Cannot get buffer address."); + return 0; + } + output_bytes = output_bytes + offset; + + int output_len = 0; + if (!dlsym_EVP_CipherFinal_ex(context, output_bytes, &output_len)) { + dlsym_EVP_CIPHER_CTX_cleanup(context); + THROW(env, "java/lang/InternalError", "Error in EVP_CipherFinal_ex."); + return 0; + } + return output_len; +} + +JNIEXPORT jint JNICALL Java_org_apache_commons_crypto_cipher_OpensslNative_doFinalByteArray + (JNIEnv *env, jclass clazz, jlong ctx, jbyteArray output, jint offset, + jint max_output_len) +{ + EVP_CIPHER_CTX *context = CONTEXT(ctx); + if (!check_doFinal_max_output_len(context, max_output_len)) { + THROW(env, "javax/crypto/ShortBufferException", \ + "Output buffer is not sufficient."); + return 0; + } + unsigned char *output_bytes = (unsigned char *) (*env)->GetByteArrayElements(env, output, 0); + if (output_bytes == NULL) { + THROW(env, "java/lang/InternalError", "Cannot get buffer address."); + return 0; + } + + int output_len = 0; + int rc = dlsym_EVP_CipherFinal_ex(context, output_bytes + offset, &output_len); + + (*env)->ReleaseByteArrayElements(env, output, (jbyte *) output_bytes, 0); + + if (rc == 0) { + dlsym_EVP_CIPHER_CTX_cleanup(context); + THROW(env, "java/lang/InternalError", "Error in EVP_CipherFinal_ex."); + return 0; + } + return output_len; +} + +JNIEXPORT void JNICALL Java_org_apache_commons_crypto_cipher_OpensslNative_clean + (JNIEnv *env, jclass clazz, jlong ctx) +{ + EVP_CIPHER_CTX *context = CONTEXT(ctx); + if (context) { + dlsym_EVP_CIPHER_CTX_free(context); + } +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/org/apache/commons/crypto/exception.c ---------------------------------------------------------------------- diff --git a/src/main/native/org/apache/commons/crypto/exception.c b/src/main/native/org/apache/commons/crypto/exception.c new file mode 100644 index 0000000..fc072e8 --- /dev/null +++ b/src/main/native/org/apache/commons/crypto/exception.c @@ -0,0 +1,124 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "exception.h" + +#include <jni.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +jthrowable newExceptionV(JNIEnv* env, const char *name, + const char *fmt, va_list ap) +{ + int need; + char buf[1], *msg = NULL; + va_list ap2; + jstring jstr = NULL; + jthrowable jthr; + jclass clazz; + jmethodID excCtor; + + va_copy(ap2, ap); + clazz = (*env)->FindClass(env, name); + if (!clazz) { + jthr = (*env)->ExceptionOccurred(env); + (*env)->ExceptionClear(env); + goto done; + } + excCtor = (*env)->GetMethodID(env, + clazz, "<init>", "(Ljava/lang/String;)V"); + if (!excCtor) { + jthr = (*env)->ExceptionOccurred(env); + (*env)->ExceptionClear(env); + goto done; + } + need = vsnprintf(buf, sizeof(buf), fmt, ap); + if (need < 0) { + fmt = "vsnprintf error"; + need = strlen(fmt); + } + msg = malloc(need + 1); + vsnprintf(msg, need + 1, fmt, ap2); + jstr = (*env)->NewStringUTF(env, msg); + if (!jstr) { + jthr = (*env)->ExceptionOccurred(env); + (*env)->ExceptionClear(env); + goto done; + } + jthr = (*env)->NewObject(env, clazz, excCtor, jstr); + if (!jthr) { + jthr = (*env)->ExceptionOccurred(env); + (*env)->ExceptionClear(env); + goto done; + } + +done: + free(msg); + va_end(ap2); + (*env)->DeleteLocalRef(env, jstr); + return jthr; +} + +jthrowable newException(JNIEnv* env, const char *name, const char *fmt, ...) +{ + va_list ap; + jthrowable jthr; + + va_start(ap, fmt); + jthr = newExceptionV(env, name, fmt, ap); + va_end(ap); + return jthr; +} + +jthrowable newRuntimeException(JNIEnv* env, const char *fmt, ...) +{ + va_list ap; + jthrowable jthr; + + va_start(ap, fmt); + jthr = newExceptionV(env, "java/lang/RuntimeException", fmt, ap); + va_end(ap); + return jthr; +} + +jthrowable newIOException(JNIEnv* env, const char *fmt, ...) +{ + va_list ap; + jthrowable jthr; + + va_start(ap, fmt); + jthr = newExceptionV(env, "java/io/IOException", fmt, ap); + va_end(ap); + return jthr; +} + +const char* terror(int errnum) +{ + +#if defined(__sun) +// MT-Safe under Solaris which doesn't support sys_errlist/sys_nerr + return strerror(errnum); +#else + if ((errnum < 0) || (errnum >= sys_nerr)) { + return "unknown error."; + } + return sys_errlist[errnum]; +#endif +} + http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/org/apache/commons/crypto/exception.h ---------------------------------------------------------------------- diff --git a/src/main/native/org/apache/commons/crypto/exception.h b/src/main/native/org/apache/commons/crypto/exception.h new file mode 100644 index 0000000..2d9a018 --- /dev/null +++ b/src/main/native/org/apache/commons/crypto/exception.h @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef CHIMERA_NATIVE_SRC_EXCEPTION_H +#define CHIMERA_NATIVE_SRC_EXCEPTION_H + +#include <jni.h> /* for jthrowable */ +#include <stdarg.h> /* for va_list */ +#include "org_apache_commons_crypto.h" + +#ifdef WINDOWS +/* + * gcc-style type-checked format arguments are not supported on Windows, so just + * stub this macro. + */ +#define TYPE_CHECKED_PRINTF_FORMAT(formatArg, varArgs) +# else +/* Use gcc type-checked format arguments. */ +#define TYPE_CHECKED_PRINTF_FORMAT(formatArg, varArgs) \ + __attribute__((format(printf, formatArg, varArgs))) +#endif + +/** + * Create a new Exception. + * + * No exceptions will be pending on return. + * + * @param env The JNI environment + * @param name full name of the Java exception class + * @param fmt printf-style format string + * @param ap printf-style arguments + * + * @return The RuntimeException + */ +jthrowable newExceptionV(JNIEnv* env, const char *name, + const char *fmt, va_list ap); + +/** + * Create a new Exception. + * + * No exceptions will be pending on return. + * + * @param env The JNI environment + * @param name full name of the Java exception class + * @param fmt printf-style format string + * @param ... printf-style arguments + * + * @return The RuntimeException + */ +jthrowable newException(JNIEnv* env, const char *name, const char *fmt, ...) + TYPE_CHECKED_PRINTF_FORMAT(3, 4); + +/** + * Create a new RuntimeException. + * + * No exceptions will be pending on return. + * + * @param env The JNI environment + * @param fmt printf-style format string + * @param ... printf-style arguments + * + * @return The RuntimeException + */ +jthrowable newRuntimeException(JNIEnv* env, const char *fmt, ...) + TYPE_CHECKED_PRINTF_FORMAT(2, 3); + +/** + * Create a new IOException. + * + * No exceptions will be pending on return. + * + * @param env The JNI environment + * @param fmt printf-style format string + * @param ... printf-style arguments + * + * @return The IOException, or another exception if we failed + * to create the NativeIOException. + */ +jthrowable newIOException(JNIEnv* env, const char *fmt, ...) + TYPE_CHECKED_PRINTF_FORMAT(2, 3); + +/** + * Thread-safe strerror alternative. + * + * @param errnum Error number. + * @return Statically allocated error string. + */ +const char* terror(int errnum); + +#undef TYPE_CHECKED_PRINTF_FORMAT +#endif http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/main/native/org/apache/commons/crypto/org_apache_commons_crypto.h ---------------------------------------------------------------------- diff --git a/src/main/native/org/apache/commons/crypto/org_apache_commons_crypto.h b/src/main/native/org/apache/commons/crypto/org_apache_commons_crypto.h new file mode 100644 index 0000000..ae965c5 --- /dev/null +++ b/src/main/native/org/apache/commons/crypto/org_apache_commons_crypto.h @@ -0,0 +1,228 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This file includes some common utilities + * for all native code used in chimera. + */ + +#if !defined ORG_APACHE_COMMONS_CRYPTO_H +#define ORG_APACHE_COMMONS_CRYPTO_H + +#if defined(_WIN32) +#undef UNIX +#define WINDOWS +#else +#undef WINDOWS +#define UNIX +#endif + +/* A helper macro to 'throw' a java exception. */ +#define THROW(env, exception_name, message) \ + { \ + jclass ecls = (*env)->FindClass(env, exception_name); \ + if (ecls) { \ + (*env)->ThrowNew(env, ecls, message); \ + (*env)->DeleteLocalRef(env, ecls); \ + } \ + } + +/* Helper macro to return if an exception is pending */ +#define PASS_EXCEPTIONS(env) \ + { \ + if ((*env)->ExceptionCheck(env)) return; \ + } + +#define PASS_EXCEPTIONS_GOTO(env, target) \ + { \ + if ((*env)->ExceptionCheck(env)) goto target; \ + } + +#define PASS_EXCEPTIONS_RET(env, ret) \ + { \ + if ((*env)->ExceptionCheck(env)) return (ret); \ + } + +/** + * Unix definitions + */ +#ifdef UNIX +#include <config.h> +#include <dlfcn.h> +#include <jni.h> + +/** + * A helper function to dlsym a 'symbol' from a given library-handle. + * + * @param env jni handle to report contingencies. + * @param handle handle to the dlopen'ed library. + * @param symbol symbol to load. + * @return returns the address where the symbol is loaded in memory, + * <code>NULL</code> on error. + */ +static __attribute__ ((unused)) +void *do_dlsym(JNIEnv *env, void *handle, const char *symbol) { + if (!env || !handle || !symbol) { + THROW(env, "java/lang/InternalError", NULL); + return NULL; + } + char *error = NULL; + void *func_ptr = dlsym(handle, symbol); + if ((error = dlerror()) != NULL) { + THROW(env, "java/lang/UnsatisfiedLinkError", symbol); + return NULL; + } + return func_ptr; +} + +/* A helper macro to dlsym the requisite dynamic symbol and bail-out on error. */ +#define LOAD_DYNAMIC_SYMBOL(func_ptr, env, handle, symbol) \ + if ((func_ptr = do_dlsym(env, handle, symbol)) == NULL) { \ + return; \ + } +#endif +// Unix part end + + +/** + * Windows definitions + */ +#ifdef WINDOWS + +/* Force using Unicode throughout the code */ +#ifndef UNICODE +#define UNICODE +#endif + +/* Microsoft C Compiler does not support the C99 inline keyword */ +#ifndef __cplusplus +#define inline __inline; +#endif // _cplusplus + +/* Optimization macros supported by GCC but for which there is no + direct equivalent in the Microsoft C compiler */ +#define likely(_c) (_c) +#define unlikely(_c) (_c) + +/* Disable certain warnings in the native CRC32 code. */ +#pragma warning(disable:4018) // Signed/unsigned mismatch. +#pragma warning(disable:4244) // Possible loss of data in conversion. +#pragma warning(disable:4267) // Possible loss of data. +#pragma warning(disable:4996) // Use of deprecated function. + +#include <Windows.h> +#include <stdio.h> +#include <jni.h> + +#define snprintf(a, b ,c, d) _snprintf_s((a), (b), _TRUNCATE, (c), (d)) + +/* A helper macro to dlsym the requisite dynamic symbol and bail-out on error. */ +#define LOAD_DYNAMIC_SYMBOL(func_type, func_ptr, env, handle, symbol) \ + if ((func_ptr = (func_type) do_dlsym(env, handle, symbol)) == NULL) { \ + return; \ + } + +/** + * A helper function to dynamic load a 'symbol' from a given library-handle. + * + * @param env jni handle to report contingencies. + * @param handle handle to the dynamic library. + * @param symbol symbol to load. + * @return returns the address where the symbol is loaded in memory, + * <code>NULL</code> on error. + */ +static FARPROC WINAPI do_dlsym(JNIEnv *env, HMODULE handle, LPCSTR symbol) { + DWORD dwErrorCode = ERROR_SUCCESS; + FARPROC func_ptr = NULL; + + if (!env || !handle || !symbol) { + THROW(env, "java/lang/InternalError", NULL); + return NULL; + } + + func_ptr = GetProcAddress(handle, symbol); + if (func_ptr == NULL) + { + THROW(env, "java/lang/UnsatisfiedLinkError", symbol); + } + return func_ptr; +} +#endif +// Windows part end + + +#define LOCK_CLASS(env, clazz, classname) \ + if ((*env)->MonitorEnter(env, clazz) != 0) { \ + char exception_msg[128]; \ + snprintf(exception_msg, 128, "Failed to lock %s", classname); \ + THROW(env, "java/lang/InternalError", exception_msg); \ + } + +#define UNLOCK_CLASS(env, clazz, classname) \ + if ((*env)->MonitorExit(env, clazz) != 0) { \ + char exception_msg[128]; \ + snprintf(exception_msg, 128, "Failed to unlock %s", classname); \ + THROW(env, "java/lang/InternalError", exception_msg); \ + } + +#define RETRY_ON_EINTR(ret, expr) do { \ + ret = expr; \ +} while ((ret == -1) && (errno == EINTR)); + +#ifdef UNIX +#include <dlfcn.h> +#include "config.h" +#endif + +#ifdef WINDOWS +#include "winutils.h" +#endif + +#include <openssl/aes.h> +#include <openssl/evp.h> +#include <openssl/err.h> + +/** + * A helper macro to convert the java 'context-handle' + * to a EVP_CIPHER_CTX pointer. + */ +#define CONTEXT(context) ((EVP_CIPHER_CTX*)((ptrdiff_t)(context))) + +/** + * A helper macro to convert the EVP_CIPHER_CTX pointer to the + * java 'context-handle'. + */ +#define JLONG(context) ((jlong)((ptrdiff_t)(context))) + +#define KEY_LENGTH_128 16 +#define KEY_LENGTH_192 24 +#define KEY_LENGTH_256 32 +#define IV_LENGTH 16 + +#define ENCRYPT_MODE 1 +#define DECRYPT_MODE 0 + +/** Currently only support AES/CTR/NoPadding. */ +#define AES_CTR 0 +#define AES_CBC 1 +#define NOPADDING 0 +#define PKCS5PADDING 1 + +#endif + +//vim: sw=2: ts=2: et