1 /* 2 * Copyright (c) 2018-2019 iXsystems Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include <sys/cdefs.h> 26 __FBSDID("$FreeBSD$"); 27 28 #include <sys/types.h> 29 #include <sys/systm.h> 30 #include <sys/param.h> 31 #include <sys/endian.h> 32 #include <opencrypto/cbc_mac.h> 33 #include <opencrypto/xform_auth.h> 34 35 /* 36 * Given two CCM_CBC_BLOCK_LEN blocks, xor 37 * them into dst, and then encrypt dst. 38 */ 39 static void 40 xor_and_encrypt(struct aes_cbc_mac_ctx *ctx, 41 const uint8_t *src, uint8_t *dst) 42 { 43 const uint64_t *b1; 44 uint64_t *b2; 45 uint64_t temp_block[CCM_CBC_BLOCK_LEN/sizeof(uint64_t)]; 46 47 b1 = (const uint64_t*)src; 48 b2 = (uint64_t*)dst; 49 50 for (size_t count = 0; 51 count < CCM_CBC_BLOCK_LEN/sizeof(uint64_t); 52 count++) { 53 temp_block[count] = b1[count] ^ b2[count]; 54 } 55 rijndaelEncrypt(ctx->keysched, ctx->rounds, (void*)temp_block, dst); 56 } 57 58 void 59 AES_CBC_MAC_Init(struct aes_cbc_mac_ctx *ctx) 60 { 61 bzero(ctx, sizeof(*ctx)); 62 } 63 64 void 65 AES_CBC_MAC_Setkey(struct aes_cbc_mac_ctx *ctx, const uint8_t *key, uint16_t klen) 66 { 67 ctx->rounds = rijndaelKeySetupEnc(ctx->keysched, key, klen * 8); 68 } 69 70 /* 71 * This is called to set the nonce, aka IV. 72 * Before this call, the authDataLength and cryptDataLength fields 73 * MUST have been set. Sadly, there's no way to return an error. 74 * 75 * The CBC-MAC algorithm requires that the first block contain the 76 * nonce, as well as information about the sizes and lengths involved. 77 */ 78 void 79 AES_CBC_MAC_Reinit(struct aes_cbc_mac_ctx *ctx, const uint8_t *nonce, uint16_t nonceLen) 80 { 81 uint8_t b0[CCM_CBC_BLOCK_LEN]; 82 uint8_t *bp = b0, flags = 0; 83 uint8_t L = 0; 84 uint64_t dataLength = ctx->cryptDataLength; 85 86 KASSERT(ctx->authDataLength != 0 || ctx->cryptDataLength != 0, 87 ("Auth Data and Data lengths cannot both be 0")); 88 89 KASSERT(nonceLen >= 7 && nonceLen <= 13, 90 ("nonceLen must be between 7 and 13 bytes")); 91 92 ctx->nonce = nonce; 93 ctx->nonceLength = nonceLen; 94 95 ctx->authDataCount = 0; 96 ctx->blockIndex = 0; 97 explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block)); 98 99 /* 100 * Need to determine the L field value. This is the number of 101 * bytes needed to specify the length of the message; the length 102 * is whatever is left in the 16 bytes after specifying flags and 103 * the nonce. 104 */ 105 L = 15 - nonceLen; 106 107 flags = ((ctx->authDataLength > 0) << 6) + 108 (((AES_CBC_MAC_HASH_LEN - 2) / 2) << 3) + 109 L - 1; 110 /* 111 * Now we need to set up the first block, which has flags, nonce, 112 * and the message length. 113 */ 114 b0[0] = flags; 115 bcopy(nonce, b0 + 1, nonceLen); 116 bp = b0 + 1 + nonceLen; 117 118 /* Need to copy L' [aka L-1] bytes of cryptDataLength */ 119 for (uint8_t *dst = b0 + sizeof(b0) - 1; dst >= bp; dst--) { 120 *dst = dataLength; 121 dataLength >>= 8; 122 } 123 /* Now need to encrypt b0 */ 124 rijndaelEncrypt(ctx->keysched, ctx->rounds, b0, ctx->block); 125 /* If there is auth data, we need to set up the staging block */ 126 if (ctx->authDataLength) { 127 if (ctx->authDataLength < ((1<<16) - (1<<8))) { 128 uint16_t sizeVal = htobe16(ctx->authDataLength); 129 bcopy(&sizeVal, ctx->staging_block, sizeof(sizeVal)); 130 ctx->blockIndex = sizeof(sizeVal); 131 } else if (ctx->authDataLength < (1ULL<<32)) { 132 uint32_t sizeVal = htobe32(ctx->authDataLength); 133 ctx->staging_block[0] = 0xff; 134 ctx->staging_block[1] = 0xfe; 135 bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal)); 136 ctx->blockIndex = 2 + sizeof(sizeVal); 137 } else { 138 uint64_t sizeVal = htobe64(ctx->authDataLength); 139 ctx->staging_block[0] = 0xff; 140 ctx->staging_block[1] = 0xff; 141 bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal)); 142 ctx->blockIndex = 2 + sizeof(sizeVal); 143 } 144 } 145 } 146 147 int 148 AES_CBC_MAC_Update(struct aes_cbc_mac_ctx *ctx, const uint8_t *data, 149 uint16_t length) 150 { 151 size_t copy_amt; 152 153 /* 154 * This will be called in one of two phases: 155 * (1) Applying authentication data, or 156 * (2) Applying the payload data. 157 * 158 * Because CBC-MAC puts the authentication data size before the 159 * data, subsequent calls won't be block-size-aligned. Which 160 * complicates things a fair bit. 161 * 162 * The payload data doesn't have that problem. 163 */ 164 165 if (ctx->authDataCount < ctx->authDataLength) { 166 /* 167 * We need to process data as authentication data. 168 * Since we may be out of sync, we may also need 169 * to pad out the staging block. 170 */ 171 const uint8_t *ptr = data; 172 while (length > 0) { 173 174 copy_amt = MIN(length, 175 sizeof(ctx->staging_block) - ctx->blockIndex); 176 177 bcopy(ptr, ctx->staging_block + ctx->blockIndex, 178 copy_amt); 179 ptr += copy_amt; 180 length -= copy_amt; 181 ctx->authDataCount += copy_amt; 182 ctx->blockIndex += copy_amt; 183 ctx->blockIndex %= sizeof(ctx->staging_block); 184 if (ctx->authDataCount == ctx->authDataLength) 185 length = 0; 186 if (ctx->blockIndex == 0 || 187 ctx->authDataCount >= ctx->authDataLength) { 188 /* 189 * We're done with this block, so we 190 * xor staging_block with block, and then 191 * encrypt it. 192 */ 193 xor_and_encrypt(ctx, ctx->staging_block, ctx->block); 194 bzero(ctx->staging_block, sizeof(ctx->staging_block)); 195 ctx->blockIndex = 0; 196 } 197 } 198 return (0); 199 } 200 /* 201 * If we're here, then we're encoding payload data. 202 * This is marginally easier, except that _Update can 203 * be called with non-aligned update lengths. As a result, 204 * we still need to use the staging block. 205 */ 206 KASSERT((length + ctx->cryptDataCount) <= ctx->cryptDataLength, 207 ("More encryption data than allowed")); 208 209 while (length) { 210 uint8_t *ptr; 211 212 copy_amt = MIN(sizeof(ctx->staging_block) - ctx->blockIndex, 213 length); 214 ptr = ctx->staging_block + ctx->blockIndex; 215 bcopy(data, ptr, copy_amt); 216 data += copy_amt; 217 ctx->blockIndex += copy_amt; 218 ctx->cryptDataCount += copy_amt; 219 length -= copy_amt; 220 if (ctx->blockIndex == sizeof(ctx->staging_block)) { 221 /* We've got a full block */ 222 xor_and_encrypt(ctx, ctx->staging_block, ctx->block); 223 ctx->blockIndex = 0; 224 bzero(ctx->staging_block, sizeof(ctx->staging_block)); 225 } 226 } 227 return (0); 228 } 229 230 void 231 AES_CBC_MAC_Final(uint8_t *buf, struct aes_cbc_mac_ctx *ctx) 232 { 233 uint8_t s0[CCM_CBC_BLOCK_LEN]; 234 235 /* 236 * We first need to check to see if we've got any data 237 * left over to encrypt. 238 */ 239 if (ctx->blockIndex != 0) { 240 xor_and_encrypt(ctx, ctx->staging_block, ctx->block); 241 ctx->cryptDataCount += ctx->blockIndex; 242 ctx->blockIndex = 0; 243 explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block)); 244 } 245 bzero(s0, sizeof(s0)); 246 s0[0] = (15 - ctx->nonceLength) - 1; 247 bcopy(ctx->nonce, s0 + 1, ctx->nonceLength); 248 rijndaelEncrypt(ctx->keysched, ctx->rounds, s0, s0); 249 for (size_t indx = 0; indx < AES_CBC_MAC_HASH_LEN; indx++) 250 buf[indx] = ctx->block[indx] ^ s0[indx]; 251 explicit_bzero(s0, sizeof(s0)); 252 } 253