xref: /freebsd-src/sys/opencrypto/cbc_mac.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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