deattack.c revision 124208
1312872Shselasky/* 2312872Shselasky * Cryptographic attack detector for ssh - source code 3312872Shselasky * 4312872Shselasky * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina. 5312872Shselasky * 6312872Shselasky * All rights reserved. Redistribution and use in source and binary 7312872Shselasky * forms, with or without modification, are permitted provided that 8312872Shselasky * this copyright notice is retained. 9312872Shselasky * 10312872Shselasky * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 11312872Shselasky * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE 12312872Shselasky * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR 13312872Shselasky * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS 14312872Shselasky * SOFTWARE. 15312872Shselasky * 16312872Shselasky * Ariel Futoransky <futo@core-sdi.com> 17312872Shselasky * <http://www.core-sdi.com> 18312872Shselasky */ 19312872Shselasky 20312872Shselasky#include "includes.h" 21312872ShselaskyRCSID("$OpenBSD: deattack.c,v 1.19 2003/09/18 08:49:45 markus Exp $"); 22312872Shselasky 23312872Shselasky#include "deattack.h" 24312872Shselasky#include "log.h" 25312872Shselasky#include "crc32.h" 26312872Shselasky#include "getput.h" 27312872Shselasky#include "xmalloc.h" 28312872Shselasky#include "deattack.h" 29312872Shselasky 30312872Shselasky/* SSH Constants */ 31312872Shselasky#define SSH_MAXBLOCKS (32 * 1024) 32312872Shselasky#define SSH_BLOCKSIZE (8) 33312872Shselasky 34312872Shselasky/* Hashing constants */ 35312872Shselasky#define HASH_MINSIZE (8 * 1024) 36322011Shselasky#define HASH_ENTRYSIZE (2) 37312872Shselasky#define HASH_FACTOR(x) ((x)*3/2) 38312872Shselasky#define HASH_UNUSEDCHAR (0xff) 39312872Shselasky#define HASH_UNUSED (0xffff) 40312872Shselasky#define HASH_IV (0xfffe) 41312872Shselasky 42312872Shselasky#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE) 43312872Shselasky 44312872Shselasky 45312872Shselasky/* Hash function (Input keys are cipher results) */ 46312872Shselasky#define HASH(x) GET_32BIT(x) 47312872Shselasky 48312872Shselasky#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE)) 49312872Shselasky 50312872Shselaskystatic void 51312872Shselaskycrc_update(u_int32_t *a, u_int32_t b) 52312872Shselasky{ 53312872Shselasky b ^= *a; 54312872Shselasky *a = ssh_crc32((u_char *) &b, sizeof(b)); 55312872Shselasky} 56312872Shselasky 57312872Shselasky/* detect if a block is used in a particular pattern */ 58312872Shselaskystatic int 59312872Shselaskycheck_crc(u_char *S, u_char *buf, u_int32_t len, 60312872Shselasky u_char *IV) 61312872Shselasky{ 62312872Shselasky u_int32_t crc; 63312872Shselasky u_char *c; 64312872Shselasky 65312872Shselasky crc = 0; 66312872Shselasky if (IV && !CMP(S, IV)) { 67312872Shselasky crc_update(&crc, 1); 68312872Shselasky crc_update(&crc, 0); 69312872Shselasky } 70312872Shselasky for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { 71312872Shselasky if (!CMP(S, c)) { 72312872Shselasky crc_update(&crc, 1); 73312872Shselasky crc_update(&crc, 0); 74312872Shselasky } else { 75312872Shselasky crc_update(&crc, 0); 76312872Shselasky crc_update(&crc, 0); 77312872Shselasky } 78312872Shselasky } 79312872Shselasky return (crc == 0); 80312872Shselasky} 81312872Shselasky 82312872Shselasky 83312872Shselasky/* Detect a crc32 compensation attack on a packet */ 84312872Shselaskyint 85312872Shselaskydetect_attack(u_char *buf, u_int32_t len, u_char *IV) 86312872Shselasky{ 87312872Shselasky static u_int16_t *h = (u_int16_t *) NULL; 88312872Shselasky static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE; 89312872Shselasky u_int32_t i, j; 90312872Shselasky u_int32_t l; 91312872Shselasky u_char *c; 92312872Shselasky u_char *d; 93312872Shselasky 94312872Shselasky if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) || 95312872Shselasky len % SSH_BLOCKSIZE != 0) { 96312872Shselasky fatal("detect_attack: bad length %d", len); 97312872Shselasky } 98312872Shselasky for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2) 99312872Shselasky ; 100312872Shselasky 101312872Shselasky if (h == NULL) { 102312872Shselasky debug("Installing crc compensation attack detector."); 103312872Shselasky h = (u_int16_t *) xmalloc(l * HASH_ENTRYSIZE); 104312872Shselasky n = l; 105312872Shselasky } else { 106312872Shselasky if (l > n) { 107312872Shselasky h = (u_int16_t *) xrealloc(h, l * HASH_ENTRYSIZE); 108312872Shselasky n = l; 109312872Shselasky } 110312872Shselasky } 111312872Shselasky 112312872Shselasky if (len <= HASH_MINBLOCKS) { 113312872Shselasky for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { 114312872Shselasky if (IV && (!CMP(c, IV))) { 115312872Shselasky if ((check_crc(c, buf, len, IV))) 116312872Shselasky return (DEATTACK_DETECTED); 117312872Shselasky else 118312872Shselasky break; 119312872Shselasky } 120312872Shselasky for (d = buf; d < c; d += SSH_BLOCKSIZE) { 121312872Shselasky if (!CMP(c, d)) { 122312872Shselasky if ((check_crc(c, buf, len, IV))) 123312872Shselasky return (DEATTACK_DETECTED); 124312872Shselasky else 125312872Shselasky break; 126312872Shselasky } 127312872Shselasky } 128312872Shselasky } 129312872Shselasky return (DEATTACK_OK); 130312872Shselasky } 131312872Shselasky memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE); 132312872Shselasky 133312872Shselasky if (IV) 134312872Shselasky h[HASH(IV) & (n - 1)] = HASH_IV; 135312872Shselasky 136312872Shselasky for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) { 137312872Shselasky for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED; 138312872Shselasky 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} 157