Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F170872511
D15446.id42971.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
64 KB
Referenced Files
None
Subscribers
None
D15446.id42971.diff
View Options
Index: contrib/tcpdump/README
===================================================================
--- contrib/tcpdump/README
+++ contrib/tcpdump/README
@@ -1 +1,225 @@
-link README.md
\ No newline at end of file
+# tcpdump
+
+[](https://travis-ci.org/the-tcpdump-group/tcpdump)
+
+To report a security issue please send an e-mail to security@tcpdump.org.
+
+To report bugs and other problems, contribute patches, request a
+feature, provide generic feedback etc please see the file
+CONTRIBUTING in the tcpdump source tree root.
+
+TCPDUMP 4.x.y
+Now maintained by "The Tcpdump Group"
+See www.tcpdump.org
+
+Anonymous Git is available via:
+
+ git clone git://bpf.tcpdump.org/tcpdump
+
+formerly from Lawrence Berkeley National Laboratory
+ Network Research Group <tcpdump@ee.lbl.gov>
+ ftp://ftp.ee.lbl.gov/old/tcpdump.tar.Z (3.4)
+
+This directory contains source code for tcpdump, a tool for network
+monitoring and data acquisition. This software was originally
+developed by the Network Research Group at the Lawrence Berkeley
+National Laboratory. The original distribution is available via
+anonymous ftp to `ftp.ee.lbl.gov`, in `tcpdump.tar.Z`. More recent
+development is performed at tcpdump.org, http://www.tcpdump.org/
+
+Tcpdump uses libpcap, a system-independent interface for user-level
+packet capture. Before building tcpdump, you must first retrieve and
+build libpcap, also originally from LBL and now being maintained by
+tcpdump.org; see http://www.tcpdump.org/ .
+
+Once libpcap is built (either install it or make sure it's in
+`../libpcap`), you can build tcpdump using the procedure in the `INSTALL.txt`
+file.
+
+The program is loosely based on SMI's "etherfind" although none of the
+etherfind code remains. It was originally written by Van Jacobson as
+part of an ongoing research project to investigate and improve tcp and
+internet gateway performance. The parts of the program originally
+taken from Sun's etherfind were later re-written by Steven McCanne of
+LBL. To insure that there would be no vestige of proprietary code in
+tcpdump, Steve wrote these pieces from the specification given by the
+manual entry, with no access to the source of tcpdump or etherfind.
+
+Over the past few years, tcpdump has been steadily improved by the
+excellent contributions from the Internet community (just browse
+through the `CHANGES` file). We are grateful for all the input.
+
+Richard Stevens gives an excellent treatment of the Internet protocols
+in his book *"TCP/IP Illustrated, Volume 1"*. If you want to learn more
+about tcpdump and how to interpret its output, pick up this book.
+
+Some tools for viewing and analyzing tcpdump trace files are available
+from the Internet Traffic Archive:
+
+* http://www.sigcomm.org/ITA/
+
+Another tool that tcpdump users might find useful is tcpslice:
+
+* https://github.com/the-tcpdump-group/tcpslice
+
+It is a program that can be used to extract portions of tcpdump binary
+trace files. See the above distribution for further details and
+documentation.
+
+Current versions can be found at www.tcpdump.org.
+
+ - The TCPdump team
+
+original text by: Steve McCanne, Craig Leres, Van Jacobson
+
+-------------------------------------
+```
+This directory also contains some short awk programs intended as
+examples of ways to reduce tcpdump data when you're tracking
+particular network problems:
+
+send-ack.awk
+ Simplifies the tcpdump trace for an ftp (or other unidirectional
+ tcp transfer). Since we assume that one host only sends and
+ the other only acks, all address information is left off and
+ we just note if the packet is a "send" or an "ack".
+
+ There is one output line per line of the original trace.
+ Field 1 is the packet time in decimal seconds, relative
+ to the start of the conversation. Field 2 is delta-time
+ from last packet. Field 3 is packet type/direction.
+ "Send" means data going from sender to receiver, "ack"
+ means an ack going from the receiver to the sender. A
+ preceding "*" indicates that the data is a retransmission.
+ A preceding "-" indicates a hole in the sequence space
+ (i.e., missing packet(s)), a "#" means an odd-size (not max
+ seg size) packet. Field 4 has the packet flags
+ (same format as raw trace). Field 5 is the sequence
+ number (start seq. num for sender, next expected seq number
+ for acks). The number in parens following an ack is
+ the delta-time from the first send of the packet to the
+ ack. A number in parens following a send is the
+ delta-time from the first send of the packet to the
+ current send (on duplicate packets only). Duplicate
+ sends or acks have a number in square brackets showing
+ the number of duplicates so far.
+
+ Here is a short sample from near the start of an ftp:
+ 3.00 0.20 send . 512
+ 3.20 0.20 ack . 1024 (0.20)
+ 3.20 0.00 send P 1024
+ 3.40 0.20 ack . 1536 (0.20)
+ 3.80 0.40 * send . 0 (3.80) [2]
+ 3.82 0.02 * ack . 1536 (0.62) [2]
+ Three seconds into the conversation, bytes 512 through 1023
+ were sent. 200ms later they were acked. Shortly thereafter
+ bytes 1024-1535 were sent and again acked after 200ms.
+ Then, for no apparent reason, 0-511 is retransmitted, 3.8
+ seconds after its initial send (the round trip time for this
+ ftp was 1sec, +-500ms). Since the receiver is expecting
+ 1536, 1536 is re-acked when 0 arrives.
+
+packetdat.awk
+ Computes chunk summary data for an ftp (or similar
+ unidirectional tcp transfer). [A "chunk" refers to
+ a chunk of the sequence space -- essentially the packet
+ sequence number divided by the max segment size.]
+
+ A summary line is printed showing the number of chunks,
+ the number of packets it took to send that many chunks
+ (if there are no lost or duplicated packets, the number
+ of packets should equal the number of chunks) and the
+ number of acks.
+
+ Following the summary line is one line of information
+ per chunk. The line contains eight fields:
+ 1 - the chunk number
+ 2 - the start sequence number for this chunk
+ 3 - time of first send
+ 4 - time of last send
+ 5 - time of first ack
+ 6 - time of last ack
+ 7 - number of times chunk was sent
+ 8 - number of times chunk was acked
+ (all times are in decimal seconds, relative to the start
+ of the conversation.)
+
+ As an example, here is the first part of the output for
+ an ftp trace:
+
+ # 134 chunks. 536 packets sent. 508 acks.
+ 1 1 0.00 5.80 0.20 0.20 4 1
+ 2 513 0.28 6.20 0.40 0.40 4 1
+ 3 1025 1.16 6.32 1.20 1.20 4 1
+ 4 1561 1.86 15.00 2.00 2.00 6 1
+ 5 2049 2.16 15.44 2.20 2.20 5 1
+ 6 2585 2.64 16.44 2.80 2.80 5 1
+ 7 3073 3.00 16.66 3.20 3.20 4 1
+ 8 3609 3.20 17.24 3.40 5.82 4 11
+ 9 4097 6.02 6.58 6.20 6.80 2 5
+
+ This says that 134 chunks were transferred (about 70K
+ since the average packet size was 512 bytes). It took
+ 536 packets to transfer the data (i.e., on the average
+ each chunk was transmitted four times). Looking at,
+ say, chunk 4, we see it represents the 512 bytes of
+ sequence space from 1561 to 2048. It was first sent
+ 1.86 seconds into the conversation. It was last
+ sent 15 seconds into the conversation and was sent
+ a total of 6 times (i.e., it was retransmitted every
+ 2 seconds on the average). It was acked once, 140ms
+ after it first arrived.
+
+stime.awk
+atime.awk
+ Output one line per send or ack, respectively, in the form
+ <time> <seq. number>
+ where <time> is the time in seconds since the start of the
+ transfer and <seq. number> is the sequence number being sent
+ or acked. I typically plot this data looking for suspicious
+ patterns.
+
+
+The problem I was looking at was the bulk-data-transfer
+throughput of medium delay network paths (1-6 sec. round trip
+time) under typical DARPA Internet conditions. The trace of the
+ftp transfer of a large file was used as the raw data source.
+The method was:
+
+ - On a local host (but not the Sun running tcpdump), connect to
+ the remote ftp.
+
+ - On the monitor Sun, start the trace going. E.g.,
+ tcpdump host local-host and remote-host and port ftp-data >tracefile
+
+ - On local, do either a get or put of a large file (~500KB),
+ preferably to the null device (to minimize effects like
+ closing the receive window while waiting for a disk write).
+
+ - When transfer is finished, stop tcpdump. Use awk to make up
+ two files of summary data (maxsize is the maximum packet size,
+ tracedata is the file of tcpdump tracedata):
+ awk -f send-ack.awk packetsize=avgsize tracedata >sa
+ awk -f packetdat.awk packetsize=avgsize tracedata >pd
+
+ - While the summary data files are printing, take a look at
+ how the transfer behaved:
+ awk -f stime.awk tracedata | xgraph
+ (90% of what you learn seems to happen in this step).
+
+ - Do all of the above steps several times, both directions,
+ at different times of day, with different protocol
+ implementations on the other end.
+
+ - Using one of the Unix data analysis packages (in my case,
+ S and Gary Perlman's Unix|Stat), spend a few months staring
+ at the data.
+
+ - Change something in the local protocol implementation and
+ redo the steps above.
+
+ - Once a week, tell your funding agent that you're discovering
+ wonderful things and you'll write up that research report
+ "real soon now".
+```
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -4830,6 +4830,8 @@
opencrypto/rmd160.c optional crypto | ipsec | ipsec_support
opencrypto/skipjack.c optional crypto | ipsec | ipsec_support
opencrypto/xform.c optional crypto | ipsec | ipsec_support
+opencrypto/ccm-cbc.c optional crypto
+opencrypto/xform_cbc_mac.c optional crypto
rpc/auth_none.c optional krpc | nfslockd | nfscl | nfsd
rpc/auth_unix.c optional krpc | nfslockd | nfscl | nfsd
rpc/authunix_prot.c optional krpc | nfslockd | nfscl | nfsd
Index: sys/conf/files.amd64
===================================================================
--- sys/conf/files.amd64
+++ sys/conf/files.amd64
@@ -174,6 +174,11 @@
compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} ${PROF} -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}" \
no-implicit-rule \
clean "aesni_ghash.o"
+aesni_ccm.o optional aesni \
+ dependency "$S/crypto/aesni/aesni_ccm.c" \
+ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} ${PROF} -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}" \
+ no-implicit-rule \
+ clean "aesni_ccm.o"
aesni_wrap.o optional aesni \
dependency "$S/crypto/aesni/aesni_wrap.c" \
compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} ${PROF} -mmmx -msse -msse4 -maes ${.IMPSRC}" \
Index: sys/conf/files.i386
===================================================================
--- sys/conf/files.i386
+++ sys/conf/files.i386
@@ -127,6 +127,11 @@
compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} ${PROF} -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}" \
no-implicit-rule \
clean "aesni_ghash.o"
+aesni_ccm.o optional aesni \
+ dependency "$S/crypto/aesni/aesni_ccm.c" \
+ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} ${PROF} -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}" \
+ no-implicit-rule \
+ clean "aesni_ccm.o"
aesni_wrap.o optional aesni \
dependency "$S/crypto/aesni/aesni_wrap.c" \
compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${NO_WCAST_QUAL} ${PROF} -mmmx -msse -msse4 -maes ${.IMPSRC}" \
Index: sys/crypto/aesni/aesni.h
===================================================================
--- sys/crypto/aesni/aesni.h
+++ sys/crypto/aesni/aesni.h
@@ -113,6 +113,15 @@
const unsigned char *tag, uint32_t nbytes, uint32_t abytes, int ibytes,
const unsigned char *key, int nr);
+/* CCM + CBC-MAC functions */
+void AES_CCM_encrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *addt, const unsigned char *ivec,
+ unsigned char *tag, uint32_t nbytes, uint32_t abytes, int ibytes,
+ const unsigned char *key, int nr);
+int AES_CCM_decrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *addt, const unsigned char *ivec,
+ const unsigned char *tag, uint32_t nbytes, uint32_t abytes, int ibytes,
+ const unsigned char *key, int nr);
int aesni_cipher_setup_common(struct aesni_session *ses, const uint8_t *key,
int keylen);
Index: sys/crypto/aesni/aesni.c
===================================================================
--- sys/crypto/aesni/aesni.c
+++ sys/crypto/aesni/aesni.c
@@ -137,9 +137,9 @@
return (EINVAL);
} else if (has_aes && has_sha)
device_set_desc(dev,
- "AES-CBC,AES-XTS,AES-GCM,AES-ICM,SHA1,SHA256");
+ "AES-CBC,AES-XTS,AES-GCM,AES-CCM,AES-ICM,SHA1,SHA256");
else if (has_aes)
- device_set_desc(dev, "AES-CBC,AES-XTS,AES-GCM,AES-ICM");
+ device_set_desc(dev, "AES-CBC,AES-XTS,AES-GCM,AES-CCM,AES-ICM");
else
device_set_desc(dev, "SHA1,SHA256");
@@ -204,6 +204,10 @@
crypto_register(sc->cid, CRYPTO_AES_192_NIST_GMAC, 0, 0);
crypto_register(sc->cid, CRYPTO_AES_256_NIST_GMAC, 0, 0);
crypto_register(sc->cid, CRYPTO_AES_XTS, 0, 0);
+ crypto_register(sc->cid, CRYPTO_AES_CCM_16, 0, 0);
+ crypto_register(sc->cid, CRYPTO_AES_128_CCM_CBC_MAC, 0, 0);
+ crypto_register(sc->cid, CRYPTO_AES_192_CCM_CBC_MAC, 0, 0);
+ crypto_register(sc->cid, CRYPTO_AES_256_CCM_CBC_MAC, 0, 0);
}
if (sc->has_sha) {
crypto_register(sc->cid, CRYPTO_SHA1, 0, 0);
@@ -251,7 +255,7 @@
struct aesni_softc *sc;
struct aesni_session *ses;
struct cryptoini *encini, *authini;
- bool gcm_hash, gcm;
+ bool gcm_hash, gcm, ccm, ccm_hash;
int error;
if (sidp == NULL || cri == NULL) {
@@ -268,6 +272,8 @@
encini = NULL;
gcm = false;
gcm_hash = false;
+ ccm = false;
+ ccm_hash = false;
for (; cri != NULL; cri = cri->cri_next) {
switch (cri->cri_alg) {
case CRYPTO_AES_NIST_GCM_16:
@@ -276,6 +282,9 @@
case CRYPTO_AES_CBC:
case CRYPTO_AES_ICM:
case CRYPTO_AES_XTS:
+ case CRYPTO_AES_CCM_16:
+ if (cri->cri_alg == CRYPTO_AES_CCM_16)
+ ccm = true;
if (!sc->has_aes)
goto unhandled;
if (encini != NULL) {
@@ -293,6 +302,14 @@
*/
gcm_hash = true;
break;
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ case CRYPTO_AES_256_CCM_CBC_MAC:
+ /*
+ * Similarly, nothing to do here.
+ */
+ ccm_hash = true;
+ break;
case CRYPTO_SHA1:
case CRYPTO_SHA1_HMAC:
case CRYPTO_SHA2_256_HMAC:
@@ -321,6 +338,9 @@
if (gcm_hash != gcm)
return (EINVAL);
+ if (ccm_hash != ccm)
+ return (EINVAL);
+
rw_wlock(&sc->lock);
if (sc->dieing) {
rw_wunlock(&sc->lock);
@@ -427,6 +447,7 @@
for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) {
switch (crd->crd_alg) {
case CRYPTO_AES_NIST_GCM_16:
+ case CRYPTO_AES_CCM_16:
needauth = 1;
/* FALLTHROUGH */
case CRYPTO_AES_CBC:
@@ -445,6 +466,9 @@
case CRYPTO_SHA1:
case CRYPTO_SHA1_HMAC:
case CRYPTO_SHA2_256_HMAC:
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ case CRYPTO_AES_256_CCM_CBC_MAC:
if (authcrd != NULL) {
error = EINVAL;
goto out;
@@ -718,6 +742,7 @@
if (enccrd != NULL) {
if ((enccrd->crd_alg == CRYPTO_AES_ICM ||
+ enccrd->crd_alg == CRYPTO_AES_CCM_16 ||
enccrd->crd_alg == CRYPTO_AES_NIST_GCM_16) &&
(enccrd->crd_flags & CRD_F_IV_EXPLICIT) == 0)
return (EINVAL);
@@ -782,7 +807,8 @@
return (ENOMEM);
authallocated = false;
- if (ses->algo == CRYPTO_AES_NIST_GCM_16) {
+ if (ses->algo == CRYPTO_AES_NIST_GCM_16 ||
+ ses->algo == CRYPTO_AES_CCM_16) {
authbuf = aesni_cipher_alloc(authcrd, crp, &authallocated);
if (authbuf == NULL) {
error = ENOMEM;
@@ -808,6 +834,7 @@
ivlen = 8;
break;
case CRYPTO_AES_NIST_GCM_16:
+ case CRYPTO_AES_CCM_16:
ivlen = 12; /* should support arbitarily larger */
break;
}
@@ -871,6 +898,26 @@
authcrd->crd_inject, GMAC_DIGEST_LEN, tag);
} else {
if (!AES_GCM_decrypt(buf, buf, authbuf, iv, tag,
+ enccrd->crd_len, authcrd->crd_len, ivlen,
+ ses->enc_schedule, ses->rounds))
+ error = EBADMSG;
+ }
+ break;
+ case CRYPTO_AES_CCM_16:
+ if (!encflag)
+ crypto_copydata(crp->crp_flags, crp->crp_buf,
+ authcrd->crd_inject, GMAC_DIGEST_LEN, tag);
+ else
+ bzero(tag, sizeof(tag));
+ if (encflag) {
+ AES_CCM_encrypt(buf, buf, authbuf, iv, tag,
+ enccrd->crd_len, authcrd->crd_len, ivlen,
+ ses->enc_schedule, ses->rounds);
+ if (authcrd != NULL)
+ crypto_copyback(crp->crp_flags, crp->crp_buf,
+ authcrd->crd_inject, GMAC_DIGEST_LEN, tag);
+ } else {
+ if (!AES_CCM_decrypt(buf, buf, authbuf, iv, tag,
enccrd->crd_len, authcrd->crd_len, ivlen,
ses->enc_schedule, ses->rounds))
error = EBADMSG;
Index: sys/crypto/aesni/aesni_ccm.c
===================================================================
--- sys/crypto/aesni/aesni_ccm.c
+++ sys/crypto/aesni/aesni_ccm.c
@@ -0,0 +1,514 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * Copyright (c) 2018 iXsystems, Inc
+ * All rights reserved.
+ *
+ * This software was developed by John-Mark Gurney under
+ * the sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ * 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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, 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 DAMAGE.
+ *
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/param.h>
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <crypto/aesni/aesni.h>
+#include <crypto/aesni/aesni_os.h>
+#else
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <strings.h>
+#include <err.h>
+#endif
+
+#include <wmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+
+#ifndef _KERNEL
+static void
+panic(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrx(1, fmt, ap);
+ va_end(ap);
+}
+#endif
+
+#ifdef CRYPTO_DEBUG
+static void
+PrintBlock(const char *label, __m128i b)
+{
+ uint8_t *ptr = (uint8_t*)&b;
+ printf("%s: ", label);
+ for (size_t i = 0; i < sizeof(b); i++)
+ printf("%02x ", ptr[i]);
+ printf("\n");
+}
+#endif
+
+#ifdef STANDALONE
+static void PrintHex(const void *, size_t);
+#endif
+
+/*
+ * Encrypt without xoring.
+ */
+static inline __m128i
+aes_encrypt(__m128i data, const unsigned char *k, int nr)
+{
+ int i;
+ __m128 retval = data;
+ const __m128i *key = (const void*)k;
+ retval = _mm_xor_si128(retval, key[0]);
+ for (i = 1; i < nr; i++) {
+ retval = _mm_aesenc_si128(retval, key[i]);
+ }
+ retval = _mm_aesenclast_si128(retval, key[nr]);
+ return retval;
+}
+
+/*
+ * Encrypt a single 128-bit block after
+ * doing an xor. This is also used to
+ * decrypt (yay symmetric encryption).
+ */
+static inline __m128i
+xor_and_encrypt(__m128i a, __m128i b, const unsigned char *k, int nr)
+{
+ __m128 retval = _mm_xor_si128(a, b);
+#ifdef CRYPTO_DEBUG
+ PrintBlock("\ta\t", a);
+ PrintBlock("\tb\t", b);
+ PrintBlock("\tresult\t", retval);
+#endif
+ retval = aes_encrypt(retval, k, nr);
+ return retval;
+}
+
+/*
+ * put value at the end of block, starting at offset.
+ * (This goes backwards, putting bytes in *until* it
+ * reaches offset.)
+ */
+static void
+append_int(size_t value, __m128i *block, size_t offset)
+{
+ int indx = sizeof(*block) - 1;
+ uint8_t *bp = (uint8_t*)block;
+ while (indx > (sizeof(*block) - offset)) {
+ bp[indx] = value & 0xff;
+ indx--;
+ value >>= 8;
+ }
+}
+
+/*
+ * Tart the CBC-MAC process. This handles the auth data.
+ */
+static __m128i
+cbc_mac_start(const unsigned char *auth_data, size_t auth_len,
+ const unsigned char *nonce, size_t nonce_len,
+ const unsigned char *key, int nr,
+ size_t data_len, size_t tag_len)
+{
+ union {
+ __m128i block;
+ uint8_t bytes[sizeof(__m128i)];
+ } retval, temp_block;
+ /* This defines where the message length goes */
+ int L = sizeof(__m128i) - 1 - nonce_len;
+ bzero(&retval, sizeof(retval));
+ retval.bytes[0] = (auth_len ? 1 : 0) * 64 |
+ (((tag_len - 2) / 2) * 8) |
+ (L - 1);
+ bcopy(nonce, &retval.bytes[1], nonce_len);
+ append_int(data_len, &retval.block, L+1);
+#ifdef CRYPTO_DEBUG
+ PrintBlock("Plain B0", retval.block);
+#endif
+ retval.block = aes_encrypt(retval.block, key, nr);
+
+ if (auth_len) {
+ /*
+ * We need to start by appending the length descriptor.
+ */
+ uint32_t auth_amt;
+ size_t copy_amt;
+ const uint8_t *auth_ptr = auth_data;
+
+ bzero(&temp_block, sizeof(temp_block));
+
+ if (auth_len < ((1<<16) - (1<<8))) {
+ uint16_t *ip = (uint16_t*)&temp_block;
+ *ip = htobe16(auth_len);
+ auth_amt = 2;
+ } else {
+ /*
+ * The current calling convention means that
+ * there can never be more than 4g of authentication
+ * data, so we don't handle the 0xffff case.
+ */
+ uint32_t *ip = (uint32_t*)&temp_block.bytes[2];
+ temp_block.bytes[0] = 0xff;
+ temp_block.bytes[1] = 0xfe;
+ *ip = htobe32(auth_len);
+ auth_amt = 2 + sizeof(*ip);
+ }
+ /*
+ * Need to copy abytes into blocks. The first block is
+ * already partially filled, by auth_amt, so we need
+ * to handle that. The last block needs to be zero padded.
+ */
+ copy_amt = MIN(auth_len - auth_amt, sizeof(temp_block) - auth_amt);
+ bcopy(auth_ptr, &temp_block.bytes[auth_amt], copy_amt);
+ auth_ptr += copy_amt;
+
+ retval.block = xor_and_encrypt(retval.block, temp_block.block, key, nr);
+
+ while (auth_ptr < auth_data + auth_len) {
+ copy_amt = MIN((auth_data + auth_len) - auth_ptr, sizeof(temp_block));
+ if (copy_amt < sizeof(retval))
+ bzero(&temp_block, sizeof(temp_block));
+ bcopy(auth_ptr, &temp_block, copy_amt);
+ retval.block = xor_and_encrypt(retval.block, temp_block.block, key, nr);
+ auth_ptr += copy_amt;
+ }
+ }
+ return retval.block;
+}
+
+/*
+ * Implement AES CCM+CBC-MAC encryption and authentication.
+ */
+void
+AES_CCM_encrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *addt, const unsigned char *nonce,
+ unsigned char *tag, uint32_t nbytes, uint32_t abytes, int nlen,
+ const unsigned char *key, int nr)
+{
+ static const int tag_length = 16; /* 128 bits */
+ int L;
+ int counter = 1; /* S0 has 0, S1 has 1 */
+ size_t copy_amt, total = 0;
+
+ union {
+ __m128i block;
+ uint8_t bytes[sizeof(__m128i)];
+ } s0, last_block, current_block, s_x, temp_block;
+
+#ifdef CRYPTO_DEBUG
+ printf("%s(%p, %p, %p, %p, %p, %u, %u, %d, %p, %d)\n",
+ __FUNCTION__, in, out, addt, nonce, tag, nbytes, abytes, nlen, key, nr);
+#endif
+
+ if (nbytes == 0)
+ return;
+ if (nlen < 0 || nlen > 15)
+ panic("%s: bad nonce length %d", __FUNCTION__, nlen);
+
+ /*
+ * We need to know how many bytes to use to describe
+ * the length of the data. Normally, nlen should be
+ * 12, which leaves us 3 bytes to do that -- 16mbytes of
+ * data to encrypt. But it can be longer or shorter.
+ */
+ L = sizeof(__m128i) - 1 - nlen;
+
+ /*
+ * Now, this shouldn't happen, but let's make sure that
+ * the data length isn't too big.
+ */
+ if (nbytes > ((1 << (8 * L)) - 1))
+ panic("%s: nbytes is %u, but length field is %d bytes",
+ __FUNCTION__, nbytes, L);
+ /*
+ * Clear out the blocks
+ */
+ explicit_bzero(&s0, sizeof(s0));
+ explicit_bzero(¤t_block, sizeof(current_block));
+
+ last_block.block = cbc_mac_start(addt, abytes, nonce, nlen,
+ key, nr, nbytes, tag_length);
+
+ /* s0 has flags, nonce, and then 0 */
+ s0.bytes[0] = L-1; /* but the flags byte only has L' */
+ bcopy(nonce, &s0.bytes[1], nlen);
+#ifdef CRYPTO_DEBUG
+ PrintBlock("s0", s0.block);
+#endif
+
+ /*
+ * Now to cycle through the rest of the data.
+ */
+ bcopy(&s0, &s_x, sizeof(s0));
+
+ while (total < nbytes) {
+ /*
+ * Copy the plain-text data into temp_block.
+ * This may need to be zero-padded.
+ */
+ copy_amt = MIN(nbytes - total, sizeof(temp_block));
+ bcopy(in+total, &temp_block, copy_amt);
+ if (copy_amt < sizeof(temp_block)) {
+ bzero(&temp_block.bytes[copy_amt], sizeof(temp_block) - copy_amt);
+ }
+#ifdef CRYPTO_DEBUG
+ PrintBlock("Plain text", temp_block.block);
+#endif
+ last_block.block = xor_and_encrypt(last_block.block,
+ temp_block.block, key, nr);
+ /* Put the counter into the s_x block */
+ append_int(counter++, &s_x.block, L+1);
+ /* Encrypt that */
+ __m128i X = aes_encrypt(s_x.block, key, nr);
+ /* XOR the plain-text with the encrypted counter block */
+ temp_block.block = _mm_xor_si128(temp_block.block, X);
+#ifdef CRYPTO_DEBUG
+ PrintBlock("Encrypted block", temp_block.block);
+#endif
+ /* And copy it out */
+ bcopy(&temp_block, out+total, copy_amt);
+ total += copy_amt;
+ }
+ /*
+ * Allgedly done with it! Except for the tag.
+ */
+#ifdef CRYPTO_DEBUG
+ PrintBlock("Final last block", last_block.block);
+#endif
+ s0.block = aes_encrypt(s0.block, key, nr);
+ temp_block.block = _mm_xor_si128(s0.block, last_block.block);
+#ifdef CRYPTO_DEBUG
+ printf("Tag length %d; ", tag_length);
+ PrintBlock("Final tag", temp_block.block);
+#endif
+ bcopy(&temp_block, tag, tag_length);
+ explicit_bzero(&s0, sizeof(s0));
+ return;
+}
+
+/*
+ * Implement AES CCM+CBC-MAC decryption and authentication.
+ * Returns 0 on failure, 1 on success.
+ *
+ * The primary difference here is that each encrypted block
+ * needs to be hashed&encrypted after it is decrypted (since
+ * the CBC-MAC is based on the plain text). This means that
+ * if the hash comparison fails, we need to zero out the
+ * output buffer completely.
+ */
+int
+AES_CCM_decrypt(const unsigned char *in, unsigned char *out,
+ const unsigned char *addt, const unsigned char *nonce,
+ const unsigned char *tag, uint32_t nbytes, uint32_t abytes, int nlen,
+ const unsigned char *key, int nr)
+{
+ static const int tag_length = 16; /* 128 bits */
+ int L;
+ int counter = 1; /* S0 has 0, S1 has 1 */
+ size_t copy_amt, total = 0;
+
+ union {
+ __m128i block;
+ uint8_t bytes[sizeof(__m128i)];
+ } s0, last_block, current_block, s_x, temp_block;
+
+#ifdef CRYPTO_DEBUG
+ printf("%s(%p, %p, %p, %p, %p, %u, %u, %d, %p, %d)\n",
+ __FUNCTION__, in, out, addt, nonce, tag, nbytes, abytes, nlen, key, nr);
+#endif
+ if (nbytes == 0)
+ return 1; // No message means no decryption!
+ if (nlen < 0 || nlen > 15)
+ panic("%s: bad nonce length %d", __FUNCTION__, nlen);
+
+ /*
+ * We need to know how many bytes to use to describe
+ * the length of the data. Normally, nlen should be
+ * 12, which leaves us 3 bytes to do that -- 16mbytes of
+ * data to encrypt. But it can be longer or shorter.
+ */
+ L = sizeof(__m128i) - 1 - nlen;
+
+ /*
+ * Now, this shouldn't happen, but let's make sure that
+ * the data length isn't too big.
+ */
+ if (nbytes > ((1 << (8 * L)) - 1))
+ panic("%s: nbytes is %u, but length field is %d bytes",
+ __FUNCTION__, nbytes, L);
+ /*
+ * Clear out the blocks
+ */
+ explicit_bzero(&s0, sizeof(s0));
+ explicit_bzero(¤t_block, sizeof(current_block));
+
+ last_block.block = cbc_mac_start(addt, abytes, nonce, nlen,
+ key, nr, nbytes, tag_length);
+ /* s0 has flags, nonce, and then 0 */
+ s0.bytes[0] = L-1; /* but the flags byte only has L' */
+ bcopy(nonce, &s0.bytes[1], nlen);
+#ifdef CRYPTO_DEBUG
+ PrintBlock("s0", s0.block);
+#endif
+
+ /*
+ * Now to cycle through the rest of the data.
+ */
+ bcopy(&s0, &s_x, sizeof(s0));
+
+ while (total < nbytes) {
+ copy_amt = MIN(nbytes - total, sizeof(temp_block));
+ bcopy(in+total, &temp_block, copy_amt);
+ if (copy_amt < sizeof(temp_block)) {
+ bzero(&temp_block.bytes[copy_amt], sizeof(temp_block) - copy_amt);
+ }
+ append_int(counter++, &s_x.block, L+1);
+ // This actually decrypts, remember
+#ifdef CRYPTO_DEBUG
+ PrintBlock("Decrypt s_x", s_x.block);
+#endif
+ __m128i X = aes_encrypt(s_x.block, key, nr);
+ if (copy_amt < sizeof(temp_block)) {
+ uint8_t *end_of_buffer = (uint8_t*)&X;
+ bzero(&temp_block.bytes[copy_amt], sizeof(temp_block) - copy_amt);
+ bzero(end_of_buffer + copy_amt, sizeof(temp_block) - copy_amt);
+ }
+ temp_block.block = _mm_xor_si128(temp_block.block, X);
+#ifdef CRYPTO_DEBUG
+ PrintBlock("Decrypted plain text", temp_block.block);
+#endif
+
+ bcopy(&temp_block, out+total, copy_amt);
+ last_block.block = xor_and_encrypt(last_block.block, temp_block.block, key, nr);
+ total += copy_amt;
+ }
+ /*
+ * Allgedly done with it! Except for the tag.
+ */
+ s0.block = aes_encrypt(s0.block, key, nr);
+ temp_block.block = _mm_xor_si128(s0.block, last_block.block);
+ // Compare the tag
+ if (bcmp(&temp_block, tag, tag_length) != 0) {
+#ifdef CRYPTO_DEBUG
+ PrintBlock("Computed tag", temp_block.block);
+ PrintBlock("Input tag ", *(const __m128i*)tag);
+#endif
+ bzero(out, nbytes);
+ return 0;
+ }
+ return 1;
+}
+
+#ifdef STANDALONE
+/*
+ * Used for testing
+ */
+/*
+ * The hard-coded key expansion for an all-zeroes key.
+ */
+static uint8_t expanded_zero_key[] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63,
+0xaa, 0xfb, 0xfb, 0xfb, 0xaa, 0xfb, 0xfb, 0xfb, 0xaa, 0xfb, 0xfb, 0xfb, 0xaa, 0xfb, 0xfb, 0xfb,
+0x6f, 0x6c, 0x6c, 0xcf, 0x0d, 0x0f, 0x0f, 0xac, 0x6f, 0x6c, 0x6c, 0xcf, 0x0d, 0x0f, 0x0f, 0xac,
+0x7d, 0x8d, 0x8d, 0x6a, 0xd7, 0x76, 0x76, 0x91, 0x7d, 0x8d, 0x8d, 0x6a, 0xd7, 0x76, 0x76, 0x91,
+0x53, 0x54, 0xed, 0xc1, 0x5e, 0x5b, 0xe2, 0x6d, 0x31, 0x37, 0x8e, 0xa2, 0x3c, 0x38, 0x81, 0x0e,
+0x96, 0x8a, 0x81, 0xc1, 0x41, 0xfc, 0xf7, 0x50, 0x3c, 0x71, 0x7a, 0x3a, 0xeb, 0x07, 0x0c, 0xab,
+0x9e, 0xaa, 0x8f, 0x28, 0xc0, 0xf1, 0x6d, 0x45, 0xf1, 0xc6, 0xe3, 0xe7, 0xcd, 0xfe, 0x62, 0xe9,
+0x2b, 0x31, 0x2b, 0xdf, 0x6a, 0xcd, 0xdc, 0x8f, 0x56, 0xbc, 0xa6, 0xb5, 0xbd, 0xbb, 0xaa, 0x1e,
+0x64, 0x06, 0xfd, 0x52, 0xa4, 0xf7, 0x90, 0x17, 0x55, 0x31, 0x73, 0xf0, 0x98, 0xcf, 0x11, 0x19,
+0x6d, 0xbb, 0xa9, 0x0b, 0x07, 0x76, 0x75, 0x84, 0x51, 0xca, 0xd3, 0x31, 0xec, 0x71, 0x79, 0x2f,
+0xe7, 0xb0, 0xe8, 0x9c, 0x43, 0x47, 0x78, 0x8b, 0x16, 0x76, 0x0b, 0x7b, 0x8e, 0xb9, 0x1a, 0x62,
+0x74, 0xed, 0x0b, 0xa1, 0x73, 0x9b, 0x7e, 0x25, 0x22, 0x51, 0xad, 0x14, 0xce, 0x20, 0xd4, 0x3b,
+0x10, 0xf8, 0x0a, 0x17, 0x53, 0xbf, 0x72, 0x9c, 0x45, 0xc9, 0x79, 0xe7, 0xcb, 0x70, 0x63, 0x85,
+};
+
+static uint8_t expanded_zero_key_2[] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63,
+0xaa, 0xfb, 0xfb, 0xfb, 0xaa, 0xfb, 0xfb, 0xfb, 0xaa, 0xfb, 0xfb, 0xfb, 0xaa, 0xfb, 0xfb, 0xfb,
+0x6f, 0x6c, 0x6c, 0xcf, 0x0d, 0x0f, 0x0f, 0xac, 0x6f, 0x6c, 0x6c, 0xcf, 0x0d, 0x0f, 0x0f, 0xac,
+0x7d, 0x8d, 0x8d, 0x6a, 0xd7, 0x76, 0x76, 0x91, 0x7d, 0x8d, 0x8d, 0x6a, 0xd7, 0x76, 0x76, 0x91,
+0x53, 0x54, 0xed, 0xc1, 0x5e, 0x5b, 0xe2, 0x6d, 0x31, 0x37, 0x8e, 0xa2, 0x3c, 0x38, 0x81, 0x0e,
+0x96, 0x8a, 0x81, 0xc1, 0x41, 0xfc, 0xf7, 0x50, 0x3c, 0x71, 0x7a, 0x3a, 0xeb, 0x07, 0x0c, 0xab,
+0x9e, 0xaa, 0x8f, 0x28, 0xc0, 0xf1, 0x6d, 0x45, 0xf1, 0xc6, 0xe3, 0xe7, 0xcd, 0xfe, 0x62, 0xe9,
+0x2b, 0x31, 0x2b, 0xdf, 0x6a, 0xcd, 0xdc, 0x8f, 0x56, 0xbc, 0xa6, 0xb5, 0xbd, 0xbb, 0xaa, 0x1e,
+0x64, 0x06, 0xfd, 0x52, 0xa4, 0xf7, 0x90, 0x17, 0x55, 0x31, 0x73, 0xf0, 0x98, 0xcf, 0x11, 0x19,
+0x6d, 0xbb, 0xa9, 0x0b, 0x07, 0x76, 0x75, 0x84, 0x51, 0xca, 0xd3, 0x31, 0xec, 0x71, 0x79, 0x2f,
+0xe7, 0xb0, 0xe8, 0x9c, 0x43, 0x47, 0x78, 0x8b, 0x16, 0x76, 0x0b, 0x7b, 0x8e, 0xb9, 0x1a, 0x62,
+0x74, 0xed, 0x0b, 0xa1, 0x73, 0x9b, 0x7e, 0x25, 0x22, 0x51, 0xad, 0x14, 0xce, 0x20, 0xd4, 0x3b,
+0x10, 0xf8, 0x0a, 0x17, 0x53, 0xbf, 0x72, 0x9c, 0x45, 0xc9, 0x79, 0xe7, 0xcb, 0x70, 0x63, 0x85,
+};
+static void
+PrintHex(const void *bytes, size_t len)
+{
+ const uint8_t *b = bytes;
+ for (size_t x = 0; x < len; x++)
+ printf("%02x ", b[x]);
+ printf("\n");
+ return;
+}
+
+int
+main(int ac, char **av)
+{
+ uint8_t tag[16];
+ uint8_t nonce[12] = { 0 };
+ unsigned char aad[] = "How now brown cow";
+// unsigned char plain[] = "Four score and seven years ago, our forefathers brought Bill & Ted";
+ unsigned char plain[4] = "abcd";
+ unsigned char crypt[sizeof(plain)];
+ unsigned char decrypted[sizeof(plain)];
+ uint8_t key[256 / 8] = { 0 };
+ int nrounds = 14; // For a 256-bit key, use 14 rounds
+ int rv;
+
+ printf("Plaintext: "); PrintHex(plain, sizeof(plain));
+ printf("aad size = %zx, nonce size = %zx, tag size = %zx\n", sizeof(aad), sizeof(nonce), sizeof(tag));
+ AES_CCM_encrypt(plain, crypt, aad, nonce, tag,
+ sizeof(plain), sizeof(aad), sizeof(nonce),
+ (const unsigned char *)expanded_zero_key, nrounds);
+ printf("Tag: "); PrintHex(tag, sizeof(tag));
+ printf("Crypt: "); PrintHex(crypt, sizeof(crypt));
+
+ rv = AES_CCM_decrypt(crypt, decrypted, aad, nonce, tag,
+ sizeof(plain), sizeof(aad), sizeof(nonce),
+ (const unsigned char *)expanded_zero_key_2, nrounds);
+ printf("%s Decrypted: ", rv == 1 ? "Successfully" : "Unsuccessfully");
+ PrintHex(decrypted, sizeof(decrypted));
+
+ return 0;
+}
+#endif
Index: sys/crypto/aesni/aesni_wrap.c
===================================================================
--- sys/crypto/aesni/aesni_wrap.c
+++ sys/crypto/aesni/aesni_wrap.c
@@ -446,6 +446,7 @@
switch (ses->algo) {
case CRYPTO_AES_ICM:
case CRYPTO_AES_NIST_GCM_16:
+ case CRYPTO_AES_CCM_16:
decsched = 0;
/* FALLTHROUGH */
case CRYPTO_AES_CBC:
Index: sys/modules/aesni/Makefile
===================================================================
--- sys/modules/aesni/Makefile
+++ sys/modules/aesni/Makefile
@@ -8,11 +8,17 @@
SRCS+= aeskeys_${MACHINE_CPUARCH}.S
SRCS+= device_if.h bus_if.h opt_bus.h cryptodev_if.h
-OBJS+= aesni_ghash.o aesni_wrap.o
+OBJS+= aesni_ghash.o aesni_wrap.o aesni_ccm.o
OBJS+= intel_sha1.o intel_sha256.o
# Remove -nostdinc so we can get the intrinsics.
aesni_ghash.o: aesni_ghash.c
+ # XXX - gcc won't understand -mpclmul
+ ${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} \
+ -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}
+ ${CTFCONVERT_CMD}
+
+aesni_ccm.o: aesni_ccm.c
# XXX - gcc won't understand -mpclmul
${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} \
-mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}
Index: sys/modules/crypto/Makefile
===================================================================
--- sys/modules/crypto/Makefile
+++ sys/modules/crypto/Makefile
@@ -46,5 +46,7 @@
SRCS += chacha-sw.c
SRCS += opt_param.h cryptodev_if.h bus_if.h device_if.h
SRCS += opt_ddb.h
+SRCS += ccm-cbc.c
+SRCS += xform_cbc_mac.c
.include <bsd.kmod.mk>
Index: sys/opencrypto/ccm-cbc.h
===================================================================
--- sys/opencrypto/ccm-cbc.h
+++ sys/opencrypto/ccm-cbc.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * Copyright (c) 2018, iXsystems Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Sean Eric Fagan, with lots of references
+ * to existing AES-CCM (gmac) code.
+ *
+ * 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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, 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 DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _CCM_H
+# define _CCM_H
+
+# include <sys/types.h>
+# include <crypto/rijndael/rijndael.h>
+
+# define CCM_CBC_BLOCK_LEN 16 /* 128 bits */
+# define CCM_CBC_MAX_DIGEST_LEN 16
+# define CCM_CBC_MIN_DIGEST_LEN 4
+
+/*
+ * This is the authentication context structure;
+ * the encryption one is similar.
+ */
+struct aes_cbc_mac_ctx {
+ uint64_t authDataLength, authDataCount;
+ uint64_t cryptDataLength;
+ int tagLength;
+ int blockIndex;
+ uint8_t staging_block[CCM_CBC_BLOCK_LEN];
+ uint8_t block[CCM_CBC_BLOCK_LEN];
+ const uint8_t *aes_key;
+ int keyLength; /* This will be in bits, not bytes! */
+ const uint8_t *nonce;
+ int nonceLength; /* This one is in bytes, not bits! */
+ /* AES state data */
+ int rounds;
+ uint32_t keysched[4*(RIJNDAEL_MAXNR+1)];
+};
+
+void AES_CBC_MAC_Init(struct aes_cbc_mac_ctx *);
+void AES_CBC_MAC_Setkey(struct aes_cbc_mac_ctx *, const uint8_t *, uint16_t);
+void AES_CBC_MAC_Reinit(struct aes_cbc_mac_ctx *, const uint8_t *, uint16_t);
+int AES_CBC_MAC_Update(struct aes_cbc_mac_ctx *, const uint8_t *, uint16_t);
+void AES_CBC_MAC_Final(uint8_t *, struct aes_cbc_mac_ctx *);
+
+#endif /* _CCM_H */
Index: sys/opencrypto/ccm-cbc.c
===================================================================
--- sys/opencrypto/ccm-cbc.c
+++ sys/opencrypto/ccm-cbc.c
@@ -0,0 +1,219 @@
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <opencrypto/ccm-cbc.h>
+#include <opencrypto/xform_auth.h>
+
+#ifdef CRYPTO_DEBUG
+static void
+PrintBlock(const char *label, void *b)
+{
+ uint8_t *ptr = b;
+ printf("%s: %s: ", __FILE__, label);
+ for (size_t i = 0; i < 16; i++)
+ printf("%02x ", ptr[i]);
+ printf("\n");
+}
+#endif
+
+/*
+ * Given two CCM_CBC_BLOCK_LEN blocks, xor
+ * them into dst, and then encrypt dst.
+ */
+static void
+xor_and_encrypt(struct aes_cbc_mac_ctx *ctx,
+ const uint8_t *src, uint8_t *dst)
+{
+ const uint64_t *b1;
+ uint64_t *b2;
+ uint64_t temp_block[CCM_CBC_BLOCK_LEN/sizeof(uint64_t)];
+ b1 = (const uint64_t*)src;
+ b2 = (uint64_t*)dst;
+
+ for (size_t count = 0;
+ count < CCM_CBC_BLOCK_LEN/sizeof(uint64_t);
+ count++) {
+ temp_block[count] = b1[count] ^ b2[count];
+ }
+ rijndaelEncrypt(ctx->keysched, ctx->rounds, (void*)temp_block, dst);
+}
+
+void
+AES_CBC_MAC_Init(struct aes_cbc_mac_ctx *ctx)
+{
+ bzero(ctx, sizeof *ctx);
+ ctx->tagLength = AES_CBC_MAC_HASH_LEN;
+}
+
+void
+AES_CBC_MAC_Setkey(struct aes_cbc_mac_ctx *ctx, const uint8_t *key, uint16_t klen)
+{
+ ctx->rounds = rijndaelKeySetupEnc(ctx->keysched, key, klen * 8);
+ return;
+}
+
+/*
+ * This is called to set the nonce, aka IV.
+ * Before this call, the authDataLength and cryptDataLength fields
+ * MUST have been set. Sadly, there's no way to return an error.
+ *
+ * The CBC-MAC algorithm requires that the first block contain the
+ * nonce, as well as information about the sizes and lengths involved.
+ */
+void
+AES_CBC_MAC_Reinit(struct aes_cbc_mac_ctx *ctx, const uint8_t *nonce, uint16_t nonceLen)
+{
+ uint8_t b0[CCM_CBC_BLOCK_LEN];
+ uint8_t *bp = b0, flags = 0;
+ uint8_t L = 0;
+ uint64_t tmp = ctx->cryptDataLength;
+
+ if (ctx->authDataLength == 0 &&
+ ctx->cryptDataLength == 0) {
+ return;
+ }
+
+ ctx->nonce = nonce;
+ ctx->nonceLength = nonceLen;
+
+ ctx->authDataCount = 0;
+ ctx->blockIndex = 0;
+ explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
+
+ /*
+ * Need to determine the L field value.
+ * This is the number of bytes needed to
+ * specify the length of the message; the
+ * length is whatever is left in the 16 bytes
+ * after specifying flags and the nonce.
+ */
+ L = (15 - nonceLen) & 0xff;
+
+ flags = (ctx->authDataLength > 0) * 64 +
+ ((ctx->tagLength-2) / 2) * 8 +
+ L - 1;
+ /*
+ * Now we need to set up the first block,
+ * which has flags, nonce, and the message length.
+ */
+ b0[0] = flags;
+ bcopy(nonce, b0+1, nonceLen);
+ bp = b0 + 1 + nonceLen;
+
+ /* Need to copy L' [aka L-1] bytes of cryptDataLength */
+ for (uint8_t *dst = b0 + sizeof(b0) - 1;
+ dst >= bp;
+ dst--) {
+ *dst = (tmp & 0xff);
+ tmp >>= 8;
+ }
+ /* Now need to encrypt b0 */
+ rijndaelEncrypt(ctx->keysched, ctx->rounds, b0, ctx->block);
+
+ /* If there is auth data, we need to set up the staging block */
+ if (ctx->authDataLength) {
+ if (ctx->authDataLength < ((1<<16) - (1<<8))) {
+ uint16_t sizeVal = htobe16(ctx->authDataLength);
+ bcopy(&sizeVal, ctx->staging_block, sizeof(sizeVal));
+ ctx->blockIndex = sizeof(sizeVal);
+ } else if (ctx->authDataLength < (1UL<<32)) {
+ uint32_t sizeVal = htobe32(ctx->authDataLength);
+ ctx->staging_block[0] = 0xff;
+ ctx->staging_block[1] = 0xfe;
+ bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal));
+ ctx->blockIndex = 2 + sizeof(sizeVal);
+ } else {
+ uint64_t sizeVal = htobe64(ctx->authDataLength);
+ ctx->staging_block[0] = 0xff;
+ ctx->staging_block[1] = 0xff;
+ bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal));
+ ctx->blockIndex = 2 + sizeof(sizeVal);
+ }
+ }
+ return;
+}
+
+int
+AES_CBC_MAC_Update(struct aes_cbc_mac_ctx *ctx, const uint8_t *data, uint16_t length)
+{
+
+ /*
+ * This will be called in one of two phases:
+ * (1) Applying authentication data, or
+ * (2) Applying the payload data.
+ * Because CBC-MAC puts the authentication data
+ * size before the data, subsequent calls won't
+ * be block-size-aligned. Which complicates things
+ * a fair bit.
+ *
+ * The payload data doesn't have that problem.
+ */
+
+ if (ctx->authDataCount < ctx->authDataLength) {
+ /*
+ * We need to process data as authentication data.
+ * Since we may be out of sync, we may also need
+ * to pad out the staging block.
+ */
+ const uint8_t *ptr = data;
+ while (length) {
+ size_t copy_amt = MIN(length,
+ sizeof(ctx->staging_block) - ctx->blockIndex);
+ bcopy(ptr, ctx->staging_block + ctx->blockIndex, copy_amt);
+ ptr += copy_amt;
+ length -= copy_amt;
+ ctx->authDataCount += copy_amt;
+ ctx->blockIndex += copy_amt;
+ ctx->blockIndex %= sizeof(ctx->staging_block);
+ if (ctx->authDataCount >= ctx->authDataLength)
+ length = 0;
+ if (ctx->blockIndex == 0 ||
+ ctx->authDataCount >= ctx->authDataLength) {
+ /*
+ * We're done with this block, so we
+ * xor staging_block with block, and then
+ * encrypt it.
+ */
+ xor_and_encrypt(ctx, ctx->staging_block, ctx->block);
+ explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
+ ctx->blockIndex = 0;
+ }
+ }
+ return (0);
+ }
+ /*
+ * If we're here, then we're encoding payload data.
+ * This is easier, as we just xor&encrypt.
+ */
+ while (length) {
+ const uint8_t *ptr;
+
+ if (length < sizeof(ctx->block)) {
+ explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
+ bcopy(data, ctx->staging_block, length);
+ ptr = ctx->staging_block;
+ length = 0;
+ } else {
+ ptr = data;
+ length -= sizeof(ctx->block);
+ }
+ xor_and_encrypt(ctx, ptr, ctx->block);
+ }
+ return (0);
+}
+
+void
+AES_CBC_MAC_Final(uint8_t *buf, struct aes_cbc_mac_ctx *ctx)
+{
+ uint8_t s0[CCM_CBC_BLOCK_LEN];
+
+ explicit_bzero(s0, sizeof(s0));
+ s0[0] = ((15 - ctx->nonceLength) & 0xff) - 1;
+ bcopy(ctx->nonce, s0+1, ctx->nonceLength);
+ rijndaelEncrypt(ctx->keysched, ctx->rounds, s0, s0);
+ for (size_t indx = 0; indx < ctx->tagLength; indx++)
+ buf[indx] = ctx->block[indx] ^ s0[indx];
+ explicit_bzero(s0, sizeof(s0));
+ return;
+}
Index: sys/opencrypto/cryptodev.h
===================================================================
--- sys/opencrypto/cryptodev.h
+++ sys/opencrypto/cryptodev.h
@@ -80,6 +80,8 @@
#define MD5_KPDK_HASH_LEN 16
#define SHA1_KPDK_HASH_LEN 20
#define AES_GMAC_HASH_LEN 16
+#define AES_CBC_MAC_HASH_LEN 16
+
/* Maximum hash algorithm result length */
#define HASH_MAX_LEN SHA2_512_HASH_LEN /* Keep this updated */
@@ -99,6 +101,9 @@
#define AES_128_GMAC_KEY_LEN 16
#define AES_192_GMAC_KEY_LEN 24
#define AES_256_GMAC_KEY_LEN 32
+#define AES_128_CBC_MAC_KEY_LEN 16
+#define AES_192_CBC_MAC_KEY_LEN 24
+#define AES_256_CBC_MAC_KEY_LEN 32
/* Encryption algorithm block sizes */
#define NULL_BLOCK_LEN 4 /* IPsec to maintain alignment */
@@ -182,7 +187,11 @@
#define CRYPTO_BLAKE2B 29 /* Blake2b hash */
#define CRYPTO_BLAKE2S 30 /* Blake2s hash */
#define CRYPTO_CHACHA20 31 /* Chacha20 stream cipher */
-#define CRYPTO_ALGORITHM_MAX 31 /* Keep updated - see below */
+#define CRYPTO_AES_CCM_16 32 /* cipher side */
+#define CRYPTO_AES_128_CCM_CBC_MAC 33 /* auth side */
+#define CRYPTO_AES_192_CCM_CBC_MAC 34 /* auth side */
+#define CRYPTO_AES_256_CCM_CBC_MAC 35 /* auth side */
+#define CRYPTO_ALGORITHM_MAX 35 /* Keep updated - see below */
#define CRYPTO_ALGO_VALID(x) ((x) >= CRYPTO_ALGORITHM_MIN && \
(x) <= CRYPTO_ALGORITHM_MAX)
Index: sys/opencrypto/cryptodev.c
===================================================================
--- sys/opencrypto/cryptodev.c
+++ sys/opencrypto/cryptodev.c
@@ -441,6 +441,9 @@
case CRYPTO_AES_NIST_GCM_16:
txform = &enc_xform_aes_nist_gcm;
break;
+ case CRYPTO_AES_CCM_16:
+ txform = &enc_xform_ccm;
+ break;
case CRYPTO_CHACHA20:
txform = &enc_xform_chacha20;
break;
@@ -482,6 +485,15 @@
thash = &auth_hash_nist_gmac_aes_256;
break;
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ thash = &auth_hash_ccm_cbc_mac_128;
+ break;
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ thash = &auth_hash_ccm_cbc_mac_192;
+ break;
+ case CRYPTO_AES_256_CCM_CBC_MAC:
+ thash = &auth_hash_ccm_cbc_mac_256;
+ break;
#ifdef notdef
case CRYPTO_MD5:
thash = &auth_hash_md5;
@@ -984,12 +996,12 @@
}
/*
- * For GCM, crd_len covers only the AAD. For other ciphers
+ * For GCM and CCM, crd_len covers only the AAD. For other ciphers
* chained with an HMAC, crd_len covers both the AAD and the
* cipher text.
*/
crda->crd_skip = 0;
- if (cse->cipher == CRYPTO_AES_NIST_GCM_16)
+ if (cse->cipher == CRYPTO_AES_NIST_GCM_16 || cse->cipher == CRYPTO_AES_CCM_16)
crda->crd_len = caead->aadlen;
else
crda->crd_len = caead->aadlen + caead->len;
Index: sys/opencrypto/cryptosoft.c
===================================================================
--- sys/opencrypto/cryptosoft.c
+++ sys/opencrypto/cryptosoft.c
@@ -487,6 +487,7 @@
caddr_t buf = (caddr_t)crp->crp_buf;
uint32_t *blkp;
int aadlen, blksz, i, ivlen, len, iskip, oskip, r;
+ int isccm = 0;
ivlen = blksz = iskip = oskip = 0;
@@ -499,6 +500,8 @@
return (EINVAL);
switch (sw->sw_alg) {
+ case CRYPTO_AES_CCM_16:
+ isccm = 1;
case CRYPTO_AES_NIST_GCM_16:
case CRYPTO_AES_NIST_GMAC:
swe = sw;
@@ -506,6 +509,10 @@
exf = swe->sw_exf;
ivlen = 12;
break;
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ case CRYPTO_AES_256_CCM_CBC_MAC:
+ isccm = 1;
case CRYPTO_AES_128_NIST_GMAC:
case CRYPTO_AES_192_NIST_GMAC:
case CRYPTO_AES_256_NIST_GMAC:
@@ -524,7 +531,8 @@
if (crde == NULL || crda == NULL)
return (EINVAL);
- if (crde->crd_alg == CRYPTO_AES_NIST_GCM_16 &&
+ if ((crde->crd_alg == CRYPTO_AES_NIST_GCM_16 ||
+ crde->crd_alg == CRYPTO_AES_CCM_16) &&
(crde->crd_flags & CRD_F_IV_EXPLICIT) == 0)
return (EINVAL);
@@ -555,6 +563,21 @@
}
}
+ if (swa) {
+ switch (swa->sw_alg) {
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ case CRYPTO_AES_256_CCM_CBC_MAC:
+ /*
+ * AES CCM-CBC needs to know the length of
+ * both the auth data, and payload data, before
+ * doing the auth computation.
+ */
+ ctx.aes_cbc_mac_ctx.authDataLength = crda->crd_len;
+ ctx.aes_cbc_mac_ctx.cryptDataLength = crde->crd_len;
+ break;
+ }
+ }
/* Supply MAC with IV */
if (axf->Reinit)
axf->Reinit(&ctx, iv, ivlen);
@@ -590,15 +613,20 @@
crypto_copydata(crp->crp_flags, buf, crde->crd_skip + i, len,
blk);
if (crde->crd_flags & CRD_F_ENCRYPT) {
+ if (isccm)
+ axf->Update(&ctx, blk, len);
if (exf->encrypt_multi != NULL)
exf->encrypt_multi(swe->sw_kschedule, blk,
len);
else
exf->encrypt(swe->sw_kschedule, blk);
- axf->Update(&ctx, blk, len);
+ if (!isccm)
+ axf->Update(&ctx, blk, len);
crypto_copyback(crp->crp_flags, buf,
crde->crd_skip + i, len, blk);
} else {
+ if (isccm)
+ exf->decrypt(swe->sw_kschedule, blk);
axf->Update(&ctx, blk, len);
}
}
@@ -629,6 +657,8 @@
r = timingsafe_bcmp(aalg, uaalg, axf->hashsize);
if (r == 0) {
/* tag matches, decrypt data */
+ if (isccm && exf->reinit)
+ exf->reinit(swe->sw_kschedule, iv);
for (i = 0; i < crde->crd_len; i += blksz) {
len = MIN(crde->crd_len - i, blksz);
if (len < blksz)
@@ -821,6 +851,9 @@
case CRYPTO_AES_NIST_GCM_16:
txf = &enc_xform_aes_nist_gcm;
goto enccommon;
+ case CRYPTO_AES_CCM_16:
+ txf = &enc_xform_ccm;
+ goto enccommon;
case CRYPTO_AES_NIST_GMAC:
txf = &enc_xform_aes_nist_gmac;
(*swd)->sw_exf = txf;
@@ -947,6 +980,15 @@
break;
#endif
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ axf = &auth_hash_ccm_cbc_mac_128;
+ goto auth4common;
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ axf = &auth_hash_ccm_cbc_mac_192;
+ goto auth4common;
+ case CRYPTO_AES_256_CCM_CBC_MAC:
+ axf = &auth_hash_ccm_cbc_mac_256;
+ goto auth4common;
case CRYPTO_AES_128_NIST_GMAC:
axf = &auth_hash_nist_gmac_aes_128;
goto auth4common;
@@ -1216,11 +1258,15 @@
goto done;
break;
+ case CRYPTO_AES_CCM_16:
case CRYPTO_AES_NIST_GCM_16:
case CRYPTO_AES_NIST_GMAC:
case CRYPTO_AES_128_NIST_GMAC:
case CRYPTO_AES_192_NIST_GMAC:
case CRYPTO_AES_256_NIST_GMAC:
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ case CRYPTO_AES_256_CCM_CBC_MAC:
crp->crp_etype = swcr_authenc(crp);
goto done;
@@ -1305,6 +1351,10 @@
REGISTER(CRYPTO_BLAKE2B);
REGISTER(CRYPTO_BLAKE2S);
REGISTER(CRYPTO_CHACHA20);
+ REGISTER(CRYPTO_AES_CCM_16);
+ REGISTER(CRYPTO_AES_128_CCM_CBC_MAC);
+ REGISTER(CRYPTO_AES_192_CCM_CBC_MAC);
+ REGISTER(CRYPTO_AES_256_CCM_CBC_MAC);
#undef REGISTER
return 0;
Index: sys/opencrypto/xform_aes_icm.c
===================================================================
--- sys/opencrypto/xform_aes_icm.c
+++ sys/opencrypto/xform_aes_icm.c
@@ -57,6 +57,7 @@
static void aes_icm_zerokey(u_int8_t **);
static void aes_icm_reinit(caddr_t, u_int8_t *);
static void aes_gcm_reinit(caddr_t, u_int8_t *);
+static void aes_ccm_reinit(caddr_t, u_int8_t *);
/* Encryption instances */
struct enc_xform enc_xform_aes_icm = {
@@ -79,6 +80,16 @@
aes_gcm_reinit,
};
+struct enc_xform enc_xform_ccm = {
+ CRYPTO_AES_CCM_16, "AES-CCM",
+ AES_ICM_BLOCK_LEN, AES_GCM_IV_LEN, AES_MIN_KEY, AES_MAX_KEY,
+ aes_icm_crypt,
+ aes_icm_crypt,
+ aes_icm_setkey,
+ aes_icm_zerokey,
+ aes_ccm_reinit,
+};
+
/*
* Encryption wrapper routines.
*/
@@ -102,6 +113,20 @@
/* GCM starts with 2 as counter 1 is used for final xor of tag. */
bzero(&ctx->ac_block[AESICM_BLOCKSIZE - 4], 4);
ctx->ac_block[AESICM_BLOCKSIZE - 1] = 2;
+}
+
+static void
+aes_ccm_reinit(caddr_t key, u_int8_t *iv)
+{
+ struct aes_icm_ctx *ctx;
+ ctx = (struct aes_icm_ctx*)key;
+
+ /* CCM has flags, then the IV, then the counter, which starts at 1 */
+ explicit_bzero(ctx->ac_block, sizeof(ctx->ac_block));
+ /* 3 bytes for length field; this gives a nonce of 12 bytes */
+ ctx->ac_block[0] = (15 - AES_GCM_IV_LEN) - 1;
+ bcopy(iv, ctx->ac_block+1, AES_GCM_IV_LEN);
+ ctx->ac_block[AESICM_BLOCKSIZE - 1] = 1;
}
static void
Index: sys/opencrypto/xform_auth.h
===================================================================
--- sys/opencrypto/xform_auth.h
+++ sys/opencrypto/xform_auth.h
@@ -41,6 +41,7 @@
#include <crypto/sha2/sha512.h>
#include <opencrypto/rmd160.h>
#include <opencrypto/gmac.h>
+#include <opencrypto/ccm-cbc.h>
#include <opencrypto/cryptodev.h>
#include <opencrypto/xform_userland.h>
@@ -77,6 +78,9 @@
extern struct auth_hash auth_hash_nist_gmac_aes_256;
extern struct auth_hash auth_hash_blake2b;
extern struct auth_hash auth_hash_blake2s;
+extern struct auth_hash auth_hash_ccm_cbc_mac_128;
+extern struct auth_hash auth_hash_ccm_cbc_mac_192;
+extern struct auth_hash auth_hash_ccm_cbc_mac_256;
union authctx {
MD5_CTX md5ctx;
@@ -86,6 +90,7 @@
SHA384_CTX sha384ctx;
SHA512_CTX sha512ctx;
struct aes_gmac_ctx aes_gmac_ctx;
+ struct aes_cbc_mac_ctx aes_cbc_mac_ctx;
};
#endif /* _CRYPTO_XFORM_AUTH_H_ */
Index: sys/opencrypto/xform_cbc_mac.c
===================================================================
--- sys/opencrypto/xform_cbc_mac.c
+++ sys/opencrypto/xform_cbc_mac.c
@@ -0,0 +1,37 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/ccm-cbc.h>
+#include <opencrypto/xform_auth.h>
+
+/* Authentication instances */
+struct auth_hash auth_hash_ccm_cbc_mac_128 = {
+ CRYPTO_AES_128_CCM_CBC_MAC, "CBC-CCM-AES-128",
+ AES_128_CBC_MAC_KEY_LEN, AES_CBC_MAC_HASH_LEN, sizeof(struct aes_cbc_mac_ctx),
+ CCM_CBC_BLOCK_LEN,
+ (void (*)(void *)) AES_CBC_MAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final
+};
+struct auth_hash auth_hash_ccm_cbc_mac_192 = {
+ CRYPTO_AES_192_CCM_CBC_MAC, "CBC-CCM-AES-192",
+ AES_192_CBC_MAC_KEY_LEN, AES_CBC_MAC_HASH_LEN, sizeof(struct aes_cbc_mac_ctx),
+ CCM_CBC_BLOCK_LEN,
+ (void (*)(void *)) AES_CBC_MAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final
+};
+struct auth_hash auth_hash_ccm_cbc_mac_256 = {
+ CRYPTO_AES_256_CCM_CBC_MAC, "CBC-CCM-AES-256",
+ AES_256_CBC_MAC_KEY_LEN, AES_CBC_MAC_HASH_LEN, sizeof(struct aes_cbc_mac_ctx),
+ CCM_CBC_BLOCK_LEN,
+ (void (*)(void *)) AES_CBC_MAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final
+};
Index: sys/opencrypto/xform_enc.h
===================================================================
--- sys/opencrypto/xform_enc.h
+++ sys/opencrypto/xform_enc.h
@@ -84,6 +84,7 @@
extern struct enc_xform enc_xform_arc4;
extern struct enc_xform enc_xform_camellia;
extern struct enc_xform enc_xform_chacha20;
+extern struct enc_xform enc_xform_ccm;
struct aes_icm_ctx {
u_int32_t ac_ek[4*(RIJNDAEL_MAXNR + 1)];
Index: tools/tools/crypto/cryptocheck.c
===================================================================
--- tools/tools/crypto/cryptocheck.c
+++ tools/tools/crypto/cryptocheck.c
@@ -131,7 +131,7 @@
const char *name;
int cipher;
int mac;
- enum { T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type;
+ enum { T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM, T_CCM } type;
const EVP_CIPHER *(*evp_cipher)(void);
const EVP_MD *(*evp_md)(void);
} algs[] = {
@@ -143,10 +143,12 @@
.evp_md = EVP_sha384 },
{ .name = "sha512", .mac = CRYPTO_SHA2_512_HMAC, .type = T_HMAC,
.evp_md = EVP_sha512 },
+#if 0
{ .name = "blake2b", .mac = CRYPTO_BLAKE2B, .type = T_HMAC,
.evp_md = EVP_blake2b512 },
{ .name = "blake2s", .mac = CRYPTO_BLAKE2S, .type = T_HMAC,
.evp_md = EVP_blake2s256 },
+#endif
{ .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,
@@ -163,8 +165,10 @@
.evp_cipher = EVP_aes_128_xts },
{ .name = "aes-xts256", .cipher = CRYPTO_AES_XTS, .type = T_BLKCIPHER,
.evp_cipher = EVP_aes_256_xts },
+#if 0
{ .name = "chacha20", .cipher = CRYPTO_CHACHA20, .type = T_BLKCIPHER,
.evp_cipher = EVP_chacha20 },
+#endif
{ .name = "aes-gcm", .cipher = CRYPTO_AES_NIST_GCM_16,
.mac = CRYPTO_AES_128_NIST_GMAC, .type = T_GCM,
.evp_cipher = EVP_aes_128_gcm },
@@ -174,6 +178,15 @@
{ .name = "aes-gcm256", .cipher = CRYPTO_AES_NIST_GCM_16,
.mac = CRYPTO_AES_256_NIST_GMAC, .type = T_GCM,
.evp_cipher = EVP_aes_256_gcm },
+ { .name = "aes-ccm", .cipher = CRYPTO_AES_CCM_16,
+ .mac = CRYPTO_AES_128_CCM_CBC_MAC, .type = T_CCM,
+ .evp_cipher = EVP_aes_128_ccm },
+ { .name = "aes-ccm192", .cipher = CRYPTO_AES_CCM_16,
+ .mac = CRYPTO_AES_192_CCM_CBC_MAC, .type = T_CCM,
+ .evp_cipher = EVP_aes_192_ccm },
+ { .name = "aes-ccm256", .cipher = CRYPTO_AES_CCM_16,
+ .mac = CRYPTO_AES_256_CCM_CBC_MAC, .type = T_CCM,
+ .evp_cipher = EVP_aes_256_ccm },
};
static bool verbose;
@@ -1025,6 +1038,199 @@
}
static void
+openssl_ccm_encrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
+ const char *iv, size_t iv_len, 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, NULL, NULL) != 1)
+ errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
+ size, ERR_error_string(ERR_get_error(), NULL));
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, NULL) != 1)
+ errx(1, "OpenSSL %s (%zu) setting iv length failed: %s", alg->name,
+ size, ERR_error_string(ERR_get_error(), NULL));
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, AES_CBC_MAC_HASH_LEN, NULL) != 1)
+ errx(1, "OpenSSL %s (%zu) setting tag length failed: %s", alg->name,
+ size, ERR_error_string(ERR_get_error(), NULL));
+ if (EVP_EncryptInit_ex(ctx, NULL, 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));
+ if (EVP_EncryptUpdate(ctx, NULL, &outl, NULL, size) != 1)
+ errx(1, "OpenSSL %s (%zu) unable to set data length: %s", alg->name,
+ size, ERR_error_string(ERR_get_error(), NULL));
+
+ 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_CBC_MAC_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_ccm(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);
+}
+
+static void
+run_ccm_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_CBC_MAC_HASH_LEN], test_tag[AES_CBC_MAC_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);
+ cleartext = alloc_buffer(size);
+ buffer = malloc(size);
+ ciphertext = malloc(size);
+ if (aad_len != 0)
+ aad = alloc_buffer(aad_len);
+ else
+ aad = NULL;
+
+ /* OpenSSL encrypt */
+ openssl_ccm_encrypt(alg, cipher, key, iv, iv_len, aad, aad_len, cleartext,
+ ciphertext, size, control_tag);
+
+ /* OCF encrypt */
+ if (!ocf_ccm(alg, key, key_len, iv, iv_len, aad, aad_len, cleartext,
+ buffer, size, test_tag, 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;
+ }
+ if (memcmp(control_tag, test_tag, sizeof(control_tag)) != 0) {
+ printf("%s (%zu) enc tag mismatch:\n", alg->name, size);
+ printf("control:\n");
+ hexdump(control_tag, sizeof(control_tag), NULL, 0);
+ printf("test (cryptodev device %s):\n", crfind(crid));
+ hexdump(test_tag, sizeof(test_tag), NULL, 0);
+ goto out;
+ }
+
+ /* OCF decrypt */
+ if (!ocf_ccm(alg, key, key_len, iv, iv_len, aad, aad_len, ciphertext,
+ buffer, size, control_tag, 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(aad);
+ free(ciphertext);
+ free(buffer);
+ free(cleartext);
+ free(iv);
+ free(key);
+}
+
+static void
run_test(struct alg *alg, size_t size)
{
@@ -1041,6 +1247,9 @@
case T_GCM:
run_gcm_test(alg, size);
break;
+ case T_CCM:
+ run_ccm_test(alg, size);
+ break;
}
}
@@ -1100,7 +1309,8 @@
u_int i;
for (i = 0; i < nitems(algs); i++)
- if (algs[i].type == T_GCM)
+ if (algs[i].type == T_GCM ||
+ algs[i].type == T_CCM)
run_test_sizes(&algs[i], sizes, nsizes);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Sep 8, 4:44 AM (19 h, 40 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38444426
Default Alt Text
D15446.id42971.diff (64 KB)
Attached To
Mode
D15446: AES CCM-CBC cryptography code
Attached
Detach File
Event Timeline
Log In to Comment