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(nonceLen >= 7 && nonceLen <= 13, 87 ("nonceLen must be between 7 and 13 bytes")); 88 89 ctx->nonce = nonce; 90 ctx->nonceLength = nonceLen; 91 92 ctx->authDataCount = 0; 93 ctx->blockIndex = 0; 94 explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block)); 95 96 /* 97 * Need to determine the L field value. This is the number of 98 * bytes needed to specify the length of the message; the length 99 * is whatever is left in the 16 bytes after specifying flags and 100 * the nonce. 101 */ 102 L = 15 - nonceLen; 103 104 flags = ((ctx->authDataLength > 0) << 6) + 105 (((AES_CBC_MAC_HASH_LEN - 2) / 2) << 3) + 106 L - 1; 107 /* 108 * Now we need to set up the first block, which has flags, nonce, 109 * and the message length. 110 */ 111 b0[0] = flags; 112 bcopy(nonce, b0 + 1, nonceLen); 113 bp = b0 + 1 + nonceLen; 114 115 /* Need to copy L' [aka L-1] bytes of cryptDataLength */ 116 for (uint8_t *dst = b0 + sizeof(b0) - 1; dst >= bp; dst--) { 117 *dst = dataLength; 118 dataLength >>= 8; 119 } 120 /* Now need to encrypt b0 */ 121 rijndaelEncrypt(ctx->keysched, ctx->rounds, b0, ctx->block); 122 /* If there is auth data, we need to set up the staging block */ 123 if (ctx->authDataLength) { 124 size_t addLength; 125 if (ctx->authDataLength < ((1<<16) - (1<<8))) { 126 uint16_t sizeVal = htobe16(ctx->authDataLength); 127 bcopy(&sizeVal, ctx->staging_block, sizeof(sizeVal)); 128 addLength = sizeof(sizeVal); 129 } else if (ctx->authDataLength < (1ULL<<32)) { 130 uint32_t sizeVal = htobe32(ctx->authDataLength); 131 ctx->staging_block[0] = 0xff; 132 ctx->staging_block[1] = 0xfe; 133 bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal)); 134 addLength = 2 + sizeof(sizeVal); 135 } else { 136 uint64_t sizeVal = htobe64(ctx->authDataLength); 137 ctx->staging_block[0] = 0xff; 138 ctx->staging_block[1] = 0xff; 139 bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal)); 140 addLength = 2 + sizeof(sizeVal); 141 } 142 ctx->blockIndex = addLength; 143 /* 144 * The length descriptor goes into the AAD buffer, so we 145 * need to account for it. 146 */ 147 ctx->authDataLength += addLength; 148 ctx->authDataCount = addLength; 149 } 150 } 151 152 int 153 AES_CBC_MAC_Update(struct aes_cbc_mac_ctx *ctx, const uint8_t *data, 154 uint16_t length) 155 { 156 size_t copy_amt; 157 158 /* 159 * This will be called in one of two phases: 160 * (1) Applying authentication data, or 161 * (2) Applying the payload data. 162 * 163 * Because CBC-MAC puts the authentication data size before the 164 * data, subsequent calls won't be block-size-aligned. Which 165 * complicates things a fair bit. 166 * 167 * The payload data doesn't have that problem. 168 */ 169 170 if (ctx->authDataCount < ctx->authDataLength) { 171 /* 172 * We need to process data as authentication data. 173 * Since we may be out of sync, we may also need 174 * to pad out the staging block. 175 */ 176 const uint8_t *ptr = data; 177 while (length > 0) { 178 179 copy_amt = MIN(length, 180 sizeof(ctx->staging_block) - ctx->blockIndex); 181 182 bcopy(ptr, ctx->staging_block + ctx->blockIndex, 183 copy_amt); 184 ptr += copy_amt; 185 length -= copy_amt; 186 ctx->authDataCount += copy_amt; 187 ctx->blockIndex += copy_amt; 188 ctx->blockIndex %= sizeof(ctx->staging_block); 189 190 if (ctx->blockIndex == 0 || 191 ctx->authDataCount == ctx->authDataLength) { 192 /* 193 * We're done with this block, so we 194 * xor staging_block with block, and then 195 * encrypt it. 196 */ 197 xor_and_encrypt(ctx, ctx->staging_block, ctx->block); 198 bzero(ctx->staging_block, sizeof(ctx->staging_block)); 199 ctx->blockIndex = 0; 200 if (ctx->authDataCount >= ctx->authDataLength) 201 break; 202 } 203 } 204 /* 205 * We'd like to be able to check length == 0 and return 206 * here, but the way OCF calls us, length is always 207 * blksize (16, in this case). So we have to count on 208 * the fact that OCF calls us separately for the AAD and 209 * for the real data. 210 */ 211 return (0); 212 } 213 /* 214 * If we're here, then we're encoding payload data. 215 * This is marginally easier, except that _Update can 216 * be called with non-aligned update lengths. As a result, 217 * we still need to use the staging block. 218 */ 219 KASSERT((length + ctx->cryptDataCount) <= ctx->cryptDataLength, 220 ("More encryption data than allowed")); 221 222 while (length) { 223 uint8_t *ptr; 224 225 copy_amt = MIN(sizeof(ctx->staging_block) - ctx->blockIndex, 226 length); 227 ptr = ctx->staging_block + ctx->blockIndex; 228 bcopy(data, ptr, copy_amt); 229 data += copy_amt; 230 ctx->blockIndex += copy_amt; 231 ctx->cryptDataCount += copy_amt; 232 length -= copy_amt; 233 if (ctx->blockIndex == sizeof(ctx->staging_block)) { 234 /* We've got a full block */ 235 xor_and_encrypt(ctx, ctx->staging_block, ctx->block); 236 ctx->blockIndex = 0; 237 bzero(ctx->staging_block, sizeof(ctx->staging_block)); 238 } 239 } 240 return (0); 241 } 242 243 void 244 AES_CBC_MAC_Final(uint8_t *buf, struct aes_cbc_mac_ctx *ctx) 245 { 246 uint8_t s0[CCM_CBC_BLOCK_LEN]; 247 248 /* 249 * We first need to check to see if we've got any data 250 * left over to encrypt. 251 */ 252 if (ctx->blockIndex != 0) { 253 xor_and_encrypt(ctx, ctx->staging_block, ctx->block); 254 ctx->cryptDataCount += ctx->blockIndex; 255 ctx->blockIndex = 0; 256 explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block)); 257 } 258 bzero(s0, sizeof(s0)); 259 s0[0] = (15 - ctx->nonceLength) - 1; 260 bcopy(ctx->nonce, s0 + 1, ctx->nonceLength); 261 rijndaelEncrypt(ctx->keysched, ctx->rounds, s0, s0); 262 for (size_t indx = 0; indx < AES_CBC_MAC_HASH_LEN; indx++) 263 buf[indx] = ctx->block[indx] ^ s0[indx]; 264 explicit_bzero(s0, sizeof(s0)); 265 } 266