adds aes wrappers

pull/2/merge
Moisés Guimarães 2017-03-03 16:24:50 -07:00
parent 0c0c2c936e
commit efc7466c67
4 changed files with 428 additions and 8 deletions

View File

@ -29,6 +29,30 @@ extern "C" {
JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Aes_mallocNativeStruct
(JNIEnv *, jobject);
/*
* Class: com_wolfssl_wolfcrypt_Aes
* Method: wc_AesSetKey
* Signature: ([B[BI)V
*/
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Aes_wc_1AesSetKey
(JNIEnv *, jobject, jbyteArray, jbyteArray, jint);
/*
* Class: com_wolfssl_wolfcrypt_Aes
* Method: native_update
* Signature: (I[BII[BI)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Aes_native_1update__I_3BII_3BI
(JNIEnv *, jobject, jint, jbyteArray, jint, jint, jbyteArray, jint);
/*
* Class: com_wolfssl_wolfcrypt_Aes
* Method: native_update
* Signature: (ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Aes_native_1update__ILjava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2
(JNIEnv *, jobject, jint, jobject, jint, jint, jobject);
#ifdef __cplusplus
}
#endif

View File

@ -25,6 +25,7 @@
#include <wolfssl/wolfcrypt/aes.h>
#include <com_wolfssl_wolfcrypt_Aes.h>
#include <wolfcrypt_jni_NativeStruct.h>
#include <wolfcrypt_jni_error.h>
/* #define WOLFCRYPT_JNI_DEBUG_ON */
@ -35,18 +36,122 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Aes_mallocNativeStruct(
{
jlong ret = 0;
#ifdef NO_AES
throwNotCompiledInException(env);
#else
#ifndef NO_AES
ret = (jlong) XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (!ret)
throwOutOfMemoryException(env, "Failed to allocate Aes object");
LogStr("new Aes() = %p\n", ret);
LogStr("new Aes() = %p\n", (void*)ret);
#else
throwNotCompiledInException(env);
#endif
return ret;
}
JNIEXPORT void JNICALL
Java_com_wolfssl_wolfcrypt_Aes_wc_1AesSetKey(
JNIEnv* env, jobject this, jbyteArray key_object, jbyteArray iv_object,
jint opmode)
{
#ifndef NO_AES
int ret = 0;
Aes* aes = (Aes*) getNativeStruct(env, this);
byte* key = getByteArray(env, key_object);
byte* iv = getByteArray(env, iv_object);
word32 keySz = getByteArrayLength(env, key_object);
ret = wc_AesSetKey(aes, key, keySz, iv, opmode);
if (ret != 0)
throwWolfCryptExceptionFromError(env, ret);
LogStr("wc_AesSetKey(aes=%p, key, iv, opmode) = %d\n", aes, ret);
#else
throwNotCompiledInException(env);
#endif
}
JNIEXPORT jint JNICALL
Java_com_wolfssl_wolfcrypt_Aes_native_1update__I_3BII_3BI(
JNIEnv* env, jobject this, jint opmode,
jbyteArray input_object, jint offset, jint length,
jbyteArray output_object, jint outputOffset)
{
#ifndef NO_AES
int ret = 0;
Aes* aes = (Aes*) getNativeStruct(env, this);
byte* input = getByteArray(env, input_object);
byte* output = getByteArray(env, output_object);
if (opmode == AES_ENCRYPTION) {
ret = wc_AesCbcEncrypt(aes, output+outputOffset, input+offset, length);
LogStr("wc_AesCbcEncrypt(aes=%p, out, in, inSz) = %d\n", aes, ret);
}
else {
ret = wc_AesCbcDecrypt(aes, output+outputOffset, input+offset, length);
LogStr("wc_AesCbcDecrypt(aes=%p, out, in, inSz) = %d\n", aes, ret);
}
releaseByteArray(env, output_object, output, ret);
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
ret = 0; /* 0 bytes stored in output */
}
else {
ret = length;
}
LogStr("input[%u]: [%p]\n", (word32)length, input + offset);
LogHex((byte*) input + offset, length);
LogStr("output[%u]: [%p]\n", (word32)length, output + outputOffset);
LogHex((byte*) output + outputOffset, length);
#else
throwNotCompiledInException(env);
#endif
return ret;
}
JNIEXPORT jint JNICALL
Java_com_wolfssl_wolfcrypt_Aes_native_1update__ILjava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2(
JNIEnv* env, jobject this, jint opmode,
jobject input_object, jint offset, jint length,
jobject output_object)
{
int ret = 0;
#ifndef NO_AES
Aes* aes = (Aes*) getNativeStruct(env, this);
byte* input = getDirectBufferAddress(env, input_object);
byte* output = getDirectBufferAddress(env, output_object);
if (opmode == AES_ENCRYPTION) {
ret = wc_AesCbcEncrypt(aes, output, input + offset, length);
LogStr("wc_AesCbcEncrypt(aes=%p, out, in, inSz) = %d\n", aes, ret);
}
else {
ret = wc_AesCbcDecrypt(aes, output, input + offset, length);
LogStr("wc_AesCbcDecrypt(aes=%p, out, in, inSz) = %d\n", aes, ret);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
ret = 0; /* 0 bytes stored in output */
}
else {
ret = length;
}
LogStr("input[%u]: [%p]\n", (word32)length, input + offset);
LogHex((byte*) input + offset, length);
LogStr("output[%u]: [%p]\n", (word32)length, output);
LogHex((byte*) output, length);
#else
throwNotCompiledInException(env);
#endif
return ret;
}

View File

@ -21,11 +21,15 @@
package com.wolfssl.wolfcrypt;
import java.nio.ByteBuffer;
import javax.crypto.ShortBufferException;
/**
* Wrapper for the native WolfCrypt Aes implementation.
*
* @author Moisés Guimarães
* @version 1.0, February 2015
* @version 2.0, March 2017
*/
public class Aes extends NativeStruct {
@ -36,5 +40,83 @@ public class Aes extends NativeStruct {
public static final int ENCRYPT_MODE = 0;
public static final int DECRYPT_MODE = 1;
private WolfCryptState state = WolfCryptState.UNINITIALIZED;
private int opmode;
protected native long mallocNativeStruct() throws OutOfMemoryError;
private native void wc_AesSetKey(byte[] key, byte[] iv, int opmode);
private native int native_update(int opmode, byte[] input, int offset,
int length, byte[] output, int outputOffset);
private native int native_update(int opmode, ByteBuffer plain, int offset,
int length, ByteBuffer cipher);
public Aes() {
}
public Aes(byte[] key, byte[] iv, int opmode) {
setKey(key, iv, opmode);
}
public void setKey(byte[] key, byte[] iv, int opmode) {
wc_AesSetKey(key, iv, opmode);
this.opmode = opmode;
state = WolfCryptState.READY;
}
public byte[] update(byte[] input, int offset, int length) {
byte[] output;
if (state == WolfCryptState.READY) {
output = new byte[input.length];
native_update(opmode, input, offset, length, output, 0);
} else {
throw new IllegalStateException(
"No available key to perform the opperation.");
}
return output;
}
public int update(byte[] input, int offset, int length, byte[] output,
int outputOffset) throws ShortBufferException {
if (state == WolfCryptState.READY) {
if (outputOffset + length > output.length)
throw new ShortBufferException(
"output buffer is too small to hold the result.");
return native_update(opmode, input, offset, length, output,
outputOffset);
} else {
throw new IllegalStateException(
"No available key to perform the opperation.");
}
}
public int update(ByteBuffer input, ByteBuffer output)
throws ShortBufferException {
int ret = 0;
if (state == WolfCryptState.READY) {
if (output.remaining() < input.remaining())
throw new ShortBufferException(
"output buffer is too small to hold the result.");
ret = native_update(opmode, input, input.position(),
input.remaining(), output);
output.position(output.position() + input.remaining());
input.position(input.position() + input.remaining());
} else {
throw new IllegalStateException(
"No available key to perform the opperation.");
}
return ret;
}
}

View File

@ -23,15 +23,224 @@ package com.wolfssl.wolfcrypt;
import static org.junit.Assert.*;
import java.nio.ByteBuffer;
import javax.crypto.ShortBufferException;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.internal.runners.statements.Fail;
import com.wolfssl.wolfcrypt.Aes;
public class AesTest {
@BeforeClass
public static void checkAvailability() {
try {
new Aes();
} catch (WolfCryptException e) {
if (e.getError() == WolfCryptError.NOT_COMPILED_IN)
System.out.println("Aes test skipped: " + e.getError());
Assume.assumeNoException(e);
}
}
@Test
public void constructorShouldInitializeNativeStruct() {
assertNotEquals(NativeStruct.NULL, new Aes().getNativeStruct());
}
@Test(expected=ShortBufferException.class)
public void updateShouldMatchUsingByteByffer() throws ShortBufferException {
String[] keys = new String[] {
"2b7e151628aed2a6abf7158809cf4f3c",
"2b7e151628aed2a6abf7158809cf4f3c",
"2b7e151628aed2a6abf7158809cf4f3c",
"2b7e151628aed2a6abf7158809cf4f3c",
"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", };
String[] ivs = new String[] {
"000102030405060708090A0B0C0D0E0F",
"7649ABAC8119B246CEE98E9B12E9197D",
"5086CB9B507219EE95DB113A917678B2",
"73BED6B8E3C1743B7116E69E22229516",
"000102030405060708090A0B0C0D0E0F",
"4F021DB243BC633D7178183A9FA071E8",
"B4D9ADA9AD7DEDF4E5E738763F69145A",
"571B242012FB7AE07FA9BAAC3DF102E0",
"000102030405060708090A0B0C0D0E0F",
"F58C4C04D6E5F1BA779EABFB5F7BFBD6",
"9CFC4E967EDB808D679F777BC6702C7D",
"39F23369A9D9BACFA530E26304231461" };
String[] inputs = new String[] {
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710",
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710",
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710" };
String[] outputs = new String[] {
"7649abac8119b246cee98e9b12e9197d",
"5086cb9b507219ee95db113a917678b2",
"73bed6b8e3c1743b7116e69e22229516",
"3ff1caa1681fac09120eca307586e1a7",
"4f021db243bc633d7178183a9fa071e8",
"b4d9ada9ad7dedf4e5e738763f69145a",
"571b242012fb7ae07fa9baac3df102e0",
"08b0e27988598881d920a9e64f5615cd",
"f58c4c04d6e5f1ba779eabfb5f7bfbd6",
"9cfc4e967edb808d679f777bc6702c7d",
"39f23369a9d9bacfa530e26304231461",
"b2eb05e2c39be9fcda6c19078c6a9d1b" };
ByteBuffer input = ByteBuffer.allocateDirect(Aes.BLOCK_SIZE);
ByteBuffer output = ByteBuffer.allocateDirect(Aes.BLOCK_SIZE);
ByteBuffer plain = ByteBuffer.allocateDirect(Aes.BLOCK_SIZE);
ByteBuffer cipher = ByteBuffer.allocateDirect(Aes.BLOCK_SIZE);
for (int i = 0; i < inputs.length; i++) {
Aes enc = new Aes(Util.h2b(keys[i]), Util.h2b(ivs[i]),
Aes.ENCRYPT_MODE);
Aes dec = new Aes(Util.h2b(keys[i]), Util.h2b(ivs[i]),
Aes.DECRYPT_MODE);
input.put(Util.h2b(inputs[i])).rewind();
output.put(Util.h2b(outputs[i])).rewind();
try {
assertEquals(Aes.BLOCK_SIZE, enc.update(input, cipher));
assertEquals(Aes.BLOCK_SIZE, dec.update(output, plain));
} catch (ShortBufferException e) {
e.printStackTrace();
fail();
}
assertEquals(Aes.BLOCK_SIZE, input.position());
assertEquals(0, input.remaining());
assertEquals(Aes.BLOCK_SIZE, output.position());
assertEquals(0, output.remaining());
assertEquals(Aes.BLOCK_SIZE, cipher.position());
assertEquals(0, cipher.remaining());
assertEquals(Aes.BLOCK_SIZE, plain.position());
assertEquals(0, plain.remaining());
input.rewind();
output.rewind();
cipher.rewind();
plain.rewind();
assertEquals(output, cipher);
assertEquals(input, plain);
/* tests ShortBufferException */
if (i == inputs.length - 1) {
cipher.position(cipher.limit());
enc.update(input, cipher);
}
}
}
@Test(expected=ShortBufferException.class)
public void updateShouldMatchUsingByteArray() throws ShortBufferException {
String[] keys = new String[] {
"2b7e151628aed2a6abf7158809cf4f3c",
"2b7e151628aed2a6abf7158809cf4f3c",
"2b7e151628aed2a6abf7158809cf4f3c",
"2b7e151628aed2a6abf7158809cf4f3c",
"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", };
String[] ivs = new String[] {
"000102030405060708090A0B0C0D0E0F",
"7649ABAC8119B246CEE98E9B12E9197D",
"5086CB9B507219EE95DB113A917678B2",
"73BED6B8E3C1743B7116E69E22229516",
"000102030405060708090A0B0C0D0E0F",
"4F021DB243BC633D7178183A9FA071E8",
"B4D9ADA9AD7DEDF4E5E738763F69145A",
"571B242012FB7AE07FA9BAAC3DF102E0",
"000102030405060708090A0B0C0D0E0F",
"F58C4C04D6E5F1BA779EABFB5F7BFBD6",
"9CFC4E967EDB808D679F777BC6702C7D",
"39F23369A9D9BACFA530E26304231461" };
String[] inputs = new String[] {
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710",
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710",
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710" };
String[] outputs = new String[] {
"7649abac8119b246cee98e9b12e9197d",
"5086cb9b507219ee95db113a917678b2",
"73bed6b8e3c1743b7116e69e22229516",
"3ff1caa1681fac09120eca307586e1a7",
"4f021db243bc633d7178183a9fa071e8",
"b4d9ada9ad7dedf4e5e738763f69145a",
"571b242012fb7ae07fa9baac3df102e0",
"08b0e27988598881d920a9e64f5615cd",
"f58c4c04d6e5f1ba779eabfb5f7bfbd6",
"9cfc4e967edb808d679f777bc6702c7d",
"39f23369a9d9bacfa530e26304231461",
"b2eb05e2c39be9fcda6c19078c6a9d1b" };
for (int i = 0; i < inputs.length; i++) {
Aes enc = new Aes(Util.h2b(keys[i]), Util.h2b(ivs[i]),
Aes.ENCRYPT_MODE);
Aes dec = new Aes(Util.h2b(keys[i]), Util.h2b(ivs[i]),
Aes.DECRYPT_MODE);
byte[] input = Util.h2b(inputs[i]);
byte[] output = Util.h2b(outputs[i]);
byte[] cipher = new byte[Aes.BLOCK_SIZE];
byte[] plain = new byte[Aes.BLOCK_SIZE];
if (i % 2 == 0) {
cipher = enc.update(input, 0, input.length);
plain = dec.update(output, 0, output.length);
} else {
try {
assertEquals(Aes.BLOCK_SIZE,
enc.update(input, 0, input.length, cipher, 0));
assertEquals(Aes.BLOCK_SIZE,
dec.update(output, 0, output.length, plain, 0));
} catch (ShortBufferException e) {
e.printStackTrace();
fail();
}
}
assertArrayEquals(output, cipher);
assertArrayEquals(input, plain);
/* tests ShortBufferException */
if (i == inputs.length - 1)
enc.update(input, 0, input.length, cipher, Aes.BLOCK_SIZE);
}
}
}