cbc_mac.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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. #include <sys/cdefs.h>
  25. __FBSDID("$FreeBSD$");
  26. #include <sys/types.h>
  27. #include <sys/systm.h>
  28. #include <sys/param.h>
  29. #include <sys/endian.h>
  30. #include <opencrypto/cbc_mac.h>
  31. #include <opencrypto/xform_auth.h>
  32. /*
  33. * Given two CCM_CBC_BLOCK_LEN blocks, xor
  34. * them into dst, and then encrypt dst.
  35. */
  36. static void
  37. xor_and_encrypt(struct aes_cbc_mac_ctx *ctx,
  38. const uint8_t *src, uint8_t *dst)
  39. {
  40. const uint64_t *b1;
  41. uint64_t *b2;
  42. uint64_t temp_block[CCM_CBC_BLOCK_LEN/sizeof(uint64_t)];
  43. b1 = (const uint64_t*)src;
  44. b2 = (uint64_t*)dst;
  45. for (size_t count = 0;
  46. count < CCM_CBC_BLOCK_LEN/sizeof(uint64_t);
  47. count++) {
  48. temp_block[count] = b1[count] ^ b2[count];
  49. }
  50. rijndaelEncrypt(ctx->keysched, ctx->rounds, (void*)temp_block, dst);
  51. }
  52. void
  53. AES_CBC_MAC_Init(void *vctx)
  54. {
  55. struct aes_cbc_mac_ctx *ctx;
  56. ctx = vctx;
  57. bzero(ctx, sizeof(*ctx));
  58. }
  59. void
  60. AES_CBC_MAC_Setkey(void *vctx, const uint8_t *key, u_int klen)
  61. {
  62. struct aes_cbc_mac_ctx *ctx;
  63. ctx = vctx;
  64. ctx->rounds = rijndaelKeySetupEnc(ctx->keysched, key, klen * 8);
  65. }
  66. /*
  67. * This is called to set the nonce, aka IV.
  68. * Before this call, the authDataLength and cryptDataLength fields
  69. * MUST have been set. Sadly, there's no way to return an error.
  70. *
  71. * The CBC-MAC algorithm requires that the first block contain the
  72. * nonce, as well as information about the sizes and lengths involved.
  73. */
  74. void
  75. AES_CBC_MAC_Reinit(void *vctx, const uint8_t *nonce, u_int nonceLen)
  76. {
  77. struct aes_cbc_mac_ctx *ctx = vctx;
  78. uint8_t b0[CCM_CBC_BLOCK_LEN];
  79. uint8_t *bp = b0, flags = 0;
  80. uint8_t L = 0;
  81. uint64_t dataLength = ctx->cryptDataLength;
  82. KASSERT(nonceLen >= 7 && nonceLen <= 13,
  83. ("nonceLen must be between 7 and 13 bytes"));
  84. ctx->nonce = nonce;
  85. ctx->nonceLength = nonceLen;
  86. ctx->authDataCount = 0;
  87. ctx->blockIndex = 0;
  88. explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
  89. /*
  90. * Need to determine the L field value. This is the number of
  91. * bytes needed to specify the length of the message; the length
  92. * is whatever is left in the 16 bytes after specifying flags and
  93. * the nonce.
  94. */
  95. L = 15 - nonceLen;
  96. flags = ((ctx->authDataLength > 0) << 6) +
  97. (((AES_CBC_MAC_HASH_LEN - 2) / 2) << 3) +
  98. L - 1;
  99. /*
  100. * Now we need to set up the first block, which has flags, nonce,
  101. * and the message length.
  102. */
  103. b0[0] = flags;
  104. bcopy(nonce, b0 + 1, nonceLen);
  105. bp = b0 + 1 + nonceLen;
  106. /* Need to copy L' [aka L-1] bytes of cryptDataLength */
  107. for (uint8_t *dst = b0 + sizeof(b0) - 1; dst >= bp; dst--) {
  108. *dst = dataLength;
  109. dataLength >>= 8;
  110. }
  111. /* Now need to encrypt b0 */
  112. rijndaelEncrypt(ctx->keysched, ctx->rounds, b0, ctx->block);
  113. /* If there is auth data, we need to set up the staging block */
  114. if (ctx->authDataLength) {
  115. size_t addLength;
  116. if (ctx->authDataLength < ((1<<16) - (1<<8))) {
  117. uint16_t sizeVal = htobe16(ctx->authDataLength);
  118. bcopy(&sizeVal, ctx->staging_block, sizeof(sizeVal));
  119. addLength = sizeof(sizeVal);
  120. } else if (ctx->authDataLength < (1ULL<<32)) {
  121. uint32_t sizeVal = htobe32(ctx->authDataLength);
  122. ctx->staging_block[0] = 0xff;
  123. ctx->staging_block[1] = 0xfe;
  124. bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal));
  125. addLength = 2 + sizeof(sizeVal);
  126. } else {
  127. uint64_t sizeVal = htobe64(ctx->authDataLength);
  128. ctx->staging_block[0] = 0xff;
  129. ctx->staging_block[1] = 0xff;
  130. bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal));
  131. addLength = 2 + sizeof(sizeVal);
  132. }
  133. ctx->blockIndex = addLength;
  134. /*
  135. * The length descriptor goes into the AAD buffer, so we
  136. * need to account for it.
  137. */
  138. ctx->authDataLength += addLength;
  139. ctx->authDataCount = addLength;
  140. }
  141. }
  142. int
  143. AES_CBC_MAC_Update(void *vctx, const void *vdata, u_int length)
  144. {
  145. struct aes_cbc_mac_ctx *ctx;
  146. const uint8_t *data;
  147. size_t copy_amt;
  148. ctx = vctx;
  149. data = vdata;
  150. /*
  151. * This will be called in one of two phases:
  152. * (1) Applying authentication data, or
  153. * (2) Applying the payload data.
  154. *
  155. * Because CBC-MAC puts the authentication data size before the
  156. * data, subsequent calls won't be block-size-aligned. Which
  157. * complicates things a fair bit.
  158. *
  159. * The payload data doesn't have that problem.
  160. */
  161. if (ctx->authDataCount < ctx->authDataLength) {
  162. /*
  163. * We need to process data as authentication data.
  164. * Since we may be out of sync, we may also need
  165. * to pad out the staging block.
  166. */
  167. const uint8_t *ptr = data;
  168. while (length > 0) {
  169. copy_amt = MIN(length,
  170. sizeof(ctx->staging_block) - ctx->blockIndex);
  171. bcopy(ptr, ctx->staging_block + ctx->blockIndex,
  172. copy_amt);
  173. ptr += copy_amt;
  174. length -= copy_amt;
  175. ctx->authDataCount += copy_amt;
  176. ctx->blockIndex += copy_amt;
  177. ctx->blockIndex %= sizeof(ctx->staging_block);
  178. if (ctx->blockIndex == 0 ||
  179. ctx->authDataCount == ctx->authDataLength) {
  180. /*
  181. * We're done with this block, so we
  182. * xor staging_block with block, and then
  183. * encrypt it.
  184. */
  185. xor_and_encrypt(ctx, ctx->staging_block, ctx->block);
  186. bzero(ctx->staging_block, sizeof(ctx->staging_block));
  187. ctx->blockIndex = 0;
  188. if (ctx->authDataCount >= ctx->authDataLength)
  189. break;
  190. }
  191. }
  192. /*
  193. * We'd like to be able to check length == 0 and return
  194. * here, but the way OCF calls us, length is always
  195. * blksize (16, in this case). So we have to count on
  196. * the fact that OCF calls us separately for the AAD and
  197. * for the real data.
  198. */
  199. return (0);
  200. }
  201. /*
  202. * If we're here, then we're encoding payload data.
  203. * This is marginally easier, except that _Update can
  204. * be called with non-aligned update lengths. As a result,
  205. * we still need to use the staging block.
  206. */
  207. KASSERT((length + ctx->cryptDataCount) <= ctx->cryptDataLength,
  208. ("More encryption data than allowed"));
  209. while (length) {
  210. uint8_t *ptr;
  211. copy_amt = MIN(sizeof(ctx->staging_block) - ctx->blockIndex,
  212. length);
  213. ptr = ctx->staging_block + ctx->blockIndex;
  214. bcopy(data, ptr, copy_amt);
  215. data += copy_amt;
  216. ctx->blockIndex += copy_amt;
  217. ctx->cryptDataCount += copy_amt;
  218. length -= copy_amt;
  219. if (ctx->blockIndex == sizeof(ctx->staging_block)) {
  220. /* We've got a full block */
  221. xor_and_encrypt(ctx, ctx->staging_block, ctx->block);
  222. ctx->blockIndex = 0;
  223. bzero(ctx->staging_block, sizeof(ctx->staging_block));
  224. }
  225. }
  226. return (0);
  227. }
  228. void
  229. AES_CBC_MAC_Final(uint8_t *buf, void *vctx)
  230. {
  231. struct aes_cbc_mac_ctx *ctx;
  232. uint8_t s0[CCM_CBC_BLOCK_LEN];
  233. ctx = vctx;
  234. /*
  235. * We first need to check to see if we've got any data
  236. * left over to encrypt.
  237. */
  238. if (ctx->blockIndex != 0) {
  239. xor_and_encrypt(ctx, ctx->staging_block, ctx->block);
  240. ctx->cryptDataCount += ctx->blockIndex;
  241. ctx->blockIndex = 0;
  242. explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
  243. }
  244. bzero(s0, sizeof(s0));
  245. s0[0] = (15 - ctx->nonceLength) - 1;
  246. bcopy(ctx->nonce, s0 + 1, ctx->nonceLength);
  247. rijndaelEncrypt(ctx->keysched, ctx->rounds, s0, s0);
  248. for (size_t indx = 0; indx < AES_CBC_MAC_HASH_LEN; indx++)
  249. buf[indx] = ctx->block[indx] ^ s0[indx];
  250. explicit_bzero(s0, sizeof(s0));
  251. }