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