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 <c...@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, <j...@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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to