sshcrcda.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /* $OpenBSD: deattack.c,v 1.14 2001/06/23 15:12:18 itojun Exp $ */
  2. /*
  3. * Cryptographic attack detector for ssh - source code
  4. *
  5. * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
  6. *
  7. * All rights reserved. Redistribution and use in source and binary
  8. * forms, with or without modification, are permitted provided that
  9. * this copyright notice is retained.
  10. *
  11. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  12. * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
  13. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
  14. * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
  15. * SOFTWARE.
  16. *
  17. * Ariel Futoransky <[email protected]>
  18. * <http://www.core-sdi.com>
  19. *
  20. * Modified for use in PuTTY by Simon Tatham
  21. */
  22. #include <assert.h>
  23. #include "misc.h"
  24. #include "ssh.h"
  25. typedef unsigned char uchar;
  26. typedef unsigned short uint16;
  27. /* SSH Constants */
  28. #define SSH_MAXBLOCKS (32 * 1024)
  29. #define SSH_BLOCKSIZE (8)
  30. /* Hashing constants */
  31. #define HASH_MINSIZE (8 * 1024)
  32. #define HASH_ENTRYSIZE (sizeof(uint16))
  33. #define HASH_FACTOR(x) ((x)*3/2)
  34. #define HASH_UNUSEDCHAR (0xff)
  35. #define HASH_UNUSED (0xffff)
  36. #define HASH_IV (0xfffe)
  37. #define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
  38. /* Hash function (Input keys are cipher results) */
  39. #define HASH(x) GET_32BIT_MSB_FIRST(x)
  40. #define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
  41. uchar ONE[4] = { 1, 0, 0, 0 };
  42. uchar ZERO[4] = { 0, 0, 0, 0 };
  43. struct crcda_ctx {
  44. uint16 *h;
  45. uint32 n;
  46. };
  47. struct crcda_ctx *crcda_make_context(void)
  48. {
  49. struct crcda_ctx *ret = snew(struct crcda_ctx);
  50. ret->h = NULL;
  51. ret->n = HASH_MINSIZE / HASH_ENTRYSIZE;
  52. return ret;
  53. }
  54. void crcda_free_context(struct crcda_ctx *ctx)
  55. {
  56. if (ctx) {
  57. sfree(ctx->h);
  58. ctx->h = NULL;
  59. sfree(ctx);
  60. }
  61. }
  62. static void crc_update(uint32 *a, void *b)
  63. {
  64. *a = crc32_update(*a, b, 4);
  65. }
  66. /* detect if a block is used in a particular pattern */
  67. static int check_crc(uchar *S, uchar *buf, uint32 len, uchar *IV)
  68. {
  69. uint32 crc;
  70. uchar *c;
  71. crc = 0;
  72. if (IV && !CMP(S, IV)) {
  73. crc_update(&crc, ONE);
  74. crc_update(&crc, ZERO);
  75. }
  76. for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
  77. if (!CMP(S, c)) {
  78. crc_update(&crc, ONE);
  79. crc_update(&crc, ZERO);
  80. } else {
  81. crc_update(&crc, ZERO);
  82. crc_update(&crc, ZERO);
  83. }
  84. }
  85. return (crc == 0);
  86. }
  87. /* Detect a crc32 compensation attack on a packet */
  88. int detect_attack(struct crcda_ctx *ctx, uchar *buf, uint32 len, uchar *IV)
  89. {
  90. register uint32 i, j;
  91. uint32 l;
  92. register uchar *c;
  93. uchar *d;
  94. assert(!(len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
  95. len % SSH_BLOCKSIZE != 0));
  96. for (l = ctx->n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
  97. ;
  98. if (ctx->h == NULL) {
  99. ctx->n = l;
  100. ctx->h = snewn(ctx->n, uint16);
  101. } else {
  102. if (l > ctx->n) {
  103. ctx->n = l;
  104. ctx->h = sresize(ctx->h, ctx->n, uint16);
  105. }
  106. }
  107. if (len <= HASH_MINBLOCKS) {
  108. for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
  109. if (IV && (!CMP(c, IV))) {
  110. if ((check_crc(c, buf, len, IV)))
  111. return 1; /* attack detected */
  112. else
  113. break;
  114. }
  115. for (d = buf; d < c; d += SSH_BLOCKSIZE) {
  116. if (!CMP(c, d)) {
  117. if ((check_crc(c, buf, len, IV)))
  118. return 1; /* attack detected */
  119. else
  120. break;
  121. }
  122. }
  123. }
  124. return 0; /* ok */
  125. }
  126. memset(ctx->h, HASH_UNUSEDCHAR, ctx->n * HASH_ENTRYSIZE);
  127. if (IV)
  128. ctx->h[HASH(IV) & (ctx->n - 1)] = HASH_IV;
  129. for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
  130. for (i = HASH(c) & (ctx->n - 1); ctx->h[i] != HASH_UNUSED;
  131. i = (i + 1) & (ctx->n - 1)) {
  132. if (ctx->h[i] == HASH_IV) {
  133. if (!CMP(c, IV)) {
  134. if (check_crc(c, buf, len, IV))
  135. return 1; /* attack detected */
  136. else
  137. break;
  138. }
  139. } else if (!CMP(c, buf + ctx->h[i] * SSH_BLOCKSIZE)) {
  140. if (check_crc(c, buf, len, IV))
  141. return 1; /* attack detected */
  142. else
  143. break;
  144. }
  145. }
  146. ctx->h[i] = j;
  147. }
  148. return 0; /* ok */
  149. }