hmac.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Implementation of HMAC (RFC 2104) for PuTTY, in a general form that
  3. * can wrap any underlying hash function.
  4. */
  5. #include "ssh.h"
  6. struct hmac {
  7. const ssh_hashalg *hashalg;
  8. ssh_hash *h_outer, *h_inner, *h_live;
  9. uint8_t *digest;
  10. strbuf *text_name;
  11. ssh2_mac mac;
  12. };
  13. struct hmac_extra {
  14. const ssh_hashalg *hashalg_base;
  15. const char *suffix, *annotation;
  16. };
  17. /* Most of hmac_new(). Takes the actual 'struct hmac' as a parameter,
  18. * because sometimes it will have been allocated in a special way. */
  19. static ssh2_mac *hmac_new_inner(struct hmac *ctx, const ssh2_macalg *alg)
  20. {
  21. const struct hmac_extra *extra = (const struct hmac_extra *)alg->extra;
  22. ctx->h_outer = ssh_hash_new(extra->hashalg_base);
  23. /* In case that hashalg was a selector vtable, we'll now switch to
  24. * using whatever real one it selected, for all future purposes. */
  25. ctx->hashalg = ssh_hash_alg(ctx->h_outer);
  26. ctx->h_inner = ssh_hash_new(ctx->hashalg);
  27. ctx->h_live = ssh_hash_new(ctx->hashalg);
  28. /*
  29. * HMAC is not well defined as a wrapper on an absolutely general
  30. * hash function; it expects that the function it's wrapping will
  31. * consume data in fixed-size blocks, and it's partially defined
  32. * in terms of that block size. So we insist that the hash we're
  33. * given must have defined a meaningful block size.
  34. */
  35. assert(ctx->hashalg->blocklen);
  36. ctx->digest = snewn(ctx->hashalg->hlen, uint8_t);
  37. ctx->text_name = strbuf_new();
  38. put_fmt(ctx->text_name, "HMAC-%s%s",
  39. ctx->hashalg->text_basename, extra->suffix);
  40. if (extra->annotation || ctx->hashalg->annotation) {
  41. put_fmt(ctx->text_name, " (");
  42. { // WINSCP
  43. const char *sep = "";
  44. if (extra->annotation) {
  45. put_fmt(ctx->text_name, "%s%s", sep, extra->annotation);
  46. sep = ", ";
  47. }
  48. if (ctx->hashalg->annotation) {
  49. put_fmt(ctx->text_name, "%s%s", sep, ctx->hashalg->annotation);
  50. sep = ", ";
  51. }
  52. put_fmt(ctx->text_name, ")");
  53. } // WINSCP
  54. }
  55. ctx->mac.vt = alg;
  56. BinarySink_DELEGATE_INIT(&ctx->mac, ctx->h_live);
  57. return &ctx->mac;
  58. }
  59. static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher)
  60. {
  61. return hmac_new_inner(snew(struct hmac), alg); /* cipher isn't needed */
  62. }
  63. static void hmac_free(ssh2_mac *mac)
  64. {
  65. struct hmac *ctx = container_of(mac, struct hmac, mac);
  66. ssh_hash_free(ctx->h_outer);
  67. ssh_hash_free(ctx->h_inner);
  68. ssh_hash_free(ctx->h_live);
  69. smemclr(ctx->digest, ctx->hashalg->hlen);
  70. sfree(ctx->digest);
  71. strbuf_free(ctx->text_name);
  72. smemclr(ctx, sizeof(*ctx));
  73. sfree(ctx);
  74. }
  75. #define PAD_OUTER 0x5C
  76. #define PAD_INNER 0x36
  77. static void hmac_key(ssh2_mac *mac, ptrlen key)
  78. {
  79. struct hmac *ctx = container_of(mac, struct hmac, mac);
  80. const uint8_t *kp;
  81. size_t klen;
  82. strbuf *sb = NULL;
  83. if (key.len > ctx->hashalg->blocklen) {
  84. /*
  85. * RFC 2104 section 2: if the key exceeds the block length of
  86. * the underlying hash, then we start by hashing the key, and
  87. * use that hash as the 'true' key for the HMAC construction.
  88. */
  89. sb = strbuf_new_nm();
  90. strbuf_append(sb, ctx->hashalg->hlen);
  91. hash_simple(ctx->hashalg, key, sb->u);
  92. { // WINSCP
  93. kp = sb->u;
  94. klen = sb->len;
  95. } // WINSCP
  96. } else {
  97. /*
  98. * A short enough key is used as is.
  99. */
  100. kp = (const uint8_t *)key.ptr;
  101. klen = key.len;
  102. }
  103. ssh_hash_reset(ctx->h_outer);
  104. { // WINSCP
  105. size_t i; // WINSCP
  106. for (i = 0; i < klen; i++)
  107. put_byte(ctx->h_outer, PAD_OUTER ^ kp[i]);
  108. for (i = klen; i < ctx->hashalg->blocklen; i++)
  109. put_byte(ctx->h_outer, PAD_OUTER);
  110. ssh_hash_reset(ctx->h_inner);
  111. for (i = 0; i < klen; i++)
  112. put_byte(ctx->h_inner, PAD_INNER ^ kp[i]);
  113. for (i = klen; i < ctx->hashalg->blocklen; i++)
  114. put_byte(ctx->h_inner, PAD_INNER);
  115. if (sb)
  116. strbuf_free(sb);
  117. } // WINSCP
  118. }
  119. static void hmac_start(ssh2_mac *mac)
  120. {
  121. struct hmac *ctx = container_of(mac, struct hmac, mac);
  122. ssh_hash_copyfrom(ctx->h_live, ctx->h_inner);
  123. }
  124. static void hmac_genresult(ssh2_mac *mac, unsigned char *output)
  125. {
  126. struct hmac *ctx = container_of(mac, struct hmac, mac);
  127. ssh_hash *htmp;
  128. /* Leave h_live and h_outer in place, so that the SSH-2 BPP can
  129. * continue regenerating test results from different-length
  130. * prefixes of the packet */
  131. ssh_hash_digest_nondestructive(ctx->h_live, ctx->digest);
  132. htmp = ssh_hash_copy(ctx->h_outer);
  133. put_data(htmp, ctx->digest, ctx->hashalg->hlen);
  134. ssh_hash_final(htmp, ctx->digest);
  135. /*
  136. * Some instances of HMAC truncate the output hash, so instead of
  137. * writing it directly to 'output' we wrote it to our own
  138. * full-length buffer, and now we copy the required amount.
  139. */
  140. memcpy(output, ctx->digest, mac->vt->len);
  141. smemclr(ctx->digest, ctx->hashalg->hlen);
  142. }
  143. static const char *hmac_text_name(ssh2_mac *mac)
  144. {
  145. struct hmac *ctx = container_of(mac, struct hmac, mac);
  146. return ctx->text_name->s;
  147. }
  148. static const struct hmac_extra ssh_hmac_sha512_extra = { &ssh_sha512, "" };
  149. const ssh2_macalg ssh_hmac_sha512 = {
  150. /*.new =*/ hmac_new,
  151. /*.free =*/ hmac_free,
  152. /*.setkey =*/ hmac_key,
  153. /*.start =*/ hmac_start,
  154. /*.genresult =*/ hmac_genresult,
  155. /*.next_message =*/ nullmac_next_message,
  156. /*.text_name =*/ hmac_text_name,
  157. /*.name =*/ "hmac-sha2-512",
  158. /*.etm_name =*/ "[email protected]",
  159. /*.len =*/ 64,
  160. /*.keylen =*/ 64,
  161. /*.extra =*/ &ssh_hmac_sha512_extra,
  162. };
  163. static const struct hmac_extra ssh_hmac_sha256_extra = { &ssh_sha256, "" };
  164. const ssh2_macalg ssh_hmac_sha256 = {
  165. // WINSCP
  166. /*.new =*/ hmac_new,
  167. /*.free =*/ hmac_free,
  168. /*.setkey =*/ hmac_key,
  169. /*.start =*/ hmac_start,
  170. /*.genresult =*/ hmac_genresult,
  171. /*.next_message =*/ nullmac_next_message,
  172. /*.text_name =*/ hmac_text_name,
  173. /*.name =*/ "hmac-sha2-256",
  174. /*.etm_name =*/ "[email protected]",
  175. /*.len =*/ 32,
  176. /*.keylen =*/ 32,
  177. /*.extra =*/ &ssh_hmac_sha256_extra,
  178. };
  179. static const struct hmac_extra ssh_hmac_md5_extra = { &ssh_md5, "" };
  180. const ssh2_macalg ssh_hmac_md5 = {
  181. // WINSCP
  182. /*.new =*/ hmac_new,
  183. /*.free =*/ hmac_free,
  184. /*.setkey =*/ hmac_key,
  185. /*.start =*/ hmac_start,
  186. /*.genresult =*/ hmac_genresult,
  187. /*.next_message =*/ nullmac_next_message,
  188. /*.text_name =*/ hmac_text_name,
  189. /*.name =*/ "hmac-md5",
  190. /*.etm_name =*/ "[email protected]",
  191. /*.len =*/ 16,
  192. /*.keylen =*/ 16,
  193. /*.extra =*/ &ssh_hmac_md5_extra,
  194. };
  195. static const struct hmac_extra ssh_hmac_sha1_extra = { &ssh_sha1, "" };
  196. const ssh2_macalg ssh_hmac_sha1 = {
  197. // WINSCP
  198. /*.new =*/ hmac_new,
  199. /*.free =*/ hmac_free,
  200. /*.setkey =*/ hmac_key,
  201. /*.start =*/ hmac_start,
  202. /*.genresult =*/ hmac_genresult,
  203. /*.next_message =*/ nullmac_next_message,
  204. /*.text_name =*/ hmac_text_name,
  205. /*.name =*/ "hmac-sha1",
  206. /*.etm_name =*/ "[email protected]",
  207. /*.len =*/ 20,
  208. /*.keylen =*/ 20,
  209. /*.extra =*/ &ssh_hmac_sha1_extra,
  210. };
  211. static const struct hmac_extra ssh_hmac_sha1_96_extra = { &ssh_sha1, "-96" };
  212. const ssh2_macalg ssh_hmac_sha1_96 = {
  213. // WINSCP
  214. /*.new =*/ hmac_new,
  215. /*.free =*/ hmac_free,
  216. /*.setkey =*/ hmac_key,
  217. /*.start =*/ hmac_start,
  218. /*.genresult =*/ hmac_genresult,
  219. /*.next_message =*/ nullmac_next_message,
  220. /*.text_name =*/ hmac_text_name,
  221. /*.name =*/ "hmac-sha1-96",
  222. /*.etm_name =*/ "[email protected]",
  223. /*.len =*/ 12,
  224. /*.keylen =*/ 20,
  225. /*.extra =*/ &ssh_hmac_sha1_96_extra,
  226. };
  227. static const struct hmac_extra ssh_hmac_sha1_buggy_extra = {
  228. &ssh_sha1, "", "bug-compatible"
  229. };
  230. const ssh2_macalg ssh_hmac_sha1_buggy = {
  231. // WINSCP
  232. /*.new =*/ hmac_new,
  233. /*.free =*/ hmac_free,
  234. /*.setkey =*/ hmac_key,
  235. /*.start =*/ hmac_start,
  236. /*.genresult =*/ hmac_genresult,
  237. /*.next_message =*/ nullmac_next_message,
  238. /*.text_name =*/ hmac_text_name,
  239. /*.name =*/ "hmac-sha1",
  240. NULL, // WINSCP
  241. /*.len =*/ 20,
  242. /*.keylen =*/ 16,
  243. /*.extra =*/ &ssh_hmac_sha1_buggy_extra,
  244. };
  245. static const struct hmac_extra ssh_hmac_sha1_96_buggy_extra = {
  246. &ssh_sha1, "-96", "bug-compatible"
  247. };
  248. const ssh2_macalg ssh_hmac_sha1_96_buggy = {
  249. // WINSCP
  250. /*.new =*/ hmac_new,
  251. /*.free =*/ hmac_free,
  252. /*.setkey =*/ hmac_key,
  253. /*.start =*/ hmac_start,
  254. /*.genresult =*/ hmac_genresult,
  255. /*.next_message =*/ nullmac_next_message,
  256. /*.text_name =*/ hmac_text_name,
  257. /*.name =*/ "hmac-sha1-96",
  258. NULL, // WINSCP
  259. /*.len =*/ 12,
  260. /*.keylen =*/ 16,
  261. /*.extra =*/ &ssh_hmac_sha1_96_buggy_extra,
  262. };
  263. ssh2_mac *hmac_new_from_hash(const ssh_hashalg *hash)
  264. {
  265. /*
  266. * Construct a custom ssh2_macalg, derived directly from the
  267. * provided hash vtable. It's included in the same memory
  268. * allocation as the struct hmac, so that it all gets freed
  269. * together.
  270. */
  271. struct alloc {
  272. struct hmac hmac;
  273. ssh2_macalg alg;
  274. struct hmac_extra extra;
  275. };
  276. struct alloc *alloc = snew(struct alloc);
  277. alloc->alg.new = hmac_new;
  278. alloc->alg.free = hmac_free;
  279. alloc->alg.setkey = hmac_key;
  280. alloc->alg.start = hmac_start;
  281. alloc->alg.genresult = hmac_genresult;
  282. alloc->alg.next_message = nullmac_next_message;
  283. alloc->alg.text_name = hmac_text_name;
  284. alloc->alg.name = NULL;
  285. alloc->alg.etm_name = NULL;
  286. alloc->alg.len = hash->hlen;
  287. alloc->alg.keylen = hash->hlen;
  288. alloc->alg.extra = &alloc->extra;
  289. alloc->extra.hashalg_base = hash;
  290. alloc->extra.suffix = "";
  291. alloc->extra.annotation = NULL;
  292. return hmac_new_inner(&alloc->hmac, &alloc->alg);
  293. }