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

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