Files
GajuMobile-Android/app/src/main/cpp/gaju-jni.c
T
2026-09-02 15:25:44 +09:00

104 lines
4.4 KiB
C

/*
* Copyright (c) 2026 QPQ IaaS AG <info@qpq.swiss>. All rights reserved.
* Project: Gajumaru Core Java Libraries <gajumaru.io>
*
* This program is dual-licensed:
* 1) Under the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version (AGPL-3.0-or-later).
*
* 2) Under a commercial/proprietary license available directly from QPQ IaaS AG.
* If you wish to use this software outside the strict constraints of the
* AGPLv3 (e.g. within a closed-source or proprietary product), you must
* purchase a commercial license from QPQ IaaS AG.
*
* Authors:
* - Craig Everett <craigeverett@qpq.swiss>
*
* SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-QPQ-Commercial
*/
#include <jni.h>
#include <sodium.h>
#include <string.h>
JNIEXPORT void JNICALL
Java_swiss_qpq_gajumobile_security_GajuNative_memzero(JNIEnv *env, jclass clazz, jbyteArray array) {
if (array == NULL) return;
jsize len = (*env)->GetArrayLength(env, array);
jbyte *data = (*env)->GetByteArrayElements(env, array, NULL);
if (data != NULL) {
sodium_memzero(data, (size_t) len);
(*env)->ReleaseByteArrayElements(env, array, data, 0);
}
}
JNIEXPORT jbyteArray JNICALL
Java_swiss_qpq_gajumobile_security_GajuNative_cryptoSignSeedKeypair(JNIEnv *env, jclass clazz, jbyteArray seed) {
if (seed == NULL || (*env)->GetArrayLength(env, seed) != crypto_sign_SEEDBYTES) return NULL;
unsigned char pk[crypto_sign_PUBLICKEYBYTES];
unsigned char sk[crypto_sign_SECRETKEYBYTES];
jbyte *seed_data = (*env)->GetByteArrayElements(env, seed, NULL);
crypto_sign_seed_keypair(pk, sk, (unsigned char *) seed_data);
(*env)->ReleaseByteArrayElements(env, seed, seed_data, JNI_ABORT);
jbyteArray result = (*env)->NewByteArray(env, crypto_sign_PUBLICKEYBYTES + crypto_sign_SECRETKEYBYTES);
(*env)->SetByteArrayRegion(env, result, 0, crypto_sign_PUBLICKEYBYTES, (jbyte *) pk);
(*env)->SetByteArrayRegion(env, result, crypto_sign_PUBLICKEYBYTES, crypto_sign_SECRETKEYBYTES, (jbyte *) sk);
sodium_memzero(pk, sizeof pk);
sodium_memzero(sk, sizeof sk);
return result;
}
JNIEXPORT jbyteArray JNICALL
Java_swiss_qpq_gajumobile_security_GajuNative_cryptoSignDetached(JNIEnv *env, jclass clazz, jbyteArray message, jbyteArray secretKey) {
if (message == NULL || secretKey == NULL || (*env)->GetArrayLength(env, secretKey) != crypto_sign_SECRETKEYBYTES) return NULL;
jsize msg_len = (*env)->GetArrayLength(env, message);
unsigned char sig[crypto_sign_BYTES];
jbyte *msg_data = (*env)->GetByteArrayElements(env, message, NULL);
jbyte *sk_data = (*env)->GetByteArrayElements(env, secretKey, NULL);
crypto_sign_detached(sig, NULL, (unsigned char *) msg_data, (unsigned long long) msg_len, (unsigned char *) sk_data);
(*env)->ReleaseByteArrayElements(env, message, msg_data, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, secretKey, sk_data, JNI_ABORT);
jbyteArray result = (*env)->NewByteArray(env, crypto_sign_BYTES);
(*env)->SetByteArrayRegion(env, result, 0, crypto_sign_BYTES, (jbyte *) sig);
return result;
}
JNIEXPORT jboolean JNICALL
Java_swiss_qpq_gajumobile_security_GajuNative_cryptoSignVerifyDetached(JNIEnv *env, jclass clazz, jbyteArray signature, jbyteArray message, jbyteArray publicKey) {
if (signature == NULL || message == NULL || publicKey == NULL) return JNI_FALSE;
if ((*env)->GetArrayLength(env, signature) != crypto_sign_BYTES) return JNI_FALSE;
if ((*env)->GetArrayLength(env, publicKey) != crypto_sign_PUBLICKEYBYTES) return JNI_FALSE;
jsize msg_len = (*env)->GetArrayLength(env, message);
jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
jbyte *msg_data = (*env)->GetByteArrayElements(env, message, NULL);
jbyte *pk_data = (*env)->GetByteArrayElements(env, publicKey, NULL);
int res = crypto_sign_verify_detached((unsigned char *) sig_data, (unsigned char *) msg_data, (unsigned long long) msg_len, (unsigned char *) pk_data);
(*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, message, msg_data, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, publicKey, pk_data, JNI_ABORT);
return res == 0 ? JNI_TRUE : JNI_FALSE;
}
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM* vm, void* reserved) {
if (sodium_init() == -1) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}