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