[BACK]Return to deattack.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/deattack.c, Revision 1.4

1.1       dugsong     1: /*
1.4     ! markus      2:  * $Id: deattack.c,v 1.3 1999/10/05 22:18:52 markus Exp $
1.2       dugsong     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 <futo@core-sdi.com>
                     18:  * <http://www.core-sdi.com> */
1.1       dugsong    19:
                     20: #include "includes.h"
                     21: #include "deattack.h"
                     22: #include "ssh.h"
1.3       markus     23: #include "crc32.h"
1.1       dugsong    24: #include "getput.h"
                     25: #include "xmalloc.h"
                     26:
                     27: /* SSH Constants */
                     28: #define SSH_MAXBLOCKS (32 * 1024)
                     29: #define SSH_BLOCKSIZE (8)
                     30:
                     31: /* Hashing constants */
                     32: #define HASH_MINSIZE (8 * 1024)
                     33: #define HASH_ENTRYSIZE (2)
                     34: #define HASH_FACTOR(x) ((x)*3/2)
                     35: #define HASH_UNUSEDCHAR (0xff)
                     36: #define HASH_UNUSED (0xffff)
                     37: #define HASH_IV     (0xfffe)
                     38:
                     39: #define HASH_MINBLOCKS  (7*SSH_BLOCKSIZE)
                     40:
                     41:
                     42: /* Hash function (Input keys are cipher results) */
                     43: #define HASH(x) GET_32BIT(x)
                     44:
                     45: #define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE))
                     46:
                     47:
                     48: void
                     49: crc_update(u_int32_t * a, u_int32_t b)
                     50: {
                     51:   b ^= *a;
                     52:   *a = crc32((unsigned char *) &b, sizeof(b));
                     53: }
                     54:
                     55: /*
                     56:    check_crc
                     57:    detects if a block is used in a particular pattern
                     58:  */
                     59:
                     60: int
                     61: check_crc(unsigned char *S, unsigned char *buf, u_int32_t len, unsigned char *IV)
                     62: {
                     63:   u_int32_t          crc;
                     64:   unsigned char  *c;
                     65:
                     66:   crc = 0;
                     67:   if (IV && !CMP(S, IV))
                     68:   {
                     69:     crc_update(&crc, 1);
                     70:     crc_update(&crc, 0);
                     71:   }
                     72:   for (c = buf; c < buf + len; c += SSH_BLOCKSIZE)
                     73:   {
                     74:     if (!CMP(S, c))
                     75:     {
                     76:       crc_update(&crc, 1);
                     77:       crc_update(&crc, 0);
                     78:     } else
                     79:     {
                     80:       crc_update(&crc, 0);
                     81:       crc_update(&crc, 0);
                     82:     }
                     83:   }
                     84:
                     85:   return (crc == 0);
                     86: }
                     87:
                     88:
                     89: /*
                     90:    detect_attack
                     91:    Detects a crc32 compensation attack on a packet
                     92:  */
                     93: int
                     94: detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV)
                     95: {
                     96:   static u_int16_t  *h = (u_int16_t *) NULL;
                     97:   static u_int16_t   n = HASH_MINSIZE / HASH_ENTRYSIZE;
                     98:   register u_int32_t i, j;
                     99:   u_int32_t          l;
                    100:   register unsigned char *c;
                    101:   unsigned char  *d;
                    102:
1.4     ! markus    103:   if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
        !           104:       len % SSH_BLOCKSIZE != 0) {
        !           105:     fatal("detect_attack: bad length %d", len);
        !           106:   }
1.1       dugsong   107:
                    108:   for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2);
                    109:
                    110:   if (h == NULL)
                    111:   {
                    112:     debug("Installing crc compensation attack detector.");
                    113:     n = l;
                    114:     h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
                    115:   } else
                    116:   {
                    117:     if (l > n)
                    118:     {
                    119:       n = l;
                    120:       h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE);
                    121:     }
                    122:   }
                    123:
                    124:
                    125:   if (len <= HASH_MINBLOCKS)
                    126:   {
                    127:     for (c = buf; c < buf + len; c += SSH_BLOCKSIZE)
                    128:     {
                    129:       if (IV && (!CMP(c, IV)))
                    130:       {
                    131:        if ((check_crc(c, buf, len, IV)))
                    132:          return (DEATTACK_DETECTED);
                    133:        else
                    134:          break;
                    135:       }
                    136:       for (d = buf; d < c; d += SSH_BLOCKSIZE)
                    137:       {
                    138:        if (!CMP(c, d))
                    139:        {
                    140:          if ((check_crc(c, buf, len, IV)))
                    141:            return (DEATTACK_DETECTED);
                    142:          else
                    143:            break;
                    144:        }
                    145:       }
                    146:     }
                    147:     return (DEATTACK_OK);
                    148:   }
                    149:   memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
                    150:
                    151:   if (IV)
                    152:     h[HASH(IV) & (n - 1)] = HASH_IV;
                    153:
                    154:
                    155:   for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++)
                    156:   {
                    157:     for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
                    158:         i = (i + 1) & (n - 1))
                    159:     {
                    160:       if (h[i] == HASH_IV)
                    161:       {
                    162:        if (!CMP(c, IV))
                    163:        {
                    164:          if (check_crc(c, buf, len, IV))
                    165:            return (DEATTACK_DETECTED);
                    166:          else
                    167:            break;
                    168:        }
                    169:       } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE))
                    170:       {
                    171:        if (check_crc(c, buf, len, IV))
                    172:          return (DEATTACK_DETECTED);
                    173:        else
                    174:          break;
                    175:       }
                    176:     }
                    177:     h[i] = j;
                    178:   }
                    179:
                    180:   return (DEATTACK_OK);
                    181: }