source: trunk/third/openssh/deattack.c @ 18759

Revision 18759, 3.5 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Cryptographic attack detector for ssh - source code
3 *
4 * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
5 *
6 * All rights reserved. Redistribution and use in source and binary
7 * forms, with or without modification, are permitted provided that
8 * this copyright notice is retained.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
11 * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
12 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
13 * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
14 * SOFTWARE.
15 *
16 * Ariel Futoransky <futo@core-sdi.com>
17 * <http://www.core-sdi.com>
18 */
19
20#include "includes.h"
21RCSID("$OpenBSD: deattack.c,v 1.18 2002/03/04 17:27:39 stevesk Exp $");
22
23#include "deattack.h"
24#include "log.h"
25#include "crc32.h"
26#include "getput.h"
27#include "xmalloc.h"
28#include "deattack.h"
29
30/* SSH Constants */
31#define SSH_MAXBLOCKS   (32 * 1024)
32#define SSH_BLOCKSIZE   (8)
33
34/* Hashing constants */
35#define HASH_MINSIZE    (8 * 1024)
36#define HASH_ENTRYSIZE  (2)
37#define HASH_FACTOR(x)  ((x)*3/2)
38#define HASH_UNUSEDCHAR (0xff)
39#define HASH_UNUSED     (0xffff)
40#define HASH_IV         (0xfffe)
41
42#define HASH_MINBLOCKS  (7*SSH_BLOCKSIZE)
43
44
45/* Hash function (Input keys are cipher results) */
46#define HASH(x)         GET_32BIT(x)
47
48#define CMP(a, b)       (memcmp(a, b, SSH_BLOCKSIZE))
49
50static void
51crc_update(u_int32_t *a, u_int32_t b)
52{
53        b ^= *a;
54        *a = ssh_crc32((u_char *) &b, sizeof(b));
55}
56
57/* detect if a block is used in a particular pattern */
58static int
59check_crc(u_char *S, u_char *buf, u_int32_t len,
60          u_char *IV)
61{
62        u_int32_t crc;
63        u_char *c;
64
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);
80}
81
82
83/* Detect a crc32 compensation attack on a packet */
84int
85detect_attack(u_char *buf, u_int32_t len, u_char *IV)
86{
87        static u_int16_t *h = (u_int16_t *) NULL;
88        static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
89        u_int32_t i, j;
90        u_int32_t l;
91        u_char *c;
92        u_char *d;
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                ;
100
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);
156}
Note: See TracBrowser for help on using the repository browser.