Merge pull request #62 from cconlon/aesgcm
Add AES-GCM and Cipher AES/GCM/NoPadding Supportpull/64/head
commit
f256662464
|
@ -39,6 +39,7 @@ The JCE provider currently supports the following algorithms:
|
|||
Cipher Class
|
||||
AES/CBC/NoPadding
|
||||
AES/CBC/PKCS5Padding
|
||||
AES/GCM/NoPadding
|
||||
DESede/CBC/NoPadding
|
||||
RSA
|
||||
RSA/ECB/PKCS1Padding
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_wolfssl_wolfcrypt_AesGcm */
|
||||
|
||||
#ifndef _Included_com_wolfssl_wolfcrypt_AesGcm
|
||||
#define _Included_com_wolfssl_wolfcrypt_AesGcm
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#undef com_wolfssl_wolfcrypt_AesGcm_NULL
|
||||
#define com_wolfssl_wolfcrypt_AesGcm_NULL 0LL
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_AesGcm
|
||||
* Method: mallocNativeStruct_internal
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_mallocNativeStruct_1internal
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_AesGcm
|
||||
* Method: wc_AesInit
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesInit
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_AesGcm
|
||||
* Method: wc_AesFree
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesFree
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_AesGcm
|
||||
* Method: wc_AesGcmSetKey
|
||||
* Signature: ([B)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmSetKey
|
||||
(JNIEnv *, jobject, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_AesGcm
|
||||
* Method: wc_AesGcmEncrypt
|
||||
* Signature: ([B[B[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmEncrypt
|
||||
(JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_AesGcm
|
||||
* Method: wc_AesGcmDecrypt
|
||||
* Signature: ([B[B[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmDecrypt
|
||||
(JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -23,6 +23,14 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Md5Enabled
|
|||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_ShaEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: Sha224Enabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha224Enabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: Sha256Enabled
|
||||
|
@ -47,6 +55,62 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha384Enable
|
|||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha512Enabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: Aes128Enabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Aes128Enabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: Aes192Enabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Aes192Enabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: Aes256Enabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Aes256Enabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: AesCbcEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_AesCbcEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: AesGcmEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_AesGcmEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: AesGcmStreamEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_AesGcmStreamEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: Des3Enabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Des3Enabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: HmacMd5Enabled
|
||||
|
@ -87,6 +151,54 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_HmacSha384En
|
|||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_HmacSha512Enabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: RsaEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_RsaEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: RsaKeyGenEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_RsaKeyGenEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: DhEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_DhEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: EccEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_EccEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: EccKeyGenEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_EccKeyGenEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_wolfcrypt_FeatureDetect
|
||||
* Method: EccDheEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_EccDheEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,409 @@
|
|||
/* jni_aesgcm.c
|
||||
*
|
||||
* Copyright (C) 2006-2024 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef WOLFSSL_USER_SETTINGS
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#elif !defined(__ANDROID__)
|
||||
#include <wolfssl/options.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/aes.h>
|
||||
|
||||
#include <com_wolfssl_wolfcrypt_AesGcm.h>
|
||||
#include <wolfcrypt_jni_NativeStruct.h>
|
||||
#include <wolfcrypt_jni_error.h>
|
||||
|
||||
/* #define WOLFCRYPT_JNI_DEBUG_ON */
|
||||
#include <wolfcrypt_jni_debug.h>
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_mallocNativeStruct_1internal
|
||||
(JNIEnv* env, jobject this)
|
||||
{
|
||||
#ifndef NO_AES
|
||||
Aes* aes = NULL;
|
||||
(void)this;
|
||||
|
||||
aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (aes == NULL) {
|
||||
throwOutOfMemoryException(env, "Failed to allocate Aes object");
|
||||
}
|
||||
else {
|
||||
XMEMSET(aes, 0, sizeof(Aes));
|
||||
}
|
||||
|
||||
LogStr("new AesGcm() = %p\n", aes);
|
||||
|
||||
return (jlong)(uintptr_t)aes;
|
||||
#else
|
||||
(void)this;
|
||||
throwNotCompiledInException(env);
|
||||
return (jlong)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesInit
|
||||
(JNIEnv* env, jobject this)
|
||||
{
|
||||
#ifndef NO_AES
|
||||
int ret = 0;
|
||||
Aes* aes = NULL;
|
||||
(void)this;
|
||||
|
||||
aes = (Aes*) getNativeStruct(env, this);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
/* getNativeStruct may throw exception, if so stop and return */
|
||||
return;
|
||||
}
|
||||
|
||||
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
|
||||
if (ret != 0) {
|
||||
throwWolfCryptExceptionFromError(env, ret);
|
||||
}
|
||||
|
||||
LogStr("wc_AesInit(aes=%p)\n", aes);
|
||||
#else
|
||||
(void)this;
|
||||
throwNotCompiledInException(env);
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesFree
|
||||
(JNIEnv* env, jobject this)
|
||||
{
|
||||
#ifndef NO_AES
|
||||
Aes* aes = NULL;
|
||||
(void)this;
|
||||
|
||||
aes = (Aes*) getNativeStruct(env, this);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
/* getNativeStruct may throw exception, if so stop and return */
|
||||
return;
|
||||
}
|
||||
|
||||
wc_AesFree(aes);
|
||||
|
||||
LogStr("wc_AesFree(aes=%p)\n", aes);
|
||||
#else
|
||||
(void)this;
|
||||
throwNotCompiledInException(env);
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmSetKey
|
||||
(JNIEnv* env, jobject this, jbyteArray keyArr)
|
||||
{
|
||||
#if !defined(NO_AES) && defined(HAVE_AESGCM)
|
||||
int ret = 0;
|
||||
Aes* aes = NULL;
|
||||
const byte* key = NULL;
|
||||
word32 keyLen = 0;
|
||||
|
||||
aes = (Aes*) getNativeStruct(env, this);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
/* getNativeStruct may throw exception, if so stop and return */
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyArr != NULL) {
|
||||
key = (const byte*)(*env)->GetByteArrayElements(env, keyArr, NULL);
|
||||
keyLen = (*env)->GetArrayLength(env, keyArr);
|
||||
}
|
||||
|
||||
if (key == NULL || keyLen == 0) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = wc_AesGcmSetKey(aes, key, keyLen);
|
||||
}
|
||||
|
||||
if (keyArr != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, keyArr, (jbyte*)key, JNI_ABORT);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
throwWolfCryptExceptionFromError(env, ret);
|
||||
}
|
||||
|
||||
LogStr("wc_AesGcmSetKey(aes = %p, keylen = %d)\n", aes, keyLen);
|
||||
#else
|
||||
(void)this;
|
||||
throwNotCompiledInException(env);
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmEncrypt
|
||||
(JNIEnv* env, jobject this, jbyteArray inputArr, jbyteArray ivArr, jbyteArray authTagArr, jbyteArray authInArr)
|
||||
{
|
||||
#if !defined(NO_AES) && defined(HAVE_AESGCM)
|
||||
int ret = 0;
|
||||
Aes* aes = NULL;
|
||||
const byte* in = NULL;
|
||||
const byte* iv = NULL;
|
||||
byte* authTag = NULL;
|
||||
const byte* authIn = NULL;
|
||||
word32 inLen = 0;
|
||||
word32 ivSz = 0;
|
||||
word32 authTagSz = 0;
|
||||
word32 authInSz = 0;
|
||||
|
||||
byte* out = NULL;
|
||||
jbyteArray outArr = NULL;
|
||||
|
||||
aes = (Aes*) getNativeStruct(env, this);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
/* getNativeStruct may throw exception, if so stop and return */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (inputArr != NULL) {
|
||||
in = (const byte*)(*env)->GetByteArrayElements(env, inputArr, NULL);
|
||||
inLen = (*env)->GetArrayLength(env, inputArr);
|
||||
}
|
||||
if (ivArr != NULL) {
|
||||
iv = (byte*)(*env)->GetByteArrayElements(env, ivArr, NULL);
|
||||
ivSz = (*env)->GetArrayLength(env, ivArr);
|
||||
}
|
||||
if (authTagArr != NULL) {
|
||||
authTag = (byte*)(*env)->GetByteArrayElements(env, authTagArr, NULL);
|
||||
authTagSz = (*env)->GetArrayLength(env, authTagArr);
|
||||
}
|
||||
if (authInArr != NULL) {
|
||||
authIn = (byte*)(*env)->GetByteArrayElements(env, authInArr, NULL);
|
||||
authInSz = (*env)->GetArrayLength(env, authInArr);
|
||||
}
|
||||
|
||||
/* authIn can be null */
|
||||
if (in == NULL || inLen == 0 || iv == NULL || ivSz == 0 ||
|
||||
authTag == NULL || authTagSz == 0) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* Allocate new buffer to hold ciphertext */
|
||||
if (ret == 0) {
|
||||
out = (byte*)XMALLOC(inLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (out == NULL) {
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
else {
|
||||
XMEMSET(out, 0, inLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = wc_AesGcmEncrypt(aes, out, in, inLen, iv, ivSz,
|
||||
authTag, authTagSz, authIn, authInSz);
|
||||
}
|
||||
|
||||
/* Create new jbyteArray to return output */
|
||||
if (ret == 0) {
|
||||
outArr = (*env)->NewByteArray(env, inLen);
|
||||
if (outArr == NULL) {
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
else {
|
||||
(*env)->SetByteArrayRegion(env, outArr, 0, inLen, (jbyte*)out);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
(*env)->DeleteLocalRef(env, outArr);
|
||||
outArr = NULL;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Commit authTag changes back to original Java array on success */
|
||||
if (authTagArr != NULL) {
|
||||
if (ret == 0) {
|
||||
(*env)->ReleaseByteArrayElements(env, authTagArr,
|
||||
(jbyte*)authTag, JNI_COMMIT);
|
||||
}
|
||||
else {
|
||||
(*env)->ReleaseByteArrayElements(env, authTagArr,
|
||||
(jbyte*)authTag, JNI_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Release all other byte arrays without changing original arrays */
|
||||
if (inputArr != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, inputArr, (jbyte*)in,
|
||||
JNI_ABORT);
|
||||
}
|
||||
if (ivArr != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, ivArr, (jbyte*)iv,
|
||||
JNI_ABORT);
|
||||
}
|
||||
if (authInArr != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, authInArr, (jbyte*)authIn,
|
||||
JNI_ABORT);
|
||||
}
|
||||
|
||||
if (out != NULL) {
|
||||
XFREE(out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
|
||||
LogStr("wc_AesGcmEncrypt(aes = %p, inLen = %d, ivSz = %d, "
|
||||
"authTagSz = %d, authInSz = %d)\n", aes, inLen, ivSz,
|
||||
authTagSz, authInSz);
|
||||
|
||||
if (ret != 0) {
|
||||
throwWolfCryptExceptionFromError(env, ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return outArr;
|
||||
|
||||
#else
|
||||
(void)this;
|
||||
(void)input;
|
||||
(void)iv;
|
||||
(void)authTag;
|
||||
(void)authIn;
|
||||
throwNotCompiledInException(env);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmDecrypt
|
||||
(JNIEnv* env, jobject this, jbyteArray inputArr, jbyteArray ivArr, jbyteArray authTagArr, jbyteArray authInArr)
|
||||
{
|
||||
#if !defined(NO_AES) && defined(HAVE_AESGCM)
|
||||
int ret = 0;
|
||||
Aes* aes = NULL;
|
||||
const byte* in = NULL;
|
||||
const byte* iv = NULL;
|
||||
const byte* authTag = NULL;
|
||||
const byte* authIn = NULL;
|
||||
word32 inLen = 0;
|
||||
word32 ivSz = 0;
|
||||
word32 authTagSz = 0;
|
||||
word32 authInSz = 0;
|
||||
|
||||
byte* out = NULL;
|
||||
jbyteArray outArr = NULL;
|
||||
|
||||
aes = (Aes*) getNativeStruct(env, this);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
/* getNativeStruct may throw exception, if so stop and return */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (inputArr != NULL) {
|
||||
in = (byte*)(*env)->GetByteArrayElements(env, inputArr, NULL);
|
||||
inLen = (*env)->GetArrayLength(env, inputArr);
|
||||
}
|
||||
if (ivArr != NULL) {
|
||||
iv = (byte*)(*env)->GetByteArrayElements(env, ivArr, NULL);
|
||||
ivSz = (*env)->GetArrayLength(env, ivArr);
|
||||
}
|
||||
if (authTagArr != NULL) {
|
||||
authTag = (byte*)(*env)->GetByteArrayElements(env, authTagArr, NULL);
|
||||
authTagSz = (*env)->GetArrayLength(env, authTagArr);
|
||||
}
|
||||
if (authInArr != NULL) {
|
||||
authIn = (byte*)(*env)->GetByteArrayElements(env, authInArr, NULL);
|
||||
authInSz = (*env)->GetArrayLength(env, authInArr);
|
||||
}
|
||||
|
||||
if (in == NULL || inLen == 0 || iv == NULL || ivSz == 0 ||
|
||||
authTag == NULL || authTagSz == 0) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
out = (byte*)XMALLOC(inLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (out == NULL) {
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
else {
|
||||
XMEMSET(out, 0, inLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = wc_AesGcmDecrypt(aes, out, in, inLen, iv, ivSz,
|
||||
authTag, authTagSz, authIn, authInSz);
|
||||
}
|
||||
|
||||
/* Create new jbyteArray to return output */
|
||||
if (ret == 0) {
|
||||
outArr = (*env)->NewByteArray(env, inLen);
|
||||
if (outArr == NULL) {
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
else {
|
||||
(*env)->SetByteArrayRegion(env, outArr, 0, inLen, (jbyte*)out);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
(*env)->DeleteLocalRef(env, outArr);
|
||||
outArr = NULL;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Release all byte arrays without changing original arrays */
|
||||
if (inputArr != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, inputArr, (jbyte*)in,
|
||||
JNI_ABORT);
|
||||
}
|
||||
if (ivArr != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, ivArr, (jbyte*)iv,
|
||||
JNI_ABORT);
|
||||
}
|
||||
if (authInArr != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, authInArr, (jbyte*)authIn,
|
||||
JNI_ABORT);
|
||||
}
|
||||
if (authTagArr != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, authTagArr, (jbyte*)authTag,
|
||||
JNI_ABORT);
|
||||
}
|
||||
|
||||
if (out != NULL) {
|
||||
XMEMSET(out, 0, inLen);
|
||||
XFREE(out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
|
||||
LogStr("wc_AesGcmDecrypt(aes = %p, inLen = %d, ivSz = %d, "
|
||||
"authTagSz = %d, authInSz = %d)\n", aes, inLen, ivSz,
|
||||
authTagSz, authInSz);
|
||||
|
||||
if (ret != 0) {
|
||||
throwWolfCryptExceptionFromError(env, ret);
|
||||
}
|
||||
|
||||
return outArr;
|
||||
|
||||
#else
|
||||
(void)this;
|
||||
(void)input;
|
||||
(void)iv;
|
||||
(void)authTag;
|
||||
(void)authIn;
|
||||
throwNotCompiledInException(env);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -52,6 +52,18 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_ShaEnabled
|
|||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha224Enabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#ifdef WOLFSSL_SHA224
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha256Enabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
|
@ -88,6 +100,90 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha512Enable
|
|||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Aes128Enabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if !defined(NO_AES) && defined(WOLFSSL_AES_128)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Aes192Enabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if !defined(NO_AES) && defined(WOLFSSL_AES_192)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Aes256Enabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if !defined(NO_AES) && defined(WOLFSSL_AES_256)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_AesCbcEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if !defined(NO_AES) && defined(HAVE_AES_CBC)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_AesGcmEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if !defined(NO_AES) && defined(HAVE_AESGCM)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_AesGcmStreamEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if !defined(NO_AES) && defined(WOLFSSL_AESGCM_STREAM)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Des3Enabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#ifndef NO_DES3
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_HmacMd5Enabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
|
@ -148,3 +244,75 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_HmacSha512En
|
|||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_RsaEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#ifndef NO_RSA
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_RsaKeyGenEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_DhEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#ifndef NO_DH
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_EccEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#ifdef HAVE_ECC
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_EccKeyGenEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if defined(HAVE_ECC) && defined(WOLFSSL_KEY_GEN)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_EccDheEnabled
|
||||
(JNIEnv* env, jclass jcl)
|
||||
{
|
||||
(void)env;
|
||||
(void)jcl;
|
||||
#if defined(HAVE_ECC) && defined(HAVE_ECC_DHE)
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,10 @@ endif
|
|||
DIST_FILES = AUTHORS build.xml COPYING examples jni LICENSING makefile makefile.linux makefile.macosx \
|
||||
pom.xml README_JCE.md README.md rpm src
|
||||
|
||||
OBJ_LIST = jni_fips.o jni_native_struct.o jni_aes.o jni_des3.o jni_md5.o \
|
||||
jni_sha.o jni_hmac.o jni_rng.o jni_rsa.o jni_dh.o jni_ecc.o \
|
||||
jni_ed25519.o jni_curve25519.o jni_chacha.o jni_error.o jni_asn.o \
|
||||
jni_logging.o jni_feature_detect.o jni_wolfobject.o
|
||||
OBJ_LIST = jni_fips.o jni_native_struct.o jni_aes.o jni_aesgcm.o jni_des3.o \
|
||||
jni_md5.o jni_sha.o jni_hmac.o jni_rng.o jni_rsa.o jni_dh.o \
|
||||
jni_ecc.o jni_ed25519.o jni_curve25519.o jni_chacha.o jni_error.o \
|
||||
jni_asn.o jni_logging.o jni_feature_detect.o jni_wolfobject.o
|
||||
OBJS = $(patsubst %,$(OUT_PATH)/%,$(OBJ_LIST))
|
||||
TARGET = $(OUT_PATH)/libwolfcryptjni.so
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ OUT_PATH = lib
|
|||
SRC_PATH = jni
|
||||
INC_PATH = $(SRC_PATH)/include
|
||||
|
||||
OBJ_LIST = jni_fips.o jni_native_struct.o jni_aes.o jni_des3.o jni_md5.o \
|
||||
jni_sha.o jni_hmac.o jni_rng.o jni_rsa.o jni_dh.o jni_ecc.o \
|
||||
jni_ed25519.o jni_curve25519.o jni_chacha.o jni_error.o jni_asn.o \
|
||||
jni_logging.o jni_feature_detect.o jni_wolfobject.o
|
||||
OBJ_LIST = jni_fips.o jni_native_struct.o jni_aes.o jni_aesgcm.o jni_des3.o \
|
||||
jni_md5.o jni_sha.o jni_hmac.o jni_rng.o jni_rsa.o jni_dh.o \
|
||||
jni_ecc.o jni_ed25519.o jni_curve25519.o jni_chacha.o jni_error.o \
|
||||
jni_asn.o jni_logging.o jni_feature_detect.o jni_wolfobject.o
|
||||
OBJS = $(patsubst %,$(OUT_PATH)/%,$(OBJ_LIST))
|
||||
TARGET = $(OUT_PATH)/libwolfcryptjni.dylib
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
infer run -- javac \
|
||||
src/main/java/com/wolfssl/wolfcrypt/Aes.java \
|
||||
src/main/java/com/wolfssl/wolfcrypt/AesGcm.java \
|
||||
src/main/java/com/wolfssl/wolfcrypt/Asn.java \
|
||||
src/main/java/com/wolfssl/wolfcrypt/BlockCipher.java \
|
||||
src/main/java/com/wolfssl/wolfcrypt/Chacha.java \
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
package com.wolfssl.provider.jce;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherSpi;
|
||||
|
@ -31,6 +32,7 @@ import javax.crypto.ShortBufferException;
|
|||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.security.AlgorithmParameters;
|
||||
|
@ -46,6 +48,7 @@ import java.security.interfaces.RSAPublicKey;
|
|||
import com.wolfssl.wolfcrypt.WolfCrypt;
|
||||
import com.wolfssl.wolfcrypt.Asn;
|
||||
import com.wolfssl.wolfcrypt.Aes;
|
||||
import com.wolfssl.wolfcrypt.AesGcm;
|
||||
import com.wolfssl.wolfcrypt.Des3;
|
||||
import com.wolfssl.wolfcrypt.Rsa;
|
||||
import com.wolfssl.wolfcrypt.Rng;
|
||||
|
@ -65,7 +68,8 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
|
||||
enum CipherMode {
|
||||
WC_ECB,
|
||||
WC_CBC
|
||||
WC_CBC,
|
||||
WC_GCM
|
||||
}
|
||||
|
||||
enum PaddingType {
|
||||
|
@ -92,10 +96,11 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
|
||||
private int blockSize = 0;
|
||||
|
||||
private Aes aes = null;
|
||||
private Des3 des3 = null;
|
||||
private Rsa rsa = null;
|
||||
private Rng rng = null;
|
||||
private Aes aes = null;
|
||||
private AesGcm aesGcm = null;
|
||||
private Des3 des3 = null;
|
||||
private Rsa rsa = null;
|
||||
private Rng rng = null;
|
||||
|
||||
/* for debug logging */
|
||||
private WolfCryptDebug debug;
|
||||
|
@ -107,6 +112,18 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
private AlgorithmParameterSpec storedSpec = null;
|
||||
private byte[] iv = null;
|
||||
|
||||
/* AES-GCM tag length (bytes) */
|
||||
private int gcmTagLen = 0;
|
||||
|
||||
/* AAD data for AES-GCM, populated via engineUpdateAAD() */
|
||||
private byte[] aadData = null;
|
||||
|
||||
/* Has update/final been called yet, gates setting of AAD for GCM */
|
||||
private boolean operationStarted = false;
|
||||
|
||||
/* Has this Cipher been inintialized? */
|
||||
private boolean cipherInitialized = false;
|
||||
|
||||
/* buffered data from update calls */
|
||||
private byte[] buffered = new byte[0];
|
||||
|
||||
|
@ -122,19 +139,12 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
|
||||
switch (cipherType) {
|
||||
case WC_AES:
|
||||
aes = new Aes();
|
||||
blockSize = Aes.BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case WC_DES3:
|
||||
des3 = new Des3();
|
||||
blockSize = Des3.BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case WC_RSA:
|
||||
rsa = new Rsa();
|
||||
rsa.setRng(this.rng);
|
||||
break;
|
||||
}
|
||||
|
||||
if (debug.DEBUG) {
|
||||
|
@ -143,6 +153,48 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset / re-create internal native struct for algorithm.
|
||||
* Should be called during wolfCryptInit() and wolfCryptFinal()
|
||||
*/
|
||||
private void InitializeNativeStructs() {
|
||||
switch (this.cipherType) {
|
||||
case WC_AES:
|
||||
if (cipherMode == CipherMode.WC_CBC) {
|
||||
if (aes != null) {
|
||||
aes.releaseNativeStruct();
|
||||
aes = null;
|
||||
}
|
||||
aes = new Aes();
|
||||
}
|
||||
else if (cipherMode == CipherMode.WC_GCM) {
|
||||
if (aesGcm != null) {
|
||||
aesGcm.releaseNativeStruct();
|
||||
aesGcm = null;
|
||||
}
|
||||
aesGcm = new AesGcm();
|
||||
}
|
||||
break;
|
||||
|
||||
case WC_DES3:
|
||||
if (des3 != null) {
|
||||
des3.releaseNativeStruct();
|
||||
des3 = null;
|
||||
}
|
||||
des3 = new Des3();
|
||||
break;
|
||||
|
||||
case WC_RSA:
|
||||
if (rsa != null) {
|
||||
rsa.releaseNativeStruct();
|
||||
rsa = null;
|
||||
}
|
||||
rsa = new Rsa();
|
||||
rsa.setRng(this.rng);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineSetMode(String mode)
|
||||
throws NoSuchAlgorithmException {
|
||||
|
@ -156,8 +208,9 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
cipherMode = CipherMode.WC_ECB;
|
||||
supported = 1;
|
||||
|
||||
if (debug.DEBUG)
|
||||
if (debug.DEBUG) {
|
||||
log("set mode to ECB");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mode.equals("CBC")) {
|
||||
|
@ -168,14 +221,28 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
cipherMode = CipherMode.WC_CBC;
|
||||
supported = 1;
|
||||
|
||||
if (debug.DEBUG)
|
||||
if (debug.DEBUG) {
|
||||
log("set mode to CBC");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mode.equals("GCM")) {
|
||||
|
||||
/* AES supports GCM */
|
||||
if (cipherType == CipherType.WC_AES) {
|
||||
cipherMode = CipherMode.WC_GCM;
|
||||
supported = 1;
|
||||
|
||||
if (debug.DEBUG) {
|
||||
log("set mode to GCM");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (supported == 0) {
|
||||
throw new NoSuchAlgorithmException(
|
||||
"Unsupported cipher mode for active algorithm choice");
|
||||
"Unsupported cipher mode for active algorithm choice: " +
|
||||
mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,8 +259,9 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
paddingType = PaddingType.WC_NONE;
|
||||
supported = 1;
|
||||
|
||||
if (debug.DEBUG)
|
||||
if (debug.DEBUG) {
|
||||
log("set padding to NoPadding");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (padding.equals("PKCS1Padding")) {
|
||||
|
@ -202,24 +270,29 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
paddingType = PaddingType.WC_PKCS1;
|
||||
supported = 1;
|
||||
|
||||
if (debug.DEBUG)
|
||||
if (debug.DEBUG) {
|
||||
log("set padding to PKCS1Padding");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (padding.equals("PKCS5Padding")) {
|
||||
|
||||
if (cipherType == CipherType.WC_AES) {
|
||||
if ((cipherType == CipherType.WC_AES) &&
|
||||
(cipherMode == CipherMode.WC_CBC)) {
|
||||
|
||||
paddingType = PaddingType.WC_PKCS5;
|
||||
supported = 1;
|
||||
|
||||
if (debug.DEBUG)
|
||||
if (debug.DEBUG) {
|
||||
log("set padding to PKCS5Padding");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (supported == 0) {
|
||||
throw new NoSuchPaddingException(
|
||||
"Unsupported padding type for active algorithm choice");
|
||||
"Unsupported padding type for active algorithm choice: " +
|
||||
padding);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,12 +307,24 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
|
||||
int size = 0;
|
||||
|
||||
if (!this.cipherInitialized) {
|
||||
throw new IllegalStateException(
|
||||
"Cipher has not been initialized yet");
|
||||
}
|
||||
|
||||
switch (this.cipherType) {
|
||||
case WC_AES:
|
||||
if (paddingType == PaddingType.WC_NONE) {
|
||||
/* wolfCrypt expects input to be padded by application to
|
||||
* block size, thus output is same size as input */
|
||||
size = inputLen;
|
||||
if (cipherMode == CipherMode.WC_GCM) {
|
||||
/* In AES-GCM mode we append the authentication tag
|
||||
* to the end of ciphertext */
|
||||
size = inputLen + this.gcmTagLen;
|
||||
}
|
||||
else {
|
||||
/* wolfCrypt expects input to be padded by application to
|
||||
* block size, thus output is same size as input */
|
||||
size = inputLen;
|
||||
}
|
||||
}
|
||||
else if (paddingType == PaddingType.WC_PKCS5) {
|
||||
size = buffered.length + inputLen;
|
||||
|
@ -330,21 +415,48 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
}
|
||||
|
||||
} else {
|
||||
if (!(spec instanceof IvParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"AlgorithmParameterSpec must be of type IvParameterSpec");
|
||||
if (cipherMode == CipherMode.WC_GCM) {
|
||||
if (!(spec instanceof GCMParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"AlgorithmParameterSpec must be of type " +
|
||||
"GCMParameterSpec");
|
||||
}
|
||||
|
||||
GCMParameterSpec gcmSpec = (GCMParameterSpec)spec;
|
||||
|
||||
if (gcmSpec.getIV() == null ||
|
||||
gcmSpec.getIV().length == 0) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"AES-GCM IV is null or 0 length");
|
||||
}
|
||||
|
||||
this.iv = gcmSpec.getIV().clone();
|
||||
|
||||
/* store tag length as bytes */
|
||||
if (gcmSpec.getTLen() == 0) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Tag length cannot be zero");
|
||||
}
|
||||
this.gcmTagLen = (gcmSpec.getTLen() / 8);
|
||||
}
|
||||
else {
|
||||
if (!(spec instanceof IvParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"AlgorithmParameterSpec must be of type " +
|
||||
"IvParameterSpec");
|
||||
}
|
||||
|
||||
IvParameterSpec ivSpec = (IvParameterSpec)spec;
|
||||
IvParameterSpec ivSpec = (IvParameterSpec)spec;
|
||||
|
||||
/* IV should be of block size length */
|
||||
if (ivSpec.getIV().length != this.blockSize) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Bad IV length (" + ivSpec.getIV().length +
|
||||
"), must be " + blockSize + " bytes long");
|
||||
/* IV should be of block size length */
|
||||
if (ivSpec.getIV().length != this.blockSize) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Bad IV length (" + ivSpec.getIV().length +
|
||||
"), must be " + blockSize + " bytes long");
|
||||
}
|
||||
|
||||
this.iv = ivSpec.getIV().clone();
|
||||
}
|
||||
|
||||
this.iv = ivSpec.getIV();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,15 +492,26 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
|
||||
/* import key */
|
||||
encodedKey = key.getEncoded();
|
||||
if (encodedKey == null)
|
||||
if (encodedKey == null) {
|
||||
throw new InvalidKeyException("Key does not support encoding");
|
||||
}
|
||||
|
||||
switch (cipherType) {
|
||||
case WC_AES:
|
||||
if (this.direction == OpMode.WC_ENCRYPT) {
|
||||
this.aes.setKey(encodedKey, iv, Aes.ENCRYPT_MODE);
|
||||
if (cipherMode == CipherMode.WC_GCM) {
|
||||
this.aesGcm.setKey(encodedKey);
|
||||
}
|
||||
else {
|
||||
this.aes.setKey(encodedKey, iv, Aes.ENCRYPT_MODE);
|
||||
}
|
||||
} else {
|
||||
this.aes.setKey(encodedKey, iv, Aes.DECRYPT_MODE);
|
||||
if (cipherMode == CipherMode.WC_GCM) {
|
||||
this.aesGcm.setKey(encodedKey);
|
||||
}
|
||||
else {
|
||||
this.aes.setKey(encodedKey, iv, Aes.DECRYPT_MODE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -425,9 +548,12 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
AlgorithmParameterSpec spec, SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
|
||||
InitializeNativeStructs();
|
||||
wolfCryptSetDirection(opmode);
|
||||
wolfCryptSetIV(spec, random);
|
||||
wolfCryptSetKey(key);
|
||||
this.operationStarted = false;
|
||||
this.cipherInitialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -438,8 +564,9 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
|
||||
wolfCryptCipherInit(opmode, key, null, random);
|
||||
|
||||
if (debug.DEBUG)
|
||||
if (debug.DEBUG) {
|
||||
log("initialized with key");
|
||||
}
|
||||
|
||||
} catch (InvalidAlgorithmParameterException iape) {
|
||||
throw new InvalidKeyException("Invalid algorithm parameters");
|
||||
|
@ -453,8 +580,9 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
|
||||
wolfCryptCipherInit(opmode, key, params, random);
|
||||
|
||||
if (debug.DEBUG)
|
||||
if (debug.DEBUG) {
|
||||
log("initialized with key and AlgorithmParameterSpec");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -466,10 +594,16 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
|
||||
try {
|
||||
|
||||
spec = params.getParameterSpec(IvParameterSpec.class);
|
||||
if (this.cipherMode == CipherMode.WC_GCM) {
|
||||
spec = params.getParameterSpec(GCMParameterSpec.class);
|
||||
}
|
||||
else {
|
||||
spec = params.getParameterSpec(IvParameterSpec.class);
|
||||
}
|
||||
|
||||
if (debug.DEBUG)
|
||||
if (debug.DEBUG) {
|
||||
log("initialized with key and AlgorithmParameters");
|
||||
}
|
||||
|
||||
} catch (InvalidParameterSpecException ipe) {
|
||||
throw new InvalidAlgorithmParameterException(ipe);
|
||||
|
@ -490,6 +624,7 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
break;
|
||||
default:
|
||||
isBlockCipher = false;
|
||||
break;
|
||||
};
|
||||
|
||||
return isBlockCipher;
|
||||
|
@ -500,16 +635,19 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
private int isValidBlockLength(int length) {
|
||||
|
||||
/* skip if not a block cipher */
|
||||
if (isBlockCipher() == false)
|
||||
if (isBlockCipher() == false) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((length % this.blockSize) != 0)
|
||||
if ((length % this.blockSize) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private byte[] wolfCryptUpdate(byte[] input, int inputOffset, int len) {
|
||||
private byte[] wolfCryptUpdate(byte[] input, int inputOffset, int len)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
int blocks = 0;
|
||||
int remaining = 0;
|
||||
|
@ -521,6 +659,8 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
if (input == null || len < 0)
|
||||
throw new IllegalArgumentException("Null input buffer or len < 0");
|
||||
|
||||
this.operationStarted = true;
|
||||
|
||||
if ((buffered.length + len) == 0) {
|
||||
/* no data to process */
|
||||
return null;
|
||||
|
@ -534,9 +674,12 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
buffered = tmpIn;
|
||||
}
|
||||
|
||||
/* keep buffered data if RSA or data is less than block size */
|
||||
if (cipherType == CipherType.WC_RSA ||
|
||||
buffered.length < blockSize) {
|
||||
/* keep buffered data if RSA or data is less than block size, or doing
|
||||
* AES-GCM without stream mode compiled natively */
|
||||
if ((cipherType == CipherType.WC_RSA) ||
|
||||
((cipherType == CipherType.WC_AES) &&
|
||||
(cipherMode == CipherMode.WC_GCM)) ||
|
||||
(buffered.length < blockSize)) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
|
@ -568,6 +711,8 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
/* process tmpIn[] */
|
||||
switch (this.cipherType) {
|
||||
|
||||
/* Only CBC mode reaches this point currently, GCM caches all
|
||||
* data internally above until final call */
|
||||
case WC_AES:
|
||||
output = this.aes.update(tmpIn, 0, tmpIn.length);
|
||||
|
||||
|
@ -603,9 +748,12 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
byte tmpIn[] = null;
|
||||
byte tmpOut[] = null;
|
||||
|
||||
this.operationStarted = true;
|
||||
totalSz = buffered.length + len;
|
||||
|
||||
/* AES-GCM does not require block size inputs */
|
||||
if (isBlockCipher() &&
|
||||
(cipherMode != CipherMode.WC_GCM) &&
|
||||
(this.direction == OpMode.WC_DECRYPT ||
|
||||
(this.direction == OpMode.WC_ENCRYPT &&
|
||||
this.paddingType != PaddingType.WC_PKCS5)) &&
|
||||
|
@ -636,10 +784,39 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
switch (this.cipherType) {
|
||||
|
||||
case WC_AES:
|
||||
tmpOut = this.aes.update(tmpIn, 0, tmpIn.length);
|
||||
if (cipherMode == CipherMode.WC_GCM) {
|
||||
if (this.direction == OpMode.WC_ENCRYPT) {
|
||||
byte[] tag = new byte[this.gcmTagLen];
|
||||
tmpOut = this.aesGcm.encrypt(tmpIn, this.iv, tag,
|
||||
this.aadData);
|
||||
|
||||
/* truncate */
|
||||
tmpOut = Arrays.copyOfRange(tmpOut, 0, tmpIn.length);
|
||||
/* Concatenate auth tag to end of ciphertext */
|
||||
byte[] totalOut = new byte[tmpOut.length + tag.length];
|
||||
System.arraycopy(tmpOut, 0, totalOut, 0, tmpOut.length);
|
||||
System.arraycopy(tag, 0, totalOut, tmpOut.length,
|
||||
tag.length);
|
||||
tmpOut = totalOut;
|
||||
}
|
||||
else {
|
||||
/* Get auth tag from end of ciphertext */
|
||||
byte[] tag = Arrays.copyOfRange(tmpIn,
|
||||
tmpIn.length - this.gcmTagLen,
|
||||
tmpIn.length);
|
||||
|
||||
/* Shrink ciphertext array down to not include tag */
|
||||
tmpIn = Arrays.copyOfRange(tmpIn, 0,
|
||||
tmpIn.length - this.gcmTagLen);
|
||||
|
||||
tmpOut = this.aesGcm.decrypt(tmpIn, this.iv, tag,
|
||||
this.aadData);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmpOut = this.aes.update(tmpIn, 0, tmpIn.length);
|
||||
|
||||
/* truncate */
|
||||
tmpOut = Arrays.copyOfRange(tmpOut, 0, tmpIn.length);
|
||||
}
|
||||
|
||||
/* strip PKCS#5/PKCS#7 padding if required */
|
||||
if (this.direction == OpMode.WC_DECRYPT &&
|
||||
|
@ -690,15 +867,21 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
/* reset state, user doesn't need to call init again before use */
|
||||
try {
|
||||
buffered = new byte[0];
|
||||
|
||||
if (this.direction == OpMode.WC_ENCRYPT) {
|
||||
wolfCryptSetDirection(Cipher.ENCRYPT_MODE);
|
||||
} else {
|
||||
wolfCryptSetDirection(Cipher.DECRYPT_MODE);
|
||||
}
|
||||
|
||||
InitializeNativeStructs();
|
||||
wolfCryptSetIV(storedSpec, null);
|
||||
wolfCryptSetKey(storedKey);
|
||||
|
||||
this.aadData = null;
|
||||
this.operationStarted = false;
|
||||
this.cipherInitialized = true;
|
||||
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
|
@ -709,10 +892,16 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
|
||||
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen)
|
||||
throws IllegalStateException {
|
||||
|
||||
byte output[];
|
||||
|
||||
if (!this.cipherInitialized) {
|
||||
throw new IllegalStateException(
|
||||
"Cipher has not been initialized yet");
|
||||
}
|
||||
|
||||
if (debug.DEBUG)
|
||||
log("update (offset: " + inputOffset + ", len: " +
|
||||
inputLen + ")");
|
||||
|
@ -725,10 +914,15 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
@Override
|
||||
protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
|
||||
byte[] output, int outputOffset)
|
||||
throws ShortBufferException {
|
||||
throws IllegalStateException, ShortBufferException {
|
||||
|
||||
byte tmpOut[];
|
||||
|
||||
if (!this.cipherInitialized) {
|
||||
throw new IllegalStateException(
|
||||
"Cipher has not been initialized yet");
|
||||
}
|
||||
|
||||
if (debug.DEBUG)
|
||||
log("update (in offset: " + inputOffset + ", len: " +
|
||||
inputLen + ", out offset: " + outputOffset + ")");
|
||||
|
@ -755,7 +949,13 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
@Override
|
||||
protected byte[] engineDoFinal(byte[] input, int inputOffset,
|
||||
int inputLen)
|
||||
throws IllegalBlockSizeException, BadPaddingException {
|
||||
throws IllegalStateException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
|
||||
if (!this.cipherInitialized) {
|
||||
throw new IllegalStateException(
|
||||
"Cipher has not been initialized yet");
|
||||
}
|
||||
|
||||
if (debug.DEBUG)
|
||||
log("final (offset: " + inputOffset + ", len: " +
|
||||
|
@ -767,11 +967,16 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
@Override
|
||||
protected int engineDoFinal(byte[] input, int inputOffset,
|
||||
int inputLen, byte[] output, int outputOffset)
|
||||
throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
throws IllegalStateException, ShortBufferException,
|
||||
IllegalBlockSizeException, BadPaddingException {
|
||||
|
||||
byte tmpOut[];
|
||||
|
||||
if (!this.cipherInitialized) {
|
||||
throw new IllegalStateException(
|
||||
"Cipher has not been initialized yet");
|
||||
}
|
||||
|
||||
if (debug.DEBUG)
|
||||
log("final (in offset: " + inputOffset + ", len: " +
|
||||
inputLen + ", out offset: " + outputOffset + ")");
|
||||
|
@ -816,6 +1021,71 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
return encodedKey.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdateAAD(byte[] src, int offset, int len)
|
||||
throws IllegalArgumentException, IllegalStateException {
|
||||
|
||||
if (this.cipherType != CipherType.WC_AES ||
|
||||
this.cipherMode != CipherMode.WC_GCM) {
|
||||
throw new IllegalStateException(
|
||||
"AAD only supported for AES-GCM");
|
||||
}
|
||||
|
||||
if (this.operationStarted) {
|
||||
throw new IllegalStateException(
|
||||
"Must set AAD before calling Cipher.update/final");
|
||||
}
|
||||
|
||||
if (!this.cipherInitialized || this.aesGcm == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cipher not initialized yet");
|
||||
}
|
||||
|
||||
if (src == null || offset < 0 || len < 0 ||
|
||||
(src.length < (offset + len))) {
|
||||
throw new IllegalArgumentException(
|
||||
"Source buffer is null or bad offset/len");
|
||||
}
|
||||
|
||||
if (this.aadData == null) {
|
||||
/* Store as new array inside object */
|
||||
this.aadData = new byte[len];
|
||||
System.arraycopy(src, offset, this.aadData, 0, len);
|
||||
}
|
||||
else {
|
||||
/* Append to existing AAD array held inside object */
|
||||
byte[] tmp = new byte[this.aadData.length + len];
|
||||
System.arraycopy(this.aadData, 0, tmp, 0, this.aadData.length);
|
||||
System.arraycopy(src, offset, tmp, this.aadData.length, len);
|
||||
this.aadData = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdateAAD(ByteBuffer src)
|
||||
throws IllegalArgumentException, IllegalStateException {
|
||||
|
||||
int originalPos = 0;
|
||||
byte[] remaining = null;
|
||||
|
||||
if (src == null) {
|
||||
throw new IllegalArgumentException("Source buffer is null");
|
||||
}
|
||||
|
||||
originalPos = src.position();
|
||||
remaining = new byte[src.remaining()];
|
||||
|
||||
src.get(remaining);
|
||||
|
||||
try {
|
||||
engineUpdateAAD(remaining, 0, remaining.length);
|
||||
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||
/* restore state of ByteBuffer on state error before returning */
|
||||
src.position(originalPos);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private String typeToString(CipherType type) {
|
||||
switch (type) {
|
||||
case WC_AES:
|
||||
|
@ -835,6 +1105,8 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
return "ECB";
|
||||
case WC_CBC:
|
||||
return "CBC";
|
||||
case WC_GCM:
|
||||
return "GCM";
|
||||
default:
|
||||
return "None";
|
||||
}
|
||||
|
@ -848,17 +1120,30 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (this.aes != null)
|
||||
if (this.aes != null) {
|
||||
this.aes.releaseNativeStruct();
|
||||
this.aes = null;
|
||||
}
|
||||
|
||||
if (this.des3 != null)
|
||||
if (this.aesGcm != null) {
|
||||
this.aesGcm.releaseNativeStruct();
|
||||
this.aesGcm = null;
|
||||
}
|
||||
|
||||
if (this.des3 != null) {
|
||||
this.des3.releaseNativeStruct();
|
||||
this.des3 = null;
|
||||
}
|
||||
|
||||
if (this.rsa != null)
|
||||
if (this.rsa != null) {
|
||||
this.rsa.releaseNativeStruct();
|
||||
this.rsa = null;
|
||||
}
|
||||
|
||||
if (this.rng != null)
|
||||
if (this.rng != null) {
|
||||
this.rng.releaseNativeStruct();
|
||||
this.rng = null;
|
||||
}
|
||||
|
||||
zeroArray(this.iv);
|
||||
|
||||
|
@ -894,6 +1179,18 @@ public class WolfCryptCipher extends CipherSpi {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for AES-GCM with no padding
|
||||
*/
|
||||
public static final class wcAESGCMNoPadding extends WolfCryptCipher {
|
||||
/**
|
||||
* Create new wcAESGCMNoPadding object
|
||||
*/
|
||||
public wcAESGCMNoPadding() {
|
||||
super(CipherType.WC_AES, CipherMode.WC_GCM, PaddingType.WC_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for DES-EDE-CBC with no padding
|
||||
*/
|
||||
|
|
|
@ -121,34 +121,58 @@ public final class WolfCryptProvider extends Provider {
|
|||
}
|
||||
|
||||
/* Cipher */
|
||||
put("Cipher.AES/CBC/NoPadding",
|
||||
if (FeatureDetect.AesCbcEnabled()) {
|
||||
put("Cipher.AES/CBC/NoPadding",
|
||||
"com.wolfssl.provider.jce.WolfCryptCipher$wcAESCBCNoPadding");
|
||||
put("Cipher.AES/CBC/PKCS5Padding",
|
||||
put("Cipher.AES/CBC/PKCS5Padding",
|
||||
"com.wolfssl.provider.jce.WolfCryptCipher$wcAESCBCPKCS5Padding");
|
||||
}
|
||||
if (FeatureDetect.AesGcmEnabled()) {
|
||||
put("Cipher.AES/GCM/NoPadding",
|
||||
"com.wolfssl.provider.jce.WolfCryptCipher$wcAESGCMNoPadding");
|
||||
}
|
||||
|
||||
put("Cipher.DESede/CBC/NoPadding",
|
||||
if (FeatureDetect.Des3Enabled()) {
|
||||
put("Cipher.DESede/CBC/NoPadding",
|
||||
"com.wolfssl.provider.jce.WolfCryptCipher$wcDESedeCBCNoPadding");
|
||||
}
|
||||
|
||||
put("Cipher.RSA",
|
||||
if (FeatureDetect.RsaEnabled()) {
|
||||
put("Cipher.RSA",
|
||||
"com.wolfssl.provider.jce.WolfCryptCipher$wcRSAECBPKCS1Padding");
|
||||
put("Cipher.RSA/ECB/PKCS1Padding",
|
||||
put("Cipher.RSA/ECB/PKCS1Padding",
|
||||
"com.wolfssl.provider.jce.WolfCryptCipher$wcRSAECBPKCS1Padding");
|
||||
}
|
||||
|
||||
/* KeyAgreement */
|
||||
put("KeyAgreement.DiffieHellman",
|
||||
if (FeatureDetect.DhEnabled()) {
|
||||
put("KeyAgreement.DiffieHellman",
|
||||
"com.wolfssl.provider.jce.WolfCryptKeyAgreement$wcDH");
|
||||
put("Alg.Alias.KeyAgreement.DH", "DiffieHellman");
|
||||
put("KeyAgreement.ECDH",
|
||||
put("Alg.Alias.KeyAgreement.DH", "DiffieHellman");
|
||||
}
|
||||
if (FeatureDetect.EccDheEnabled()) {
|
||||
put("KeyAgreement.ECDH",
|
||||
"com.wolfssl.provider.jce.WolfCryptKeyAgreement$wcECDH");
|
||||
}
|
||||
|
||||
/* KeyPairGenerator */
|
||||
put("KeyPairGenerator.RSA",
|
||||
if (FeatureDetect.RsaKeyGenEnabled()) {
|
||||
put("KeyPairGenerator.RSA",
|
||||
"com.wolfssl.provider.jce.WolfCryptKeyPairGenerator$wcKeyPairGenRSA");
|
||||
put("KeyPairGenerator.EC",
|
||||
}
|
||||
if (FeatureDetect.EccKeyGenEnabled()) {
|
||||
put("KeyPairGenerator.EC",
|
||||
"com.wolfssl.provider.jce.WolfCryptKeyPairGenerator$wcKeyPairGenECC");
|
||||
put("KeyPairGenerator.DH",
|
||||
}
|
||||
if (FeatureDetect.DhEnabled()) {
|
||||
put("KeyPairGenerator.DH",
|
||||
"com.wolfssl.provider.jce.WolfCryptKeyPairGenerator$wcKeyPairGenDH");
|
||||
put("Alg.Alias.KeyPairGenerator.DiffieHellman", "DH");
|
||||
put("Alg.Alias.KeyPairGenerator.DiffieHellman", "DH");
|
||||
}
|
||||
|
||||
/* KeyStore */
|
||||
put("KeyStore.WKS",
|
||||
"com.wolfssl.provider.jce.WolfSSLKeyStore$WolfSSLKeyStoreWKS");
|
||||
|
||||
/* If using a FIPS version of wolfCrypt, allow private key to be
|
||||
* exported for use. Only applicable to FIPS 140-3 */
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
/* AesGcm.java
|
||||
*
|
||||
* Copyright (C) 2006-2024 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
package com.wolfssl.wolfcrypt;
|
||||
|
||||
/**
|
||||
* Wrapper for native wolfCrypt AES-GCM implementation.
|
||||
*/
|
||||
public class AesGcm extends NativeStruct {
|
||||
|
||||
private WolfCryptState state = WolfCryptState.UNINITIALIZED;
|
||||
|
||||
/* Lock around object state */
|
||||
protected final Object stateLock = new Object();
|
||||
|
||||
/* Lock around native Aes poiner use */
|
||||
private final Object aesLock = new Object();
|
||||
|
||||
/* Native JNI methods, implemented in jni/jni_aesgcm.c */
|
||||
private native long mallocNativeStruct_internal() throws OutOfMemoryError;
|
||||
private native void wc_AesInit();
|
||||
private native void wc_AesFree();
|
||||
private native void wc_AesGcmSetKey(byte[] key);
|
||||
private native byte[] wc_AesGcmEncrypt(byte[] input, byte[] iv,
|
||||
byte[] authTagOut, byte[] authIn);
|
||||
private native byte[] wc_AesGcmDecrypt(byte[] input, byte[] iv,
|
||||
byte[] authTag, byte[] authIn);
|
||||
|
||||
/**
|
||||
* Create and initialize new AesGcm object
|
||||
*/
|
||||
public AesGcm() {
|
||||
init();
|
||||
}
|
||||
|
||||
public AesGcm(byte[] key) {
|
||||
init();
|
||||
setKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Malloc native Aes structure via JNI. Called by NativeStruct
|
||||
* constructor when this object is created.
|
||||
*
|
||||
* @return native allocated pointer
|
||||
*
|
||||
* @throws OutOfMemoryError when malloc fails with memory error
|
||||
*/
|
||||
@Override
|
||||
protected long mallocNativeStruct()
|
||||
throws OutOfMemoryError {
|
||||
|
||||
synchronized (pointerLock) {
|
||||
return mallocNativeStruct_internal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release native Aes structure memory via JNI. Either called explicitly
|
||||
* by application or from NativeStruct finalize() method upon object
|
||||
* cleanup.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void releaseNativeStruct() {
|
||||
free();
|
||||
super.releaseNativeStruct();
|
||||
}
|
||||
|
||||
/** Initialize AesGcm object and underlying native Aes structure */
|
||||
protected void init() {
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (state == WolfCryptState.UNINITIALIZED) {
|
||||
synchronized (pointerLock) {
|
||||
wc_AesInit();
|
||||
}
|
||||
state = WolfCryptState.INITIALIZED;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Native resources already initialized");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Free AesGcm object and underlying native Aes structure */
|
||||
protected synchronized void free() {
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (state != WolfCryptState.UNINITIALIZED) {
|
||||
synchronized (pointerLock) {
|
||||
wc_AesFree();
|
||||
}
|
||||
state = WolfCryptState.UNINITIALIZED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set AES-GCM key.
|
||||
*
|
||||
* @param key AES key as byte array. Supported key lengths include:
|
||||
* 16 bytes (128-bit)
|
||||
* 24 bytes (192-bit)
|
||||
* 32 bytes (256-bit)
|
||||
*
|
||||
* @throws WolfCryptException if native operation fails
|
||||
* @throws IllegalStateException if key has already been set
|
||||
*/
|
||||
public synchronized void setKey(byte[] key)
|
||||
throws WolfCryptException, IllegalStateException {
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (state == WolfCryptState.INITIALIZED) {
|
||||
synchronized (pointerLock) {
|
||||
wc_AesGcmSetKey(key);
|
||||
}
|
||||
state = WolfCryptState.READY;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Key has already been set for this AesGcm object, " +
|
||||
"or object not initialized");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt data with AES-GCM.
|
||||
*
|
||||
* @param input input data to be encrypted
|
||||
* @param iv IV for AES-GCM operation
|
||||
* @param authTagOut output byte array for auth tag to be placed. Should
|
||||
* be sized to desired tag size, which can be between wolfSSL
|
||||
* minimum auth tag size (default 12) and AES block size (16).
|
||||
* User compiling native wolfSSL can override default minimum
|
||||
* auth tag size by defining WOLFSSL_MIN_AUTH_TAG_SZ.
|
||||
* @param authIn additional data to be authenticated but not encrypted,
|
||||
* can be null if no additional data desired or available.
|
||||
*
|
||||
* @return encrypted cipertext buffer
|
||||
*
|
||||
* @throws WolfCryptException if native operation fails
|
||||
* @throws IllegalStateException if key has already been set
|
||||
*/
|
||||
public synchronized byte[] encrypt(byte[] input, byte[] iv,
|
||||
byte[] authTagOut, byte[] authIn)
|
||||
throws IllegalStateException, WolfCryptException {
|
||||
|
||||
byte[] output = null;
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (state == WolfCryptState.READY) {
|
||||
synchronized (pointerLock) {
|
||||
output = wc_AesGcmEncrypt(input, iv, authTagOut, authIn);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Object has not bee initialized or set up");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data with AES-GCM.
|
||||
*
|
||||
* @param input ciphertext to be decrypted
|
||||
* @param iv IV for AES-GCM operation
|
||||
* @param authTag authentication tag generated during encryption operation
|
||||
* @param authIn additional data to be authenticated but not decrypted
|
||||
*
|
||||
* @return decrypted plaintext buffer
|
||||
*
|
||||
* @throws WolfCryptException if native operation fails
|
||||
* @throws IllegalStateException if key has already been set
|
||||
*/
|
||||
public synchronized byte[] decrypt(byte[] input, byte[] iv, byte[] authTag,
|
||||
byte[] authIn) throws IllegalStateException, WolfCryptException {
|
||||
|
||||
byte[] output = null;
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (state == WolfCryptState.READY) {
|
||||
synchronized (pointerLock) {
|
||||
output = wc_AesGcmDecrypt(input, iv, authTag, authIn);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Object has not been initialized or set up");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,13 @@ public class FeatureDetect {
|
|||
*/
|
||||
public static native boolean ShaEnabled();
|
||||
|
||||
/**
|
||||
* Tests if SHA-224 is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean Sha224Enabled();
|
||||
|
||||
/**
|
||||
* Tests if SHA-256 is compiled into the native wolfSSL library.
|
||||
*
|
||||
|
@ -62,6 +69,57 @@ public class FeatureDetect {
|
|||
*/
|
||||
public static native boolean Sha512Enabled();
|
||||
|
||||
/**
|
||||
* Tests if AES-128 is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean Aes128Enabled();
|
||||
|
||||
/**
|
||||
* Tests if AES-192 is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean Aes192Enabled();
|
||||
|
||||
/**
|
||||
* Tests if AES-256 is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean Aes256Enabled();
|
||||
|
||||
/**
|
||||
* Tests if AES-CBC is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean AesCbcEnabled();
|
||||
|
||||
|
||||
/**
|
||||
* Tests if AES-GCM is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean AesGcmEnabled();
|
||||
|
||||
/**
|
||||
* Tests if AES-GCM stream mode (WOLFSSL_AESGCM_STREAM) is compiled into
|
||||
* native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean AesGcmStreamEnabled();
|
||||
|
||||
/**
|
||||
* Tests if 3DES is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean Des3Enabled();
|
||||
|
||||
/**
|
||||
* Tests if HMAC-MD5 is compiled into the native wolfSSL library and
|
||||
* available for use.
|
||||
|
@ -102,6 +160,49 @@ public class FeatureDetect {
|
|||
*/
|
||||
public static native boolean HmacSha512Enabled();
|
||||
|
||||
/**
|
||||
* Tests if RSA is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean RsaEnabled();
|
||||
|
||||
/**
|
||||
* Tests if RSA key generation is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean RsaKeyGenEnabled();
|
||||
|
||||
/**
|
||||
* Tests if DH is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean DhEnabled();
|
||||
|
||||
/**
|
||||
* Tests if ECC is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean EccEnabled();
|
||||
|
||||
/**
|
||||
* Tests if ECC key generation is compiled into the native wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean EccKeyGenEnabled();
|
||||
|
||||
/**
|
||||
* Tests if ECDHE / wc_ecc_shared_secret() is compiled into the native
|
||||
* wolfSSL library.
|
||||
*
|
||||
* @return true if enabled, otherwise false if not compiled in.
|
||||
*/
|
||||
public static native boolean EccDheEnabled();
|
||||
|
||||
/**
|
||||
* Loads JNI library.
|
||||
*
|
||||
|
|
|
@ -34,10 +34,12 @@ import java.util.concurrent.Executors;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.BadPaddingException;
|
||||
|
@ -55,6 +57,7 @@ import java.security.InvalidKeyException;
|
|||
import java.security.InvalidAlgorithmParameterException;
|
||||
|
||||
import com.wolfssl.wolfcrypt.WolfCrypt;
|
||||
import com.wolfssl.wolfcrypt.FeatureDetect;
|
||||
import com.wolfssl.wolfcrypt.Fips;
|
||||
import com.wolfssl.provider.jce.WolfCryptProvider;
|
||||
import com.wolfssl.wolfcrypt.WolfCryptException;
|
||||
|
@ -65,6 +68,7 @@ public class WolfCryptCipherTest {
|
|||
private static String supportedJCEAlgos[] = {
|
||||
"AES/CBC/NoPadding",
|
||||
"AES/CBC/PKCS5Padding",
|
||||
"AES/GCM/NoPadding",
|
||||
"DESede/CBC/NoPadding",
|
||||
"RSA",
|
||||
"RSA/ECB/PKCS1Padding"
|
||||
|
@ -111,6 +115,7 @@ public class WolfCryptCipherTest {
|
|||
/* fill expected block size HashMap */
|
||||
expectedBlockSizes.put("AES/CBC/NoPadding", 16);
|
||||
expectedBlockSizes.put("AES/CBC/PKCS5Padding", 16);
|
||||
expectedBlockSizes.put("AES/GCM/NoPadding", 16);
|
||||
expectedBlockSizes.put("DESede/CBC/NoPadding", 8);
|
||||
expectedBlockSizes.put("RSA", 0);
|
||||
expectedBlockSizes.put("RSA/ECB/PKCS1Padding", 0);
|
||||
|
@ -172,7 +177,7 @@ public class WolfCryptCipherTest {
|
|||
BadPaddingException {
|
||||
|
||||
CipherVector vectors[] = new CipherVector[] {
|
||||
/* test vectors {key, iv, input, output } */
|
||||
/* test vectors {key, iv, input, output, tag, aad } */
|
||||
new CipherVector(
|
||||
new byte[] {
|
||||
(byte)0x30, (byte)0x31, (byte)0x32, (byte)0x33,
|
||||
|
@ -197,7 +202,8 @@ public class WolfCryptCipherTest {
|
|||
(byte)0x5f, (byte)0x42, (byte)0x81, (byte)0x53,
|
||||
(byte)0x2c, (byte)0xcc, (byte)0x9d, (byte)0x46,
|
||||
(byte)0x77, (byte)0xa2, (byte)0x33, (byte)0xcb
|
||||
}
|
||||
},
|
||||
null, null
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -215,7 +221,19 @@ public class WolfCryptCipherTest {
|
|||
SecretKeySpec key = new SecretKeySpec(vectors[i].getKey(), "AES");
|
||||
IvParameterSpec spec = new IvParameterSpec(vectors[i].getIV());
|
||||
|
||||
/* getOutputSize() before init() should throw exception */
|
||||
try {
|
||||
cipher.getOutputSize(vectors[i].getInput().length);
|
||||
fail("getOutputSize() before init() should fail");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected, continue */
|
||||
}
|
||||
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
|
||||
assertEquals(vectors[i].getOutput().length,
|
||||
cipher.getOutputSize(vectors[i].getInput().length));
|
||||
|
||||
output = cipher.doFinal(vectors[i].input);
|
||||
|
||||
assertArrayEquals(output, vectors[i].output);
|
||||
|
@ -758,7 +776,8 @@ public class WolfCryptCipherTest {
|
|||
(byte)0x44, (byte)0xaa, (byte)0xb5, (byte)0xf0,
|
||||
(byte)0x5f, (byte)0x34, (byte)0xb4, (byte)0xde,
|
||||
(byte)0xb5, (byte)0xbd, (byte)0x2a, (byte)0xbb
|
||||
}
|
||||
},
|
||||
null, null
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -1474,6 +1493,772 @@ public class WolfCryptCipherTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* test vectors {key, iv, input, output, tag, aad } */
|
||||
CipherVector aesGcmVectors[] = new CipherVector[] {
|
||||
/* AES-GCM-128 */
|
||||
/* The following is an interesting test case from the example
|
||||
* FIPS test vectors for AES-GCM. IVlen = 1 byte */
|
||||
new CipherVector(
|
||||
new byte[] { /* key (k3 from test.c) */
|
||||
(byte)0xbb, (byte)0x01, (byte)0xd7, (byte)0x03,
|
||||
(byte)0x81, (byte)0x1c, (byte)0x10, (byte)0x1a,
|
||||
(byte)0x35, (byte)0xe0, (byte)0xff, (byte)0xd2,
|
||||
(byte)0x91, (byte)0xba, (byte)0xf2, (byte)0x4b
|
||||
},
|
||||
new byte[] { /* iv (iv3 from test.c) */
|
||||
(byte)0xca
|
||||
},
|
||||
new byte[] { /* input (p3 from test.c) */
|
||||
(byte)0x57, (byte)0xce, (byte)0x45, (byte)0x1f,
|
||||
(byte)0xa5, (byte)0xe2, (byte)0x35, (byte)0xa5,
|
||||
(byte)0x8e, (byte)0x1a, (byte)0xa2, (byte)0x3b,
|
||||
(byte)0x77, (byte)0xcb, (byte)0xaf, (byte)0xe2
|
||||
},
|
||||
new byte[] { /* output (c3 from test.c) */
|
||||
(byte)0x6b, (byte)0x5f, (byte)0xb3, (byte)0x9d,
|
||||
(byte)0xc1, (byte)0xc5, (byte)0x7a, (byte)0x4f,
|
||||
(byte)0xf3, (byte)0x51, (byte)0x4d, (byte)0xc2,
|
||||
(byte)0xd5, (byte)0xf0, (byte)0xd0, (byte)0x07
|
||||
},
|
||||
new byte[] { /* tag (t3 from test.c) */
|
||||
(byte)0x06, (byte)0x90, (byte)0xed, (byte)0x01,
|
||||
(byte)0x34, (byte)0xdd, (byte)0xc6, (byte)0x95,
|
||||
(byte)0x31, (byte)0x2e, (byte)0x2a, (byte)0xf9,
|
||||
(byte)0x57, (byte)0x7a, (byte)0x1e, (byte)0xa6
|
||||
},
|
||||
new byte[] { /* aad (a3 from test.c) */
|
||||
(byte)0x40, (byte)0xfc, (byte)0xdc, (byte)0xd7,
|
||||
(byte)0x4a, (byte)0xd7, (byte)0x8b, (byte)0xf1,
|
||||
(byte)0x3e, (byte)0x7c, (byte)0x60, (byte)0x55,
|
||||
(byte)0x50, (byte)0x51, (byte)0xdd, (byte)0x54
|
||||
}
|
||||
),
|
||||
|
||||
/* AES-GCM-192 */
|
||||
/* FIPS, QAT and PIC32MZ HW Crypto only support 12-byte IV */
|
||||
/* Test Case 12, uses same plaintext and AAD data. */
|
||||
new CipherVector(
|
||||
new byte[] { /* key (k2 from test.c) */
|
||||
(byte)0xfe, (byte)0xff, (byte)0xe9, (byte)0x92,
|
||||
(byte)0x86, (byte)0x65, (byte)0x73, (byte)0x1c,
|
||||
(byte)0x6d, (byte)0x6a, (byte)0x8f, (byte)0x94,
|
||||
(byte)0x67, (byte)0x30, (byte)0x83, (byte)0x08,
|
||||
(byte)0xfe, (byte)0xff, (byte)0xe9, (byte)0x92,
|
||||
(byte)0x86, (byte)0x65, (byte)0x73, (byte)0x1c
|
||||
},
|
||||
new byte[] { /* iv (iv2 from test.c) */
|
||||
(byte)0x93, (byte)0x13, (byte)0x22, (byte)0x5d,
|
||||
(byte)0xf8, (byte)0x84, (byte)0x06, (byte)0xe5,
|
||||
(byte)0x55, (byte)0x90, (byte)0x9c, (byte)0x5a,
|
||||
(byte)0xff, (byte)0x52, (byte)0x69, (byte)0xaa,
|
||||
(byte)0x6a, (byte)0x7a, (byte)0x95, (byte)0x38,
|
||||
(byte)0x53, (byte)0x4f, (byte)0x7d, (byte)0xa1,
|
||||
(byte)0xe4, (byte)0xc3, (byte)0x03, (byte)0xd2,
|
||||
(byte)0xa3, (byte)0x18, (byte)0xa7, (byte)0x28,
|
||||
(byte)0xc3, (byte)0xc0, (byte)0xc9, (byte)0x51,
|
||||
(byte)0x56, (byte)0x80, (byte)0x95, (byte)0x39,
|
||||
(byte)0xfc, (byte)0xf0, (byte)0xe2, (byte)0x42,
|
||||
(byte)0x9a, (byte)0x6b, (byte)0x52, (byte)0x54,
|
||||
(byte)0x16, (byte)0xae, (byte)0xdb, (byte)0xf5,
|
||||
(byte)0xa0, (byte)0xde, (byte)0x6a, (byte)0x57,
|
||||
(byte)0xa6, (byte)0x37, (byte)0xb3, (byte)0x9b
|
||||
},
|
||||
new byte[] { /* input (p from test.c) */
|
||||
(byte)0xd9, (byte)0x31, (byte)0x32, (byte)0x25,
|
||||
(byte)0xf8, (byte)0x84, (byte)0x06, (byte)0xe5,
|
||||
(byte)0xa5, (byte)0x59, (byte)0x09, (byte)0xc5,
|
||||
(byte)0xaf, (byte)0xf5, (byte)0x26, (byte)0x9a,
|
||||
(byte)0x86, (byte)0xa7, (byte)0xa9, (byte)0x53,
|
||||
(byte)0x15, (byte)0x34, (byte)0xf7, (byte)0xda,
|
||||
(byte)0x2e, (byte)0x4c, (byte)0x30, (byte)0x3d,
|
||||
(byte)0x8a, (byte)0x31, (byte)0x8a, (byte)0x72,
|
||||
(byte)0x1c, (byte)0x3c, (byte)0x0c, (byte)0x95,
|
||||
(byte)0x95, (byte)0x68, (byte)0x09, (byte)0x53,
|
||||
(byte)0x2f, (byte)0xcf, (byte)0x0e, (byte)0x24,
|
||||
(byte)0x49, (byte)0xa6, (byte)0xb5, (byte)0x25,
|
||||
(byte)0xb1, (byte)0x6a, (byte)0xed, (byte)0xf5,
|
||||
(byte)0xaa, (byte)0x0d, (byte)0xe6, (byte)0x57,
|
||||
(byte)0xba, (byte)0x63, (byte)0x7b, (byte)0x39
|
||||
},
|
||||
new byte[] { /* output (c2 from test.c) */
|
||||
(byte)0xd2, (byte)0x7e, (byte)0x88, (byte)0x68,
|
||||
(byte)0x1c, (byte)0xe3, (byte)0x24, (byte)0x3c,
|
||||
(byte)0x48, (byte)0x30, (byte)0x16, (byte)0x5a,
|
||||
(byte)0x8f, (byte)0xdc, (byte)0xf9, (byte)0xff,
|
||||
(byte)0x1d, (byte)0xe9, (byte)0xa1, (byte)0xd8,
|
||||
(byte)0xe6, (byte)0xb4, (byte)0x47, (byte)0xef,
|
||||
(byte)0x6e, (byte)0xf7, (byte)0xb7, (byte)0x98,
|
||||
(byte)0x28, (byte)0x66, (byte)0x6e, (byte)0x45,
|
||||
(byte)0x81, (byte)0xe7, (byte)0x90, (byte)0x12,
|
||||
(byte)0xaf, (byte)0x34, (byte)0xdd, (byte)0xd9,
|
||||
(byte)0xe2, (byte)0xf0, (byte)0x37, (byte)0x58,
|
||||
(byte)0x9b, (byte)0x29, (byte)0x2d, (byte)0xb3,
|
||||
(byte)0xe6, (byte)0x7c, (byte)0x03, (byte)0x67,
|
||||
(byte)0x45, (byte)0xfa, (byte)0x22, (byte)0xe7,
|
||||
(byte)0xe9, (byte)0xb7, (byte)0x37, (byte)0x3b
|
||||
},
|
||||
new byte[] { /* tag (t2 from test.c) */
|
||||
(byte)0xdc, (byte)0xf5, (byte)0x66, (byte)0xff,
|
||||
(byte)0x29, (byte)0x1c, (byte)0x25, (byte)0xbb,
|
||||
(byte)0xb8, (byte)0x56, (byte)0x8f, (byte)0xc3,
|
||||
(byte)0xd3, (byte)0x76, (byte)0xa6, (byte)0xd9
|
||||
},
|
||||
new byte[] { /* aad (a from test.c) */
|
||||
(byte)0xfe, (byte)0xed, (byte)0xfa, (byte)0xce,
|
||||
(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef,
|
||||
(byte)0xfe, (byte)0xed, (byte)0xfa, (byte)0xce,
|
||||
(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef,
|
||||
(byte)0xab, (byte)0xad, (byte)0xda, (byte)0xd2
|
||||
}
|
||||
),
|
||||
|
||||
/* AES-GCM-256 */
|
||||
/* This is Test Case 16 from the document Galois/Counter Mode of
|
||||
* Operation (GCM) by McGrew and Viega. */
|
||||
new CipherVector(
|
||||
new byte[] { /* key (k1 from test.c) */
|
||||
(byte)0xfe, (byte)0xff, (byte)0xe9, (byte)0x92,
|
||||
(byte)0x86, (byte)0x65, (byte)0x73, (byte)0x1c,
|
||||
(byte)0x6d, (byte)0x6a, (byte)0x8f, (byte)0x94,
|
||||
(byte)0x67, (byte)0x30, (byte)0x83, (byte)0x08,
|
||||
(byte)0xfe, (byte)0xff, (byte)0xe9, (byte)0x92,
|
||||
(byte)0x86, (byte)0x65, (byte)0x73, (byte)0x1c,
|
||||
(byte)0x6d, (byte)0x6a, (byte)0x8f, (byte)0x94,
|
||||
(byte)0x67, (byte)0x30, (byte)0x83, (byte)0x08
|
||||
},
|
||||
new byte[] { /* iv (iv1 from test.c) */
|
||||
(byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe,
|
||||
(byte)0xfa, (byte)0xce, (byte)0xdb, (byte)0xad,
|
||||
(byte)0xde, (byte)0xca, (byte)0xf8, (byte)0x88
|
||||
},
|
||||
new byte[] { /* input (p from test.c) */
|
||||
(byte)0xd9, (byte)0x31, (byte)0x32, (byte)0x25,
|
||||
(byte)0xf8, (byte)0x84, (byte)0x06, (byte)0xe5,
|
||||
(byte)0xa5, (byte)0x59, (byte)0x09, (byte)0xc5,
|
||||
(byte)0xaf, (byte)0xf5, (byte)0x26, (byte)0x9a,
|
||||
(byte)0x86, (byte)0xa7, (byte)0xa9, (byte)0x53,
|
||||
(byte)0x15, (byte)0x34, (byte)0xf7, (byte)0xda,
|
||||
(byte)0x2e, (byte)0x4c, (byte)0x30, (byte)0x3d,
|
||||
(byte)0x8a, (byte)0x31, (byte)0x8a, (byte)0x72,
|
||||
(byte)0x1c, (byte)0x3c, (byte)0x0c, (byte)0x95,
|
||||
(byte)0x95, (byte)0x68, (byte)0x09, (byte)0x53,
|
||||
(byte)0x2f, (byte)0xcf, (byte)0x0e, (byte)0x24,
|
||||
(byte)0x49, (byte)0xa6, (byte)0xb5, (byte)0x25,
|
||||
(byte)0xb1, (byte)0x6a, (byte)0xed, (byte)0xf5,
|
||||
(byte)0xaa, (byte)0x0d, (byte)0xe6, (byte)0x57,
|
||||
(byte)0xba, (byte)0x63, (byte)0x7b, (byte)0x39
|
||||
},
|
||||
new byte[] { /* output (c1 from test.c) */
|
||||
(byte)0x52, (byte)0x2d, (byte)0xc1, (byte)0xf0,
|
||||
(byte)0x99, (byte)0x56, (byte)0x7d, (byte)0x07,
|
||||
(byte)0xf4, (byte)0x7f, (byte)0x37, (byte)0xa3,
|
||||
(byte)0x2a, (byte)0x84, (byte)0x42, (byte)0x7d,
|
||||
(byte)0x64, (byte)0x3a, (byte)0x8c, (byte)0xdc,
|
||||
(byte)0xbf, (byte)0xe5, (byte)0xc0, (byte)0xc9,
|
||||
(byte)0x75, (byte)0x98, (byte)0xa2, (byte)0xbd,
|
||||
(byte)0x25, (byte)0x55, (byte)0xd1, (byte)0xaa,
|
||||
(byte)0x8c, (byte)0xb0, (byte)0x8e, (byte)0x48,
|
||||
(byte)0x59, (byte)0x0d, (byte)0xbb, (byte)0x3d,
|
||||
(byte)0xa7, (byte)0xb0, (byte)0x8b, (byte)0x10,
|
||||
(byte)0x56, (byte)0x82, (byte)0x88, (byte)0x38,
|
||||
(byte)0xc5, (byte)0xf6, (byte)0x1e, (byte)0x63,
|
||||
(byte)0x93, (byte)0xba, (byte)0x7a, (byte)0x0a,
|
||||
(byte)0xbc, (byte)0xc9, (byte)0xf6, (byte)0x62
|
||||
},
|
||||
new byte[] { /* tag (t1 from test.c) */
|
||||
(byte)0x76, (byte)0xfc, (byte)0x6e, (byte)0xce,
|
||||
(byte)0x0f, (byte)0x4e, (byte)0x17, (byte)0x68,
|
||||
(byte)0xcd, (byte)0xdf, (byte)0x88, (byte)0x53,
|
||||
(byte)0xbb, (byte)0x2d, (byte)0x55, (byte)0x1b
|
||||
},
|
||||
new byte[] { /* aad (a from test.c) */
|
||||
(byte)0xfe, (byte)0xed, (byte)0xfa, (byte)0xce,
|
||||
(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef,
|
||||
(byte)0xfe, (byte)0xed, (byte)0xfa, (byte)0xce,
|
||||
(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef,
|
||||
(byte)0xab, (byte)0xad, (byte)0xda, (byte)0xd2
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
/*
|
||||
* Test Cipher("AES/GCM/NoPadding") processing with single call to
|
||||
* doFinal().
|
||||
*/
|
||||
@Test
|
||||
public void testAesGcmNoPadding() throws NoSuchAlgorithmException,
|
||||
InvalidKeyException, IllegalBlockSizeException, NoSuchProviderException,
|
||||
InvalidAlgorithmParameterException, BadPaddingException,
|
||||
NoSuchPaddingException {
|
||||
|
||||
|
||||
byte output[] = null;
|
||||
byte plain[] = null;
|
||||
|
||||
if (!enabledJCEAlgos.contains("AES/GCM/NoPadding")) {
|
||||
/* skip if AES-GCM is not enabled */
|
||||
return;
|
||||
}
|
||||
|
||||
Cipher enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
Cipher dec = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
|
||||
for (int i = 0; i < aesGcmVectors.length; i++) {
|
||||
|
||||
/* skip AES-128 vector if not compiled in native library */
|
||||
if ((i == 0) && (!FeatureDetect.Aes128Enabled())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip AES-192 vector if not compiled in native library, or if
|
||||
* using wolfCrypt FIPS since it only supports 12-byte IVs */
|
||||
if ((i == 1) && (!FeatureDetect.Aes192Enabled() || Fips.enabled)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip AES-256 vector if not compiled in native library */
|
||||
if ((i == 2) && (!FeatureDetect.Aes256Enabled())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
byte[] vOut = aesGcmVectors[i].getOutput();
|
||||
byte[] vTag = aesGcmVectors[i].getTag();
|
||||
byte[] tmpOut = new byte[vOut.length + vTag.length];
|
||||
SecretKeySpec key = new SecretKeySpec(
|
||||
aesGcmVectors[i].getKey(), "AES");
|
||||
GCMParameterSpec spec = new GCMParameterSpec(
|
||||
(vTag.length * 8), aesGcmVectors[i].getIV());
|
||||
|
||||
if (i == 0) {
|
||||
/* getOutputSize() before init() should throw exception */
|
||||
try {
|
||||
enc.getOutputSize(aesGcmVectors[i].getInput().length);
|
||||
fail("getOutputSize() before init() should fail");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected, continue */
|
||||
}
|
||||
}
|
||||
|
||||
/* Encrypt */
|
||||
enc.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
enc.updateAAD(aesGcmVectors[i].getAAD());
|
||||
assertEquals(tmpOut.length,
|
||||
enc.getOutputSize(aesGcmVectors[i].getInput().length));
|
||||
output = enc.doFinal(aesGcmVectors[i].getInput());
|
||||
|
||||
/* Concatenate tag to ciphertext, JCE Cipher does this internally */
|
||||
System.arraycopy(vOut, 0, tmpOut, 0, vOut.length);
|
||||
System.arraycopy(vTag, 0, tmpOut, vOut.length, vTag.length);
|
||||
|
||||
assertArrayEquals(tmpOut, output);
|
||||
|
||||
/* Decrypt */
|
||||
dec.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
dec.updateAAD(aesGcmVectors[i].getAAD());
|
||||
plain = dec.doFinal(output);
|
||||
|
||||
/* plain is just ciphertext, no tag */
|
||||
assertArrayEquals(aesGcmVectors[i].getInput(), plain);
|
||||
|
||||
/* ----- confirm wrong result if no AAD given but needed ----- */
|
||||
enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
enc.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
output = enc.doFinal(aesGcmVectors[i].getInput());
|
||||
/* Concatenate tag to ciphertext, JCE Cipher does this internally */
|
||||
System.arraycopy(vOut, 0, tmpOut, 0, vOut.length);
|
||||
System.arraycopy(vTag, 0, tmpOut, vOut.length, vTag.length);
|
||||
if (Arrays.equals(tmpOut, output)) {
|
||||
fail("Encrypt without needed AAD should not match expected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Cipher("AES/GCM/NoPadding") with multiple calls to update()
|
||||
* on both encrypt and decrypt.
|
||||
*/
|
||||
@Test
|
||||
public void testAesGcmNoPaddingWithUpdate()
|
||||
throws NoSuchAlgorithmException, InvalidKeyException,
|
||||
IllegalBlockSizeException, NoSuchProviderException,
|
||||
InvalidAlgorithmParameterException, BadPaddingException,
|
||||
NoSuchPaddingException {
|
||||
|
||||
byte tmp[] = null;
|
||||
byte output[] = null;
|
||||
byte plain[] = null;
|
||||
|
||||
if (!enabledJCEAlgos.contains("AES/GCM/NoPadding")) {
|
||||
/* skip if AES-GCM is not enabled */
|
||||
return;
|
||||
}
|
||||
|
||||
Cipher enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
Cipher dec = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
|
||||
for (int i = 0; i < aesGcmVectors.length; i++) {
|
||||
|
||||
int inIdx = 0;
|
||||
int outIdx = 0;
|
||||
int fourByteBlocks = 0;
|
||||
int remainingBytes = 0;
|
||||
byte[] vIn = aesGcmVectors[i].getInput();
|
||||
byte[] vOut = aesGcmVectors[i].getOutput();
|
||||
byte[] vTag = aesGcmVectors[i].getTag();
|
||||
byte[] tmpOut = new byte[vOut.length + vTag.length];
|
||||
SecretKeySpec key = new SecretKeySpec(
|
||||
aesGcmVectors[i].getKey(), "AES");
|
||||
GCMParameterSpec spec = new GCMParameterSpec(
|
||||
(vTag.length * 8), aesGcmVectors[i].getIV());
|
||||
|
||||
/* skip AES-128 vector if not compiled in native library */
|
||||
if ((i == 0) && (!FeatureDetect.Aes128Enabled())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip AES-192 vector if not compiled in native library, or if
|
||||
* using wolfCrypt FIPS since it only supports 12-byte IVs */
|
||||
if ((i == 1) && (!FeatureDetect.Aes192Enabled() || Fips.enabled)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip AES-256 vector if not compiled in native library */
|
||||
if ((i == 2) && (!FeatureDetect.Aes256Enabled())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ----- ENCRYPT (vIn -> output) ----- */
|
||||
|
||||
enc.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
enc.updateAAD(aesGcmVectors[i].getAAD());
|
||||
|
||||
/* Expected output is size vOut + vTag.length */
|
||||
output = new byte[vOut.length + vTag.length];
|
||||
|
||||
/* Process via update() by 4-byte blocks */
|
||||
fourByteBlocks = vIn.length / 4;
|
||||
remainingBytes = vIn.length % 4;
|
||||
|
||||
for (int j = 0; j < fourByteBlocks; j++) {
|
||||
tmp = enc.update(Arrays.copyOfRange(vIn, inIdx, inIdx + 4));
|
||||
assertNotNull(tmp);
|
||||
if (FeatureDetect.AesGcmStreamEnabled()) {
|
||||
assertEquals(4, tmp.length);
|
||||
} else {
|
||||
assertEquals(0, tmp.length);
|
||||
}
|
||||
System.arraycopy(tmp, 0, output, outIdx, tmp.length);
|
||||
inIdx += 4;
|
||||
outIdx += tmp.length;
|
||||
}
|
||||
|
||||
/* Process any remaining data (CipherVector.input length was not
|
||||
* a multiple of 4 bytes */
|
||||
if (remainingBytes > 0) {
|
||||
tmp = enc.update(Arrays.copyOfRange(vIn, inIdx,
|
||||
inIdx + remainingBytes));
|
||||
assertNotNull(tmp);
|
||||
if (FeatureDetect.AesGcmStreamEnabled()) {
|
||||
assertEquals(remainingBytes, tmp.length);
|
||||
} else {
|
||||
assertEquals(0, tmp.length);
|
||||
}
|
||||
System.arraycopy(tmp, 0, output, outIdx, tmp.length);
|
||||
inIdx += remainingBytes;
|
||||
outIdx += tmp.length;
|
||||
}
|
||||
|
||||
/* doFinal() should get tag (or whole ciphertext if AES-GCM
|
||||
* streaming is not enabled at native wolfSSL level) */
|
||||
tmp = enc.doFinal();
|
||||
assertNotNull(tmp);
|
||||
if (FeatureDetect.AesGcmStreamEnabled()) {
|
||||
assertEquals(vTag.length, tmp.length);
|
||||
} else {
|
||||
assertEquals(tmpOut.length, tmp.length);
|
||||
}
|
||||
System.arraycopy(tmp, 0, output, outIdx, tmp.length);
|
||||
outIdx += tmp.length;
|
||||
|
||||
/* Sanity check on total length written */
|
||||
assertEquals(output.length, outIdx);
|
||||
|
||||
/* Concatenate tag to end of ciphertext from our test vector, JCE
|
||||
* Cipher class already does this internally and will be the format
|
||||
* returned from update/final */
|
||||
System.arraycopy(vOut, 0, tmpOut, 0, vOut.length);
|
||||
System.arraycopy(vTag, 0, tmpOut, vOut.length, vTag.length);
|
||||
|
||||
/* Encrypted matches vector output? */
|
||||
assertArrayEquals(tmpOut, output);
|
||||
|
||||
/* ----- DECRYPT (output -> plain) ----- */
|
||||
|
||||
/* Sanity check, makes sure we built up output correctly */
|
||||
assertArrayEquals(tmpOut, output);
|
||||
|
||||
/* Decrypt */
|
||||
dec.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
dec.updateAAD(aesGcmVectors[i].getAAD());
|
||||
|
||||
/* plain is just plaintext, no tag */
|
||||
plain = new byte[vIn.length];
|
||||
|
||||
/* Process via update() by 4-byte blocks */
|
||||
fourByteBlocks = output.length / 4;
|
||||
remainingBytes = output.length % 4;
|
||||
|
||||
inIdx = 0;
|
||||
outIdx = 0;
|
||||
|
||||
for (int j = 0; j < fourByteBlocks; j++) {
|
||||
tmp = dec.update(Arrays.copyOfRange(output, inIdx, inIdx + 4));
|
||||
assertNotNull(tmp);
|
||||
if (FeatureDetect.AesGcmStreamEnabled()) {
|
||||
assertEquals(4, tmp.length);
|
||||
} else {
|
||||
assertEquals(0, tmp.length);
|
||||
}
|
||||
System.arraycopy(tmp, 0, plain, outIdx, tmp.length);
|
||||
inIdx += 4;
|
||||
outIdx += tmp.length;
|
||||
}
|
||||
|
||||
/* Process any remaining data (output length was not
|
||||
* a multiple of 4 bytes */
|
||||
if (remainingBytes > 0) {
|
||||
tmp = dec.update(Arrays.copyOfRange(output, inIdx,
|
||||
inIdx + remainingBytes));
|
||||
assertNotNull(tmp);
|
||||
if (FeatureDetect.AesGcmStreamEnabled()) {
|
||||
assertEquals(remainingBytes, tmp.length);
|
||||
} else {
|
||||
assertEquals(0, tmp.length);
|
||||
}
|
||||
System.arraycopy(tmp, 0, plain, outIdx, tmp.length);
|
||||
inIdx += remainingBytes;
|
||||
outIdx += tmp.length;
|
||||
}
|
||||
|
||||
/* doFinal() will return whole plaintext if AES-GCM
|
||||
* streaming is not enabled at native wolfSSL level */
|
||||
tmp = dec.doFinal();
|
||||
assertNotNull(tmp);
|
||||
if (FeatureDetect.AesGcmStreamEnabled()) {
|
||||
assertEquals(0, tmp.length);
|
||||
} else {
|
||||
assertEquals(vIn.length, tmp.length);
|
||||
}
|
||||
System.arraycopy(tmp, 0, plain, outIdx, tmp.length);
|
||||
outIdx += tmp.length;
|
||||
|
||||
/* Sanity check on total length written */
|
||||
assertEquals(plain.length, outIdx);
|
||||
|
||||
/* Decrypted matches vector input? */
|
||||
assertArrayEquals(vIn, plain);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Cipher("AES/GCM/NoPadding") to make sure updateAAD() correctly
|
||||
* throws an exception when called after a call to update or doFinal.
|
||||
*/
|
||||
@Test
|
||||
public void testAesGcmNoPaddingUpdateAADByteArray()
|
||||
throws NoSuchAlgorithmException, InvalidKeyException,
|
||||
IllegalBlockSizeException, NoSuchProviderException,
|
||||
InvalidAlgorithmParameterException, BadPaddingException,
|
||||
NoSuchPaddingException {
|
||||
|
||||
int i = 0;
|
||||
byte output[] = null;
|
||||
byte plain[] = null;
|
||||
CipherVector vect = null;
|
||||
byte[] vOut = null;
|
||||
byte[] vIn = null;
|
||||
byte[] vKey = null;
|
||||
byte[] vIV = null;
|
||||
byte[] vTag = null;
|
||||
byte[] vAAD = null;
|
||||
|
||||
if (!enabledJCEAlgos.contains("AES/GCM/NoPadding")) {
|
||||
/* skip if AES-GCM is not enabled */
|
||||
return;
|
||||
}
|
||||
|
||||
Cipher enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
Cipher dec = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
|
||||
/* Try to pick a vector based on what is compiled in natively,
|
||||
* doesn't matter too much which vector we get */
|
||||
if (FeatureDetect.Aes128Enabled()) {
|
||||
vect = aesGcmVectors[0];
|
||||
}
|
||||
else if (FeatureDetect.Aes192Enabled() && !Fips.enabled) {
|
||||
vect = aesGcmVectors[1];
|
||||
}
|
||||
else if (FeatureDetect.Aes256Enabled()) {
|
||||
vect = aesGcmVectors[2];
|
||||
}
|
||||
else {
|
||||
/* No test vector found, skipping test */
|
||||
return;
|
||||
}
|
||||
|
||||
vOut = vect.getOutput();
|
||||
vIn = vect.getInput();
|
||||
vKey = vect.getKey();
|
||||
vIV = vect.getIV();
|
||||
vTag = vect.getTag();
|
||||
vAAD = vect.getAAD();
|
||||
|
||||
byte[] tmpOut = new byte[vOut.length + vTag.length];
|
||||
SecretKeySpec key = new SecretKeySpec(vKey, "AES");
|
||||
GCMParameterSpec spec = new GCMParameterSpec(
|
||||
(vTag.length * 8), vIV);
|
||||
|
||||
/* Encrypt, test calling updateAAD() multiple times */
|
||||
enc.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
|
||||
for (i = 0; i < vAAD.length; i++) {
|
||||
enc.updateAAD(new byte[] {vAAD[i]});
|
||||
}
|
||||
output = enc.doFinal(vIn);
|
||||
|
||||
/* Concatenate tag to end of ciphertext, JCE Cipher class already
|
||||
* does this internally */
|
||||
System.arraycopy(vOut, 0, tmpOut, 0, vOut.length);
|
||||
System.arraycopy(vTag, 0, tmpOut, vOut.length, vTag.length);
|
||||
|
||||
assertArrayEquals(tmpOut, output);
|
||||
|
||||
/* Decrypt, test calling updateAAD() multiple times */
|
||||
dec.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
for (i = 0; i < vAAD.length; i++) {
|
||||
dec.updateAAD(new byte[] {vAAD[i]});
|
||||
}
|
||||
plain = dec.doFinal(output);
|
||||
|
||||
/* plain is just ciphertext, no tag */
|
||||
assertArrayEquals(vIn, plain);
|
||||
|
||||
/* ----- updateAAD() after update() should fail ----- */
|
||||
enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
enc.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
enc.update(vIn);
|
||||
try {
|
||||
enc.updateAAD(vAAD);
|
||||
fail("updateAAD() after update() should throw exception");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* ----- updateAAD() throws exception if called before init ----- */
|
||||
enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
try {
|
||||
enc.updateAAD(vAAD);
|
||||
fail("updateAAD() before init() should throw exception");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Cipher("AES/GCM/NoPadding") to make sure updateAAD() correctly
|
||||
* throws an exception when called after a call to update or doFinal,
|
||||
* using ByteBuffer method.
|
||||
*/
|
||||
@Test
|
||||
public void testAesGcmNoPaddingUpdateAADByteBuffer()
|
||||
throws NoSuchAlgorithmException, InvalidKeyException,
|
||||
IllegalBlockSizeException, NoSuchProviderException,
|
||||
InvalidAlgorithmParameterException, BadPaddingException,
|
||||
NoSuchPaddingException {
|
||||
|
||||
int i = 0;
|
||||
byte output[] = null;
|
||||
byte plain[] = null;
|
||||
CipherVector vect = null;
|
||||
byte[] vOut = null;
|
||||
byte[] vIn = null;
|
||||
byte[] vKey = null;
|
||||
byte[] vIV = null;
|
||||
byte[] vTag = null;
|
||||
byte[] vAAD = null;
|
||||
|
||||
if (!enabledJCEAlgos.contains("AES/GCM/NoPadding")) {
|
||||
/* skip if AES-GCM is not enabled */
|
||||
return;
|
||||
}
|
||||
|
||||
Cipher enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
Cipher dec = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
|
||||
/* Try to pick a vector based on what is compiled in natively,
|
||||
* doesn't matter too much which vector we get */
|
||||
if (FeatureDetect.Aes128Enabled()) {
|
||||
vect = aesGcmVectors[0];
|
||||
}
|
||||
else if (FeatureDetect.Aes192Enabled() && !Fips.enabled) {
|
||||
vect = aesGcmVectors[1];
|
||||
}
|
||||
else if (FeatureDetect.Aes256Enabled()) {
|
||||
vect = aesGcmVectors[2];
|
||||
}
|
||||
else {
|
||||
/* No test vector found, skipping test */
|
||||
return;
|
||||
}
|
||||
|
||||
vOut = vect.getOutput();
|
||||
vIn = vect.getInput();
|
||||
vKey = vect.getKey();
|
||||
vIV = vect.getIV();
|
||||
vTag = vect.getTag();
|
||||
vAAD = vect.getAAD();
|
||||
|
||||
byte[] tmpOut = new byte[vOut.length + vTag.length];
|
||||
SecretKeySpec key = new SecretKeySpec(vKey, "AES");
|
||||
GCMParameterSpec spec = new GCMParameterSpec(
|
||||
(vTag.length * 8), vIV);
|
||||
|
||||
/* Encrypt, test calling updateAAD() multiple times */
|
||||
enc.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
|
||||
for (i = 0; i < vAAD.length; i++) {
|
||||
enc.updateAAD(ByteBuffer.wrap(new byte[] {vAAD[i]}));
|
||||
}
|
||||
output = enc.doFinal(vIn);
|
||||
|
||||
/* Concatenate tag to end of ciphertext, JCE Cipher class already
|
||||
* does this internally */
|
||||
System.arraycopy(vOut, 0, tmpOut, 0, vOut.length);
|
||||
System.arraycopy(vTag, 0, tmpOut, vOut.length, vTag.length);
|
||||
|
||||
assertArrayEquals(tmpOut, output);
|
||||
|
||||
/* Decrypt, test calling updateAAD() multiple times */
|
||||
dec.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
for (i = 0; i < vAAD.length; i++) {
|
||||
dec.updateAAD(ByteBuffer.wrap(new byte[] {vAAD[i]}));
|
||||
}
|
||||
plain = dec.doFinal(output);
|
||||
|
||||
/* plain is just ciphertext, no tag */
|
||||
assertArrayEquals(vIn, plain);
|
||||
|
||||
/* ----- updateAAD() after update() should fail ----- */
|
||||
enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
enc.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
enc.update(vIn);
|
||||
try {
|
||||
enc.updateAAD(ByteBuffer.wrap(vAAD));
|
||||
fail("updateAAD() after update() should throw exception");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* ----- updateAAD() throws exception if called before init ----- */
|
||||
enc = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
try {
|
||||
enc.updateAAD(ByteBuffer.wrap(vAAD));
|
||||
fail("updateAAD() before init() should throw exception");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Cipher("AES/GCM/NoPadding") interop if other provider is available.
|
||||
*/
|
||||
@Test
|
||||
public void testAesGcmNoPaddingInterop() throws NoSuchAlgorithmException,
|
||||
InvalidKeyException, IllegalBlockSizeException, NoSuchProviderException,
|
||||
InvalidAlgorithmParameterException, BadPaddingException,
|
||||
NoSuchPaddingException {
|
||||
|
||||
|
||||
byte cipher[] = null;
|
||||
byte plain[] = null;
|
||||
|
||||
if (!enabledJCEAlgos.contains("AES/GCM/NoPadding")) {
|
||||
/* skip if AES-GCM is not enabled */
|
||||
return;
|
||||
}
|
||||
|
||||
if (interopProvider == null) {
|
||||
/* no interop provider available, skip */
|
||||
return;
|
||||
}
|
||||
|
||||
Cipher ciphA = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
Cipher ciphB = Cipher.getInstance("AES/GCM/NoPadding", interopProvider);
|
||||
|
||||
for (int i = 0; i < aesGcmVectors.length; i++) {
|
||||
|
||||
/* skip AES-128 vector if not compiled in native library */
|
||||
if ((i == 0) && (!FeatureDetect.Aes128Enabled())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip AES-192 vector if not compiled in native library, or if
|
||||
* using wolfCrypt FIPS since it only supports 12-byte IVs */
|
||||
if ((i == 1) && (!FeatureDetect.Aes192Enabled() || Fips.enabled)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip AES-256 vector if not compiled in native library */
|
||||
if ((i == 2) && (!FeatureDetect.Aes256Enabled())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
byte[] vOut = aesGcmVectors[i].getOutput();
|
||||
byte[] vIn = aesGcmVectors[i].getInput();
|
||||
byte[] vKey = aesGcmVectors[i].getKey();
|
||||
byte[] vIV = aesGcmVectors[i].getIV();
|
||||
byte[] vTag = aesGcmVectors[i].getTag();
|
||||
byte[] vAAD = aesGcmVectors[i].getAAD();
|
||||
|
||||
/* Concatenate tag to ciphertext, JCE Cipher does this internally */
|
||||
byte[] tmpOut = new byte[vOut.length + vTag.length];
|
||||
System.arraycopy(vOut, 0, tmpOut, 0, vOut.length);
|
||||
System.arraycopy(vTag, 0, tmpOut, vOut.length, vTag.length);
|
||||
|
||||
SecretKeySpec key = new SecretKeySpec(vKey, "AES");
|
||||
GCMParameterSpec spec = new GCMParameterSpec(
|
||||
(vTag.length * 8), vIV);
|
||||
|
||||
/* Encrypt with wolfJCE */
|
||||
ciphA.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
ciphA.updateAAD(vAAD);
|
||||
cipher = ciphA.doFinal(vIn);
|
||||
assertArrayEquals(tmpOut, cipher);
|
||||
|
||||
/* Decrypt with INTEROP provider */
|
||||
ciphB.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
ciphB.updateAAD(vAAD);
|
||||
plain = ciphB.doFinal(cipher);
|
||||
assertArrayEquals(vIn, plain);
|
||||
|
||||
/* Reset Cipher (same IV can't be used twice) */
|
||||
ciphA = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);
|
||||
ciphB = Cipher.getInstance("AES/GCM/NoPadding", interopProvider);
|
||||
|
||||
/* Encrypt with INTEROP provider */
|
||||
ciphB.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||
ciphB.updateAAD(vAAD);
|
||||
cipher = ciphB.doFinal(vIn);
|
||||
assertArrayEquals(tmpOut, cipher);
|
||||
|
||||
/* Decrypt with wolfJCE */
|
||||
ciphA.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
ciphA.updateAAD(vAAD);
|
||||
plain = ciphA.doFinal(cipher);
|
||||
assertArrayEquals(vIn, plain);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDESedeCbcNoPadding()
|
||||
throws NoSuchProviderException, NoSuchAlgorithmException,
|
||||
|
@ -1511,13 +2296,15 @@ public class WolfCryptCipherTest {
|
|||
(byte)0x12, (byte)0xd5, (byte)0x08, (byte)0x98,
|
||||
(byte)0x18, (byte)0x94, (byte)0x15, (byte)0x74,
|
||||
(byte)0x87, (byte)0x12, (byte)0x7d, (byte)0xb0
|
||||
}
|
||||
},
|
||||
null, null
|
||||
)
|
||||
};
|
||||
|
||||
byte output[];
|
||||
|
||||
if (!enabledJCEAlgos.contains("DESede/CBC/NoPadding")) {
|
||||
if (!enabledJCEAlgos.contains("DESede/CBC/NoPadding") ||
|
||||
!FeatureDetect.Des3Enabled()) {
|
||||
/* bail out if 3DES is not enabled */
|
||||
return;
|
||||
}
|
||||
|
@ -1579,7 +2366,8 @@ public class WolfCryptCipherTest {
|
|||
|
||||
byte tmp[];
|
||||
|
||||
if (!enabledJCEAlgos.contains("DESede/CBC/NoPadding")) {
|
||||
if (!enabledJCEAlgos.contains("DESede/CBC/NoPadding") ||
|
||||
!FeatureDetect.Des3Enabled()) {
|
||||
/* bail out if 3DES is not enabled */
|
||||
return;
|
||||
}
|
||||
|
@ -1636,7 +2424,8 @@ public class WolfCryptCipherTest {
|
|||
(byte)0x90, (byte)0xab, (byte)0xcd, (byte)0xef,
|
||||
};
|
||||
|
||||
if (!enabledJCEAlgos.contains("DESede/CBC/NoPadding")) {
|
||||
if (!enabledJCEAlgos.contains("DESede/CBC/NoPadding") ||
|
||||
!FeatureDetect.Des3Enabled()) {
|
||||
/* skip if DESede/CBC/NoPadding is not enabled */
|
||||
return;
|
||||
}
|
||||
|
@ -1742,7 +2531,7 @@ public class WolfCryptCipherTest {
|
|||
(byte)0x20, (byte)0x6f, (byte)0x66, (byte)0x66,
|
||||
(byte)0x2e
|
||||
},
|
||||
null
|
||||
null, null, null
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -2125,7 +2914,7 @@ public class WolfCryptCipherTest {
|
|||
(byte)0x20, (byte)0x6f, (byte)0x66, (byte)0x66,
|
||||
(byte)0x2e
|
||||
},
|
||||
null
|
||||
null, null, null
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -2236,13 +3025,17 @@ public class WolfCryptCipherTest {
|
|||
private byte iv[];
|
||||
private byte input[];
|
||||
private byte output[];
|
||||
private byte tag[]; /* AES-GCM auth tag */
|
||||
private byte aad[]; /* AES-GCM additional auth data */
|
||||
|
||||
public CipherVector(byte[] key, byte[] iv, byte[] input,
|
||||
byte[] output) {
|
||||
byte[] output, byte[] tag, byte[] aad) {
|
||||
this.key = key;
|
||||
this.iv = iv;
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
this.tag = tag;
|
||||
this.aad = aad;
|
||||
}
|
||||
|
||||
public void setKey(byte[] key) {
|
||||
|
@ -2261,6 +3054,14 @@ public class WolfCryptCipherTest {
|
|||
this.output = output;
|
||||
}
|
||||
|
||||
public void setTag(byte[] tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public void setAad(byte[] aad) {
|
||||
this.aad = aad;
|
||||
}
|
||||
|
||||
public byte[] getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
@ -2276,6 +3077,14 @@ public class WolfCryptCipherTest {
|
|||
public byte[] getOutput() {
|
||||
return this.output;
|
||||
}
|
||||
|
||||
public byte[] getTag() {
|
||||
return this.tag;
|
||||
}
|
||||
|
||||
public byte[] getAAD() {
|
||||
return this.aad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,993 @@
|
|||
/* AesGcmTest.java
|
||||
*
|
||||
* Copyright (C) 2006-2024 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
package com.wolfssl.wolfcrypt.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import javax.crypto.ShortBufferException;
|
||||
import java.nio.ByteBuffer;
|
||||
import javax.crypto.ShortBufferException;
|
||||
|
||||
import org.junit.Assume;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.wolfssl.wolfcrypt.Fips;
|
||||
import com.wolfssl.wolfcrypt.AesGcm;
|
||||
import com.wolfssl.wolfcrypt.FeatureDetect;
|
||||
import com.wolfssl.wolfcrypt.NativeStruct;
|
||||
import com.wolfssl.wolfcrypt.WolfCryptError;
|
||||
import com.wolfssl.wolfcrypt.WolfCryptException;
|
||||
|
||||
public class AesGcmTest {
|
||||
|
||||
/*
|
||||
* This is Test Case 16 from the document Galois/
|
||||
* Counter Mode of Operation (GCM) by McGrew and
|
||||
* Viega.
|
||||
*/
|
||||
byte[] p = new byte[] {
|
||||
(byte)0xd9, (byte)0x31, (byte)0x32, (byte)0x25,
|
||||
(byte)0xf8, (byte)0x84, (byte)0x06, (byte)0xe5,
|
||||
(byte)0xa5, (byte)0x59, (byte)0x09, (byte)0xc5,
|
||||
(byte)0xaf, (byte)0xf5, (byte)0x26, (byte)0x9a,
|
||||
(byte)0x86, (byte)0xa7, (byte)0xa9, (byte)0x53,
|
||||
(byte)0x15, (byte)0x34, (byte)0xf7, (byte)0xda,
|
||||
(byte)0x2e, (byte)0x4c, (byte)0x30, (byte)0x3d,
|
||||
(byte)0x8a, (byte)0x31, (byte)0x8a, (byte)0x72,
|
||||
(byte)0x1c, (byte)0x3c, (byte)0x0c, (byte)0x95,
|
||||
(byte)0x95, (byte)0x68, (byte)0x09, (byte)0x53,
|
||||
(byte)0x2f, (byte)0xcf, (byte)0x0e, (byte)0x24,
|
||||
(byte)0x49, (byte)0xa6, (byte)0xb5, (byte)0x25,
|
||||
(byte)0xb1, (byte)0x6a, (byte)0xed, (byte)0xf5,
|
||||
(byte)0xaa, (byte)0x0d, (byte)0xe6, (byte)0x57,
|
||||
(byte)0xba, (byte)0x63, (byte)0x7b, (byte)0x39
|
||||
};
|
||||
|
||||
byte[] a = new byte[] {
|
||||
(byte)0xfe, (byte)0xed, (byte)0xfa, (byte)0xce,
|
||||
(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef,
|
||||
(byte)0xfe, (byte)0xed, (byte)0xfa, (byte)0xce,
|
||||
(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef,
|
||||
(byte)0xab, (byte)0xad, (byte)0xda, (byte)0xd2
|
||||
};
|
||||
|
||||
/* AES-256 test vectors */
|
||||
byte[] k1 = new byte[] {
|
||||
(byte)0xfe, (byte)0xff, (byte)0xe9, (byte)0x92,
|
||||
(byte)0x86, (byte)0x65, (byte)0x73, (byte)0x1c,
|
||||
(byte)0x6d, (byte)0x6a, (byte)0x8f, (byte)0x94,
|
||||
(byte)0x67, (byte)0x30, (byte)0x83, (byte)0x08,
|
||||
(byte)0xfe, (byte)0xff, (byte)0xe9, (byte)0x92,
|
||||
(byte)0x86, (byte)0x65, (byte)0x73, (byte)0x1c,
|
||||
(byte)0x6d, (byte)0x6a, (byte)0x8f, (byte)0x94,
|
||||
(byte)0x67, (byte)0x30, (byte)0x83, (byte)0x08
|
||||
};
|
||||
byte[] iv1 = new byte[] {
|
||||
(byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe,
|
||||
(byte)0xfa, (byte)0xce, (byte)0xdb, (byte)0xad,
|
||||
(byte)0xde, (byte)0xca, (byte)0xf8, (byte)0x88
|
||||
};
|
||||
|
||||
byte[] c1 = new byte[] {
|
||||
(byte)0x52, (byte)0x2d, (byte)0xc1, (byte)0xf0,
|
||||
(byte)0x99, (byte)0x56, (byte)0x7d, (byte)0x07,
|
||||
(byte)0xf4, (byte)0x7f, (byte)0x37, (byte)0xa3,
|
||||
(byte)0x2a, (byte)0x84, (byte)0x42, (byte)0x7d,
|
||||
(byte)0x64, (byte)0x3a, (byte)0x8c, (byte)0xdc,
|
||||
(byte)0xbf, (byte)0xe5, (byte)0xc0, (byte)0xc9,
|
||||
(byte)0x75, (byte)0x98, (byte)0xa2, (byte)0xbd,
|
||||
(byte)0x25, (byte)0x55, (byte)0xd1, (byte)0xaa,
|
||||
(byte)0x8c, (byte)0xb0, (byte)0x8e, (byte)0x48,
|
||||
(byte)0x59, (byte)0x0d, (byte)0xbb, (byte)0x3d,
|
||||
(byte)0xa7, (byte)0xb0, (byte)0x8b, (byte)0x10,
|
||||
(byte)0x56, (byte)0x82, (byte)0x88, (byte)0x38,
|
||||
(byte)0xc5, (byte)0xf6, (byte)0x1e, (byte)0x63,
|
||||
(byte)0x93, (byte)0xba, (byte)0x7a, (byte)0x0a,
|
||||
(byte)0xbc, (byte)0xc9, (byte)0xf6, (byte)0x62
|
||||
};
|
||||
|
||||
byte[] t1 = new byte[] {
|
||||
(byte)0x76, (byte)0xfc, (byte)0x6e, (byte)0xce,
|
||||
(byte)0x0f, (byte)0x4e, (byte)0x17, (byte)0x68,
|
||||
(byte)0xcd, (byte)0xdf, (byte)0x88, (byte)0x53,
|
||||
(byte)0xbb, (byte)0x2d, (byte)0x55, (byte)0x1b
|
||||
};
|
||||
|
||||
/* AES-192 test vectors */
|
||||
|
||||
/* FIPS, QAT and PIC32MZ HW Crypto only support 12-byte IV */
|
||||
/* Test Case 12, uses same plaintext and AAD data. */
|
||||
byte[] k2 = new byte[] {
|
||||
(byte)0xfe, (byte)0xff, (byte)0xe9, (byte)0x92,
|
||||
(byte)0x86, (byte)0x65, (byte)0x73, (byte)0x1c,
|
||||
(byte)0x6d, (byte)0x6a, (byte)0x8f, (byte)0x94,
|
||||
(byte)0x67, (byte)0x30, (byte)0x83, (byte)0x08,
|
||||
(byte)0xfe, (byte)0xff, (byte)0xe9, (byte)0x92,
|
||||
(byte)0x86, (byte)0x65, (byte)0x73, (byte)0x1c
|
||||
};
|
||||
|
||||
byte[] iv2 = new byte[] {
|
||||
(byte)0x93, (byte)0x13, (byte)0x22, (byte)0x5d,
|
||||
(byte)0xf8, (byte)0x84, (byte)0x06, (byte)0xe5,
|
||||
(byte)0x55, (byte)0x90, (byte)0x9c, (byte)0x5a,
|
||||
(byte)0xff, (byte)0x52, (byte)0x69, (byte)0xaa,
|
||||
(byte)0x6a, (byte)0x7a, (byte)0x95, (byte)0x38,
|
||||
(byte)0x53, (byte)0x4f, (byte)0x7d, (byte)0xa1,
|
||||
(byte)0xe4, (byte)0xc3, (byte)0x03, (byte)0xd2,
|
||||
(byte)0xa3, (byte)0x18, (byte)0xa7, (byte)0x28,
|
||||
(byte)0xc3, (byte)0xc0, (byte)0xc9, (byte)0x51,
|
||||
(byte)0x56, (byte)0x80, (byte)0x95, (byte)0x39,
|
||||
(byte)0xfc, (byte)0xf0, (byte)0xe2, (byte)0x42,
|
||||
(byte)0x9a, (byte)0x6b, (byte)0x52, (byte)0x54,
|
||||
(byte)0x16, (byte)0xae, (byte)0xdb, (byte)0xf5,
|
||||
(byte)0xa0, (byte)0xde, (byte)0x6a, (byte)0x57,
|
||||
(byte)0xa6, (byte)0x37, (byte)0xb3, (byte)0x9b
|
||||
};
|
||||
|
||||
byte[] c2 = new byte[] {
|
||||
(byte)0xd2, (byte)0x7e, (byte)0x88, (byte)0x68,
|
||||
(byte)0x1c, (byte)0xe3, (byte)0x24, (byte)0x3c,
|
||||
(byte)0x48, (byte)0x30, (byte)0x16, (byte)0x5a,
|
||||
(byte)0x8f, (byte)0xdc, (byte)0xf9, (byte)0xff,
|
||||
(byte)0x1d, (byte)0xe9, (byte)0xa1, (byte)0xd8,
|
||||
(byte)0xe6, (byte)0xb4, (byte)0x47, (byte)0xef,
|
||||
(byte)0x6e, (byte)0xf7, (byte)0xb7, (byte)0x98,
|
||||
(byte)0x28, (byte)0x66, (byte)0x6e, (byte)0x45,
|
||||
(byte)0x81, (byte)0xe7, (byte)0x90, (byte)0x12,
|
||||
(byte)0xaf, (byte)0x34, (byte)0xdd, (byte)0xd9,
|
||||
(byte)0xe2, (byte)0xf0, (byte)0x37, (byte)0x58,
|
||||
(byte)0x9b, (byte)0x29, (byte)0x2d, (byte)0xb3,
|
||||
(byte)0xe6, (byte)0x7c, (byte)0x03, (byte)0x67,
|
||||
(byte)0x45, (byte)0xfa, (byte)0x22, (byte)0xe7,
|
||||
(byte)0xe9, (byte)0xb7, (byte)0x37, (byte)0x3b
|
||||
};
|
||||
|
||||
byte[] t2 = new byte[] {
|
||||
(byte)0xdc, (byte)0xf5, (byte)0x66, (byte)0xff,
|
||||
(byte)0x29, (byte)0x1c, (byte)0x25, (byte)0xbb,
|
||||
(byte)0xb8, (byte)0x56, (byte)0x8f, (byte)0xc3,
|
||||
(byte)0xd3, (byte)0x76, (byte)0xa6, (byte)0xd9
|
||||
};
|
||||
|
||||
/* AES-128 test vectors */
|
||||
/* The following is an interesting test case from the example
|
||||
* FIPS test vectors for AES-GCM. IVlen = 1 byte */
|
||||
byte[] p3 = new byte[] {
|
||||
(byte)0x57, (byte)0xce, (byte)0x45, (byte)0x1f,
|
||||
(byte)0xa5, (byte)0xe2, (byte)0x35, (byte)0xa5,
|
||||
(byte)0x8e, (byte)0x1a, (byte)0xa2, (byte)0x3b,
|
||||
(byte)0x77, (byte)0xcb, (byte)0xaf, (byte)0xe2
|
||||
};
|
||||
|
||||
byte[] k3 = new byte[] {
|
||||
(byte)0xbb, (byte)0x01, (byte)0xd7, (byte)0x03,
|
||||
(byte)0x81, (byte)0x1c, (byte)0x10, (byte)0x1a,
|
||||
(byte)0x35, (byte)0xe0, (byte)0xff, (byte)0xd2,
|
||||
(byte)0x91, (byte)0xba, (byte)0xf2, (byte)0x4b
|
||||
};
|
||||
|
||||
byte[] iv3 = new byte[] {
|
||||
(byte)0xca
|
||||
};
|
||||
|
||||
byte[] c3 = new byte[] {
|
||||
(byte)0x6b, (byte)0x5f, (byte)0xb3, (byte)0x9d,
|
||||
(byte)0xc1, (byte)0xc5, (byte)0x7a, (byte)0x4f,
|
||||
(byte)0xf3, (byte)0x51, (byte)0x4d, (byte)0xc2,
|
||||
(byte)0xd5, (byte)0xf0, (byte)0xd0, (byte)0x07
|
||||
};
|
||||
|
||||
byte[] a3 = new byte[] {
|
||||
(byte)0x40, (byte)0xfc, (byte)0xdc, (byte)0xd7,
|
||||
(byte)0x4a, (byte)0xd7, (byte)0x8b, (byte)0xf1,
|
||||
(byte)0x3e, (byte)0x7c, (byte)0x60, (byte)0x55,
|
||||
(byte)0x50, (byte)0x51, (byte)0xdd, (byte)0x54
|
||||
};
|
||||
|
||||
byte[] t3 = new byte[] {
|
||||
(byte)0x06, (byte)0x90, (byte)0xed, (byte)0x01,
|
||||
(byte)0x34, (byte)0xdd, (byte)0xc6, (byte)0x95,
|
||||
(byte)0x31, (byte)0x2e, (byte)0x2a, (byte)0xf9,
|
||||
(byte)0x57, (byte)0x7a, (byte)0x1e, (byte)0xa6
|
||||
};
|
||||
|
||||
/**
|
||||
* Make sure AesGcm class is available and not compiled out in native lib
|
||||
*/
|
||||
@BeforeClass
|
||||
public static void checkAvailability() {
|
||||
try {
|
||||
new AesGcm();
|
||||
} catch (WolfCryptException e) {
|
||||
if (e.getError() == WolfCryptError.NOT_COMPILED_IN)
|
||||
System.out.println("AES-GCM test skipped: " + e.getError());
|
||||
Assume.assumeNoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AesGcm() constructor should initialize internal NativeStruct object
|
||||
*/
|
||||
@Test
|
||||
public void constructorShouldInitializeNativeStruct() {
|
||||
assertNotEquals(NativeStruct.NULL, new AesGcm().getNativeStruct());
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic argument checks on AesGcm.setKey()
|
||||
*/
|
||||
@Test
|
||||
public void testSetKey() throws WolfCryptException {
|
||||
|
||||
AesGcm aes = null;
|
||||
|
||||
/* Setting null key in constructor should fail */
|
||||
try {
|
||||
aes = new AesGcm(null);
|
||||
fail("AesGcm(null) should throw exception");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* Test setting key after object creation */
|
||||
|
||||
/* 128-bit key */
|
||||
if (FeatureDetect.Aes128Enabled()) {
|
||||
aes = new AesGcm();
|
||||
aes.setKey(k3);
|
||||
aes.releaseNativeStruct();
|
||||
}
|
||||
|
||||
/* 192-bit key */
|
||||
if (FeatureDetect.Aes192Enabled()) {
|
||||
aes = new AesGcm();
|
||||
aes.setKey(k2);
|
||||
aes.releaseNativeStruct();
|
||||
}
|
||||
|
||||
/* 256-bit key */
|
||||
if (FeatureDetect.Aes256Enabled()) {
|
||||
aes = new AesGcm();
|
||||
aes.setKey(k1);
|
||||
aes.releaseNativeStruct();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAesGcm128() throws WolfCryptException {
|
||||
|
||||
AesGcm enc = new AesGcm();
|
||||
AesGcm dec = new AesGcm();
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t3.length];
|
||||
|
||||
/* skip test if AES-128 is not compiled in native library */
|
||||
if (!FeatureDetect.Aes128Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* encrypt before key setup should throw exception */
|
||||
try {
|
||||
enc.encrypt(null, null, null, null);
|
||||
fail("encrypt() before setKey() should throw exception");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* decrypt before key setup should throw exception */
|
||||
try {
|
||||
dec.decrypt(null, null, null, null);
|
||||
fail("decrypt() before setKey() should throw exception");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
enc.setKey(k3);
|
||||
dec.setKey(k3);
|
||||
|
||||
/* success case */
|
||||
cipher = enc.encrypt(p3, iv3, tag, a3);
|
||||
assertArrayEquals(c3, cipher);
|
||||
assertArrayEquals(t3, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv3, tag, a3);
|
||||
assertArrayEquals(p3, plain);
|
||||
|
||||
/* bad encrypt arguments: null input */
|
||||
try {
|
||||
enc.encrypt(null, iv3, tag, a3);
|
||||
fail("encrypt() with null input should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad encrypt arguments: null iv */
|
||||
try {
|
||||
enc.encrypt(p3, null, tag, a3);
|
||||
fail("encrypt() with null IV should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad encrypt arguments: null tag */
|
||||
try {
|
||||
enc.encrypt(p3, iv3, null, a3);
|
||||
fail("encrypt() with null auth tag should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null input */
|
||||
try {
|
||||
enc.decrypt(null, iv3, tag, a3);
|
||||
fail("decrypt() with null input should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null iv */
|
||||
try {
|
||||
enc.decrypt(cipher, null, tag, a3);
|
||||
fail("decrypt() with null IV should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null tag */
|
||||
try {
|
||||
enc.decrypt(cipher, iv3, null, a3);
|
||||
fail("decrypt() with null auth tag should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* release native structs */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAesGcm192() throws WolfCryptException {
|
||||
|
||||
AesGcm enc = new AesGcm();
|
||||
AesGcm dec = new AesGcm();
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t2.length];
|
||||
|
||||
/* skip test if AES-192 is not compiled in native library, or if
|
||||
* using wolfCrypt FIPS since it only supports 12-byte IVs */
|
||||
if (!FeatureDetect.Aes192Enabled() || Fips.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
enc.setKey(k2);
|
||||
dec.setKey(k2);
|
||||
|
||||
/* success case */
|
||||
cipher = enc.encrypt(p, iv2, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c2, cipher);
|
||||
assertArrayEquals(t2, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv2, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* bad encrypt arguments: null input */
|
||||
try {
|
||||
enc.encrypt(null, iv2, tag, a);
|
||||
fail("encrypt() with null input should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad encrypt arguments: null iv */
|
||||
try {
|
||||
enc.encrypt(p, null, tag, a);
|
||||
fail("encrypt() with null IV should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad encrypt arguments: null tag */
|
||||
try {
|
||||
enc.encrypt(p, iv2, null, a);
|
||||
fail("encrypt() with null auth tag should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null input */
|
||||
try {
|
||||
enc.decrypt(null, iv2, tag, a);
|
||||
fail("decrypt() with null input should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null iv */
|
||||
try {
|
||||
enc.decrypt(cipher, null, tag, a);
|
||||
fail("decrypt() with null IV should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null tag */
|
||||
try {
|
||||
enc.decrypt(cipher, iv2, null, a);
|
||||
fail("decrypt() with null auth tag should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* release native structs */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAesGcm256() throws WolfCryptException {
|
||||
|
||||
AesGcm enc = new AesGcm();
|
||||
AesGcm dec = new AesGcm();
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t1.length];
|
||||
|
||||
/* skip test if AES-192 is not compiled in native library, or if
|
||||
* using wolfCrypt FIPS since it only supports 12-byte IVs */
|
||||
if (!FeatureDetect.Aes256Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
enc.setKey(k1);
|
||||
dec.setKey(k1);
|
||||
|
||||
/* success case */
|
||||
cipher = enc.encrypt(p, iv1, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c1, cipher);
|
||||
assertArrayEquals(t1, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv1, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* bad encrypt arguments: null input */
|
||||
try {
|
||||
enc.encrypt(null, iv1, tag, a);
|
||||
fail("encrypt() with null input should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad encrypt arguments: null iv */
|
||||
try {
|
||||
enc.encrypt(p, null, tag, a);
|
||||
fail("encrypt() with null IV should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad encrypt arguments: null tag */
|
||||
try {
|
||||
enc.encrypt(p, iv1, null, a);
|
||||
fail("encrypt() with null auth tag should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null input */
|
||||
try {
|
||||
enc.decrypt(null, iv1, tag, a);
|
||||
fail("decrypt() with null input should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null iv */
|
||||
try {
|
||||
enc.decrypt(cipher, null, tag, a);
|
||||
fail("decrypt() with null IV should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* bad decrypt arguments: null tag */
|
||||
try {
|
||||
enc.decrypt(cipher, iv1, null, a);
|
||||
fail("decrypt() with null auth tag should fail");
|
||||
} catch (WolfCryptException e) {
|
||||
/* expected */
|
||||
}
|
||||
|
||||
/* release native structs */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseAndReinitObjectAes128() throws WolfCryptException {
|
||||
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t3.length];
|
||||
|
||||
/* skip test if AES-128 is not compiled in native library */
|
||||
if (!FeatureDetect.Aes128Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AesGcm enc = new AesGcm(k3);
|
||||
AesGcm dec = new AesGcm(k3);
|
||||
|
||||
cipher = enc.encrypt(p3, iv3, tag, a3);
|
||||
assertArrayEquals(c3, cipher);
|
||||
assertArrayEquals(t3, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv3, tag, a3);
|
||||
assertArrayEquals(p3, plain);
|
||||
|
||||
/* free objects */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
|
||||
/* try to re-init and re-use them */
|
||||
enc = new AesGcm(k3);
|
||||
dec = new AesGcm(k3);
|
||||
|
||||
cipher = enc.encrypt(p3, iv3, tag, a3);
|
||||
assertArrayEquals(c3, cipher);
|
||||
assertArrayEquals(t3, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv3, tag, a3);
|
||||
assertArrayEquals(p3, plain);
|
||||
|
||||
/* free again */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseAndReinitObjectAes192() throws WolfCryptException {
|
||||
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t2.length];
|
||||
|
||||
/* skip test if AES-192 is not compiled in native library, or if
|
||||
* using wolfCrypt FIPS since it only supports 12-byte IVs */
|
||||
if (!FeatureDetect.Aes192Enabled() || Fips.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
AesGcm enc = new AesGcm(k2);
|
||||
AesGcm dec = new AesGcm(k2);
|
||||
|
||||
cipher = enc.encrypt(p, iv2, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c2, cipher);
|
||||
assertArrayEquals(t2, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv2, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* free objects */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
|
||||
/* try to re-init and re-use them */
|
||||
enc = new AesGcm(k2);
|
||||
dec = new AesGcm(k2);
|
||||
|
||||
cipher = enc.encrypt(p, iv2, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c2, cipher);
|
||||
assertArrayEquals(t2, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv2, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* free again */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseAndReinitObjectAes256() throws WolfCryptException {
|
||||
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t1.length];
|
||||
|
||||
/* skip test if AES-256 is not compiled in native library */
|
||||
if (!FeatureDetect.Aes256Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AesGcm enc = new AesGcm(k1);
|
||||
AesGcm dec = new AesGcm(k1);
|
||||
|
||||
cipher = enc.encrypt(p, iv1, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c1, cipher);
|
||||
assertArrayEquals(t1, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv1, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* free objects */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
|
||||
/* try to re-init and re-use them */
|
||||
enc = new AesGcm(k1);
|
||||
dec = new AesGcm(k1);
|
||||
|
||||
cipher = enc.encrypt(p, iv1, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c1, cipher);
|
||||
assertArrayEquals(t1, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv1, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* free again */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReuseObjectAes128() throws WolfCryptException {
|
||||
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t3.length];
|
||||
|
||||
/* skip test if AES-128 is not compiled in native library */
|
||||
if (!FeatureDetect.Aes128Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AesGcm enc = new AesGcm(k3);
|
||||
AesGcm dec = new AesGcm(k3);
|
||||
|
||||
cipher = enc.encrypt(p3, iv3, tag, a3);
|
||||
assertArrayEquals(c3, cipher);
|
||||
assertArrayEquals(t3, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv3, tag, a3);
|
||||
assertArrayEquals(p3, plain);
|
||||
|
||||
/* now, try to reuse existing enc/dec objects */
|
||||
cipher = enc.encrypt(p3, iv3, tag, a3);
|
||||
assertArrayEquals(c3, cipher);
|
||||
assertArrayEquals(t3, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv3, tag, a3);
|
||||
assertArrayEquals(p3, plain);
|
||||
|
||||
/* free native structs */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReuseObjectAes192() throws WolfCryptException {
|
||||
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t2.length];
|
||||
|
||||
/* skip test if AES-192 is not compiled in native library, or if
|
||||
* using wolfCrypt FIPS since it only supports 12-byte IVs */
|
||||
if (!FeatureDetect.Aes192Enabled() || Fips.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
AesGcm enc = new AesGcm(k2);
|
||||
AesGcm dec = new AesGcm(k2);
|
||||
|
||||
cipher = enc.encrypt(p, iv2, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c2, cipher);
|
||||
assertArrayEquals(t2, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv2, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* now, try to reuse existing enc/dec objects */
|
||||
cipher = enc.encrypt(p, iv2, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c2, cipher);
|
||||
assertArrayEquals(t2, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv2, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* free native structs */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReuseObjectAes256() throws WolfCryptException {
|
||||
|
||||
byte[] cipher = null;
|
||||
byte[] plain = null;
|
||||
byte[] tag = new byte[t1.length];
|
||||
|
||||
/* skip test if AES-256 is not compiled in native library */
|
||||
if (!FeatureDetect.Aes256Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AesGcm enc = new AesGcm(k1);
|
||||
AesGcm dec = new AesGcm(k1);
|
||||
|
||||
cipher = enc.encrypt(p, iv1, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c1, cipher);
|
||||
assertArrayEquals(t1, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv1, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* now, try to reuse existing enc/dec objects */
|
||||
cipher = enc.encrypt(p, iv1, tag, a);
|
||||
assertNotNull(cipher);
|
||||
assertArrayEquals(c1, cipher);
|
||||
assertArrayEquals(t1, tag);
|
||||
|
||||
plain = dec.decrypt(cipher, iv1, tag, a);
|
||||
assertNotNull(plain);
|
||||
assertArrayEquals(p, plain);
|
||||
|
||||
/* free native structs */
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadedAes128() throws InterruptedException {
|
||||
|
||||
int numThreads = 20;
|
||||
ExecutorService service = Executors.newFixedThreadPool(numThreads);
|
||||
final CountDownLatch latch = new CountDownLatch(numThreads);
|
||||
final LinkedBlockingQueue<Integer> results = new LinkedBlockingQueue<>();
|
||||
final byte[] rand2kBuf = new byte[2048];
|
||||
|
||||
/* skip test if AES-128 is not compiled in native library */
|
||||
if (!FeatureDetect.Aes128Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* fill large input buffer with random bytes */
|
||||
new Random().nextBytes(rand2kBuf);
|
||||
|
||||
/* encrypt / decrypt input data, make sure decrypted matches original */
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
service.submit(new Runnable() {
|
||||
@Override public void run() {
|
||||
|
||||
int ret = 0;
|
||||
AesGcm enc = new AesGcm(k3);
|
||||
AesGcm dec = new AesGcm(k3);
|
||||
byte[] cipher = new byte[2048];
|
||||
byte[] plain = new byte[2048];
|
||||
byte[] tag = new byte[t3.length];
|
||||
|
||||
try {
|
||||
cipher = enc.encrypt(rand2kBuf, iv3, tag, null);
|
||||
plain = dec.decrypt(cipher, iv3, tag, null);
|
||||
|
||||
/* make sure decrypted is same as input */
|
||||
if (Arrays.equals(rand2kBuf, plain)) {
|
||||
results.add(0);
|
||||
}
|
||||
else {
|
||||
/* not equal, error case */
|
||||
results.add(1);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
results.add(1);
|
||||
|
||||
} finally {
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* wait for all threads to complete */
|
||||
latch.await();
|
||||
|
||||
/* compare all digests, all should be the same across threads */
|
||||
Iterator<Integer> listIterator = results.iterator();
|
||||
while (listIterator.hasNext()) {
|
||||
Integer cur = listIterator.next();
|
||||
if (cur == 1) {
|
||||
fail("Threading error in AES-GMC-128 thread test");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadedAes192() throws InterruptedException {
|
||||
|
||||
int numThreads = 20;
|
||||
ExecutorService service = Executors.newFixedThreadPool(numThreads);
|
||||
final CountDownLatch latch = new CountDownLatch(numThreads);
|
||||
final LinkedBlockingQueue<Integer> results = new LinkedBlockingQueue<>();
|
||||
final byte[] rand2kBuf = new byte[2048];
|
||||
|
||||
/* skip test if AES-192 is not compiled in native library, or if
|
||||
* using wolfCrypt FIPS since it only supports 12-byte IVs */
|
||||
if (!FeatureDetect.Aes192Enabled() || Fips.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* fill large input buffer with random bytes */
|
||||
new Random().nextBytes(rand2kBuf);
|
||||
|
||||
/* encrypt / decrypt input data, make sure decrypted matches original */
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
service.submit(new Runnable() {
|
||||
@Override public void run() {
|
||||
|
||||
int ret = 0;
|
||||
AesGcm enc = new AesGcm(k2);
|
||||
AesGcm dec = new AesGcm(k2);
|
||||
byte[] cipher = new byte[2048];
|
||||
byte[] plain = new byte[2048];
|
||||
byte[] tag = new byte[t2.length];
|
||||
|
||||
try {
|
||||
cipher = enc.encrypt(rand2kBuf, iv2, tag, null);
|
||||
plain = dec.decrypt(cipher, iv2, tag, null);
|
||||
|
||||
/* make sure decrypted is same as input */
|
||||
if (Arrays.equals(rand2kBuf, plain)) {
|
||||
results.add(0);
|
||||
}
|
||||
else {
|
||||
/* not equal, error case */
|
||||
results.add(1);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
results.add(1);
|
||||
|
||||
} finally {
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* wait for all threads to complete */
|
||||
latch.await();
|
||||
|
||||
/* compare all digests, all should be the same across threads */
|
||||
Iterator<Integer> listIterator = results.iterator();
|
||||
while (listIterator.hasNext()) {
|
||||
Integer cur = listIterator.next();
|
||||
if (cur == 1) {
|
||||
fail("Threading error in AES-GCM-192 thread test");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadedAes256() throws InterruptedException {
|
||||
|
||||
int numThreads = 20;
|
||||
ExecutorService service = Executors.newFixedThreadPool(numThreads);
|
||||
final CountDownLatch latch = new CountDownLatch(numThreads);
|
||||
final LinkedBlockingQueue<Integer> results = new LinkedBlockingQueue<>();
|
||||
final byte[] rand2kBuf = new byte[2048];
|
||||
|
||||
/* skip test if AES-256 is not compiled in native library */
|
||||
if (!FeatureDetect.Aes256Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* fill large input buffer with random bytes */
|
||||
new Random().nextBytes(rand2kBuf);
|
||||
|
||||
/* encrypt / decrypt input data, make sure decrypted matches original */
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
service.submit(new Runnable() {
|
||||
@Override public void run() {
|
||||
|
||||
int ret = 0;
|
||||
AesGcm enc = new AesGcm(k1);
|
||||
AesGcm dec = new AesGcm(k1);
|
||||
byte[] cipher = new byte[2048];
|
||||
byte[] plain = new byte[2048];
|
||||
byte[] tag = new byte[t1.length];
|
||||
|
||||
try {
|
||||
cipher = enc.encrypt(rand2kBuf, iv1, tag, null);
|
||||
plain = dec.decrypt(cipher, iv1, tag, null);
|
||||
|
||||
/* make sure decrypted is same as input */
|
||||
if (Arrays.equals(rand2kBuf, plain)) {
|
||||
results.add(0);
|
||||
}
|
||||
else {
|
||||
/* not equal, error case */
|
||||
results.add(1);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
results.add(1);
|
||||
|
||||
} finally {
|
||||
enc.releaseNativeStruct();
|
||||
dec.releaseNativeStruct();
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* wait for all threads to complete */
|
||||
latch.await();
|
||||
|
||||
/* compare all digests, all should be the same across threads */
|
||||
Iterator<Integer> listIterator = results.iterator();
|
||||
while (listIterator.hasNext()) {
|
||||
Integer cur = listIterator.next();
|
||||
if (cur == 1) {
|
||||
fail("Threading error in AES-GCM-256 thread test");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import org.junit.runners.Suite.SuiteClasses;
|
|||
@RunWith(Suite.class)
|
||||
@SuiteClasses({
|
||||
AesTest.class,
|
||||
AesGcmTest.class,
|
||||
Des3Test.class,
|
||||
ChachaTest.class,
|
||||
Md5Test.class,
|
||||
|
|
Loading…
Reference in New Issue