/* * Copyright (c) 2026 QPQ IaaS AG . All rights reserved. * Project: Gajumaru Core Java Libraries * * 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 * * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-QPQ-Commercial */ #include #include #include 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; }