// SPDX-License-Identifier: BSD-2-Clause
/*
  Copyright (c) Matthias Schiffer <mschiffer@universe-factory.net>
  All rights reserved.
*/

/**
   \file

   Generated lists of ciphers and their implementations
*/


#include "crypto.h"
#include "fastd.h"


extern const fastd_cipher_info_t fastd_cipher_info_aes128_ctr;
extern const fastd_cipher_t fastd_cipher_aes128_ctr_openssl;
extern const fastd_cipher_info_t fastd_cipher_info_null;
extern const fastd_cipher_t fastd_cipher_null_memcpy;
extern const fastd_cipher_info_t fastd_cipher_info_salsa20;
extern const fastd_cipher_t fastd_cipher_salsa20_xmm;
extern const fastd_cipher_t fastd_cipher_salsa20_nacl;
extern const fastd_cipher_info_t fastd_cipher_info_salsa2012;
extern const fastd_cipher_t fastd_cipher_salsa2012_xmm;
extern const fastd_cipher_t fastd_cipher_salsa2012_nacl;


/** A cipher implementation */
typedef struct fastd_cipher_impl {
	const char *name;			/**< The name of the cipher implementation */
	const fastd_cipher_t *impl;		/**< The cipher implementation */
} fastd_cipher_impl_t;

/** A cipher */
typedef struct cipher_entry {
	const char *name;			/**< The name of the cipher */
	const fastd_cipher_info_t *info;	/**< The associated cipher information */
	const fastd_cipher_impl_t *impls;	/**< NULL-terminated array of cipher implementations */
} cipher_entry_t;

static const fastd_cipher_impl_t cipher_aes128_ctr_impls[] = {
{"openssl", &fastd_cipher_aes128_ctr_openssl},
{NULL, NULL}
};
static const fastd_cipher_impl_t cipher_null_impls[] = {
{"memcpy", &fastd_cipher_null_memcpy},
{NULL, NULL}
};
static const fastd_cipher_impl_t cipher_salsa20_impls[] = {
{"xmm", &fastd_cipher_salsa20_xmm},
{"nacl", &fastd_cipher_salsa20_nacl},
{NULL, NULL}
};
static const fastd_cipher_impl_t cipher_salsa2012_impls[] = {
{"xmm", &fastd_cipher_salsa2012_xmm},
{"nacl", &fastd_cipher_salsa2012_nacl},
{NULL, NULL}
};


/** The list of supported ciphers */
static const cipher_entry_t ciphers[] = {
	{"aes128-ctr", &fastd_cipher_info_aes128_ctr, cipher_aes128_ctr_impls},
{"null", &fastd_cipher_info_null, cipher_null_impls},
{"salsa20", &fastd_cipher_info_salsa20, cipher_salsa20_impls},
{"salsa2012", &fastd_cipher_info_salsa2012, cipher_salsa2012_impls},

};

/** The list of chosen cipher implementations */
static const fastd_cipher_t *cipher_conf[array_size(ciphers)] = {};


/** Checks if a cipher implementation is available on the runtime platform */
static inline bool cipher_available(const fastd_cipher_t *cipher) {
	return (!cipher->available) || cipher->available();
}

void fastd_cipher_init(void) {
	size_t i, j;
	for (i = 0; i < array_size(ciphers); i++) {
		for (j = 0; ciphers[i].impls[j].impl; j++) {
			if (cipher_available(ciphers[i].impls[j].impl))
				break;
		}

		cipher_conf[i] = ciphers[i].impls[j].impl;
	}
}

bool fastd_cipher_config(const char *name, const char *impl) {
	size_t i;
	for (i = 0; i < array_size(ciphers); i++) {
		if (!strcmp(ciphers[i].name, name)) {
			size_t j;
			for (j = 0; ciphers[i].impls[j].impl; j++) {
				if (!strcmp(ciphers[i].impls[j].name, impl)) {
					if (!cipher_available(ciphers[i].impls[j].impl))
						return false;

					cipher_conf[i] = ciphers[i].impls[j].impl;
					return true;
				}
			}

			return false;
		}
	}

	return false;
}

const fastd_cipher_info_t * fastd_cipher_info_get_by_name(const char *name) {
	size_t i;
	for (i = 0; i < array_size(ciphers); i++) {
		if (strcmp(ciphers[i].name, name))
			continue;

		if (cipher_conf[i])
			return ciphers[i].info;

		break;
	}

	return NULL;
}

const fastd_cipher_t * fastd_cipher_get(const fastd_cipher_info_t *info) {
	size_t i;
	for (i = 0; i < array_size(ciphers); i++) {
		if (ciphers[i].info == info)
			return cipher_conf[i];
	}

	return NULL;
}
