1a99bc4c3SSean Eric Fagan /*
2a99bc4c3SSean Eric Fagan * Copyright (c) 2018-2019 iXsystems Inc. All rights reserved.
3a99bc4c3SSean Eric Fagan *
4a99bc4c3SSean Eric Fagan * Redistribution and use in source and binary forms, with or without
5a99bc4c3SSean Eric Fagan * modification, are permitted provided that the following conditions
6a99bc4c3SSean Eric Fagan * are met:
7a99bc4c3SSean Eric Fagan * 1. Redistributions of source code must retain the above copyright
8a99bc4c3SSean Eric Fagan * notice, this list of conditions and the following disclaimer.
9a99bc4c3SSean Eric Fagan * 2. Redistributions in binary form must reproduce the above copyright
10a99bc4c3SSean Eric Fagan * notice, this list of conditions and the following disclaimer in the
11a99bc4c3SSean Eric Fagan * documentation and/or other materials provided with the distribution.
12a99bc4c3SSean Eric Fagan *
13a99bc4c3SSean Eric Fagan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14a99bc4c3SSean Eric Fagan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15a99bc4c3SSean Eric Fagan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16a99bc4c3SSean Eric Fagan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17a99bc4c3SSean Eric Fagan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18a99bc4c3SSean Eric Fagan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19a99bc4c3SSean Eric Fagan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20a99bc4c3SSean Eric Fagan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21a99bc4c3SSean Eric Fagan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22a99bc4c3SSean Eric Fagan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23a99bc4c3SSean Eric Fagan */
24a99bc4c3SSean Eric Fagan
25a99bc4c3SSean Eric Fagan #include <sys/types.h>
26a99bc4c3SSean Eric Fagan #include <sys/systm.h>
27a99bc4c3SSean Eric Fagan #include <sys/param.h>
28a99bc4c3SSean Eric Fagan #include <sys/endian.h>
29a99bc4c3SSean Eric Fagan #include <opencrypto/cbc_mac.h>
30a99bc4c3SSean Eric Fagan #include <opencrypto/xform_auth.h>
31a99bc4c3SSean Eric Fagan
32a99bc4c3SSean Eric Fagan /*
33a99bc4c3SSean Eric Fagan * Given two CCM_CBC_BLOCK_LEN blocks, xor
34a99bc4c3SSean Eric Fagan * them into dst, and then encrypt dst.
35a99bc4c3SSean Eric Fagan */
36a99bc4c3SSean Eric Fagan static void
xor_and_encrypt(struct aes_cbc_mac_ctx * ctx,const uint8_t * src,uint8_t * dst)37a99bc4c3SSean Eric Fagan xor_and_encrypt(struct aes_cbc_mac_ctx *ctx,
38a99bc4c3SSean Eric Fagan const uint8_t *src, uint8_t *dst)
39a99bc4c3SSean Eric Fagan {
40*96c25381SMark Johnston #define NWORDS (CCM_CBC_BLOCK_LEN / sizeof(uint64_t))
41*96c25381SMark Johnston uint64_t b1[NWORDS], b2[NWORDS], temp[NWORDS];
42a99bc4c3SSean Eric Fagan
43*96c25381SMark Johnston memcpy(b1, src, CCM_CBC_BLOCK_LEN);
44*96c25381SMark Johnston memcpy(b2, dst, CCM_CBC_BLOCK_LEN);
45a99bc4c3SSean Eric Fagan
46*96c25381SMark Johnston for (size_t count = 0; count < NWORDS; count++)
47*96c25381SMark Johnston temp[count] = b1[count] ^ b2[count];
48*96c25381SMark Johnston rijndaelEncrypt(ctx->keysched, ctx->rounds, (void *)temp, dst);
49*96c25381SMark Johnston #undef NWORDS
50a99bc4c3SSean Eric Fagan }
51a99bc4c3SSean Eric Fagan
52a99bc4c3SSean Eric Fagan void
AES_CBC_MAC_Init(void * vctx)539b6b2f86SJohn Baldwin AES_CBC_MAC_Init(void *vctx)
54a99bc4c3SSean Eric Fagan {
559b6b2f86SJohn Baldwin struct aes_cbc_mac_ctx *ctx;
569b6b2f86SJohn Baldwin
579b6b2f86SJohn Baldwin ctx = vctx;
58a99bc4c3SSean Eric Fagan bzero(ctx, sizeof(*ctx));
59a99bc4c3SSean Eric Fagan }
60a99bc4c3SSean Eric Fagan
61a99bc4c3SSean Eric Fagan void
AES_CBC_MAC_Setkey(void * vctx,const uint8_t * key,u_int klen)629b6b2f86SJohn Baldwin AES_CBC_MAC_Setkey(void *vctx, const uint8_t *key, u_int klen)
63a99bc4c3SSean Eric Fagan {
649b6b2f86SJohn Baldwin struct aes_cbc_mac_ctx *ctx;
659b6b2f86SJohn Baldwin
669b6b2f86SJohn Baldwin ctx = vctx;
67a99bc4c3SSean Eric Fagan ctx->rounds = rijndaelKeySetupEnc(ctx->keysched, key, klen * 8);
68a99bc4c3SSean Eric Fagan }
69a99bc4c3SSean Eric Fagan
70a99bc4c3SSean Eric Fagan /*
71a99bc4c3SSean Eric Fagan * This is called to set the nonce, aka IV.
72a99bc4c3SSean Eric Fagan *
734361c4ebSJohn Baldwin * Note that the caller is responsible for constructing b0 as well
744361c4ebSJohn Baldwin * as the length and padding around the AAD and passing that data
754361c4ebSJohn Baldwin * to _Update.
76a99bc4c3SSean Eric Fagan */
77a99bc4c3SSean Eric Fagan void
AES_CBC_MAC_Reinit(void * vctx,const uint8_t * nonce,u_int nonceLen)789b6b2f86SJohn Baldwin AES_CBC_MAC_Reinit(void *vctx, const uint8_t *nonce, u_int nonceLen)
79a99bc4c3SSean Eric Fagan {
809b6b2f86SJohn Baldwin struct aes_cbc_mac_ctx *ctx = vctx;
81a99bc4c3SSean Eric Fagan
82a99bc4c3SSean Eric Fagan ctx->nonce = nonce;
83a99bc4c3SSean Eric Fagan ctx->nonceLength = nonceLen;
84a99bc4c3SSean Eric Fagan
85a99bc4c3SSean Eric Fagan ctx->blockIndex = 0;
86a99bc4c3SSean Eric Fagan
874361c4ebSJohn Baldwin /* XOR b0 with all 0's on first call to _Update. */
884361c4ebSJohn Baldwin memset(ctx->block, 0, CCM_CBC_BLOCK_LEN);
89a99bc4c3SSean Eric Fagan }
90a99bc4c3SSean Eric Fagan
91a99bc4c3SSean Eric Fagan int
AES_CBC_MAC_Update(void * vctx,const void * vdata,u_int length)929b6b2f86SJohn Baldwin AES_CBC_MAC_Update(void *vctx, const void *vdata, u_int length)
93a99bc4c3SSean Eric Fagan {
949b6b2f86SJohn Baldwin struct aes_cbc_mac_ctx *ctx;
959b6b2f86SJohn Baldwin const uint8_t *data;
96a99bc4c3SSean Eric Fagan size_t copy_amt;
97a99bc4c3SSean Eric Fagan
989b6b2f86SJohn Baldwin ctx = vctx;
999b6b2f86SJohn Baldwin data = vdata;
1009b6b2f86SJohn Baldwin
101a99bc4c3SSean Eric Fagan /*
1024361c4ebSJohn Baldwin * _Update can be called with non-aligned update lengths. Use
1034361c4ebSJohn Baldwin * the staging block when necessary.
104a99bc4c3SSean Eric Fagan */
1054361c4ebSJohn Baldwin while (length != 0) {
106a99bc4c3SSean Eric Fagan uint8_t *ptr;
107a99bc4c3SSean Eric Fagan
1084361c4ebSJohn Baldwin /*
1094361c4ebSJohn Baldwin * If there is no partial block and the length is at
1104361c4ebSJohn Baldwin * least a full block, encrypt the full block without
1114361c4ebSJohn Baldwin * copying to the staging block.
1124361c4ebSJohn Baldwin */
1134361c4ebSJohn Baldwin if (ctx->blockIndex == 0 && length >= CCM_CBC_BLOCK_LEN) {
1144361c4ebSJohn Baldwin xor_and_encrypt(ctx, data, ctx->block);
1154361c4ebSJohn Baldwin length -= CCM_CBC_BLOCK_LEN;
1164361c4ebSJohn Baldwin data += CCM_CBC_BLOCK_LEN;
1174361c4ebSJohn Baldwin continue;
1184361c4ebSJohn Baldwin }
1194361c4ebSJohn Baldwin
120a99bc4c3SSean Eric Fagan copy_amt = MIN(sizeof(ctx->staging_block) - ctx->blockIndex,
121a99bc4c3SSean Eric Fagan length);
122a99bc4c3SSean Eric Fagan ptr = ctx->staging_block + ctx->blockIndex;
123a99bc4c3SSean Eric Fagan bcopy(data, ptr, copy_amt);
124a99bc4c3SSean Eric Fagan data += copy_amt;
125a99bc4c3SSean Eric Fagan ctx->blockIndex += copy_amt;
126a99bc4c3SSean Eric Fagan length -= copy_amt;
127a99bc4c3SSean Eric Fagan if (ctx->blockIndex == sizeof(ctx->staging_block)) {
128a99bc4c3SSean Eric Fagan /* We've got a full block */
129a99bc4c3SSean Eric Fagan xor_and_encrypt(ctx, ctx->staging_block, ctx->block);
130a99bc4c3SSean Eric Fagan ctx->blockIndex = 0;
131a99bc4c3SSean Eric Fagan }
132a99bc4c3SSean Eric Fagan }
133a99bc4c3SSean Eric Fagan return (0);
134a99bc4c3SSean Eric Fagan }
135a99bc4c3SSean Eric Fagan
136a99bc4c3SSean Eric Fagan void
AES_CBC_MAC_Final(uint8_t * buf,void * vctx)1379b6b2f86SJohn Baldwin AES_CBC_MAC_Final(uint8_t *buf, void *vctx)
138a99bc4c3SSean Eric Fagan {
1399b6b2f86SJohn Baldwin struct aes_cbc_mac_ctx *ctx;
140a99bc4c3SSean Eric Fagan uint8_t s0[CCM_CBC_BLOCK_LEN];
141a99bc4c3SSean Eric Fagan
1429b6b2f86SJohn Baldwin ctx = vctx;
1439b6b2f86SJohn Baldwin
144a99bc4c3SSean Eric Fagan /*
145a99bc4c3SSean Eric Fagan * We first need to check to see if we've got any data
146a99bc4c3SSean Eric Fagan * left over to encrypt.
147a99bc4c3SSean Eric Fagan */
148a99bc4c3SSean Eric Fagan if (ctx->blockIndex != 0) {
1494361c4ebSJohn Baldwin memset(ctx->staging_block + ctx->blockIndex, 0,
1504361c4ebSJohn Baldwin CCM_CBC_BLOCK_LEN - ctx->blockIndex);
151a99bc4c3SSean Eric Fagan xor_and_encrypt(ctx, ctx->staging_block, ctx->block);
152a99bc4c3SSean Eric Fagan }
1534361c4ebSJohn Baldwin explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
1544361c4ebSJohn Baldwin
155a99bc4c3SSean Eric Fagan bzero(s0, sizeof(s0));
156a99bc4c3SSean Eric Fagan s0[0] = (15 - ctx->nonceLength) - 1;
157a99bc4c3SSean Eric Fagan bcopy(ctx->nonce, s0 + 1, ctx->nonceLength);
158a99bc4c3SSean Eric Fagan rijndaelEncrypt(ctx->keysched, ctx->rounds, s0, s0);
159a99bc4c3SSean Eric Fagan for (size_t indx = 0; indx < AES_CBC_MAC_HASH_LEN; indx++)
160a99bc4c3SSean Eric Fagan buf[indx] = ctx->block[indx] ^ s0[indx];
161a99bc4c3SSean Eric Fagan explicit_bzero(s0, sizeof(s0));
162a99bc4c3SSean Eric Fagan }
163