hmac.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * cifra - embedded cryptography library
  3. * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
  4. *
  5. * To the extent possible under law, the author(s) have dedicated all
  6. * copyright and related and neighboring rights to this software to the
  7. * public domain worldwide. This software is distributed without any
  8. * warranty.
  9. *
  10. * You should have received a copy of the CC0 Public Domain Dedication
  11. * along with this software. If not, see
  12. * <http://creativecommons.org/publicdomain/zero/1.0/>.
  13. */
  14. #include "hmac.h"
  15. #include "chash.h"
  16. #include "bitops.h"
  17. #include "handy.h"
  18. #include "tassert.h"
  19. #include <string.h>
  20. void cf_hmac_init(cf_hmac_ctx *ctx,
  21. const cf_chash *hash,
  22. const uint8_t *key, size_t nkey)
  23. {
  24. assert(ctx);
  25. assert(hash);
  26. mem_clean(ctx, sizeof *ctx);
  27. ctx->hash = hash;
  28. /* Prepare key: */
  29. uint8_t k[CF_CHASH_MAXBLK];
  30. /* Shorten long keys. */
  31. if (nkey > hash->blocksz)
  32. {
  33. /* Standard doesn't cover case where blocksz < hashsz.
  34. * FIPS186-1 seems to want to append a negative number of zero bytes.
  35. * In any case, we only have a k buffer of CF_CHASH_MAXBLK! */
  36. assert(hash->hashsz <= hash->blocksz);
  37. cf_hash(hash, key, nkey, k);
  38. key = k;
  39. nkey = hash->hashsz;
  40. }
  41. /* Right zero-pad short keys. */
  42. if (k != key)
  43. memcpy(k, key, nkey);
  44. if (hash->blocksz > nkey)
  45. memset(k + nkey, 0, hash->blocksz - nkey);
  46. /* Start inner hash computation */
  47. uint8_t blk[CF_CHASH_MAXBLK];
  48. xor_b8(blk, k, 0x36, hash->blocksz);
  49. hash->init(&ctx->inner);
  50. hash->update(&ctx->inner, blk, hash->blocksz);
  51. /* And outer. */
  52. xor_b8(blk, k, 0x5c, hash->blocksz);
  53. hash->init(&ctx->outer);
  54. hash->update(&ctx->outer, blk, hash->blocksz);
  55. mem_clean(blk, sizeof blk);
  56. mem_clean(k, sizeof k);
  57. }
  58. void cf_hmac_update(cf_hmac_ctx *ctx, const void *data, size_t ndata)
  59. {
  60. assert(ctx && ctx->hash);
  61. ctx->hash->update(&ctx->inner, data, ndata);
  62. }
  63. void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out)
  64. {
  65. assert(ctx && ctx->hash);
  66. assert(out);
  67. uint8_t innerh[CF_MAXHASH];
  68. ctx->hash->digest(&ctx->inner, innerh);
  69. ctx->hash->update(&ctx->outer, innerh, ctx->hash->hashsz);
  70. ctx->hash->digest(&ctx->outer, out);
  71. mem_clean(ctx, sizeof *ctx);
  72. }
  73. void cf_hmac(const uint8_t *key, size_t nkey,
  74. const uint8_t *msg, size_t nmsg,
  75. uint8_t *out,
  76. const cf_chash *hash)
  77. {
  78. cf_hmac_ctx ctx;
  79. assert(out);
  80. assert(hash);
  81. cf_hmac_init(&ctx, hash, key, nkey);
  82. cf_hmac_update(&ctx, msg, nmsg);
  83. cf_hmac_finish(&ctx, out);
  84. }