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: }