/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2024 Brett A C Sheffield <bacs@librecast.net> */

#include "test.h"
#include "key.h"

#define MESSAGE (const unsigned char *) "test"
#define MESSAGE_LEN 4
#define CIPHERTEXT_LEN (crypto_box_MACBYTES + MESSAGE_LEN)
int verify_crypto_key(unsigned char *public, unsigned char *secret)
{
	unsigned char nonce[crypto_box_NONCEBYTES];
	unsigned char ciphertext[CIPHERTEXT_LEN];
	int rc;

	randombytes_buf(nonce, sizeof nonce);
	rc = crypto_box_easy(ciphertext, MESSAGE, MESSAGE_LEN, nonce, public, secret);
	if (!test_assert(rc == 0, "crypto_secretbox_easy()")) return test_status;

	unsigned char decrypted[MESSAGE_LEN];
	rc = crypto_box_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce, public, secret);
	test_assert(rc == 0, "decrypt message");
	return test_status;
}

int verify_signing_key(unsigned char *public, unsigned char *secret)
{
	unsigned char signed_message[crypto_sign_BYTES + MESSAGE_LEN];
	unsigned long long signed_message_len;
	int rc;

	rc = crypto_sign(signed_message, &signed_message_len, MESSAGE, MESSAGE_LEN, secret);
	if (!test_assert(rc == 0, "crypto_secretbox_easy()")) return test_status;

	unsigned char unsigned_message[MESSAGE_LEN];
	unsigned long long unsigned_message_len;
	rc = crypto_sign_open(unsigned_message, &unsigned_message_len, signed_message,
			signed_message_len, public);
	test_assert(rc == 0, "verify signature");
	return test_status;
}

int main(void)
{
	char name[] = "key_gen_combopair_hex() - generate hex keypair + verify";
	key_combo_t keyring;
	char *psk_hex = keyring.phex + HEXKEY_PUBLIC_CRYPTBYTES;
	char *ssk_hex = keyring.shex + HEXKEY_SECRET_CRYPTBYTES;
	unsigned char public_bin[KEY_PUBLIC_BYTES];
	unsigned char secret_bin[KEY_SECRET_BYTES];
	unsigned char *psk_bin = public_bin + crypto_box_PUBLICKEYBYTES;
	unsigned char *ssk_bin = secret_bin + crypto_box_SECRETKEYBYTES;
	int rc;

	test_name(name);

	rc = key_gen_combopair_hex(&keyring);
	test_assert(rc == 0, "key_gen_combopair_hex()");

	/* decode encryption keys */
	rc = sodium_hex2bin(
			public_bin, crypto_box_PUBLICKEYBYTES,
			keyring.phex, HEXKEY_PUBLIC_CRYPTBYTES,
			NULL, NULL, NULL);
	test_assert(rc == 0, "sodium_hex2bin() - decode public encryption key");
	rc = sodium_hex2bin(
			secret_bin, crypto_box_SECRETKEYBYTES,
			keyring.shex, HEXKEY_SECRET_CRYPTBYTES,
			NULL, NULL, NULL);
	test_assert(rc == 0, "sodium_hex2bin() - decode secret encryption key");

	/* decode signing keys */
	rc = sodium_hex2bin(
			psk_bin, crypto_sign_PUBLICKEYBYTES,
			psk_hex, HEXKEY_PUBLIC_SIGNBYTES,
			NULL, NULL, NULL);
	test_assert(rc == 0, "sodium_hex2bin() - decode public signing key");
	rc = sodium_hex2bin(
			ssk_bin, crypto_sign_SECRETKEYBYTES,
			ssk_hex, HEXKEY_SECRET_SIGNBYTES,
			NULL, NULL, NULL);
	test_assert(rc == 0, "sodium_hex2bin() - decode secret signing key");

	/* verify the first part of the key is an encryption key */
	if (verify_crypto_key(public_bin, secret_bin)) return test_status;

	/* verify the second part of the key is a signing key */
	if (verify_signing_key(psk_bin, ssk_bin)) return test_status;

	return 0;
}
