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.
This commit is contained in:
md_5 2014-07-01 20:13:30 +10:00
parent 21be93a1b1
commit 7318750ed0
7 changed files with 39 additions and 102 deletions

View File

@ -1,3 +1,3 @@
#!/bin/sh #!/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

View File

@ -1,56 +0,0 @@
#include "net_md_5_bungee_NativeCipherImpl.h"
#include <openssl/aes.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#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);
}
}

View File

@ -0,0 +1,22 @@
#include <openssl/evp.h>
#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);
}

View File

@ -10,10 +10,10 @@ extern "C" {
/* /*
* Class: net_md_5_bungee_NativeCipherImpl * Class: net_md_5_bungee_NativeCipherImpl
* Method: init * Method: init
* Signature: ([B)J * Signature: (Z[B)J
*/ */
JNIEXPORT jlong JNICALL Java_net_md_15_bungee_NativeCipherImpl_init JNIEXPORT jlong JNICALL Java_net_md_15_bungee_NativeCipherImpl_init
(JNIEnv *, jobject, jbyteArray); (JNIEnv *, jobject, jboolean, jbyteArray);
/* /*
* Class: net_md_5_bungee_NativeCipherImpl * 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 * Class: net_md_5_bungee_NativeCipherImpl
* Method: cipher * Method: cipher
* Signature: (ZJ[BJJI)V * Signature: (JJJI)V
*/ */
JNIEXPORT void JNICALL Java_net_md_15_bungee_NativeCipherImpl_cipher 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 #ifdef __cplusplus
} }

View File

@ -17,12 +17,9 @@ public class NativeCipher implements BungeeCipher
@Getter @Getter
private final NativeCipherImpl nativeCipher = new NativeCipherImpl(); private final NativeCipherImpl nativeCipher = new NativeCipherImpl();
private boolean forEncryption;
private byte[] iv;
/*============================================================================*/ /*============================================================================*/
private static boolean loaded; private static boolean loaded;
private long ctx;
private long pointer;
public static boolean isSupported() public static boolean isSupported()
{ {
@ -62,22 +59,18 @@ public class NativeCipher implements BungeeCipher
public void init(boolean forEncryption, SecretKey key) throws GeneralSecurityException public void init(boolean forEncryption, SecretKey key) throws GeneralSecurityException
{ {
Preconditions.checkArgument( key.getEncoded().length == 16, "Invalid key size" ); Preconditions.checkArgument( key.getEncoded().length == 16, "Invalid key size" );
if ( pointer != 0 ) free();
{
nativeCipher.free( pointer ); this.ctx = nativeCipher.init( forEncryption, key.getEncoded() );
}
this.forEncryption = forEncryption;
this.iv = key.getEncoded(); // initialize the IV
this.pointer = nativeCipher.init( key.getEncoded() );
} }
@Override @Override
public void free() public void free()
{ {
if ( pointer != 0 ) if ( ctx != 0 )
{ {
nativeCipher.free( pointer ); nativeCipher.free( ctx );
pointer = 0; ctx = 0;
} }
} }
@ -87,8 +80,7 @@ public class NativeCipher implements BungeeCipher
// Smoke tests // Smoke tests
in.memoryAddress(); in.memoryAddress();
out.memoryAddress(); out.memoryAddress();
Preconditions.checkState( pointer != 0, "Invalid pointer to AES key!" ); Preconditions.checkState( ctx != 0, "Invalid pointer to AES key!" );
Preconditions.checkState( iv != null, "Invalid IV!" );
// Store how many bytes we can cipher // Store how many bytes we can cipher
int length = in.readableBytes(); int length = in.readableBytes();
@ -96,7 +88,7 @@ public class NativeCipher implements BungeeCipher
out.ensureWritable( length ); out.ensureWritable( length );
// Cipher the bytes // 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 // Go to the end of the buffer, all bytes would of been read
in.readerIndex( in.writerIndex() ); in.readerIndex( in.writerIndex() );

View File

@ -3,30 +3,9 @@ package net.md_5.bungee;
class NativeCipherImpl class NativeCipherImpl
{ {
/** native long init(boolean forEncryption, byte[] key);
* Initializes the key.
*
* @param key the key to for encryption
* @return the pointer to key
*/
native long init(byte[] key);
/** native void free(long ctx);
* Frees the key.
*
* @param key the pointer to key
*/
native void free(long key);
/** native void cipher(long ctx, long in, long out, int length);
* 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);
} }