2 * Cryptographic attack detector for ssh - source code
4 * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
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.
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
16 * Ariel Futoransky <futo@core-sdi.com>
17 * <http://www.core-sdi.com>
21 RCSID("$OpenBSD: deattack.c,v 1.18 2002/03/04 17:27:39 stevesk Exp $");
23 #pragma ident "%Z%%M% %I% %E% SMI"
33 * CRC attack detection has a worst-case behaviour that is O(N^2) over
34 * the number of identical blocks in a packet. This behaviour can be
35 * exploited to create a limited denial of service attack.
37 * However, because we are dealing with encrypted data, identical
38 * blocks should only occur every 2^35 maximally-sized packets or so.
39 * Consequently, we can detect this DoS by looking for identical blocks
42 * The parameter below determines how many identical blocks we will
43 * accept in a single packet, trading off between attack detection and
44 * likelihood of terminating a legitimate connection. A value of 32
45 * corresponds to an average of 2^40 messages before an attack is
48 #define MAX_IDENTICAL 32
51 #define SSH_MAXBLOCKS (32 * 1024)
52 #define SSH_BLOCKSIZE (8)
54 /* Hashing constants */
55 #define HASH_MINSIZE (8 * 1024)
56 #define HASH_ENTRYSIZE (2)
57 #define HASH_FACTOR(x) ((x)*3/2)
58 #define HASH_UNUSEDCHAR (0xff)
59 #define HASH_UNUSED (0xffff)
60 #define HASH_IV (0xfffe)
62 #define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
65 /* Hash function (Input keys are cipher results) */
66 #define HASH(x) GET_32BIT(x)
68 #define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
71 crc_update(u_int32_t
*a
, u_int32_t b
)
74 *a
= ssh_crc32((u_char
*) &b
, sizeof(b
));
77 /* detect if a block is used in a particular pattern */
79 check_crc(u_char
*S
, u_char
*buf
, u_int32_t len
,
86 if (IV
&& !CMP(S
, IV
)) {
90 for (c
= buf
; c
< buf
+ len
; c
+= SSH_BLOCKSIZE
) {
103 /* Detect a crc32 compensation attack on a packet */
105 detect_attack(u_char
*buf
, u_int32_t len
, u_char
*IV
)
107 static u_int16_t
*h
= (u_int16_t
*) NULL
;
108 static u_int32_t n
= HASH_MINSIZE
/ HASH_ENTRYSIZE
;
114 if (len
> (SSH_MAXBLOCKS
* SSH_BLOCKSIZE
) ||
115 len
% SSH_BLOCKSIZE
!= 0) {
116 fatal("detect_attack: bad length %d", len
);
118 for (l
= n
; l
< HASH_FACTOR(len
/ SSH_BLOCKSIZE
); l
= l
<< 2)
122 debug("Installing crc compensation attack detector.");
124 h
= (u_int16_t
*) xmalloc(n
* HASH_ENTRYSIZE
);
128 h
= (u_int16_t
*) xrealloc(h
, n
* HASH_ENTRYSIZE
);
132 if (len
<= HASH_MINBLOCKS
) {
133 for (c
= buf
; c
< buf
+ len
; c
+= SSH_BLOCKSIZE
) {
134 if (IV
&& (!CMP(c
, IV
))) {
135 if ((check_crc(c
, buf
, len
, IV
)))
136 return (DEATTACK_DETECTED
);
140 for (d
= buf
; d
< c
; d
+= SSH_BLOCKSIZE
) {
142 if ((check_crc(c
, buf
, len
, IV
)))
143 return (DEATTACK_DETECTED
);
149 return (DEATTACK_OK
);
151 memset(h
, HASH_UNUSEDCHAR
, n
* HASH_ENTRYSIZE
);
154 h
[HASH(IV
) & (n
- 1)] = HASH_IV
;
156 for (c
= buf
, same
= j
= 0; c
< (buf
+ len
); c
+= SSH_BLOCKSIZE
, j
++) {
157 for (i
= HASH(c
) & (n
- 1); h
[i
] != HASH_UNUSED
;
158 i
= (i
+ 1) & (n
- 1)) {
159 if (h
[i
] == HASH_IV
) {
161 if (check_crc(c
, buf
, len
, IV
))
162 return (DEATTACK_DETECTED
);
166 } else if (!CMP(c
, buf
+ h
[i
] * SSH_BLOCKSIZE
)) {
167 if (++same
> MAX_IDENTICAL
)
168 return (DEATTACK_DOS_DETECTED
);
169 if (check_crc(c
, buf
, len
, IV
))
170 return (DEATTACK_DETECTED
);
177 return (DEATTACK_OK
);