xref: /haiku/src/libs/compat/openbsd_wlan/crypto/cmac.c (revision 97f11716bfaa0f385eb0e28a52bf56a5023b9e99)
1 /*	$OpenBSD: cmac.c,v 1.3 2017/05/02 17:07:06 mikeb Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * This code implements the CMAC (Cipher-based Message Authentication)
21  * algorithm described in FIPS SP800-38B using the AES-128 cipher.
22  */
23 
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 
27 #include <crypto/aes.h>
28 #include <crypto/cmac.h>
29 
30 #define LSHIFT(v, r) do {					\
31 	int i;							\
32 	for (i = 0; i < 15; i++)				\
33 		(r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7;		\
34 	(r)[15] = (v)[15] << 1;					\
35 } while (0)
36 
37 #define XOR(v, r) do {						\
38 	int i;							\
39 	for (i = 0; i < 16; i++)				\
40 		(r)[i] ^= (v)[i];				\
41 } while (0)
42 
43 void
AES_CMAC_Init(AES_CMAC_CTX * ctx)44 AES_CMAC_Init(AES_CMAC_CTX *ctx)
45 {
46 	memset(ctx->X, 0, sizeof ctx->X);
47 	ctx->M_n = 0;
48 }
49 
50 void
AES_CMAC_SetKey(AES_CMAC_CTX * ctx,const u_int8_t key[AES_CMAC_KEY_LENGTH])51 AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const u_int8_t key[AES_CMAC_KEY_LENGTH])
52 {
53 	AES_Setkey(&ctx->aesctx, key, 16);
54 }
55 
56 void
AES_CMAC_Update(AES_CMAC_CTX * ctx,const u_int8_t * data,u_int len)57 AES_CMAC_Update(AES_CMAC_CTX *ctx, const u_int8_t *data, u_int len)
58 {
59 	u_int mlen;
60 
61 	if (ctx->M_n > 0) {
62 		mlen = MIN(16 - ctx->M_n, len);
63 		memcpy(ctx->M_last + ctx->M_n, data, mlen);
64 		ctx->M_n += mlen;
65 		if (ctx->M_n < 16 || len == mlen)
66 			return;
67 		XOR(ctx->M_last, ctx->X);
68 		AES_Encrypt(&ctx->aesctx, ctx->X, ctx->X);
69 		data += mlen;
70 		len -= mlen;
71 	}
72 	while (len > 16) {	/* not last block */
73 		XOR(data, ctx->X);
74 		AES_Encrypt(&ctx->aesctx, ctx->X, ctx->X);
75 		data += 16;
76 		len -= 16;
77 	}
78 	/* potential last block, save it */
79 	memcpy(ctx->M_last, data, len);
80 	ctx->M_n = len;
81 }
82 
83 void
AES_CMAC_Final(u_int8_t digest[AES_CMAC_DIGEST_LENGTH],AES_CMAC_CTX * ctx)84 AES_CMAC_Final(u_int8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx)
85 {
86 	u_int8_t K[16];
87 
88 	/* generate subkey K1 */
89 	memset(K, 0, sizeof K);
90 	AES_Encrypt(&ctx->aesctx, K, K);
91 
92 	if (K[0] & 0x80) {
93 		LSHIFT(K, K);
94 		K[15] ^= 0x87;
95 	} else
96 		LSHIFT(K, K);
97 
98 	if (ctx->M_n == 16) {
99 		/* last block was a complete block */
100 		XOR(K, ctx->M_last);
101 	} else {
102 		/* generate subkey K2 */
103 		if (K[0] & 0x80) {
104 			LSHIFT(K, K);
105 			K[15] ^= 0x87;
106 		} else
107 			LSHIFT(K, K);
108 
109 		/* padding(M_last) */
110 		ctx->M_last[ctx->M_n] = 0x80;
111 		while (++ctx->M_n < 16)
112 			ctx->M_last[ctx->M_n] = 0;
113 
114 		XOR(K, ctx->M_last);
115 	}
116 	XOR(ctx->M_last, ctx->X);
117 	AES_Encrypt(&ctx->aesctx, ctx->X, digest);
118 
119 	explicit_bzero(K, sizeof K);
120 }
121