diff options
author | Luca Deri <deri@ntop.org> | 2019-08-22 19:25:58 +0200 |
---|---|---|
committer | Luca Deri <deri@ntop.org> | 2019-08-22 19:25:58 +0200 |
commit | e7c0ac37d87958c80115e7553ea39b26668ce360 (patch) | |
tree | a3d6adb3b5379fc9ac67916cda6dbd8f5a09ae29 /src | |
parent | 385e848a0f61b9e517f096b010070a6dd61d1f62 (diff) |
Implemented HASSH (https://github.com/salesforce/hassh)
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_typedefs.h | 1 | ||||
-rw-r--r-- | src/lib/protocols/ssh.c | 240 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 216 | ||||
-rw-r--r-- | src/lib/third_party/include/ndpi_md5.h | 18 | ||||
-rw-r--r-- | src/lib/third_party/src/ndpi_md5.c | 204 |
5 files changed, 458 insertions, 221 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 089547570..c206da93c 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1171,6 +1171,7 @@ struct ndpi_flow_struct { struct { char client_signature[48], server_signature[48]; + char hassh_client[33], hassh_server[33]; } ssh; struct { diff --git a/src/lib/protocols/ssh.c b/src/lib/protocols/ssh.c index 1a20078c3..7e5ca5e62 100644 --- a/src/lib/protocols/ssh.c +++ b/src/lib/protocols/ssh.c @@ -2,7 +2,7 @@ * ssh.c * * Copyright (C) 2009-2011 by ipoque GmbH - * Copyright (C) 2011-18 - ntop.org + * Copyright (C) 2011-19 - ntop.org * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH @@ -19,7 +19,7 @@ * * You should have received a copy of the GNU Lesser General Public License * along with nDPI. If not, see <http://www.gnu.org/licenses/>. - * + * */ #include "ndpi_protocol_ids.h" @@ -27,12 +27,134 @@ #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SSH #include "ndpi_api.h" +#include "ndpi_md5.h" + +/* + HASSH - https://github.com/salesforce/hassh + + https://github.com/salesforce/hassh/blob/master/python/hassh.py + + [server] + skex = packet.ssh.kex_algorithms + seastc = packet.ssh.encryption_algorithms_server_to_client + smastc = packet.ssh.mac_algorithms_server_to_client + scastc = packet.ssh.compression_algorithms_server_to_client + hasshs_str = ';'.join([skex, seastc, smastc, scastc]) + + [client] + ckex = packet.ssh.kex_algorithms + ceacts = packet.ssh.encryption_algorithms_client_to_server + cmacts = packet.ssh.mac_algorithms_client_to_server + ccacts = packet.ssh.compression_algorithms_client_to_server + hassh_str = ';'.join([ckex, ceacts, cmacts, ccacts]) +*/ + +/* #define SSH_DEBUG 1 */ + +/* ************************************************************************ */ static void ndpi_int_ssh_add_connection(struct ndpi_detection_module_struct - *ndpi_struct, struct ndpi_flow_struct *flow){ + *ndpi_struct, struct ndpi_flow_struct *flow) { ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSH, NDPI_PROTOCOL_UNKNOWN); } +/* ************************************************************************ */ + +static u_int16_t concat_hash_string(struct ndpi_packet_struct *packet, + char *buf, u_int8_t client_hash) { + u_int16_t offset = 22, buf_out_len = 0; + u_int32_t len = ntohl(*(u_int32_t*)&packet->payload[offset]); + + if(len < (packet->payload_packet_len-offset)) { + /* ssh.kex_algorithms [C/S] */ + offset += 4; + strncpy(buf, (const char *)&packet->payload[offset], buf_out_len = len); + buf[buf_out_len++] = ';'; + offset += len; + + /* ssh.server_host_key_algorithms [None] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + offset += 4 + len; + + /* ssh.encryption_algorithms_client_to_server [C] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + + if(client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + buf[buf_out_len++] = ';'; + offset += len; + } else + offset += 4 + len; + + /* ssh.encryption_algorithms_server_to_client [S] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(!client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + buf[buf_out_len++] = ';'; + offset += len; + } else + offset += 4 + len; + + /* ssh.mac_algorithms_client_to_server [C] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + buf[buf_out_len++] = ';'; + offset += len; + } else + offset += 4 + len; + + /* ssh.mac_algorithms_server_to_client [S] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(!client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + buf[buf_out_len++] = ';'; + offset += len; + } else + offset += 4 + len; + + /* ssh.compression_algorithms_client_to_server [C] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + offset += len; + } else + offset += 4 + len; + + /* ssh.compression_algorithms_server_to_client [S] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(!client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + offset += len; + } else + offset += 4 + len; + + /* ssh.languages_client_to_server [None] */ + + /* ssh.languages_server_to_client [None] */ + } + +#ifdef SSH_DEBUG + printf("\n[SSH] %s\n", buf); +#endif + + return(buf_out_len); +} + +/* ************************************************************************ */ + static void ndpi_ssh_zap_cr(char *str, int len) { len--; @@ -45,46 +167,132 @@ static void ndpi_ssh_zap_cr(char *str, int len) { } } -void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) -{ - struct ndpi_packet_struct *packet = &flow->packet; +/* ************************************************************************ */ + +void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { + struct ndpi_packet_struct *packet = &flow->packet; + +#ifdef SSH_DEBUG + printf("\n[SSH] [stage: %u]\n", flow->l4.tcp.ssh_stage); +#endif - if (flow->l4.tcp.ssh_stage == 0) { - if (packet->payload_packet_len > 7 && packet->payload_packet_len < 100 + if(flow->l4.tcp.ssh_stage == 0) { + if(packet->payload_packet_len > 7 && packet->payload_packet_len < 100 && memcmp(packet->payload, "SSH-", 4) == 0) { if(!ndpi_struct->disable_metadata_export) { - int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len); + int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len); + strncpy(flow->protos.ssh.client_signature, (const char *)packet->payload, len); flow->protos.ssh.client_signature[len] = '\0'; ndpi_ssh_zap_cr(flow->protos.ssh.client_signature, len); + +#ifdef SSH_DEBUG + printf("\n[SSH] [client_signature: %s]\n", flow->protos.ssh.client_signature); +#endif } - + NDPI_LOG_DBG2(ndpi_struct, "ssh stage 0 passed\n"); flow->l4.tcp.ssh_stage = 1 + packet->packet_direction; + flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH; return; } - } else if (flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) { - if (packet->payload_packet_len > 7 && packet->payload_packet_len < 500 + } else if(flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) { + if(packet->payload_packet_len > 7 && packet->payload_packet_len < 500 && memcmp(packet->payload, "SSH-", 4) == 0) { if(!ndpi_struct->disable_metadata_export) { int len = ndpi_min(sizeof(flow->protos.ssh.server_signature)-1, packet->payload_packet_len); + strncpy(flow->protos.ssh.server_signature, (const char *)packet->payload, len); flow->protos.ssh.server_signature[len] = '\0'; ndpi_ssh_zap_cr(flow->protos.ssh.server_signature, len); + +#ifdef SSH_DEBUG + printf("\n[SSH] [server_signature: %s]\n", flow->protos.ssh.server_signature); +#endif + + NDPI_LOG_DBG2(ndpi_struct, "ssh stage 1 passed\n"); + flow->l4.tcp.ssh_stage++;; + flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH; + } else { + NDPI_LOG_INFO(ndpi_struct, "found ssh\n"); + ndpi_int_ssh_add_connection(ndpi_struct, flow); } - - NDPI_LOG_INFO(ndpi_struct, "found ssh\n"); - - ndpi_int_ssh_add_connection(ndpi_struct, flow); + +#ifdef SSH_DEBUG + printf("\n[SSH] [completed stage: %u]\n", flow->l4.tcp.ssh_stage); +#endif + return; + } + } else { + u_int8_t msgcode = *(packet->payload + 5); + ndpi_MD5_CTX ctx; + +#ifdef SSH_DEBUG + printf("\n[SSH] [stage: %u][msg: %u]\n", flow->l4.tcp.ssh_stage, msgcode); +#endif + if(msgcode == 20 /* key exchange init */) { + char *hassh_buf = calloc(packet->payload_packet_len, sizeof(char)); + u_int i, len; + + if(hassh_buf) { + if(flow->l4.tcp.ssh_stage == 3) { + u_char fingerprint_client[16]; + + len = concat_hash_string(packet, hassh_buf, 1 /* client */); + + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, (const unsigned char *)hassh_buf, len); + ndpi_MD5Final(fingerprint_client, &ctx); + +#ifdef SSH_DEBUG + { + printf("\n[SSH] [client][%s][", hassh_buf); + for(i=0; i<16; i++) printf("%02X", fingerprint_client[i]); + printf("]\n"); + } +#endif + for(i=0; i<16; i++) sprintf(&flow->protos.ssh.hassh_client[i*2], "%02X", fingerprint_client[i] & 0xFF); + flow->protos.ssh.hassh_client[32] = '\0'; + } else { + u_char fingerprint_server[16]; + + len = concat_hash_string(packet, hassh_buf, 0 /* server */); + + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, (const unsigned char *)hassh_buf, len); + ndpi_MD5Final(fingerprint_server, &ctx); + +#ifdef SSH_DEBUG + { + printf("\n[SSH] [server][%s][", hassh_buf); + for(i=0; i<16; i++) printf("%02X", fingerprint_server[i]); + printf("]\n"); + } +#endif + + for(i=0; i<16; i++) sprintf(&flow->protos.ssh.hassh_server[i*2], "%02X", fingerprint_server[i] & 0xFF); + flow->protos.ssh.hassh_server[32] = '\0'; + } + + free(hassh_buf); + } } + + if(flow->l4.tcp.ssh_stage++ == 4) { + NDPI_LOG_INFO(ndpi_struct, "found ssh\n"); + ndpi_int_ssh_add_connection(ndpi_struct, flow); + } + + return; } NDPI_LOG_DBG(ndpi_struct, "excluding ssh at stage %d\n", flow->l4.tcp.ssh_stage); NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_SSH); } +/* ************************************************************************ */ void init_ssh_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index d2aa5f1a9..d9b7b0962 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -26,6 +26,7 @@ #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_TLS #include "ndpi_api.h" +#include "ndpi_md5.h" // #define DEBUG_TLS 1 @@ -37,202 +38,6 @@ extern u_int8_t is_skype_flow(struct ndpi_detection_module_struct *ndpi_struct, /* **************************************** */ -typedef struct MD5Context { - uint32_t buf[4]; - uint32_t bits[2]; - unsigned char in[64]; -} MD5_CTX; - -/* **************************************** */ - -static int is_big_endian(void) { - static const int n = 1; - return ((char *) &n)[0] == 0; -} - -static void byteReverse(unsigned char *buf, unsigned longs) { - // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN - if (is_big_endian()) { - do { - uint32_t t; - - t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - * (uint32_t *) buf = t; - buf += 4; - } while (--longs); - } -} - -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious -// initialization constants. -static void MD5Init(MD5_CTX *ctx) { - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { - uint32_t a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) { - uint32_t t; - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) - ctx->bits[1]++; - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += t; - len -= t; - } - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += 64; - len -= 64; - } - - memcpy(ctx->in, buf, len); -} - -static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) { - unsigned count; - unsigned char *p; - uint32_t *c = (uint32_t*)ctx->in; - - count = (ctx->bits[0] >> 3) & 0x3F; - - p = ctx->in + count; - *p++ = 0x80; - count = 64 - 1 - count; - if (count < 8) { - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - memset(ctx->in, 0, 56); - } else { - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - c[14] = ctx->bits[0]; - c[15] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset((char *) ctx, 0, sizeof(*ctx)); -} - -/* **************************************** */ - static u_int32_t ndpi_tls_refine_master_protocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, u_int32_t protocol) { struct ndpi_packet_struct *packet = &flow->packet; @@ -375,7 +180,7 @@ int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct, u_int8_t invalid_ja3 = 0; u_int16_t pkt_tls_version = (packet->payload[1] << 8) + packet->payload[2], ja3_str_len; char ja3_str[JA3_STR_LEN]; - MD5_CTX ctx; + ndpi_MD5_CTX ctx; u_char md5_hash[16]; if(packet->udp) { @@ -521,9 +326,9 @@ int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct, printf("[JA3] Server: %s \n", ja3_str); #endif - MD5Init(&ctx); - MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); - MD5Final(md5_hash, &ctx); + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); + ndpi_MD5Final(md5_hash, &ctx); for(i=0, j=0; i<16; i++) j += snprintf(&flow->protos.stun_ssl.ssl.ja3_server[j], @@ -834,14 +639,15 @@ int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct, #ifdef DEBUG_TLS printf("[JA3] Client: %s \n", ja3_str); #endif - - MD5Init(&ctx); - MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); - MD5Final(md5_hash, &ctx); + + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); + ndpi_MD5Final(md5_hash, &ctx); for(i=0, j=0; i<16; i++) j += snprintf(&flow->protos.stun_ssl.ssl.ja3_client[j], - sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x", md5_hash[i]); + sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x", + md5_hash[i]); #ifdef DEBUG_TLS printf("[JA3] Client: %s \n", flow->protos.stun_ssl.ssl.ja3_client); diff --git a/src/lib/third_party/include/ndpi_md5.h b/src/lib/third_party/include/ndpi_md5.h new file mode 100644 index 000000000..f7dd9b946 --- /dev/null +++ b/src/lib/third_party/include/ndpi_md5.h @@ -0,0 +1,18 @@ +/* + Contributed code pasted here to make nDPI self-contained with no + external dependencies +*/ + +/* **************************************** */ + +typedef struct ndpi_MD5Context { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +} ndpi_MD5_CTX; + +/* **************************************** */ + +extern void ndpi_MD5Init(ndpi_MD5_CTX *ctx); +extern void ndpi_MD5Update(ndpi_MD5_CTX *ctx, unsigned char const *buf, unsigned len); +extern void ndpi_MD5Final(unsigned char digest[16], ndpi_MD5_CTX *ctx); diff --git a/src/lib/third_party/src/ndpi_md5.c b/src/lib/third_party/src/ndpi_md5.c new file mode 100644 index 000000000..fefe9d65f --- /dev/null +++ b/src/lib/third_party/src/ndpi_md5.c @@ -0,0 +1,204 @@ +/* + Contributed code pasted here to make nDPI self-contained with no + external dependencies +*/ + +#include "ndpi_api.h" +#include "ndpi_md5.h" + +/* **************************************** */ + +static int is_big_endian(void) { + static const int n = 1; + return ((char *) &n)[0] == 0; +} + +static void byte_reverse(unsigned char *buf, unsigned longs) { + // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN + if (is_big_endian()) { + do { + u_int32_t t; + + t = (u_int32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + * (u_int32_t *) buf = t; + buf += 4; + } while (--longs); + } +} + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* **************************************** */ + +// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious +// initialization constants. +void ndpi_MD5Init(ndpi_MD5_CTX *ctx) { + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* **************************************** */ + +static void MD5Transform(u_int32_t buf[4], u_int32_t const in[16]) { + u_int32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* **************************************** */ + +void ndpi_MD5Update(ndpi_MD5_CTX *ctx, unsigned char const *buf, unsigned len) { + u_int32_t t; + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u_int32_t) len << 3)) < t) + ctx->bits[1]++; + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byte_reverse(ctx->in, 16); + MD5Transform(ctx->buf, (u_int32_t *) ctx->in); + buf += t; + len -= t; + } + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byte_reverse(ctx->in, 16); + MD5Transform(ctx->buf, (u_int32_t *) ctx->in); + buf += 64; + len -= 64; + } + + memcpy(ctx->in, buf, len); +} + +/* **************************************** */ + +void ndpi_MD5Final(unsigned char digest[16], ndpi_MD5_CTX *ctx) { + unsigned count; + unsigned char *p; + u_int32_t *c = (u_int32_t*)ctx->in; + + count = (ctx->bits[0] >> 3) & 0x3F; + + p = ctx->in + count; + *p++ = 0x80; + count = 64 - 1 - count; + if (count < 8) { + memset(p, 0, count); + byte_reverse(ctx->in, 16); + MD5Transform(ctx->buf, (u_int32_t *) ctx->in); + memset(ctx->in, 0, 56); + } else { + memset(p, 0, count - 8); + } + byte_reverse(ctx->in, 14); + + c[14] = ctx->bits[0]; + c[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (u_int32_t *) ctx->in); + byte_reverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset((char *) ctx, 0, sizeof(*ctx)); +} + |