/*
 * bfdiff.c - differential test: kernel bf_skey/bf_enc vs LibreSSL's own
 * bf_skey/bf_enc (compiled from the guest's /usr/src trees), random keys,
 * len 1..120 (covers wrap loop fully + the >72 clamp).
 *
 * kernel objects compiled with -DBF_set_key=k_BF_set_key -DBF_encrypt=k_BF_encrypt
 * libressl objects with -DBF_set_key=l_BF_set_key -DBF_encrypt=l_BF_encrypt
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <crypto/blowfish/blowfish.h>

void k_BF_set_key(BF_KEY *, int, unsigned char *);
void k_BF_encrypt(BF_LONG *, BF_KEY *);
void l_BF_set_key(BF_KEY *, int, unsigned char *);
void l_BF_encrypt(BF_LONG *, BF_KEY *);

int
main(void)
{
	BF_KEY kk, lk;
	unsigned char key[120], seed = 57;
	BF_LONG a[2], b[2];
	int len, fails = 0;
	unsigned i;

	for (len = 1; len <= 120; len++) {
		/* cheap deterministic pseudo-random key */
		for (i = 0; i < (unsigned)len; i++) {
			seed = seed * 1103515245 + 12345;
			key[i] = (seed >> 16) & 0xff;
		}
		memset(&kk, 0, sizeof(kk));
		memset(&lk, 0, sizeof(lk));
		k_BF_set_key(&kk, len, key);
		l_BF_set_key(&lk, len, key);
		if (memcmp(&kk, &lk, sizeof(BF_KEY)) != 0) {
			printf("FAIL schedule mismatch len=%d\n", len);
			fails++;
			continue;
		}
		a[0] = 0x01234567; a[1] = 0x89abcdef;
		b[0] = a[0]; b[1] = a[1];
		k_BF_encrypt(a, &kk);
		l_BF_encrypt(b, &lk);
		if (a[0] != b[0] || a[1] != b[1]) {
			printf("FAIL encrypt mismatch len=%d\n", len);
			fails++;
		}
	}
	printf("%s: kernel-vs-libressl bf differential, len 1..120, %d failures\n",
	    fails ? "RESULT-FAIL" : "RESULT-PASS", fails);
	return fails ? 1 : 0;
}
