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" 21 RCSID("$OpenBSD: deattack.c,v 1.18 2002/03/04 17:27:39 stevesk Exp $"); 22 23 #pragma ident "%Z%%M% %I% %E% SMI" 24 25 #include "deattack.h" 26 #include "log.h" 27 #include "crc32.h" 28 #include "getput.h" 29 #include "xmalloc.h" 30 #include "deattack.h" 31 32 /* SSH Constants */ 33 #define SSH_MAXBLOCKS (32 * 1024) 34 #define SSH_BLOCKSIZE (8) 35 36 /* Hashing constants */ 37 #define HASH_MINSIZE (8 * 1024) 38 #define HASH_ENTRYSIZE (2) 39 #define HASH_FACTOR(x) ((x)*3/2) 40 #define HASH_UNUSEDCHAR (0xff) 41 #define HASH_UNUSED (0xffff) 42 #define HASH_IV (0xfffe) 43 44 #define HASH_MINBLOCKS (7*SSH_BLOCKSIZE) 45 46 47 /* Hash function (Input keys are cipher results) */ 48 #define HASH(x) GET_32BIT(x) 49 50 #define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE)) 51 52 static void 53 crc_update(u_int32_t *a, u_int32_t b) 54 { 55 b ^= *a; 56 *a = ssh_crc32((u_char *) &b, sizeof(b)); 57 } 58 59 /* detect if a block is used in a particular pattern */ 60 static int 61 check_crc(u_char *S, u_char *buf, u_int32_t len, 62 u_char *IV) 63 { 64 u_int32_t crc; 65 u_char *c; 66 67 crc = 0; 68 if (IV && !CMP(S, IV)) { 69 crc_update(&crc, 1); 70 crc_update(&crc, 0); 71 } 72 for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { 73 if (!CMP(S, c)) { 74 crc_update(&crc, 1); 75 crc_update(&crc, 0); 76 } else { 77 crc_update(&crc, 0); 78 crc_update(&crc, 0); 79 } 80 } 81 return (crc == 0); 82 } 83 84 85 /* Detect a crc32 compensation attack on a packet */ 86 int 87 detect_attack(u_char *buf, u_int32_t len, u_char *IV) 88 { 89 static u_int16_t *h = (u_int16_t *) NULL; 90 static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE; 91 u_int32_t i, j; 92 u_int32_t l; 93 u_char *c; 94 u_char *d; 95 96 if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) || 97 len % SSH_BLOCKSIZE != 0) { 98 fatal("detect_attack: bad length %d", len); 99 } 100 for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2) 101 ; 102 103 if (h == NULL) { 104 debug("Installing crc compensation attack detector."); 105 n = l; 106 h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE); 107 } else { 108 if (l > n) { 109 n = l; 110 h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE); 111 } 112 } 113 114 if (len <= HASH_MINBLOCKS) { 115 for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { 116 if (IV && (!CMP(c, IV))) { 117 if ((check_crc(c, buf, len, IV))) 118 return (DEATTACK_DETECTED); 119 else 120 break; 121 } 122 for (d = buf; d < c; d += SSH_BLOCKSIZE) { 123 if (!CMP(c, d)) { 124 if ((check_crc(c, buf, len, IV))) 125 return (DEATTACK_DETECTED); 126 else 127 break; 128 } 129 } 130 } 131 return (DEATTACK_OK); 132 } 133 memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE); 134 135 if (IV) 136 h[HASH(IV) & (n - 1)] = HASH_IV; 137 138 for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) { 139 for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED; 140 i = (i + 1) & (n - 1)) { 141 if (h[i] == HASH_IV) { 142 if (!CMP(c, IV)) { 143 if (check_crc(c, buf, len, IV)) 144 return (DEATTACK_DETECTED); 145 else 146 break; 147 } 148 } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) { 149 if (check_crc(c, buf, len, IV)) 150 return (DEATTACK_DETECTED); 151 else 152 break; 153 } 154 } 155 h[i] = j; 156 } 157 return (DEATTACK_OK); 158 } 159