svn commit: r331417 - head/tools/tools/crypto

Conrad Meyer cem at FreeBSD.org
Fri Mar 23 04:31:20 UTC 2018


Author: cem
Date: Fri Mar 23 04:31:19 2018
New Revision: 331417
URL: https://svnweb.freebsd.org/changeset/base/331417

Log:
  Bring in JHB's cryptocheck tool
  
  It can be used to validate basic algorithm correctness on a variety of inputs,
  by comarison to openssl.
  
  While here, add some sanity to the crypto/Makefile.
  
  The tool may not be perfect, but getting it in tree where collaboration can
  happen is a nice first step.  The pace of development outside of svn seems
  to have slowed down mid-2017.
  
  Obtained from:	github bsdjhb/freebsd:cryptocheck
  Sponsored by:	Dell EMC Isilon

Added:
  head/tools/tools/crypto/cryptocheck.c   (contents, props changed)
Modified:
  head/tools/tools/crypto/Makefile

Modified: head/tools/tools/crypto/Makefile
==============================================================================
--- head/tools/tools/crypto/Makefile	Fri Mar 23 03:48:45 2018	(r331416)
+++ head/tools/tools/crypto/Makefile	Fri Mar 23 04:31:19 2018	(r331417)
@@ -1,5 +1,6 @@
 #	$FreeBSD$
 #
+# Copyright (c) 2018		Conrad Meyer <cem at FreeBSD.org>
 # Copyright (c) 2002, 2003	Sam Leffler, Errno Consulting
 # All rights reserved.
 #
@@ -25,40 +26,23 @@
 # SUCH DAMAGE.
 #
 
-ALL=	cryptotest cryptokeytest cryptostats \
+PROGS=	cryptocheck cryptotest cryptokeytest cryptostats \
 	ubsecstats hifnstats ipsecstats safestats
-BINDIR=	/usr/local/bin
+MAN=
+BINDIR?=	/usr/local/bin
 
-all:	${ALL}
+# cryptocheck: test symmetric crypto functions
+LIBADD.cryptocheck+=	crypto ssl util
 
-# program to test asymmetric crypto functions
-cryptokeytest: cryptokeytest.c
-	${CC} -o cryptokeytest cryptokeytest.c -lcrypto
+# cryptokeytest: test asymmetric crypto functions
+LIBADD.cryptokeytest+=	crypto
 
-# program to dump statistics kept by the core crypto code
-cryptostats: cryptostats.c
-	${CC} -o cryptostats cryptostats.c
+# cryptostats: dump statistics kept by the core crypto code
+# ubsecstats: print statistics kept by the Broadcom driver
+# hifnstats: print statistics kept by the HIFN driver
+# safestats: statistics kept by the SafeNet driver
+# ipsecstats: print statistics kept by fast ipsec
 
-# program to print statistics kept by the Broadcom driver
-ubsecstats: ubsecstats.c
-	${CC} -o ubsecstats ubsecstats.c
+CLEANFILES+=	core a.out
 
-# program to print statistics kept by the HIFN driver
-hifnstats: hifnstats.c
-	${CC} -o hifnstats hifnstats.c
-
-# program to print statistics kept by the SafeNet driver
-safestats: safestats.c
-	${CC} -o safestats safestats.c
-
-# program to print statistics kept by fast ipsec
-ipsecstats: ipsecstats.c
-	${CC} -o ipsecstats ipsecstats.c
-
-clean:
-	rm -f ${ALL} core a.out
-
-install: ${ALL}
-	for i in ${ALL}; do \
-		install $$i ${DESTDIR}${BINDIR}; \
-	done
+.include <bsd.progs.mk>

Added: head/tools/tools/crypto/cryptocheck.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/tools/crypto/cryptocheck.c	Fri Mar 23 04:31:19 2018	(r331417)
@@ -0,0 +1,1168 @@
+/*-
+ * Copyright (c) 2017 John Baldwin, <jhb at FreeBSD.org>
+ * Copyright (c) 2004 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * A different tool for checking hardware crypto support.  Whereas
+ * cryptotest is focused on simple performance numbers, this tool is
+ * focused on correctness.  For each crypto operation, it performs the
+ * operation once in software via OpenSSL and a second time via
+ * OpenCrypto and compares the results.
+ *
+ * cryptocheck [-vz] [-A aad length] [-a algorithm] [-d dev] [size ...]
+ *
+ * Options:
+ *	-v	Verbose.
+ *	-z	Run all algorithms on a variety of buffer sizes.
+ *
+ * Supported algorithms:
+ *	all		Run all tests
+ *	hmac		Run all hmac tests
+ *	blkcipher	Run all block cipher tests
+ *	authenc		Run all authenticated encryption tests
+ *	aead		Run all authenticated encryption with associated data
+ *			tests
+ *
+ * HMACs:
+ *	sha1		sha1 hmac
+ *	sha256		256-bit sha2 hmac
+ *	sha384		384-bit sha2 hmac
+ *	sha512		512-bit	sha2 hmac
+ *
+ * Block Ciphers:
+ *	aes-cbc		128-bit aes cbc
+ *	aes-cbc192	192-bit	aes cbc
+ *	aes-cbc256	256-bit aes cbc
+ *	aes-ctr		128-bit aes ctr
+ *	aes-ctr192	192-bit aes ctr
+ *	aes-ctr256	256-bit aes ctr
+ *	aes-xts		128-bit aes xts
+ *	aes-xts256	256-bit aes xts
+ *
+ * Authenticated Encryption:
+ *	<block cipher>+<hmac>
+ *
+ * Authenticated Encryption with Associated Data:
+ *	aes-gcm		128-bit aes gcm
+ *	aes-gcm192	192-bit aes gcm
+ *	aes-gcm256	256-bit aes gcm
+ */
+
+#include <sys/param.h>
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/err.h>
+#include <openssl/hmac.h>
+
+#include <crypto/cryptodev.h>
+
+/* XXX: Temporary hack */
+#ifndef COP_F_CIPHER_FIRST
+#define	COP_F_CIPHER_FIRST	0x0001	/* Cipher before MAC. */
+#endif
+
+struct alg {
+	const char *name;
+	int cipher;
+	int mac;
+	enum { T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type;
+	const EVP_CIPHER *(*evp_cipher)(void);
+	const EVP_MD *(*evp_md)(void);
+} algs[] = {
+	{ .name = "sha1", .mac = CRYPTO_SHA1_HMAC, .type = T_HMAC,
+	  .evp_md = EVP_sha1 },
+	{ .name = "sha256", .mac = CRYPTO_SHA2_256_HMAC, .type = T_HMAC,
+	  .evp_md = EVP_sha256 },
+	{ .name = "sha384", .mac = CRYPTO_SHA2_384_HMAC, .type = T_HMAC,
+	  .evp_md = EVP_sha384 },
+	{ .name = "sha512", .mac = CRYPTO_SHA2_512_HMAC, .type = T_HMAC,
+	  .evp_md = EVP_sha512 },
+	{ .name = "aes-cbc", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
+	  .evp_cipher = EVP_aes_128_cbc },
+	{ .name = "aes-cbc192", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
+	  .evp_cipher = EVP_aes_192_cbc },
+	{ .name = "aes-cbc256", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
+	  .evp_cipher = EVP_aes_256_cbc },
+	{ .name = "aes-ctr", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
+	  .evp_cipher = EVP_aes_128_ctr },
+	{ .name = "aes-ctr192", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
+	  .evp_cipher = EVP_aes_192_ctr },
+	{ .name = "aes-ctr256", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
+	  .evp_cipher = EVP_aes_256_ctr },
+	{ .name = "aes-xts", .cipher = CRYPTO_AES_XTS, .type = T_BLKCIPHER,
+	  .evp_cipher = EVP_aes_128_xts },
+	{ .name = "aes-xts256", .cipher = CRYPTO_AES_XTS, .type = T_BLKCIPHER,
+	  .evp_cipher = EVP_aes_256_xts },
+	{ .name = "aes-gcm", .cipher = CRYPTO_AES_NIST_GCM_16,
+	  .mac = CRYPTO_AES_128_NIST_GMAC, .type = T_GCM,
+	  .evp_cipher = EVP_aes_128_gcm },
+	{ .name = "aes-gcm192", .cipher = CRYPTO_AES_NIST_GCM_16,
+	  .mac = CRYPTO_AES_192_NIST_GMAC, .type = T_GCM,
+	  .evp_cipher = EVP_aes_192_gcm },
+	{ .name = "aes-gcm256", .cipher = CRYPTO_AES_NIST_GCM_16,
+	  .mac = CRYPTO_AES_256_NIST_GMAC, .type = T_GCM,
+	  .evp_cipher = EVP_aes_256_gcm },
+};
+
+static bool verbose;
+static int crid;
+static size_t aad_len;
+
+static void
+usage(void)
+{
+	fprintf(stderr,
+	    "usage: cryptocheck [-z] [-a algorithm] [-d dev] [size ...]\n");
+	exit(1);
+}
+
+static struct alg *
+find_alg(const char *name)
+{
+	u_int i;
+
+	for (i = 0; i < nitems(algs); i++)
+		if (strcasecmp(algs[i].name, name) == 0)
+			return (&algs[i]);
+	return (NULL);
+}
+
+static struct alg *
+build_authenc(struct alg *cipher, struct alg *hmac)
+{
+	static struct alg authenc;
+	char *name;
+
+	assert(cipher->type == T_BLKCIPHER);
+	assert(hmac->type == T_HMAC);
+	memset(&authenc, 0, sizeof(authenc));
+	asprintf(&name, "%s+%s", cipher->name, hmac->name);
+	authenc.name = name;
+	authenc.cipher = cipher->cipher;
+	authenc.mac = hmac->mac;
+	authenc.type = T_AUTHENC;
+	authenc.evp_cipher = cipher->evp_cipher;
+	authenc.evp_md = hmac->evp_md;
+	return (&authenc);
+}
+
+static struct alg *
+build_authenc_name(const char *name)
+{
+	struct alg *cipher, *hmac;
+	const char *hmac_name;
+	char *cp, *cipher_name;
+
+	cp = strchr(name, '+');
+	cipher_name = strndup(name, cp - name);
+	hmac_name = cp + 1;
+	cipher = find_alg(cipher_name);
+	free(cipher_name);
+	if (cipher == NULL)
+		errx(1, "Invalid cipher %s", cipher_name);
+	hmac = find_alg(hmac_name);
+	if (hmac == NULL)
+		errx(1, "Invalid hash %s", hmac_name);
+	return (build_authenc(cipher, hmac));
+}
+
+static int
+devcrypto(void)
+{
+	static int fd = -1;
+
+	if (fd < 0) {
+		fd = open("/dev/crypto", O_RDWR | O_CLOEXEC, 0);
+		if (fd < 0)
+			err(1, "/dev/crypto");
+	}
+	return (fd);
+}
+
+static int
+crlookup(const char *devname)
+{
+	struct crypt_find_op find;
+
+	if (strncmp(devname, "soft", 4) == 0)
+		return CRYPTO_FLAG_SOFTWARE;
+
+	find.crid = -1;
+	strlcpy(find.name, devname, sizeof(find.name));
+	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
+		err(1, "ioctl(CIOCFINDDEV)");
+	return (find.crid);
+}
+
+const char *
+crfind(int crid)
+{
+	static struct crypt_find_op find;
+
+	if (crid == CRYPTO_FLAG_SOFTWARE)
+		return ("soft");
+	else if (crid == CRYPTO_FLAG_HARDWARE)
+		return ("unknown");
+
+	bzero(&find, sizeof(find));
+	find.crid = crid;
+	if (ioctl(devcrypto(), CRIOFINDDEV, &find) == -1)
+		err(1, "ioctl(CIOCFINDDEV): crid %d", crid);
+	return (find.name);
+}
+
+static int
+crget(void)
+{
+	int fd;
+
+	if (ioctl(devcrypto(), CRIOGET, &fd) == -1)
+		err(1, "ioctl(CRIOGET)");
+	if (fcntl(fd, F_SETFD, 1) == -1)
+		err(1, "fcntl(F_SETFD) (crget)");
+	return fd;
+}
+
+static char
+rdigit(void)
+{
+	const char a[] = {
+		0x10,0x54,0x11,0x48,0x45,0x12,0x4f,0x13,0x49,0x53,0x14,0x41,
+		0x15,0x16,0x4e,0x55,0x54,0x17,0x18,0x4a,0x4f,0x42,0x19,0x01
+	};
+	return 0x20+a[random()%nitems(a)];
+}
+
+static char *
+alloc_buffer(size_t len)
+{
+	char *buf;
+	size_t i;
+
+	buf = malloc(len);
+	for (i = 0; i < len; i++)
+		buf[i] = rdigit();
+	return (buf);
+}
+
+static char *
+generate_iv(size_t len, struct alg *alg)
+{
+	char *iv;
+
+	iv = alloc_buffer(len);
+	switch (alg->cipher) {
+	case CRYPTO_AES_ICM:
+		/* Clear the low 32 bits of the IV to hold the counter. */
+		iv[len - 4] = 0;
+		iv[len - 3] = 0;
+		iv[len - 2] = 0;
+		iv[len - 1] = 0;
+		break;
+	case CRYPTO_AES_XTS:
+		/*
+		 * Clear the low 64-bits to only store a 64-bit block
+		 * number.
+		 */
+		iv[len - 8] = 0;
+		iv[len - 7] = 0;
+		iv[len - 6] = 0;
+		iv[len - 5] = 0;
+		iv[len - 4] = 0;
+		iv[len - 3] = 0;
+		iv[len - 2] = 0;
+		iv[len - 1] = 0;
+		break;
+	}
+	return (iv);
+}
+
+static bool
+ocf_hmac(struct alg *alg, const char *buffer, size_t size, const char *key,
+    size_t key_len, char *digest, int *cridp)
+{
+	struct session2_op sop;
+	struct crypt_op cop;
+	int fd;
+
+	memset(&sop, 0, sizeof(sop));
+	memset(&cop, 0, sizeof(cop));
+	sop.crid = crid;
+	sop.mackeylen = key_len;
+	sop.mackey = (char *)key;
+	sop.mac = alg->mac;
+	fd = crget();
+	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
+		warn("cryptodev %s HMAC not supported for device %s",
+		    alg->name, crfind(crid));
+		close(fd);
+		return (false);
+	}
+
+	cop.ses = sop.ses;
+	cop.op = 0;
+	cop.len = size;
+	cop.src = (char *)buffer;
+	cop.dst = NULL;
+	cop.mac = digest;
+	cop.iv = NULL;
+
+	if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
+		warn("cryptodev %s (%zu) HMAC failed for device %s", alg->name,
+		    size, crfind(crid));
+		close(fd);
+		return (false);
+	}
+
+	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
+		warn("ioctl(CIOCFSESSION)");
+
+	close(fd);
+	*cridp = sop.crid;
+	return (true);
+}
+
+static void
+run_hmac_test(struct alg *alg, size_t size)
+{
+	const EVP_MD *md;
+	char *key, *buffer;
+	u_int key_len, digest_len;
+	int crid;
+	char control_digest[EVP_MAX_MD_SIZE], test_digest[EVP_MAX_MD_SIZE];
+
+	memset(control_digest, 0x3c, sizeof(control_digest));
+	memset(test_digest, 0x3c, sizeof(test_digest));
+
+	md = alg->evp_md();
+	key_len = EVP_MD_size(md);
+	assert(EVP_MD_size(md) <= sizeof(control_digest));
+
+	key = alloc_buffer(key_len);
+	buffer = alloc_buffer(size);
+
+	/* OpenSSL HMAC. */
+	digest_len = sizeof(control_digest);
+	if (HMAC(md, key, key_len, (u_char *)buffer, size,
+	    (u_char *)control_digest, &digest_len) == NULL)
+		errx(1, "OpenSSL %s (%zu) HMAC failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+
+	/* cryptodev HMAC. */
+	if (!ocf_hmac(alg, buffer, size, key, key_len, test_digest, &crid))
+		goto out;
+	if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
+		if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
+			printf("%s (%zu) mismatch in trailer:\n",
+			    alg->name, size);
+		else
+			printf("%s (%zu) mismatch:\n", alg->name, size);
+		printf("control:\n");
+		hexdump(control_digest, sizeof(control_digest), NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(test_digest, sizeof(test_digest), NULL, 0);
+		goto out;
+	}
+
+	if (verbose)
+		printf("%s (%zu) matched (cryptodev device %s)\n",
+		    alg->name, size, crfind(crid));
+
+out:
+	free(buffer);
+	free(key);
+}
+
+static void
+openssl_cipher(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
+    const char *iv, const char *input, char *output, size_t size, int enc)
+{
+	EVP_CIPHER_CTX *ctx;
+	int outl, total;
+
+	ctx = EVP_CIPHER_CTX_new();
+	if (ctx == NULL)
+		errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	if (EVP_CipherInit_ex(ctx, cipher, NULL, (const u_char *)key,
+	    (const u_char *)iv, enc) != 1)
+		errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	if (EVP_CipherUpdate(ctx, (u_char *)output, &outl,
+	    (const u_char *)input, size) != 1)
+		errx(1, "OpenSSL %s (%zu) cipher update failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	total = outl;
+	if (EVP_CipherFinal_ex(ctx, (u_char *)output + outl, &outl) != 1)
+		errx(1, "OpenSSL %s (%zu) cipher final failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	total += outl;
+	if (total != size)
+		errx(1, "OpenSSL %s (%zu) cipher size mismatch: %d", alg->name,
+		    size, total);
+	EVP_CIPHER_CTX_free(ctx);
+}
+
+static bool
+ocf_cipher(struct alg *alg, const char *key, size_t key_len,
+    const char *iv, const char *input, char *output, size_t size, int enc,
+    int *cridp)
+{
+	struct session2_op sop;
+	struct crypt_op cop;
+	int fd;
+
+	memset(&sop, 0, sizeof(sop));
+	memset(&cop, 0, sizeof(cop));
+	sop.crid = crid;
+	sop.keylen = key_len;
+	sop.key = (char *)key;
+	sop.cipher = alg->cipher;
+	fd = crget();
+	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
+		warn("cryptodev %s block cipher not supported for device %s",
+		    alg->name, crfind(crid));
+		close(fd);
+		return (false);
+	}
+
+	cop.ses = sop.ses;
+	cop.op = enc ? COP_ENCRYPT : COP_DECRYPT;
+	cop.len = size;
+	cop.src = (char *)input;
+	cop.dst = output;
+	cop.mac = NULL;
+	cop.iv = (char *)iv;
+
+	if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
+		warn("cryptodev %s (%zu) block cipher failed for device %s",
+		    alg->name, size, crfind(crid));
+		close(fd);
+		return (false);
+	}
+
+	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
+		warn("ioctl(CIOCFSESSION)");
+
+	close(fd);
+	*cridp = sop.crid;
+	return (true);
+}
+
+static void
+run_blkcipher_test(struct alg *alg, size_t size)
+{
+	const EVP_CIPHER *cipher;
+	char *buffer, *cleartext, *ciphertext;
+	char *iv, *key;
+	u_int iv_len, key_len;
+	int crid;
+
+	cipher = alg->evp_cipher();
+	if (size % EVP_CIPHER_block_size(cipher) != 0) {
+		if (verbose)
+			printf(
+			    "%s (%zu): invalid buffer size (block size %d)\n",
+			    alg->name, size, EVP_CIPHER_block_size(cipher));
+		return;
+	}
+
+	key_len = EVP_CIPHER_key_length(cipher);
+	iv_len = EVP_CIPHER_iv_length(cipher);
+
+	key = alloc_buffer(key_len);
+	iv = generate_iv(iv_len, alg);
+	cleartext = alloc_buffer(size);
+	buffer = malloc(size);
+	ciphertext = malloc(size);
+
+	/* OpenSSL cipher. */
+	openssl_cipher(alg, cipher, key, iv, cleartext, ciphertext, size, 1);
+	if (size > 0 && memcmp(cleartext, ciphertext, size) == 0)
+		errx(1, "OpenSSL %s (%zu): cipher text unchanged", alg->name,
+		    size);
+	openssl_cipher(alg, cipher, key, iv, ciphertext, buffer, size, 0);
+	if (memcmp(cleartext, buffer, size) != 0) {
+		printf("OpenSSL %s (%zu): cipher mismatch:", alg->name, size);
+		printf("original:\n");
+		hexdump(cleartext, size, NULL, 0);
+		printf("decrypted:\n");
+		hexdump(buffer, size, NULL, 0);
+		exit(1);
+	}
+
+	/* OCF encrypt. */
+	if (!ocf_cipher(alg, key, key_len, iv, cleartext, buffer, size, 1,
+	    &crid))
+		goto out;
+	if (memcmp(ciphertext, buffer, size) != 0) {
+		printf("%s (%zu) encryption mismatch:\n", alg->name, size);
+		printf("control:\n");
+		hexdump(ciphertext, size, NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(buffer, size, NULL, 0);
+		goto out;
+	}
+
+	/* OCF decrypt. */
+	if (!ocf_cipher(alg, key, key_len, iv, ciphertext, buffer, size, 0,
+	    &crid))
+		goto out;
+	if (memcmp(cleartext, buffer, size) != 0) {
+		printf("%s (%zu) decryption mismatch:\n", alg->name, size);
+		printf("control:\n");
+		hexdump(cleartext, size, NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(buffer, size, NULL, 0);
+		goto out;
+	}
+
+	if (verbose)
+		printf("%s (%zu) matched (cryptodev device %s)\n",
+		    alg->name, size, crfind(crid));
+
+out:
+	free(ciphertext);
+	free(buffer);
+	free(cleartext);
+	free(iv);
+	free(key);
+}
+
+static bool
+ocf_authenc(struct alg *alg, const char *cipher_key, size_t cipher_key_len,
+    const char *iv, size_t iv_len, const char *auth_key, size_t auth_key_len,
+    const char *aad, size_t aad_len, const char *input, char *output,
+    size_t size, char *digest, int enc, int *cridp)
+{
+	struct session2_op sop;
+	int fd;
+
+	memset(&sop, 0, sizeof(sop));
+	sop.crid = crid;
+	sop.keylen = cipher_key_len;
+	sop.key = (char *)cipher_key;
+	sop.cipher = alg->cipher;
+	sop.mackeylen = auth_key_len;
+	sop.mackey = (char *)auth_key;
+	sop.mac = alg->mac;
+	fd = crget();
+	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
+		warn("cryptodev %s AUTHENC not supported for device %s",
+		    alg->name, crfind(crid));
+		close(fd);
+		return (false);
+	}
+
+	if (aad_len != 0) {
+		struct crypt_aead caead;
+
+		memset(&caead, 0, sizeof(caead));
+		caead.ses = sop.ses;
+		caead.op = enc ? COP_ENCRYPT : COP_DECRYPT;
+		caead.flags = enc ? COP_F_CIPHER_FIRST : 0;
+		caead.len = size;
+		caead.aadlen = aad_len;
+		caead.ivlen = iv_len;
+		caead.src = (char *)input;
+		caead.dst = output;
+		caead.aad = (char *)aad;
+		caead.tag = digest;
+		caead.iv = (char *)iv;
+
+		if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) {
+			warn("cryptodev %s (%zu) failed for device %s",
+			    alg->name, size, crfind(crid));
+			close(fd);
+			return (false);
+		}
+	} else {
+		struct crypt_op cop;
+
+		memset(&cop, 0, sizeof(cop));
+		cop.ses = sop.ses;
+		cop.op = enc ? COP_ENCRYPT : COP_DECRYPT;
+		cop.flags = enc ? COP_F_CIPHER_FIRST : 0;
+		cop.len = size;
+		cop.src = (char *)input;
+		cop.dst = output;
+		cop.mac = digest;
+		cop.iv = (char *)iv;
+
+		if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
+			warn("cryptodev %s (%zu) AUTHENC failed for device %s",
+			    alg->name, size, crfind(crid));
+			close(fd);
+			return (false);
+		}
+	}
+
+	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
+		warn("ioctl(CIOCFSESSION)");
+
+	close(fd);
+	*cridp = sop.crid;
+	return (true);
+}
+
+static void
+run_authenc_test(struct alg *alg, size_t size)
+{
+	const EVP_CIPHER *cipher;
+	const EVP_MD *md;
+	char *aad, *buffer, *cleartext, *ciphertext;
+	char *iv, *auth_key, *cipher_key;
+	u_int iv_len, auth_key_len, cipher_key_len, digest_len;
+	int crid;
+	char control_digest[EVP_MAX_MD_SIZE], test_digest[EVP_MAX_MD_SIZE];
+
+	cipher = alg->evp_cipher();
+	if (size % EVP_CIPHER_block_size(cipher) != 0) {
+		if (verbose)
+			printf(
+			    "%s (%zu): invalid buffer size (block size %d)\n",
+			    alg->name, size, EVP_CIPHER_block_size(cipher));
+		return;
+	}
+
+	memset(control_digest, 0x3c, sizeof(control_digest));
+	memset(test_digest, 0x3c, sizeof(test_digest));
+
+	md = alg->evp_md();
+
+	cipher_key_len = EVP_CIPHER_key_length(cipher);
+	iv_len = EVP_CIPHER_iv_length(cipher);
+	auth_key_len = EVP_MD_size(md);
+
+	cipher_key = alloc_buffer(cipher_key_len);
+	iv = generate_iv(iv_len, alg);
+	auth_key = alloc_buffer(auth_key_len);
+	cleartext = alloc_buffer(aad_len + size);
+	buffer = malloc(aad_len + size);
+	ciphertext = malloc(aad_len + size);
+
+	/* OpenSSL encrypt + HMAC. */
+	if (aad_len != 0)
+		memcpy(ciphertext, cleartext, aad_len);
+	openssl_cipher(alg, cipher, cipher_key, iv, cleartext + aad_len,
+	    ciphertext + aad_len, size, 1);
+	if (size > 0 && memcmp(cleartext + aad_len, ciphertext + aad_len,
+	    size) == 0)
+		errx(1, "OpenSSL %s (%zu): cipher text unchanged", alg->name,
+		    size);
+	digest_len = sizeof(control_digest);
+	if (HMAC(md, auth_key, auth_key_len, (u_char *)ciphertext,
+	    aad_len + size, (u_char *)control_digest, &digest_len) == NULL)
+		errx(1, "OpenSSL %s (%zu) HMAC failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+
+	/* OCF encrypt + HMAC. */
+	if (!ocf_authenc(alg, cipher_key, cipher_key_len, iv, iv_len, auth_key,
+	    auth_key_len, aad_len != 0 ? cleartext : NULL, aad_len,
+	    cleartext + aad_len, buffer + aad_len, size, test_digest, 1, &crid))
+		goto out;
+	if (memcmp(ciphertext + aad_len, buffer + aad_len, size) != 0) {
+		printf("%s (%zu) encryption mismatch:\n", alg->name, size);
+		printf("control:\n");
+		hexdump(ciphertext + aad_len, size, NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(buffer + aad_len, size, NULL, 0);
+		goto out;
+	}
+	if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
+		if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
+			printf("%s (%zu) enc hash mismatch in trailer:\n",
+			    alg->name, size);
+		else
+			printf("%s (%zu) enc hash mismatch:\n", alg->name,
+			    size);
+		printf("control:\n");
+		hexdump(control_digest, sizeof(control_digest), NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(test_digest, sizeof(test_digest), NULL, 0);
+		goto out;
+	}
+
+	/* OCF HMAC + decrypt. */
+	memset(test_digest, 0x3c, sizeof(test_digest));
+	if (!ocf_authenc(alg, cipher_key, cipher_key_len, iv, iv_len, auth_key,
+	    auth_key_len, aad_len != 0 ? ciphertext : NULL, aad_len,
+	    ciphertext + aad_len, buffer + aad_len, size, test_digest, 0,
+	    &crid))
+		goto out;
+	if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
+		if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
+			printf("%s (%zu) dec hash mismatch in trailer:\n",
+			    alg->name, size);
+		else
+			printf("%s (%zu) dec hash mismatch:\n", alg->name,
+			    size);
+		printf("control:\n");
+		hexdump(control_digest, sizeof(control_digest), NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(test_digest, sizeof(test_digest), NULL, 0);
+		goto out;
+	}
+	if (memcmp(cleartext + aad_len, buffer + aad_len, size) != 0) {
+		printf("%s (%zu) decryption mismatch:\n", alg->name, size);
+		printf("control:\n");
+		hexdump(cleartext, size, NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(buffer, size, NULL, 0);
+		goto out;
+	}
+
+	if (verbose)
+		printf("%s (%zu) matched (cryptodev device %s)\n",
+		    alg->name, size, crfind(crid));
+
+out:
+	free(ciphertext);
+	free(buffer);
+	free(cleartext);
+	free(auth_key);
+	free(iv);
+	free(cipher_key);
+}
+
+static void
+openssl_gcm_encrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
+    const char *iv, const char *aad, size_t aad_len, const char *input,
+    char *output, size_t size, char *tag)
+{
+	EVP_CIPHER_CTX *ctx;
+	int outl, total;
+
+	ctx = EVP_CIPHER_CTX_new();
+	if (ctx == NULL)
+		errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	if (EVP_EncryptInit_ex(ctx, cipher, NULL, (const u_char *)key,
+	    (const u_char *)iv) != 1)
+		errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	if (aad != NULL) {
+		if (EVP_EncryptUpdate(ctx, NULL, &outl, (const u_char *)aad,
+		    aad_len) != 1)
+			errx(1, "OpenSSL %s (%zu) aad update failed: %s",
+			    alg->name, size,
+			    ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (EVP_EncryptUpdate(ctx, (u_char *)output, &outl,
+	    (const u_char *)input, size) != 1)
+		errx(1, "OpenSSL %s (%zu) encrypt update failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	total = outl;
+	if (EVP_EncryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1)
+		errx(1, "OpenSSL %s (%zu) encrypt final failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	total += outl;
+	if (total != size)
+		errx(1, "OpenSSL %s (%zu) encrypt size mismatch: %d", alg->name,
+		    size, total);
+	if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, AES_GMAC_HASH_LEN,
+	    tag) != 1)
+		errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	EVP_CIPHER_CTX_free(ctx);
+}
+
+static bool
+ocf_gcm(struct alg *alg, const char *key, size_t key_len, const char *iv,
+    size_t iv_len, const char *aad, size_t aad_len, const char *input,
+    char *output, size_t size, char *tag, int enc, int *cridp)
+{
+	struct session2_op sop;
+	struct crypt_aead caead;
+	int fd;
+
+	memset(&sop, 0, sizeof(sop));
+	memset(&caead, 0, sizeof(caead));
+	sop.crid = crid;
+	sop.keylen = key_len;
+	sop.key = (char *)key;
+	sop.cipher = alg->cipher;
+	sop.mackeylen = key_len;
+	sop.mackey = (char *)key;
+	sop.mac = alg->mac;
+	fd = crget();
+	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
+		warn("cryptodev %s not supported for device %s",
+		    alg->name, crfind(crid));
+		close(fd);
+		return (false);
+	}
+
+	caead.ses = sop.ses;
+	caead.op = enc ? COP_ENCRYPT : COP_DECRYPT;
+	caead.len = size;
+	caead.aadlen = aad_len;
+	caead.ivlen = iv_len;
+	caead.src = (char *)input;
+	caead.dst = output;
+	caead.aad = (char *)aad;
+	caead.tag = tag;
+	caead.iv = (char *)iv;
+
+	if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) {
+		warn("cryptodev %s (%zu) failed for device %s",
+		    alg->name, size, crfind(crid));
+		close(fd);
+		return (false);
+	}
+
+	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
+		warn("ioctl(CIOCFSESSION)");
+
+	close(fd);
+	*cridp = sop.crid;
+	return (true);
+}
+
+#ifdef notused
+static bool
+openssl_gcm_decrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
+    const char *iv, const char *aad, size_t aad_len, const char *input,
+    char *output, size_t size, char *tag)
+{
+	EVP_CIPHER_CTX *ctx;
+	int outl, total;
+	bool valid;
+
+	ctx = EVP_CIPHER_CTX_new();
+	if (ctx == NULL)
+		errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	if (EVP_DecryptInit_ex(ctx, cipher, NULL, (const u_char *)key,
+	    (const u_char *)iv) != 1)
+		errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	if (aad != NULL) {
+		if (EVP_DecryptUpdate(ctx, NULL, &outl, (const u_char *)aad,
+		    aad_len) != 1)
+			errx(1, "OpenSSL %s (%zu) aad update failed: %s",
+			    alg->name, size,
+			    ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (EVP_DecryptUpdate(ctx, (u_char *)output, &outl,
+	    (const u_char *)input, size) != 1)
+		errx(1, "OpenSSL %s (%zu) decrypt update failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	total = outl;
+	if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, AES_GMAC_HASH_LEN,
+	    tag) != 1)
+		errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	valid = (EVP_DecryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1);
+	total += outl;
+	if (total != size)
+		errx(1, "OpenSSL %s (%zu) decrypt size mismatch: %d", alg->name,
+		    size, total);
+	EVP_CIPHER_CTX_free(ctx);
+	return (valid);
+}
+#endif
+
+static void
+run_gcm_test(struct alg *alg, size_t size)
+{
+	const EVP_CIPHER *cipher;
+	char *aad, *buffer, *cleartext, *ciphertext;
+	char *iv, *key;
+	u_int iv_len, key_len;
+	int crid;
+	char control_tag[AES_GMAC_HASH_LEN], test_tag[AES_GMAC_HASH_LEN];
+
+	cipher = alg->evp_cipher();
+	if (size % EVP_CIPHER_block_size(cipher) != 0) {
+		if (verbose)
+			printf(
+			    "%s (%zu): invalid buffer size (block size %d)\n",
+			    alg->name, size, EVP_CIPHER_block_size(cipher));
+		return;
+	}
+
+	memset(control_tag, 0x3c, sizeof(control_tag));
+	memset(test_tag, 0x3c, sizeof(test_tag));
+
+	key_len = EVP_CIPHER_key_length(cipher);
+	iv_len = EVP_CIPHER_iv_length(cipher);
+
+	key = alloc_buffer(key_len);
+	iv = generate_iv(iv_len, alg);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list