[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.5

1.1       dugsong     1: /*
1.5     ! markus      2:  * $Id: deattack.c,v 1.4 1999/11/02 19:42:35 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 */
1.5     ! markus     28: #define SSH_MAXBLOCKS  (32 * 1024)
        !            29: #define SSH_BLOCKSIZE  (8)
1.1       dugsong    30:
                     31: /* Hashing constants */
1.5     ! markus     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)
1.1       dugsong    38:
1.5     ! markus     39: #define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
1.1       dugsong    40:
                     41:
                     42: /* Hash function (Input keys are cipher results) */
1.5     ! markus     43: #define HASH(x)                GET_32BIT(x)
1.1       dugsong    44:
1.5     ! markus     45: #define CMP(a,b)       (memcmp(a, b, SSH_BLOCKSIZE))
1.1       dugsong    46:
                     47:
                     48: void
1.5     ! markus     49: crc_update(u_int32_t *a, u_int32_t b)
1.1       dugsong    50: {
1.5     ! markus     51:        b ^= *a;
        !            52:        *a = crc32((unsigned char *) &b, sizeof(b));
1.1       dugsong    53: }
                     54:
1.5     ! markus     55: /* detect if a block is used in a particular pattern */
1.1       dugsong    56: int
1.5     ! markus     57: check_crc(unsigned char *S, unsigned char *buf, u_int32_t len,
        !            58:          unsigned char *IV)
1.1       dugsong    59: {
1.5     ! markus     60:        u_int32_t crc;
        !            61:        unsigned char *c;
1.1       dugsong    62:
1.5     ! markus     63:        crc = 0;
        !            64:        if (IV && !CMP(S, IV)) {
        !            65:                crc_update(&crc, 1);
        !            66:                crc_update(&crc, 0);
        !            67:        }
        !            68:        for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
        !            69:                if (!CMP(S, c)) {
        !            70:                        crc_update(&crc, 1);
        !            71:                        crc_update(&crc, 0);
        !            72:                } else {
        !            73:                        crc_update(&crc, 0);
        !            74:                        crc_update(&crc, 0);
        !            75:                }
        !            76:        }
        !            77:        return (crc == 0);
1.1       dugsong    78: }
                     79:
                     80:
1.5     ! markus     81: /* Detect a crc32 compensation attack on a packet */
1.1       dugsong    82: int
                     83: detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV)
                     84: {
1.5     ! markus     85:        static u_int16_t *h = (u_int16_t *) NULL;
        !            86:        static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
        !            87:        register u_int32_t i, j;
        !            88:        u_int32_t l;
        !            89:        register unsigned char *c;
        !            90:        unsigned char *d;
        !            91:
        !            92:        if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
        !            93:            len % SSH_BLOCKSIZE != 0) {
        !            94:                fatal("detect_attack: bad length %d", len);
        !            95:        }
        !            96:        for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
        !            97:                ;
1.1       dugsong    98:
1.5     ! markus     99:        if (h == NULL) {
        !           100:                debug("Installing crc compensation attack detector.");
        !           101:                n = l;
        !           102:                h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
        !           103:        } else {
        !           104:                if (l > n) {
        !           105:                        n = l;
        !           106:                        h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE);
        !           107:                }
        !           108:        }
        !           109:
        !           110:        if (len <= HASH_MINBLOCKS) {
        !           111:                for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
        !           112:                        if (IV && (!CMP(c, IV))) {
        !           113:                                if ((check_crc(c, buf, len, IV)))
        !           114:                                        return (DEATTACK_DETECTED);
        !           115:                                else
        !           116:                                        break;
        !           117:                        }
        !           118:                        for (d = buf; d < c; d += SSH_BLOCKSIZE) {
        !           119:                                if (!CMP(c, d)) {
        !           120:                                        if ((check_crc(c, buf, len, IV)))
        !           121:                                                return (DEATTACK_DETECTED);
        !           122:                                        else
        !           123:                                                break;
        !           124:                                }
        !           125:                        }
        !           126:                }
        !           127:                return (DEATTACK_OK);
        !           128:        }
        !           129:        memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
        !           130:
        !           131:        if (IV)
        !           132:                h[HASH(IV) & (n - 1)] = HASH_IV;
        !           133:
        !           134:        for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
        !           135:                for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
        !           136:                     i = (i + 1) & (n - 1)) {
        !           137:                        if (h[i] == HASH_IV) {
        !           138:                                if (!CMP(c, IV)) {
        !           139:                                        if (check_crc(c, buf, len, IV))
        !           140:                                                return (DEATTACK_DETECTED);
        !           141:                                        else
        !           142:                                                break;
        !           143:                                }
        !           144:                        } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
        !           145:                                if (check_crc(c, buf, len, IV))
        !           146:                                        return (DEATTACK_DETECTED);
        !           147:                                else
        !           148:                                        break;
        !           149:                        }
        !           150:                }
        !           151:                h[i] = j;
        !           152:        }
        !           153:        return (DEATTACK_OK);
1.1       dugsong   154: }