From 7318750ed08d0b09b3722a3b712ac6f5b32575af Mon Sep 17 00:00:00 2001 From: md_5 Date: Tue, 1 Jul 2014 20:13:30 +1000 Subject: [PATCH] Update native cipher to make use of the OpenSSL EVP API so that it can actually utilise hardware acceleration and other goodies. Whereas before OpenSSL would often lose benchmarks now it always wins. --- native/compile-native.sh | 2 +- native/src/main/c/NativeCipherImpl.c | 56 ------------------ native/src/main/c/NativeCipherImpl.cpp | 22 +++++++ .../main/c/net_md_5_bungee_NativeCipherImpl.h | 8 +-- .../java/net/md_5/bungee/NativeCipher.java | 26 +++----- .../net/md_5/bungee/NativeCipherImpl.java | 27 +-------- native/src/main/resources/native-cipher.so | Bin 8277 -> 8333 bytes 7 files changed, 39 insertions(+), 102 deletions(-) delete mode 100644 native/src/main/c/NativeCipherImpl.c create mode 100644 native/src/main/c/NativeCipherImpl.cpp diff --git a/native/compile-native.sh b/native/compile-native.sh index 45e1164f..1baca889 100755 --- a/native/compile-native.sh +++ b/native/compile-native.sh @@ -1,3 +1,3 @@ #!/bin/sh -gcc -shared -fPIC -O3 -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/ src/main/c/NativeCipherImpl.c -o src/main/resources/native-cipher.so -lcrypto +g++ -shared -fPIC -O3 -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/ src/main/c/NativeCipherImpl.cpp -o src/main/resources/native-cipher.so -lcrypto diff --git a/native/src/main/c/NativeCipherImpl.c b/native/src/main/c/NativeCipherImpl.c deleted file mode 100644 index 6e35aa68..00000000 --- a/native/src/main/c/NativeCipherImpl.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "net_md_5_bungee_NativeCipherImpl.h" -#include -#include -#include -#include -#define BYTE unsigned char - -jlong Java_net_md_15_bungee_NativeCipherImpl_init -(JNIEnv* env, jobject obj, jbyteArray key) -{ - AES_KEY *aes_key = malloc(sizeof(AES_KEY)); - - jboolean isKeyCopy; - BYTE *key_bytes = (BYTE*)(*env)->GetByteArrayElements(env, key, &isKeyCopy); - int key_length = (*env)->GetArrayLength(env, key) * 8; // in bits - - AES_set_encrypt_key(key_bytes, key_length, aes_key); - - if (isKeyCopy) { - (*env)->ReleaseByteArrayElements(env, key, (jbyte*)key_bytes, JNI_ABORT); - } - return (long) aes_key; -} -void Java_net_md_15_bungee_NativeCipherImpl_free -(JNIEnv* env, jobject obj, jlong key) -{ - free((AES_KEY*)key); -} -void Java_net_md_15_bungee_NativeCipherImpl_cipher -(JNIEnv* env, jobject obj, jboolean forEncryption, jlong key, jbyteArray iv, jlong in, jlong out, jint length) -{ - AES_KEY *aes_key = (AES_KEY*)key; - - size_t buffer_length = (size_t) length; - - BYTE *input = (BYTE*) in; - BYTE *output = (BYTE*) out; - - jboolean isCopy; - BYTE *iv_bytes = (BYTE*)(*env)->GetByteArrayElements(env, iv, &isCopy); - - AES_cfb8_encrypt( - input, // input buffer - output, // output buffer - buffer_length, // readable bytes - aes_key, // encryption key - iv_bytes, // IV - NULL, // not needed - forEncryption ? AES_ENCRYPT : AES_DECRYPT // encryption mode - ); - - // IV has changed, let's copy it back - if (isCopy) { - (*env)->ReleaseByteArrayElements(env, iv, (jbyte*)iv_bytes, 0); - } -} diff --git a/native/src/main/c/NativeCipherImpl.cpp b/native/src/main/c/NativeCipherImpl.cpp new file mode 100644 index 00000000..1c2981dd --- /dev/null +++ b/native/src/main/c/NativeCipherImpl.cpp @@ -0,0 +1,22 @@ +#include +#include "net_md_5_bungee_NativeCipherImpl.h" + +typedef unsigned char byte; + +jlong JNICALL Java_net_md_15_bungee_NativeCipherImpl_init(JNIEnv* env, jobject obj, jboolean forEncryption, jbyteArray key) { + jbyte *keyBytes = env->GetByteArrayElements(key, NULL); + + EVP_CIPHER_CTX *cipherCtx = new EVP_CIPHER_CTX(); + EVP_CipherInit(cipherCtx, EVP_aes_128_cfb8(), (byte*) keyBytes, (byte*) keyBytes, forEncryption); + + env->ReleaseByteArrayElements(key, keyBytes, JNI_ABORT); + return (jlong) cipherCtx; +} + +void Java_net_md_15_bungee_NativeCipherImpl_free(JNIEnv* env, jobject obj, jlong ctx) { + EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*) ctx); +} + +void Java_net_md_15_bungee_NativeCipherImpl_cipher(JNIEnv* env, jobject obj, jlong ctx, jlong in, jlong out, jint length) { + EVP_CipherUpdate((EVP_CIPHER_CTX*) ctx, (byte*) out, &length, (byte*) in, length); +} diff --git a/native/src/main/c/net_md_5_bungee_NativeCipherImpl.h b/native/src/main/c/net_md_5_bungee_NativeCipherImpl.h index 87e30b03..c4187cc9 100644 --- a/native/src/main/c/net_md_5_bungee_NativeCipherImpl.h +++ b/native/src/main/c/net_md_5_bungee_NativeCipherImpl.h @@ -10,10 +10,10 @@ extern "C" { /* * Class: net_md_5_bungee_NativeCipherImpl * Method: init - * Signature: ([B)J + * Signature: (Z[B)J */ JNIEXPORT jlong JNICALL Java_net_md_15_bungee_NativeCipherImpl_init - (JNIEnv *, jobject, jbyteArray); + (JNIEnv *, jobject, jboolean, jbyteArray); /* * Class: net_md_5_bungee_NativeCipherImpl @@ -26,10 +26,10 @@ JNIEXPORT void JNICALL Java_net_md_15_bungee_NativeCipherImpl_free /* * Class: net_md_5_bungee_NativeCipherImpl * Method: cipher - * Signature: (ZJ[BJJI)V + * Signature: (JJJI)V */ JNIEXPORT void JNICALL Java_net_md_15_bungee_NativeCipherImpl_cipher - (JNIEnv *, jobject, jboolean, jlong, jbyteArray, jlong, jlong, jint); + (JNIEnv *, jobject, jlong, jlong, jlong, jint); #ifdef __cplusplus } diff --git a/native/src/main/java/net/md_5/bungee/NativeCipher.java b/native/src/main/java/net/md_5/bungee/NativeCipher.java index 3dc6920a..96f9c83c 100644 --- a/native/src/main/java/net/md_5/bungee/NativeCipher.java +++ b/native/src/main/java/net/md_5/bungee/NativeCipher.java @@ -17,12 +17,9 @@ public class NativeCipher implements BungeeCipher @Getter private final NativeCipherImpl nativeCipher = new NativeCipherImpl(); - private boolean forEncryption; - private byte[] iv; /*============================================================================*/ private static boolean loaded; - - private long pointer; + private long ctx; public static boolean isSupported() { @@ -62,22 +59,18 @@ public class NativeCipher implements BungeeCipher public void init(boolean forEncryption, SecretKey key) throws GeneralSecurityException { Preconditions.checkArgument( key.getEncoded().length == 16, "Invalid key size" ); - if ( pointer != 0 ) - { - nativeCipher.free( pointer ); - } - this.forEncryption = forEncryption; - this.iv = key.getEncoded(); // initialize the IV - this.pointer = nativeCipher.init( key.getEncoded() ); + free(); + + this.ctx = nativeCipher.init( forEncryption, key.getEncoded() ); } @Override public void free() { - if ( pointer != 0 ) + if ( ctx != 0 ) { - nativeCipher.free( pointer ); - pointer = 0; + nativeCipher.free( ctx ); + ctx = 0; } } @@ -87,8 +80,7 @@ public class NativeCipher implements BungeeCipher // Smoke tests in.memoryAddress(); out.memoryAddress(); - Preconditions.checkState( pointer != 0, "Invalid pointer to AES key!" ); - Preconditions.checkState( iv != null, "Invalid IV!" ); + Preconditions.checkState( ctx != 0, "Invalid pointer to AES key!" ); // Store how many bytes we can cipher int length = in.readableBytes(); @@ -96,7 +88,7 @@ public class NativeCipher implements BungeeCipher out.ensureWritable( length ); // Cipher the bytes - nativeCipher.cipher( forEncryption, pointer, iv, in.memoryAddress() + in.readerIndex(), out.memoryAddress() + out.writerIndex(), length ); + nativeCipher.cipher( ctx, in.memoryAddress() + in.readerIndex(), out.memoryAddress() + out.writerIndex(), length ); // Go to the end of the buffer, all bytes would of been read in.readerIndex( in.writerIndex() ); diff --git a/native/src/main/java/net/md_5/bungee/NativeCipherImpl.java b/native/src/main/java/net/md_5/bungee/NativeCipherImpl.java index 261a84ec..2167b1c4 100644 --- a/native/src/main/java/net/md_5/bungee/NativeCipherImpl.java +++ b/native/src/main/java/net/md_5/bungee/NativeCipherImpl.java @@ -3,30 +3,9 @@ package net.md_5.bungee; class NativeCipherImpl { - /** - * Initializes the key. - * - * @param key the key to for encryption - * @return the pointer to key - */ - native long init(byte[] key); + native long init(boolean forEncryption, byte[] key); - /** - * Frees the key. - * - * @param key the pointer to key - */ - native void free(long key); + native void free(long ctx); - /** - * This method will encrypt some data in AES-CFB8 using the specified key. - * - * @param forEncryption encryption / decryption mode - * @param key the pointer to key - * @param iv the iv to use - * @param in the starting memory address for reading data - * @param out the starting memory address for writing data - * @param length the length of data to read / write - */ - native void cipher(boolean forEncryption, long key, byte[] iv, long in, long out, int length); + native void cipher(long ctx, long in, long out, int length); } diff --git a/native/src/main/resources/native-cipher.so b/native/src/main/resources/native-cipher.so index 03d70f6d70920cc175577d79108a1e12fdec506d..9fd92de91ea498ce0f52cb7d9085ec67b136f2c1 100755 GIT binary patch delta 2568 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