si-srtp.1.1-19-g1159848.source-code.SrtpCipherGcmAuthOnlyOpenSsl.c Maven / Gradle / Ivy
/*
* Copyright @ 2016 - present 8x8, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct {
EVP_CIPHER_CTX* cipher;
GCM128_CONTEXT* gcm;
} AES_GCM_CONTEXT;
/* Encrypt one block with an EVP_CIPHER_CTX, with a function signature
* compatible with block128_f */
static void EVP_encrypt(const unsigned char in[16],
unsigned char out[16], const void *ctx)
{
EVP_CIPHER_CTX* ctx_ = (EVP_CIPHER_CTX*)ctx;
int len = 16;
EVP_EncryptUpdate(ctx_, out, &len, in, len);
assert(len == 16);
}
/*
* Class: org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi
* Method: CRYPTO_gcm128_new
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi_CRYPTO_1gcm128_1new
(JNIEnv *env, jclass clazz)
{
AES_GCM_CONTEXT* ctx = malloc(sizeof(AES_GCM_CONTEXT));
if (ctx == NULL)
{
goto fail;
}
ctx->cipher = EVP_CIPHER_CTX_new();
if (ctx->cipher == NULL)
{
goto fail;
}
ctx->gcm = NULL;
return (jlong)(uintptr_t)ctx;
fail:
if (ctx != NULL)
{
if (ctx->cipher != NULL)
{
EVP_CIPHER_CTX_free(ctx->cipher);
}
free(ctx);
}
return 0;
}
/*
* Class: org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi
* Method: CRYPTO_gcm128_release
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi_CRYPTO_1gcm128_1release
(JNIEnv *env, jclass clazz, jlong ctx)
{
if (ctx != 0)
{
AES_GCM_CONTEXT* ctx_ = (AES_GCM_CONTEXT*) (uintptr_t) ctx;
if (ctx_->gcm != NULL)
{
CRYPTO_gcm128_release(ctx_->gcm);
}
EVP_CIPHER_CTX_free(ctx_->cipher);
free(ctx_);
}
}
/*
* Class: org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi
* Method: CRYPTO_gcm128_init
* Signature: (J[B)Z
*/
JNIEXPORT jboolean JNICALL Java_org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi_CRYPTO_1gcm128_1init
(JNIEnv *env, jobject thiz, jlong ctx, jbyteArray key)
{
jboolean r = JNI_FALSE;
AES_GCM_CONTEXT* ctx_ = (AES_GCM_CONTEXT*)ctx;
size_t keylen = (size_t)(*env)->GetArrayLength(env, key);
unsigned char *key_ = (unsigned char*)(*env)->GetPrimitiveArrayCritical(env, key, NULL);
if (key_ == NULL)
goto exit;
const EVP_CIPHER* cipher;
switch(keylen)
{
case 16:
cipher = EVP_aes_128_ecb();
break;
case 24:
cipher = EVP_aes_192_ecb();
break;
case 32:
cipher = EVP_aes_256_ecb();
break;
default:
goto exit;
}
r = EVP_EncryptInit_ex(ctx_->cipher, cipher, NULL, key_, NULL);
if (!r)
{
goto exit;
}
ctx_->gcm = CRYPTO_gcm128_new(ctx_->cipher, EVP_encrypt);
r = (ctx_->gcm != NULL);
exit:
if (key_ != NULL)
(*env)->ReleasePrimitiveArrayCritical(env, key, key_, 0);
return r;
}
/*
* Class: org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi
* Method: CRYPTO_gcm128_setiv
* Signature: (J[BI)Z
*/
JNIEXPORT jboolean JNICALL Java_org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi_CRYPTO_1gcm128_1setiv
(JNIEnv *env, jobject thiz, jlong ctx, jbyteArray iv, jint len)
{
jboolean ok = JNI_FALSE;
AES_GCM_CONTEXT* ctx_ = (AES_GCM_CONTEXT*)ctx;
if (ctx_->gcm == NULL)
return JNI_FALSE; /* Not initialized */
unsigned char *iv_ = (unsigned char*)(*env)->GetPrimitiveArrayCritical(env, iv, NULL);
if (iv_ == NULL)
return JNI_FALSE;
CRYPTO_gcm128_setiv(ctx_->gcm, iv_, len);
ok = JNI_TRUE;
(*env)->ReleasePrimitiveArrayCritical(env, iv, iv_, 0);
return ok;
}
/*
* Class: org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi
* Method: CRYPTO_gcm128_aad
* Signature: (J[BII)Z
*/
JNIEXPORT jboolean JNICALL Java_org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi_CRYPTO_1gcm128_1aad
(JNIEnv *env, jobject thiz, jlong ctx, jbyteArray in, jint inOffset, jint len)
{
jboolean ok = 0;
AES_GCM_CONTEXT* ctx_ = (AES_GCM_CONTEXT*)ctx;
if (ctx_->gcm == NULL)
return JNI_FALSE; /* Not initialized */
unsigned char *in_ = (unsigned char*)(*env)->GetPrimitiveArrayCritical(env, in, NULL);
if (in_ == NULL)
return JNI_FALSE;
ok = (CRYPTO_gcm128_aad(ctx_->gcm, in_ + inOffset, len) == 0);
(*env)->ReleasePrimitiveArrayCritical(env, in, in_, 0);
return ok;
}
/* A null cipher, suitable for passing as ctr128_f. */
static void null_cipher(const unsigned char *in, unsigned char *out,
size_t blocks, const void *key,
const unsigned char ivec[16])
{
return;
}
/*
* Class: org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi
* Method: CRYPTO_gcm128_decrypt
* Signature: (J[BII)Z
*/
JNIEXPORT jboolean JNICALL Java_org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi_CRYPTO_1gcm128_1decrypt
(JNIEnv *env, jobject thiz, jlong ctx, jbyteArray in, jint inOffset, jint len)
{
jboolean ok = 0;
AES_GCM_CONTEXT* ctx_ = (AES_GCM_CONTEXT*)ctx;
if (ctx_->gcm == NULL)
return JNI_FALSE; /* Not initialized */
unsigned char *in_ = (unsigned char*)(*env)->GetPrimitiveArrayCritical(env, in, NULL);
if (in_ == NULL)
return JNI_FALSE;
/* In order to do auth-without-decrypt with an OpenSSL GCM_CONTEXT, we call
* int CRYPTO_gcm128_decrypt_ctr32 with a no-op stream cipher. */
ok = (CRYPTO_gcm128_decrypt_ctr32(ctx_->gcm, in_ + inOffset,
in_ + inOffset, len, null_cipher) == 0);
(*env)->ReleasePrimitiveArrayCritical(env, in, in_, 0);
return ok;
}
/*
* Class: org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi
* Method: CRYPTO_gcm128_finish
* Signature: (J[BII)Z
*/
JNIEXPORT jboolean JNICALL Java_org_jitsi_srtp_crypto_OpenSslAesGcmAuthOnlyCipherSpi_CRYPTO_1gcm128_1finish
(JNIEnv * env, jobject thiz, jlong ctx, jbyteArray tag, jint tagOffset, jint tagLen)
{
int ok = 0;
AES_GCM_CONTEXT* ctx_ = (AES_GCM_CONTEXT*)ctx;
if (ctx_->gcm == NULL)
return JNI_FALSE; /* Not initialized */
unsigned char *tag_ = (unsigned char*)(*env)->GetPrimitiveArrayCritical(env, tag, NULL);
if (!tag_)
return JNI_FALSE;
ok = (CRYPTO_gcm128_finish(ctx_->gcm, tag_ + tagOffset, tagLen) == 0);
(*env)->ReleasePrimitiveArrayCritical(env, tag, tag_, 0);
return ok;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy