17cff9f37SSean Eric Fagan /*-
28e6af6adSJohn Baldwin * Copyright (c) 2014-2021 The FreeBSD Foundation
37cff9f37SSean Eric Fagan * Copyright (c) 2018 iXsystems, Inc
47cff9f37SSean Eric Fagan * All rights reserved.
57cff9f37SSean Eric Fagan *
68e6af6adSJohn Baldwin * Portions of this software were developed by John-Mark Gurney
78e6af6adSJohn Baldwin * under the sponsorship of the FreeBSD Foundation and
87cff9f37SSean Eric Fagan * Rubicon Communications, LLC (Netgate).
98e6af6adSJohn Baldwin *
108e6af6adSJohn Baldwin * Portions of this software were developed by Ararat River
118e6af6adSJohn Baldwin * Consulting, LLC under sponsorship of the FreeBSD Foundation.
128e6af6adSJohn Baldwin *
137cff9f37SSean Eric Fagan * Redistribution and use in source and binary forms, with or without
147cff9f37SSean Eric Fagan * modification, are permitted provided that the following conditions
157cff9f37SSean Eric Fagan * are met:
167cff9f37SSean Eric Fagan * 1. Redistributions of source code must retain the above copyright
177cff9f37SSean Eric Fagan * notice, this list of conditions and the following disclaimer.
187cff9f37SSean Eric Fagan * 2. Redistributions in binary form must reproduce the above copyright
197cff9f37SSean Eric Fagan * notice, this list of conditions and the following disclaimer in the
207cff9f37SSean Eric Fagan * documentation and/or other materials provided with the distribution.
217cff9f37SSean Eric Fagan *
227cff9f37SSean Eric Fagan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
237cff9f37SSean Eric Fagan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
247cff9f37SSean Eric Fagan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
257cff9f37SSean Eric Fagan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
267cff9f37SSean Eric Fagan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
277cff9f37SSean Eric Fagan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
287cff9f37SSean Eric Fagan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
297cff9f37SSean Eric Fagan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
307cff9f37SSean Eric Fagan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
317cff9f37SSean Eric Fagan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
327cff9f37SSean Eric Fagan * SUCH DAMAGE.
337cff9f37SSean Eric Fagan *
347cff9f37SSean Eric Fagan *
357cff9f37SSean Eric Fagan * This file implements AES-CCM+CBC-MAC, as described
367cff9f37SSean Eric Fagan * at https://tools.ietf.org/html/rfc3610, using Intel's
377cff9f37SSean Eric Fagan * AES-NI instructions.
387cff9f37SSean Eric Fagan *
397cff9f37SSean Eric Fagan */
407cff9f37SSean Eric Fagan
417cff9f37SSean Eric Fagan #include <sys/types.h>
427cff9f37SSean Eric Fagan #include <sys/endian.h>
437cff9f37SSean Eric Fagan #include <sys/param.h>
447cff9f37SSean Eric Fagan
457cff9f37SSean Eric Fagan #include <sys/systm.h>
467cff9f37SSean Eric Fagan #include <crypto/aesni/aesni.h>
477cff9f37SSean Eric Fagan #include <crypto/aesni/aesni_os.h>
487cff9f37SSean Eric Fagan #include <crypto/aesni/aesencdec.h>
497cff9f37SSean Eric Fagan #define AESNI_ENC(d, k, nr) aesni_enc(nr-1, (const __m128i*)k, d)
507cff9f37SSean Eric Fagan
517cff9f37SSean Eric Fagan #include <wmmintrin.h>
527cff9f37SSean Eric Fagan #include <emmintrin.h>
537cff9f37SSean Eric Fagan #include <smmintrin.h>
547cff9f37SSean Eric Fagan
557cff9f37SSean Eric Fagan /*
567cff9f37SSean Eric Fagan * Encrypt a single 128-bit block after
577cff9f37SSean Eric Fagan * doing an xor. This is also used to
587cff9f37SSean Eric Fagan * decrypt (yay symmetric encryption).
597cff9f37SSean Eric Fagan */
607cff9f37SSean Eric Fagan static inline __m128i
xor_and_encrypt(__m128i a,__m128i b,const unsigned char * k,int nr)617cff9f37SSean Eric Fagan xor_and_encrypt(__m128i a, __m128i b, const unsigned char *k, int nr)
627cff9f37SSean Eric Fagan {
636fe286edSConrad Meyer __m128i retval = _mm_xor_si128(a, b);
647cff9f37SSean Eric Fagan
657cff9f37SSean Eric Fagan retval = AESNI_ENC(retval, k, nr);
667cff9f37SSean Eric Fagan return (retval);
677cff9f37SSean Eric Fagan }
687cff9f37SSean Eric Fagan
697cff9f37SSean Eric Fagan /*
707cff9f37SSean Eric Fagan * Put value at the end of block, starting at offset.
717cff9f37SSean Eric Fagan * (This goes backwards, putting bytes in *until* it
727cff9f37SSean Eric Fagan * reaches offset.)
737cff9f37SSean Eric Fagan */
747cff9f37SSean Eric Fagan static void
append_int(size_t value,__m128i * block,size_t offset)757cff9f37SSean Eric Fagan append_int(size_t value, __m128i *block, size_t offset)
767cff9f37SSean Eric Fagan {
777cff9f37SSean Eric Fagan int indx = sizeof(*block) - 1;
787cff9f37SSean Eric Fagan uint8_t *bp = (uint8_t*)block;
797cff9f37SSean Eric Fagan
807cff9f37SSean Eric Fagan while (indx > (sizeof(*block) - offset)) {
817cff9f37SSean Eric Fagan bp[indx] = value & 0xff;
827cff9f37SSean Eric Fagan indx--;
837cff9f37SSean Eric Fagan value >>= 8;
847cff9f37SSean Eric Fagan }
857cff9f37SSean Eric Fagan }
867cff9f37SSean Eric Fagan
877cff9f37SSean Eric Fagan /*
887cff9f37SSean Eric Fagan * Start the CBC-MAC process. This handles the auth data.
897cff9f37SSean Eric Fagan */
907cff9f37SSean Eric Fagan 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)917cff9f37SSean Eric Fagan cbc_mac_start(const unsigned char *auth_data, size_t auth_len,
927cff9f37SSean Eric Fagan const unsigned char *nonce, size_t nonce_len,
937cff9f37SSean Eric Fagan const unsigned char *key, int nr,
947cff9f37SSean Eric Fagan size_t data_len, size_t tag_len)
957cff9f37SSean Eric Fagan {
967cff9f37SSean Eric Fagan __m128i cbc_block, staging_block;
977cff9f37SSean Eric Fagan uint8_t *byte_ptr;
987cff9f37SSean Eric Fagan /* This defines where the message length goes */
997cff9f37SSean Eric Fagan int L = sizeof(__m128i) - 1 - nonce_len;
1007cff9f37SSean Eric Fagan
1017cff9f37SSean Eric Fagan /*
1027cff9f37SSean Eric Fagan * Set up B0 here. This has the flags byte,
1037cff9f37SSean Eric Fagan * followed by the nonce, followed by the
1047cff9f37SSean Eric Fagan * length of the message.
1057cff9f37SSean Eric Fagan */
1067cff9f37SSean Eric Fagan cbc_block = _mm_setzero_si128();
1077cff9f37SSean Eric Fagan byte_ptr = (uint8_t*)&cbc_block;
1087cff9f37SSean Eric Fagan byte_ptr[0] = ((auth_len > 0) ? 1 : 0) * 64 |
1097cff9f37SSean Eric Fagan (((tag_len - 2) / 2) * 8) |
1107cff9f37SSean Eric Fagan (L - 1);
1117cff9f37SSean Eric Fagan bcopy(nonce, byte_ptr + 1, nonce_len);
1127cff9f37SSean Eric Fagan append_int(data_len, &cbc_block, L+1);
1137cff9f37SSean Eric Fagan cbc_block = AESNI_ENC(cbc_block, key, nr);
1147cff9f37SSean Eric Fagan
1157cff9f37SSean Eric Fagan if (auth_len != 0) {
1167cff9f37SSean Eric Fagan /*
1177cff9f37SSean Eric Fagan * We need to start by appending the length descriptor.
1187cff9f37SSean Eric Fagan */
1197cff9f37SSean Eric Fagan uint32_t auth_amt;
1207cff9f37SSean Eric Fagan size_t copy_amt;
1217cff9f37SSean Eric Fagan const uint8_t *auth_ptr = auth_data;
1227cff9f37SSean Eric Fagan
1237cff9f37SSean Eric Fagan staging_block = _mm_setzero_si128();
1247cff9f37SSean Eric Fagan
1257cff9f37SSean Eric Fagan /*
1267cff9f37SSean Eric Fagan * The current OCF calling convention means that
1277cff9f37SSean Eric Fagan * there can never be more than 4g of authentication
1287cff9f37SSean Eric Fagan * data, so we don't handle the 0xffff case.
1297cff9f37SSean Eric Fagan */
1307cff9f37SSean Eric Fagan KASSERT(auth_len < (1ULL << 32),
1317cff9f37SSean Eric Fagan ("%s: auth_len (%zu) larger than 4GB",
1327cff9f37SSean Eric Fagan __FUNCTION__, auth_len));
1337cff9f37SSean Eric Fagan
1347cff9f37SSean Eric Fagan if (auth_len < ((1 << 16) - (1 << 8))) {
1357cff9f37SSean Eric Fagan /*
1367cff9f37SSean Eric Fagan * If the auth data length is less than
1377cff9f37SSean Eric Fagan * 0xff00, we don't need to encode a length
1387cff9f37SSean Eric Fagan * specifier, just the length of the auth
1397cff9f37SSean Eric Fagan * data.
1407cff9f37SSean Eric Fagan */
1417cff9f37SSean Eric Fagan be16enc(&staging_block, auth_len);
1427cff9f37SSean Eric Fagan auth_amt = 2;
1437cff9f37SSean Eric Fagan } else if (auth_len < (1ULL << 32)) {
1447cff9f37SSean Eric Fagan /*
1457cff9f37SSean Eric Fagan * Two bytes for the length prefix, and then
1467cff9f37SSean Eric Fagan * four bytes for the length. This makes a total
1477cff9f37SSean Eric Fagan * of 6 bytes to describe the auth data length.
1487cff9f37SSean Eric Fagan */
1497cff9f37SSean Eric Fagan be16enc(&staging_block, 0xfffe);
1507cff9f37SSean Eric Fagan be32enc((char*)&staging_block + 2, auth_len);
1517cff9f37SSean Eric Fagan auth_amt = 6;
1527cff9f37SSean Eric Fagan } else
1537cff9f37SSean Eric Fagan panic("%s: auth len too large", __FUNCTION__);
1547cff9f37SSean Eric Fagan
1557cff9f37SSean Eric Fagan /*
1567cff9f37SSean Eric Fagan * Need to copy abytes into blocks. The first block is
1577cff9f37SSean Eric Fagan * already partially filled, by auth_amt, so we need
1587cff9f37SSean Eric Fagan * to handle that. The last block needs to be zero padded.
1597cff9f37SSean Eric Fagan */
160b0b2161cSJohn Baldwin copy_amt = MIN(auth_len,
1617cff9f37SSean Eric Fagan sizeof(staging_block) - auth_amt);
1627cff9f37SSean Eric Fagan byte_ptr = (uint8_t*)&staging_block;
1637cff9f37SSean Eric Fagan bcopy(auth_ptr, &byte_ptr[auth_amt], copy_amt);
1647cff9f37SSean Eric Fagan auth_ptr += copy_amt;
1657cff9f37SSean Eric Fagan
1667cff9f37SSean Eric Fagan cbc_block = xor_and_encrypt(cbc_block, staging_block, key, nr);
1677cff9f37SSean Eric Fagan
1687cff9f37SSean Eric Fagan while (auth_ptr < auth_data + auth_len) {
1697cff9f37SSean Eric Fagan copy_amt = MIN((auth_data + auth_len) - auth_ptr,
1707cff9f37SSean Eric Fagan sizeof(staging_block));
1717cff9f37SSean Eric Fagan if (copy_amt < sizeof(staging_block))
1727cff9f37SSean Eric Fagan bzero(&staging_block, sizeof(staging_block));
1737cff9f37SSean Eric Fagan bcopy(auth_ptr, &staging_block, copy_amt);
1747cff9f37SSean Eric Fagan cbc_block = xor_and_encrypt(cbc_block, staging_block,
1757cff9f37SSean Eric Fagan key, nr);
1767cff9f37SSean Eric Fagan auth_ptr += copy_amt;
1777cff9f37SSean Eric Fagan }
1787cff9f37SSean Eric Fagan }
1797cff9f37SSean Eric Fagan return (cbc_block);
1807cff9f37SSean Eric Fagan }
1817cff9f37SSean Eric Fagan
1827cff9f37SSean Eric Fagan /*
1837cff9f37SSean Eric Fagan * Implement AES CCM+CBC-MAC encryption and authentication.
1847cff9f37SSean Eric Fagan *
1857cff9f37SSean Eric Fagan * A couple of notes:
1868e6af6adSJohn Baldwin * Since abytes is limited to a 32 bit value here, the AAD is
1877cff9f37SSean Eric Fagan * limited to 4 gigabytes or less.
1887cff9f37SSean Eric Fagan */
1897cff9f37SSean Eric Fagan 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,int tag_length,const unsigned char * key,int nr)1907cff9f37SSean Eric Fagan AES_CCM_encrypt(const unsigned char *in, unsigned char *out,
1917cff9f37SSean Eric Fagan const unsigned char *addt, const unsigned char *nonce,
1927cff9f37SSean Eric Fagan unsigned char *tag, uint32_t nbytes, uint32_t abytes, int nlen,
193*655eb762SJohn Baldwin int tag_length, const unsigned char *key, int nr)
1947cff9f37SSean Eric Fagan {
1957cff9f37SSean Eric Fagan int L;
1967cff9f37SSean Eric Fagan int counter = 1; /* S0 has 0, S1 has 1 */
1977cff9f37SSean Eric Fagan size_t copy_amt, total = 0;
1987cff9f37SSean Eric Fagan uint8_t *byte_ptr;
1997cff9f37SSean Eric Fagan __m128i s0, rolling_mac, s_x, staging_block;
2007cff9f37SSean Eric Fagan
2017cff9f37SSean Eric Fagan /* NIST 800-38c section A.1 says n is [7, 13]. */
2027cff9f37SSean Eric Fagan if (nlen < 7 || nlen > 13)
2037cff9f37SSean Eric Fagan panic("%s: bad nonce length %d", __FUNCTION__, nlen);
2047cff9f37SSean Eric Fagan
2057cff9f37SSean Eric Fagan /*
2067cff9f37SSean Eric Fagan * We need to know how many bytes to use to describe
2077cff9f37SSean Eric Fagan * the length of the data. Normally, nlen should be
2087cff9f37SSean Eric Fagan * 12, which leaves us 3 bytes to do that -- 16mbytes of
2097cff9f37SSean Eric Fagan * data to encrypt. But it can be longer or shorter;
2107cff9f37SSean Eric Fagan * this impacts the length of the message.
2117cff9f37SSean Eric Fagan */
2127cff9f37SSean Eric Fagan L = sizeof(__m128i) - 1 - nlen;
2137cff9f37SSean Eric Fagan
2147cff9f37SSean Eric Fagan /*
2157cff9f37SSean Eric Fagan * Clear out the blocks
2167cff9f37SSean Eric Fagan */
2177cff9f37SSean Eric Fagan s0 = _mm_setzero_si128();
2187cff9f37SSean Eric Fagan
2197cff9f37SSean Eric Fagan rolling_mac = cbc_mac_start(addt, abytes, nonce, nlen,
2207cff9f37SSean Eric Fagan key, nr, nbytes, tag_length);
2217cff9f37SSean Eric Fagan
2227cff9f37SSean Eric Fagan /* s0 has flags, nonce, and then 0 */
2237cff9f37SSean Eric Fagan byte_ptr = (uint8_t*)&s0;
2247cff9f37SSean Eric Fagan byte_ptr[0] = L - 1; /* but the flags byte only has L' */
2257cff9f37SSean Eric Fagan bcopy(nonce, &byte_ptr[1], nlen);
2267cff9f37SSean Eric Fagan
2277cff9f37SSean Eric Fagan /*
2287cff9f37SSean Eric Fagan * Now to cycle through the rest of the data.
2297cff9f37SSean Eric Fagan */
2307cff9f37SSean Eric Fagan bcopy(&s0, &s_x, sizeof(s0));
2317cff9f37SSean Eric Fagan
2327cff9f37SSean Eric Fagan while (total < nbytes) {
2337cff9f37SSean Eric Fagan /*
2347cff9f37SSean Eric Fagan * Copy the plain-text data into staging_block.
2357cff9f37SSean Eric Fagan * This may need to be zero-padded.
2367cff9f37SSean Eric Fagan */
2377cff9f37SSean Eric Fagan copy_amt = MIN(nbytes - total, sizeof(staging_block));
2387cff9f37SSean Eric Fagan bcopy(in+total, &staging_block, copy_amt);
2397cff9f37SSean Eric Fagan if (copy_amt < sizeof(staging_block)) {
2407cff9f37SSean Eric Fagan byte_ptr = (uint8_t*)&staging_block;
2417cff9f37SSean Eric Fagan bzero(&byte_ptr[copy_amt],
2427cff9f37SSean Eric Fagan sizeof(staging_block) - copy_amt);
2437cff9f37SSean Eric Fagan }
2447cff9f37SSean Eric Fagan rolling_mac = xor_and_encrypt(rolling_mac, staging_block,
2457cff9f37SSean Eric Fagan key, nr);
2467cff9f37SSean Eric Fagan /* Put the counter into the s_x block */
2477cff9f37SSean Eric Fagan append_int(counter++, &s_x, L+1);
2487cff9f37SSean Eric Fagan /* Encrypt that */
2497cff9f37SSean Eric Fagan __m128i X = AESNI_ENC(s_x, key, nr);
2507cff9f37SSean Eric Fagan /* XOR the plain-text with the encrypted counter block */
2517cff9f37SSean Eric Fagan staging_block = _mm_xor_si128(staging_block, X);
2527cff9f37SSean Eric Fagan /* And copy it out */
2537cff9f37SSean Eric Fagan bcopy(&staging_block, out+total, copy_amt);
2547cff9f37SSean Eric Fagan total += copy_amt;
2557cff9f37SSean Eric Fagan }
2567cff9f37SSean Eric Fagan /*
2577cff9f37SSean Eric Fagan * Allegedly done with it! Except for the tag.
2587cff9f37SSean Eric Fagan */
2597cff9f37SSean Eric Fagan s0 = AESNI_ENC(s0, key, nr);
2607cff9f37SSean Eric Fagan staging_block = _mm_xor_si128(s0, rolling_mac);
2617cff9f37SSean Eric Fagan bcopy(&staging_block, tag, tag_length);
2627cff9f37SSean Eric Fagan explicit_bzero(&s0, sizeof(s0));
2637cff9f37SSean Eric Fagan explicit_bzero(&staging_block, sizeof(staging_block));
2647cff9f37SSean Eric Fagan explicit_bzero(&s_x, sizeof(s_x));
2657cff9f37SSean Eric Fagan explicit_bzero(&rolling_mac, sizeof(rolling_mac));
2667cff9f37SSean Eric Fagan }
2677cff9f37SSean Eric Fagan
2687cff9f37SSean Eric Fagan /*
2697cff9f37SSean Eric Fagan * Implement AES CCM+CBC-MAC decryption and authentication.
2707cff9f37SSean Eric Fagan * Returns 0 on failure, 1 on success.
2717cff9f37SSean Eric Fagan *
2727cff9f37SSean Eric Fagan * The primary difference here is that each encrypted block
2737cff9f37SSean Eric Fagan * needs to be hashed&encrypted after it is decrypted (since
2747cff9f37SSean Eric Fagan * the CBC-MAC is based on the plain text). This means that
2757cff9f37SSean Eric Fagan * we do the decryption twice -- first to verify the tag,
2767cff9f37SSean Eric Fagan * and second to decrypt and copy it out.
2777cff9f37SSean Eric Fagan *
2787cff9f37SSean Eric Fagan * To avoid annoying code copying, we implement the main
2797cff9f37SSean Eric Fagan * loop as a separate function.
2807cff9f37SSean Eric Fagan *
2817cff9f37SSean Eric Fagan * Call with out as NULL to not store the decrypted results;
2827cff9f37SSean Eric Fagan * call with hashp as NULL to not run the authentication.
2837cff9f37SSean Eric Fagan * Calling with neither as NULL does the decryption and
2847cff9f37SSean Eric Fagan * authentication as a single pass (which is not allowed
2857cff9f37SSean Eric Fagan * per the specification, really).
2867cff9f37SSean Eric Fagan *
2877cff9f37SSean Eric Fagan * If hashp is non-NULL, it points to the post-AAD computed
2887cff9f37SSean Eric Fagan * checksum.
2897cff9f37SSean Eric Fagan */
2907cff9f37SSean Eric Fagan static void
decrypt_loop(const unsigned char * in,unsigned char * out,size_t nbytes,__m128i s0,size_t nonce_length,__m128i * macp,const unsigned char * key,int nr)2917cff9f37SSean Eric Fagan decrypt_loop(const unsigned char *in, unsigned char *out, size_t nbytes,
2927cff9f37SSean Eric Fagan __m128i s0, size_t nonce_length, __m128i *macp,
2937cff9f37SSean Eric Fagan const unsigned char *key, int nr)
2947cff9f37SSean Eric Fagan {
2957cff9f37SSean Eric Fagan size_t total = 0;
2967cff9f37SSean Eric Fagan __m128i s_x = s0, mac_block;
2977cff9f37SSean Eric Fagan int counter = 1;
2987cff9f37SSean Eric Fagan const size_t L = sizeof(__m128i) - 1 - nonce_length;
2997cff9f37SSean Eric Fagan __m128i pad_block, staging_block;
3007cff9f37SSean Eric Fagan
3017cff9f37SSean Eric Fagan /*
3027cff9f37SSean Eric Fagan * The starting mac (post AAD, if any).
3037cff9f37SSean Eric Fagan */
3047cff9f37SSean Eric Fagan if (macp != NULL)
3057cff9f37SSean Eric Fagan mac_block = *macp;
3067cff9f37SSean Eric Fagan
3077cff9f37SSean Eric Fagan while (total < nbytes) {
3087cff9f37SSean Eric Fagan size_t copy_amt = MIN(nbytes - total, sizeof(staging_block));
3097cff9f37SSean Eric Fagan
3107cff9f37SSean Eric Fagan if (copy_amt < sizeof(staging_block)) {
3117cff9f37SSean Eric Fagan staging_block = _mm_setzero_si128();
3127cff9f37SSean Eric Fagan }
3137cff9f37SSean Eric Fagan bcopy(in+total, &staging_block, copy_amt);
3147cff9f37SSean Eric Fagan
3157cff9f37SSean Eric Fagan /*
3167cff9f37SSean Eric Fagan * staging_block has the current block of input data,
3177cff9f37SSean Eric Fagan * zero-padded if necessary. This is used in computing
3187cff9f37SSean Eric Fagan * both the decrypted data, and the authentication tag.
3197cff9f37SSean Eric Fagan */
3207cff9f37SSean Eric Fagan append_int(counter++, &s_x, L+1);
3217cff9f37SSean Eric Fagan /*
3227cff9f37SSean Eric Fagan * The tag is computed based on the decrypted data.
3237cff9f37SSean Eric Fagan */
3247cff9f37SSean Eric Fagan pad_block = AESNI_ENC(s_x, key, nr);
3257cff9f37SSean Eric Fagan if (copy_amt < sizeof(staging_block)) {
3267cff9f37SSean Eric Fagan /*
3277cff9f37SSean Eric Fagan * Need to pad out pad_block with 0.
3287cff9f37SSean Eric Fagan * (staging_block was set to 0's above.)
3297cff9f37SSean Eric Fagan */
3307cff9f37SSean Eric Fagan uint8_t *end_of_buffer = (uint8_t*)&pad_block;
3317cff9f37SSean Eric Fagan bzero(end_of_buffer + copy_amt,
3327cff9f37SSean Eric Fagan sizeof(pad_block) - copy_amt);
3337cff9f37SSean Eric Fagan }
3347cff9f37SSean Eric Fagan staging_block = _mm_xor_si128(staging_block, pad_block);
3357cff9f37SSean Eric Fagan
3367cff9f37SSean Eric Fagan if (out)
3377cff9f37SSean Eric Fagan bcopy(&staging_block, out+total, copy_amt);
3387cff9f37SSean Eric Fagan
3397cff9f37SSean Eric Fagan if (macp)
3407cff9f37SSean Eric Fagan mac_block = xor_and_encrypt(mac_block, staging_block,
3417cff9f37SSean Eric Fagan key, nr);
3427cff9f37SSean Eric Fagan total += copy_amt;
3437cff9f37SSean Eric Fagan }
3447cff9f37SSean Eric Fagan
3457cff9f37SSean Eric Fagan if (macp)
3467cff9f37SSean Eric Fagan *macp = mac_block;
3477cff9f37SSean Eric Fagan
3487cff9f37SSean Eric Fagan explicit_bzero(&pad_block, sizeof(pad_block));
3497cff9f37SSean Eric Fagan explicit_bzero(&staging_block, sizeof(staging_block));
3507cff9f37SSean Eric Fagan explicit_bzero(&mac_block, sizeof(mac_block));
3517cff9f37SSean Eric Fagan }
3527cff9f37SSean Eric Fagan
3537cff9f37SSean Eric Fagan /*
3547cff9f37SSean Eric Fagan * The exposed decryption routine. This is practically a
3557cff9f37SSean Eric Fagan * copy of the encryption routine, except that the order
3567cff9f37SSean Eric Fagan * in which the tag is created is changed.
3577cff9f37SSean Eric Fagan * XXX combine the two functions at some point!
3587cff9f37SSean Eric Fagan */
3597cff9f37SSean Eric Fagan 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,int tag_length,const unsigned char * key,int nr)3607cff9f37SSean Eric Fagan AES_CCM_decrypt(const unsigned char *in, unsigned char *out,
3617cff9f37SSean Eric Fagan const unsigned char *addt, const unsigned char *nonce,
3627cff9f37SSean Eric Fagan const unsigned char *tag, uint32_t nbytes, uint32_t abytes, int nlen,
363*655eb762SJohn Baldwin int tag_length, const unsigned char *key, int nr)
3647cff9f37SSean Eric Fagan {
3657cff9f37SSean Eric Fagan int L;
3667cff9f37SSean Eric Fagan __m128i s0, rolling_mac, staging_block;
3677cff9f37SSean Eric Fagan uint8_t *byte_ptr;
3687cff9f37SSean Eric Fagan
3697cff9f37SSean Eric Fagan if (nlen < 0 || nlen > 15)
3707cff9f37SSean Eric Fagan panic("%s: bad nonce length %d", __FUNCTION__, nlen);
3717cff9f37SSean Eric Fagan
3727cff9f37SSean Eric Fagan /*
3737cff9f37SSean Eric Fagan * We need to know how many bytes to use to describe
3747cff9f37SSean Eric Fagan * the length of the data. Normally, nlen should be
3757cff9f37SSean Eric Fagan * 12, which leaves us 3 bytes to do that -- 16mbytes of
3767cff9f37SSean Eric Fagan * data to encrypt. But it can be longer or shorter.
3777cff9f37SSean Eric Fagan */
3787cff9f37SSean Eric Fagan L = sizeof(__m128i) - 1 - nlen;
3797cff9f37SSean Eric Fagan
3807cff9f37SSean Eric Fagan /*
3817cff9f37SSean Eric Fagan * Clear out the blocks
3827cff9f37SSean Eric Fagan */
3837cff9f37SSean Eric Fagan s0 = _mm_setzero_si128();
3847cff9f37SSean Eric Fagan
3857cff9f37SSean Eric Fagan rolling_mac = cbc_mac_start(addt, abytes, nonce, nlen,
3867cff9f37SSean Eric Fagan key, nr, nbytes, tag_length);
3877cff9f37SSean Eric Fagan /* s0 has flags, nonce, and then 0 */
3887cff9f37SSean Eric Fagan byte_ptr = (uint8_t*)&s0;
3897cff9f37SSean Eric Fagan byte_ptr[0] = L-1; /* but the flags byte only has L' */
3907cff9f37SSean Eric Fagan bcopy(nonce, &byte_ptr[1], nlen);
3917cff9f37SSean Eric Fagan
3927cff9f37SSean Eric Fagan /*
3937cff9f37SSean Eric Fagan * Now to cycle through the rest of the data.
3947cff9f37SSean Eric Fagan */
3957cff9f37SSean Eric Fagan decrypt_loop(in, NULL, nbytes, s0, nlen, &rolling_mac, key, nr);
3967cff9f37SSean Eric Fagan
3977cff9f37SSean Eric Fagan /*
3987cff9f37SSean Eric Fagan * Compare the tag.
3997cff9f37SSean Eric Fagan */
4007cff9f37SSean Eric Fagan staging_block = _mm_xor_si128(AESNI_ENC(s0, key, nr), rolling_mac);
4017cff9f37SSean Eric Fagan if (timingsafe_bcmp(&staging_block, tag, tag_length) != 0) {
4027cff9f37SSean Eric Fagan return (0);
4037cff9f37SSean Eric Fagan }
4047cff9f37SSean Eric Fagan
4057cff9f37SSean Eric Fagan /*
4067cff9f37SSean Eric Fagan * Push out the decryption results this time.
4077cff9f37SSean Eric Fagan */
4087cff9f37SSean Eric Fagan decrypt_loop(in, out, nbytes, s0, nlen, NULL, key, nr);
4097cff9f37SSean Eric Fagan return (1);
4107cff9f37SSean Eric Fagan }
411