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 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 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 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 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