diff options
author | Luca Deri <deri@ntop.org> | 2023-12-22 20:39:44 +0100 |
---|---|---|
committer | Luca Deri <deri@ntop.org> | 2023-12-22 20:40:42 +0100 |
commit | 8285fffdaeda5d2405360719a57f817b4772e6d1 (patch) | |
tree | 293b33f5c1264f9038988aae9b33e1f0ac7a388c /src | |
parent | b90c18e9069cd5b3cfcda718263b910e949d8b57 (diff) |
Implements JA4 Support (#2191)
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_typedefs.h | 2 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 486 | ||||
-rw-r--r-- | src/lib/third_party/include/ndpi_sha256.h | 35 | ||||
-rw-r--r-- | src/lib/third_party/src/ndpi_sha256.c | 160 |
4 files changed, 517 insertions, 166 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 41e1beb2d..077e6fd92 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1292,7 +1292,7 @@ struct ndpi_flow_struct { struct { char *server_names, *advertised_alpns, *negotiated_alpn, *tls_supported_versions, *issuerDN, *subjectDN; u_int32_t notBefore, notAfter; - char ja3_client[33], ja3_server[33]; + char ja3_client[33], ja3_server[33], ja4_client[37]; u_int16_t server_cipher; u_int8_t sha1_certificate_fingerprint[20]; u_int8_t hello_processed:1, ch_direction:1, subprotocol_detected:1, fingerprint_set:1, _pad:4; diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 11caaae8a..8949e22e5 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -25,6 +25,7 @@ #include "ndpi_api.h" #include "ndpi_md5.h" #include "ndpi_sha1.h" +#include "ndpi_sha256.h" #include "ndpi_encryption.h" #include "ndpi_private.h" @@ -55,23 +56,25 @@ static void ndpi_search_tls_wrapper(struct ndpi_detection_module_struct *ndpi_st */ #define JA_STR_LEN 1024 -#define MAX_NUM_JA 512 +#define MAX_NUM_JA 128 #define MAX_JA_STRLEN 256 union ja_info { struct { u_int16_t tls_handshake_version; - u_int16_t num_cipher, cipher[MAX_NUM_JA]; - u_int16_t num_tls_extension, tls_extension[MAX_NUM_JA]; + u_int16_t num_ciphers, cipher[MAX_NUM_JA]; + u_int16_t num_tls_extensions, tls_extension[MAX_NUM_JA]; u_int16_t num_elliptic_curve, elliptic_curve[MAX_NUM_JA]; u_int16_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA]; - char signature_algorithms[MAX_JA_STRLEN], supported_versions[MAX_JA_STRLEN], alpn[MAX_JA_STRLEN]; + u_int16_t num_signature_algorithms, signature_algorithms[MAX_NUM_JA]; + u_int16_t num_supported_versions, supported_versions[MAX_NUM_JA]; + char signature_algorithms_str[MAX_JA_STRLEN], alpn[MAX_JA_STRLEN]; } client; - + struct { u_int16_t tls_handshake_version; - u_int16_t num_cipher, cipher[MAX_NUM_JA]; - u_int16_t num_tls_extension, tls_extension[MAX_NUM_JA]; + u_int16_t num_ciphers, cipher[MAX_NUM_JA]; + u_int16_t num_tls_extensions, tls_extension[MAX_NUM_JA]; u_int16_t tls_supported_version; u_int16_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA]; char alpn[MAX_JA_STRLEN]; @@ -521,16 +524,16 @@ void processCertificateElements(struct ndpi_detection_module_struct *ndpi_struct if(flow->protos.tls_quic.notBefore > TLS_LIMIT_DATE) if((flow->protos.tls_quic.notAfter-flow->protos.tls_quic.notBefore) > TLS_THRESHOLD) { char str[64]; - + snprintf(str, sizeof(str), "TLS Cert lasts %u days", (flow->protos.tls_quic.notAfter-flow->protos.tls_quic.notBefore) / 86400); ndpi_set_risk(ndpi_struct, flow, NDPI_TLS_CERT_VALIDITY_TOO_LONG, str); /* Certificate validity longer than 13 months */ } - + if((time_sec < flow->protos.tls_quic.notBefore) || (time_sec > flow->protos.tls_quic.notAfter)) { char str[96], b[32], e[32]; - struct tm result; + struct tm result; time_t theTime; theTime = flow->protos.tls_quic.notBefore; @@ -538,13 +541,13 @@ void processCertificateElements(struct ndpi_detection_module_struct *ndpi_struct theTime = flow->protos.tls_quic.notAfter; strftime(e, sizeof(e), "%d/%b/%Y %H:%M:%S", ndpi_gmtime_r(&theTime, &result)); - + snprintf(str, sizeof(str), "%s - %s", b, e); ndpi_set_risk(ndpi_struct, flow, NDPI_TLS_CERTIFICATE_EXPIRED, str); /* Certificate expired */ } else if((time_sec > flow->protos.tls_quic.notBefore) && (time_sec > (flow->protos.tls_quic.notAfter - (ndpi_struct->tls_certificate_expire_in_x_days * 86400)))) { char str[96], b[32], e[32]; - struct tm result; + struct tm result; time_t theTime; theTime = flow->protos.tls_quic.notBefore; @@ -750,10 +753,10 @@ void processCertificateElements(struct ndpi_detection_module_struct *ndpi_struct /* Last resort: we check if this is a trusted issuerDN */ if(ndpi_check_issuerdn_risk_exception(ndpi_struct, flow->protos.tls_quic.issuerDN)) return; /* This is a trusted DN */ - + ndpi_set_risk(ndpi_struct, flow, NDPI_TLS_SELFSIGNED_CERTIFICATE, flow->protos.tls_quic.subjectDN); } - + #if DEBUG_TLS printf("[TLS] %s() SubjectDN [%s]\n", __FUNCTION__, rdnSeqBuf); #endif @@ -1122,10 +1125,10 @@ static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct, /* Use positive values for c->s e negative for s->c */ if(packet->packet_direction != 0) blen = -blen; - + flow->l4.tcp.tls.tls_application_blocks_len[flow->l4.tcp.tls.num_tls_blocks++] = blen; } - + #ifdef DEBUG_TLS_BLOCKS printf("*** [TLS Block] [len: %u][num_tls_blocks: %u/%u]\n", len-5, flow->l4.tcp.tls.num_tls_blocks, ndpi_struct->num_tls_blocks_to_follow); @@ -1455,7 +1458,7 @@ static void tlsCheckUncommonALPN(struct ndpi_detection_module_struct *ndpi_struc if(!is_a_common_alpn(ndpi_struct, alpn_start, alpn_len)) { char str[64]; size_t str_len; - + #ifdef DEBUG_TLS printf("TLS uncommon ALPN found: %.*s\n", (int)alpn_len, alpn_start); #endif @@ -1520,17 +1523,17 @@ static void checkExtensions(struct ndpi_detection_module_struct *ndpi_struct, /* see: https://www.wireshark.org/docs/wsar_html/packet-tls-utils_8h_source.html */ static u_int16_t const allowed_non_iana_extensions[] = { 65486 /* ESNI */, 13172 /* NPN - Next Proto Neg */, 17513 /* ALPS */, - 30032 /* Channel ID */, 65445 /* QUIC transport params */, - /* GREASE extensions */ - 2570, 6682, 10794, 14906, 19018, 23130, 27242, - 31354, 35466, 39578, 43690, 47802, 51914, 56026, - 60138, 64250, - /* Groups */ - 1035, 10794, 16696, 23130, 31354, 35466, 51914, - /* Ciphers */ - 102, 129, 52243, 52244, 57363, 65279, 65413, - /* ECH */ - 65037 + 30032 /* Channel ID */, 65445 /* QUIC transport params */, + /* GREASE extensions */ + 2570, 6682, 10794, 14906, 19018, 23130, 27242, + 31354, 35466, 39578, 43690, 47802, 51914, 56026, + 60138, 64250, + /* Groups */ + 1035, 10794, 16696, 23130, 31354, 35466, 51914, + /* Ciphers */ + 102, 129, 52243, 52244, 57363, 65279, 65413, + /* ECH */ + 65037 }; size_t const allowed_non_iana_extensions_size = sizeof(allowed_non_iana_extensions) / sizeof(allowed_non_iana_extensions[0]); @@ -1547,7 +1550,7 @@ static void checkExtensions(struct ndpi_detection_module_struct *ndpi_struct, break; } } - + if(extension_found == 0) { char str[64]; @@ -1566,9 +1569,9 @@ static void checkExtensions(struct ndpi_detection_module_struct *ndpi_struct, if(extension_id == 53 || extension_id == 54) { char str[64]; - + snprintf(str, sizeof(str), "Extn id %u", extension_id); - + #ifdef DEBUG_TLS printf("[TLS] suspicious DTLS-only extension id: %u\n", extension_id); #endif @@ -1590,29 +1593,178 @@ static int check_sni_is_numeric_ip(char *sni) { return 0; } +/* **************************************** */ + +static int u_int16_t_cmpfunc(const void * a, const void * b) { return(*(u_int16_t*)a - *(u_int16_t*)b); } + +/* **************************************** */ + +static void ndpi_compute_ja4(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + u_int32_t quic_version, + union ja_info *ja) { + BYTE tmp_str[JA_STR_LEN]; + u_int tmp_str_len, num_extn; + SHA256_CTX sha_ctx; + BYTE sha_hash[SHA256_BLOCK_SIZE]; + char ja_str[JA_STR_LEN]; + u_int16_t ja_str_len, i; + int rc; + u_int16_t tls_handshake_version = ja->client.tls_handshake_version; + + /* + Compute JA4 TLS/QUIC client + + https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md + + (QUIC=”q” or TCP=”t”) + (2 character TLS version) + (SNI=”d” or no SNI=”i”) + (2 character count of ciphers) + (2 character count of extensions) + (first and last characters of first ALPN extension value) + _ + (sha256 hash of the list of cipher hex codes sorted in hex order, truncated to 12 characters) + _ + (sha256 hash of (the list of extension hex codes sorted in hex order)_(the list of signature algorithms), truncated to 12 characters) + */ + ja_str[0] = (quic_version != 0) ? 'q' : 't'; + + for(i=0; i<ja->client.num_supported_versions; i++) { + if((ja->client.supported_versions[i] != 0x0A0A /* GREASE */) + && (tls_handshake_version < ja->client.supported_versions[i])) + tls_handshake_version = ja->client.supported_versions[i]; + } + + switch(tls_handshake_version) { + case 0x0304: /* TLS 1.3 = “13” */ + ja_str[1] = '1', ja_str[2] = '3'; + break; + + case 0x0303: /* TLS 1.2 = “12” */ + ja_str[1] = '1', ja_str[2] = '2'; + break; + + case 0x0302: /* TLS 1.1 = “11” */ + ja_str[1] = '1', ja_str[2] = '1'; + break; + + case 0x0301: /* TLS 1.0 = “10” */ + ja_str[1] = '1', ja_str[2] = '0'; + break; + + case 0x0300: /* SSL 3.0 = “s3” */ + ja_str[1] = 's', ja_str[2] = '3'; + break; + + case 0x0200: /* SSL 2.0 = “s2” */ + ja_str[1] = 's', ja_str[2] = '2'; + break; + + case 0x0100: /* SSL 1.0 = “s1” */ + ja_str[1] = 's', ja_str[2] = '3'; + break; + + default: + ja_str[1] = '0', ja_str[2] = '0'; + break; + } + + ja_str[3] = ndpi_isset_risk(ndpi_struct, flow, NDPI_NUMERIC_IP_HOST) ? 'i' : 'd', ja_str_len = 4; + + /* JA4_a */ + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, "%02u%02u%c%c_", + ja->client.num_ciphers, ja->client.num_tls_extensions, + (ja->client.alpn[0] == '\0') ? '0' : ja->client.alpn[0], + (ja->client.alpn[0] == '\0') ? '0' : ja->client.alpn[1]); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; + + /* Sort ciphers and extensions */ + qsort(&ja->client.cipher, ja->client.num_ciphers, sizeof(u_int16_t), u_int16_t_cmpfunc); + qsort(&ja->client.tls_extension, ja->client.num_tls_extensions, sizeof(u_int16_t), u_int16_t_cmpfunc); + + tmp_str_len = 0; + for(i=0; i<ja->client.num_ciphers; i++) { + rc = ndpi_snprintf((char *)&tmp_str[tmp_str_len], JA_STR_LEN-tmp_str_len, "%s%04x", + (i > 0) ? "," : "", ja->client.cipher[i]); + if((rc > 0) && (tmp_str_len + rc < JA_STR_LEN)) tmp_str_len += rc; else break; + } + + ndpi_sha256_init(&sha_ctx); + ndpi_sha256_update(&sha_ctx, tmp_str, tmp_str_len); + ndpi_sha256_final(&sha_ctx, sha_hash); + + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, + "%02x%02x%02x%02x%02x%02x_", + sha_hash[0], sha_hash[1], sha_hash[2], + sha_hash[3], sha_hash[4], sha_hash[5]); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; + +#ifdef DEBUG_JA + printf("[CIPHER] %s [len: %u]\n", tmp_str, tmp_str_len); +#endif + + tmp_str_len = 0; + for(i=0, num_extn = 0; i<ja->client.num_tls_extensions; i++) { + if((ja->client.tls_extension[i] > 0) && (ja->client.tls_extension[i] != 0x10 /* ALPN extension */)) { + rc = ndpi_snprintf((char *)&tmp_str[tmp_str_len], JA_STR_LEN-tmp_str_len, "%s%04x", + (num_extn > 0) ? "," : "", ja->client.tls_extension[i]); + if((rc > 0) && (tmp_str_len + rc < JA_STR_LEN)) tmp_str_len += rc; else break; + num_extn++; + } + } + + for(i=0; i<ja->client.num_signature_algorithms; i++) { + rc = ndpi_snprintf((char *)&tmp_str[tmp_str_len], JA_STR_LEN-tmp_str_len, "%s%04x", + (i > 0) ? "," : "_", ja->client.signature_algorithms[i]); + if((rc > 0) && (tmp_str_len + rc < JA_STR_LEN)) tmp_str_len += rc; else break; + } + +#ifdef DEBUG_JA + printf("[EXTN] %s [len: %u]\n", tmp_str, tmp_str_len); +#endif + + ndpi_sha256_init(&sha_ctx); + ndpi_sha256_update(&sha_ctx, tmp_str, tmp_str_len); + ndpi_sha256_final(&sha_ctx, sha_hash); + + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, + "%02x%02x%02x%02x%02x%02x", + sha_hash[0], sha_hash[1], sha_hash[2], + sha_hash[3], sha_hash[4], sha_hash[5]); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; + +#ifdef DEBUG_JA + printf("[JA4] %s [len: %lu]\n", ja_str, strlen(ja_str)); +#endif + + snprintf(flow->protos.tls_quic.ja4_client, + sizeof(flow->protos.tls_quic.ja4_client), + "%s", ja_str); + +} /* **************************************** */ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, uint32_t quic_version) { + struct ndpi_flow_struct *flow, u_int32_t quic_version) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; - union ja_info ja3; - u_int8_t invalid_ja3 = 0; - u_int16_t tls_version, ja3_str_len; - char ja3_str[JA_STR_LEN]; + union ja_info ja; + u_int8_t invalid_ja = 0; + u_int16_t tls_version, ja_str_len; + char ja_str[JA_STR_LEN]; ndpi_MD5_CTX ctx; u_char md5_hash[16]; u_int32_t i, j; u_int16_t total_len; u_int8_t handshake_type; - int is_quic = (quic_version != 0); - int is_dtls = packet->udp && (!is_quic); + bool is_quic = (quic_version != 0); + bool is_dtls = packet->udp && (!is_quic); #ifdef DEBUG_TLS printf("TLS %s() called\n", __FUNCTION__); #endif - handshake_type = packet->payload[0]; total_len = (packet->payload[1] << 16) + (packet->payload[2] << 8) + packet->payload[3]; @@ -1644,12 +1796,12 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if(handshake_type == 0x02 /* Server Hello */) { int rc; - ja3.server.num_cipher = 0; - ja3.server.num_tls_extension = 0; - ja3.server.num_elliptic_curve_point_format = 0; - ja3.server.alpn[0] = '\0'; + ja.server.num_ciphers = 0; + ja.server.num_tls_extensions = 0; + ja.server.num_elliptic_curve_point_format = 0; + ja.server.alpn[0] = '\0'; - ja3.server.tls_handshake_version = tls_version; + ja.server.tls_handshake_version = tls_version; #ifdef DEBUG_TLS printf("TLS Server Hello [version: 0x%04X]\n", tls_version); @@ -1669,19 +1821,19 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if((offset+3) > packet->payload_packet_len) return(0); /* Not found */ - ja3.server.num_cipher = 1, ja3.server.cipher[0] = ntohs(*((u_int16_t*)&packet->payload[offset])); - if((flow->protos.tls_quic.server_unsafe_cipher = ndpi_is_safe_ssl_cipher(ja3.server.cipher[0])) == 1) { + ja.server.num_ciphers = 1, ja.server.cipher[0] = ntohs(*((u_int16_t*)&packet->payload[offset])); + if((flow->protos.tls_quic.server_unsafe_cipher = ndpi_is_safe_ssl_cipher(ja.server.cipher[0])) == 1) { char str[64]; char unknown_cipher[8]; - snprintf(str, sizeof(str), "Cipher %s", ndpi_cipher2str(ja3.server.cipher[0], unknown_cipher)); + snprintf(str, sizeof(str), "Cipher %s", ndpi_cipher2str(ja.server.cipher[0], unknown_cipher)); ndpi_set_risk(ndpi_struct, flow, NDPI_TLS_WEAK_CIPHER, str); } - - flow->protos.tls_quic.server_cipher = ja3.server.cipher[0]; + + flow->protos.tls_quic.server_cipher = ja.server.cipher[0]; #ifdef DEBUG_TLS - printf("TLS [server][session_id_len: %u][cipher: %04X]\n", session_id_len, ja3.server.cipher[0]); + printf("TLS [server][session_id_len: %u][cipher: %04X]\n", session_id_len, ja.server.cipher[0]); #endif offset += 2 + 1; @@ -1708,8 +1860,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, break; } - if(ja3.server.num_tls_extension < MAX_NUM_JA) - ja3.server.tls_extension[ja3.server.num_tls_extension++] = extension_id; + if(ja.server.num_tls_extensions < MAX_NUM_JA) + ja.server.tls_extension[ja.server.num_tls_extensions++] = extension_id; #ifdef DEBUG_TLS printf("TLS [server][extension_id: %u/0x%04X][len: %u]\n", @@ -1725,7 +1877,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, printf("TLS [server] [TLS version: 0x%04X]\n", tls_version); #endif - flow->protos.tls_quic.ssl_version = ja3.server.tls_supported_version = tls_version; + flow->protos.tls_quic.ssl_version = ja.server.tls_supported_version = tls_version; } } else if(extension_id == 16 /* application_layer_protocol_negotiation (ALPN) */ && offset + 6 < packet->payload_packet_len) { @@ -1790,14 +1942,14 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, flow->protos.tls_quic.advertised_alpns == NULL) tlsCheckUncommonALPN(ndpi_struct, flow, flow->protos.tls_quic.negotiated_alpn); - alpn_str_len = ndpi_min(sizeof(ja3.server.alpn), (size_t)alpn_str_len); - memcpy(ja3.server.alpn, alpn_str, alpn_str_len); + alpn_str_len = ndpi_min(sizeof(ja.server.alpn), (size_t)alpn_str_len); + memcpy(ja.server.alpn, alpn_str, alpn_str_len); if(alpn_str_len > 0) - ja3.server.alpn[alpn_str_len - 1] = '\0'; + ja.server.alpn[alpn_str_len - 1] = '\0'; /* Replace , with - as in JA3 */ - for(i=0; ja3.server.alpn[i] != '\0'; i++) - if(ja3.server.alpn[i] == ',') ja3.server.alpn[i] = '-'; + for(i=0; ja.server.alpn[i] != '\0'; i++) + if(ja.server.alpn[i] == ',') ja.server.alpn[i] = '-'; } else if(extension_id == 11 /* ec_point_formats groups */) { u_int16_t s_offset = offset+4 + 1; @@ -1812,17 +1964,17 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, printf("Server TLS [EllipticCurveFormat: %u]\n", s_group); #endif - if(ja3.server.num_elliptic_curve_point_format < MAX_NUM_JA) - ja3.server.elliptic_curve_point_format[ja3.server.num_elliptic_curve_point_format++] = s_group; + if(ja.server.num_elliptic_curve_point_format < MAX_NUM_JA) + ja.server.elliptic_curve_point_format[ja.server.num_elliptic_curve_point_format++] = s_group; else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS - printf("Server TLS Invalid num elliptic %u\n", ja3.server.num_elliptic_curve_point_format); + printf("Server TLS Invalid num elliptic %u\n", ja.server.num_elliptic_curve_point_format); #endif } } } else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS printf("Server TLS Invalid len %u vs %u\n", s_offset+extension_len, total_len); #endif @@ -1837,33 +1989,33 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if(flow->protos.tls_quic.ssl_version == 0) flow->protos.tls_quic.ssl_version = tls_version; - ja3_str_len = ndpi_snprintf(ja3_str, JA_STR_LEN, "%u,", ja3.server.tls_handshake_version); + ja_str_len = ndpi_snprintf(ja_str, JA_STR_LEN, "%u,", ja.server.tls_handshake_version); - for(i=0; (i<ja3.server.num_cipher) && (JA_STR_LEN > ja3_str_len); i++) { - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.server.cipher[i]); + for(i=0; (i<ja.server.num_ciphers) && (JA_STR_LEN > ja_str_len); i++) { + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, "%s%u", (i > 0) ? "-" : "", ja.server.cipher[i]); - if(rc <= 0) break; else ja3_str_len += rc; + if(rc <= 0) break; else ja_str_len += rc; } - if(JA_STR_LEN > ja3_str_len) { - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, ","); - if(rc > 0 && ja3_str_len + rc < JA_STR_LEN) ja3_str_len += rc; + if(JA_STR_LEN > ja_str_len) { + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, ","); + if(rc > 0 && ja_str_len + rc < JA_STR_LEN) ja_str_len += rc; } /* ********** */ - for(i=0; (i<ja3.server.num_tls_extension) && (JA_STR_LEN > ja3_str_len); i++) { - int rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.server.tls_extension[i]); + for(i=0; (i<ja.server.num_tls_extensions) && (JA_STR_LEN > ja_str_len); i++) { + int rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, "%s%u", (i > 0) ? "-" : "", ja.server.tls_extension[i]); - if(rc <= 0) break; else ja3_str_len += rc; + if(rc <= 0) break; else ja_str_len += rc; } #ifdef DEBUG_TLS - printf("[JA3] Server: %s \n", ja3_str); + printf("[JA3] Server: %s \n", ja_str); #endif ndpi_MD5Init(&ctx); - ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); + ndpi_MD5Update(&ctx, (const unsigned char *)ja_str, strlen(ja_str)); ndpi_MD5Final(md5_hash, &ctx); for(i=0, j=0; i<16; i++) { @@ -1879,25 +2031,26 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t cipher_len, cipher_offset; u_int8_t cookie_len = 0; - ja3.client.num_cipher = 0; - ja3.client.num_tls_extension = 0; - ja3.client.num_elliptic_curve = 0; - ja3.client.num_elliptic_curve_point_format = 0; - ja3.client.signature_algorithms[0] = '\0'; - ja3.client.supported_versions[0] = '\0'; - ja3.client.alpn[0] = '\0'; + ja.client.num_ciphers = 0; + ja.client.num_tls_extensions = 0; + ja.client.num_elliptic_curve = 0; + ja.client.num_elliptic_curve_point_format = 0; + ja.client.num_signature_algorithms = 0; + ja.client.num_supported_versions = 0; + ja.client.signature_algorithms_str[0] = '\0'; + ja.client.alpn[0] = '\0'; - flow->protos.tls_quic.ssl_version = ja3.client.tls_handshake_version = tls_version; + flow->protos.tls_quic.ssl_version = ja.client.tls_handshake_version = tls_version; if(flow->protos.tls_quic.ssl_version < 0x0303) /* < TLSv1.2 */ { char str[32], buf[32]; u_int8_t unknown_tls_version; - + snprintf(str, sizeof(str), "%s", ndpi_ssl_version2str(buf, sizeof(buf), flow->protos.tls_quic.ssl_version, &unknown_tls_version)); ndpi_set_risk(ndpi_struct, flow, NDPI_TLS_OBSOLETE_VERSION, str); } - + if((session_id_len+base_offset+3) > packet->payload_packet_len) return(0); /* Not found */ @@ -1938,12 +2091,12 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, printf("Client TLS [non-GREASE cipher suite: %u/0x%04X] [%d/%u]\n", cipher_id, cipher_id, i, cipher_len); #endif - if(ja3.client.num_cipher < MAX_NUM_JA) - ja3.client.cipher[ja3.client.num_cipher++] = cipher_id; + if(ja.client.num_ciphers < MAX_NUM_JA) + ja.client.cipher[ja.client.num_ciphers++] = cipher_id; else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS - printf("Client TLS Invalid cipher %u\n", ja3.client.num_cipher); + printf("Client TLS Invalid cipher %u\n", ja.client.num_ciphers); #endif } @@ -2013,7 +2166,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, this_is_not_safari); #endif } else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS printf("Client TLS Invalid len %u vs %u\n", (cipher_offset+cipher_len), total_len); #endif @@ -2078,12 +2231,12 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, ((packet->payload[extn_off] & 0xF) != 0xA)) { /* Skip GREASE */ - if(ja3.client.num_tls_extension < MAX_NUM_JA) - ja3.client.tls_extension[ja3.client.num_tls_extension++] = extension_id; + if(ja.client.num_tls_extensions < MAX_NUM_JA) + ja.client.tls_extension[ja.client.num_tls_extensions++] = extension_id; else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS - printf("Client TLS Invalid extensions %u\n", ja3.client.num_tls_extension); + printf("Client TLS Invalid extensions %u\n", ja.client.num_tls_extensions); #endif } } @@ -2105,11 +2258,11 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, #endif if(ndpi_is_valid_hostname(sni, sni_len) == 0) { ndpi_set_risk(ndpi_struct, flow, NDPI_INVALID_CHARACTERS, sni); - + /* This looks like an attack */ ndpi_set_risk(ndpi_struct, flow, NDPI_POSSIBLE_EXPLOIT, NULL); } - + if(!is_quic) { if(ndpi_match_hostname_protocol(ndpi_struct, flow, __get_master(ndpi_struct, flow), sni, sni_len)) flow->protos.tls_quic.subprotocol_detected = 1; @@ -2118,13 +2271,12 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, flow->protos.tls_quic.subprotocol_detected = 1; } - if(flow->protos.tls_quic.subprotocol_detected == 0 && - check_sni_is_numeric_ip(sni) == 1) { + if((flow->protos.tls_quic.subprotocol_detected == 0) + && (check_sni_is_numeric_ip(sni) == 1)) { ndpi_set_risk(ndpi_struct, flow, NDPI_NUMERIC_IP_HOST, sni); } - if(ndpi_check_dga_name(ndpi_struct, flow, - sni, 1, 0)) { + if(ndpi_check_dga_name(ndpi_struct, flow, sni, 1, 0)) { #ifdef DEBUG_TLS printf("[TLS] SNI: (DGA) [%s]\n", sni); #endif @@ -2164,18 +2316,18 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if((s_group == 0) || (packet->payload[s_offset+i] != packet->payload[s_offset+i+1]) || ((packet->payload[s_offset+i] & 0xF) != 0xA)) { /* Skip GREASE */ - if(ja3.client.num_elliptic_curve < MAX_NUM_JA) - ja3.client.elliptic_curve[ja3.client.num_elliptic_curve++] = s_group; + if(ja.client.num_elliptic_curve < MAX_NUM_JA) + ja.client.elliptic_curve[ja.client.num_elliptic_curve++] = s_group; else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS - printf("Client TLS Invalid num elliptic %u\n", ja3.client.num_elliptic_curve); + printf("Client TLS Invalid num elliptic %u\n", ja.client.num_elliptic_curve); #endif } } } } else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS printf("Client TLS Invalid len %u vs %u\n", (s_offset+extension_len-1), total_len); #endif @@ -2194,25 +2346,25 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, printf("Client TLS [EllipticCurveFormat: %u]\n", s_group); #endif - if(ja3.client.num_elliptic_curve_point_format < MAX_NUM_JA) - ja3.client.elliptic_curve_point_format[ja3.client.num_elliptic_curve_point_format++] = s_group; + if(ja.client.num_elliptic_curve_point_format < MAX_NUM_JA) + ja.client.elliptic_curve_point_format[ja.client.num_elliptic_curve_point_format++] = s_group; else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS - printf("Client TLS Invalid num elliptic %u\n", ja3.client.num_elliptic_curve_point_format); + printf("Client TLS Invalid num elliptic %u\n", ja.client.num_elliptic_curve_point_format); #endif } } } else { - invalid_ja3 = 1; + invalid_ja = 1; #ifdef DEBUG_TLS printf("Client TLS Invalid len %u vs %u\n", s_offset+extension_len, total_len); #endif } } else if(extension_id == 13 /* signature algorithms */ && offset+extension_offset+1 < total_len) { - int s_offset = offset+extension_offset, safari_signature_algorithms = 0, chrome_signature_algorithms = 0, - duplicate_found = 0, last_signature = 0; + int s_offset = offset+extension_offset, safari_signature_algorithms = 0, + chrome_signature_algorithms = 0, duplicate_found = 0, last_signature = 0, id; u_int16_t tot_signature_algorithms_len = ntohs(*((u_int16_t*)&packet->payload[s_offset])); #ifdef DEBUG_TLS @@ -2220,20 +2372,25 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, #endif s_offset += 2; - tot_signature_algorithms_len = ndpi_min((sizeof(ja3.client.signature_algorithms) / 2) - 1, tot_signature_algorithms_len); + tot_signature_algorithms_len = ndpi_min((sizeof(ja.client.signature_algorithms_str) / 2) - 1, tot_signature_algorithms_len); -#ifdef TLS_HANDLE_SIGNATURE_ALGORITMS - size_t size = ndpi_min(tot_signature_algorithms_len / 2, MAX_NUM_TLS_SIGNATURE_ALGORITHMS); + size_t sa_size = ndpi_min(tot_signature_algorithms_len / 2, MAX_NUM_TLS_SIGNATURE_ALGORITHMS); - if (s_offset + 2 * size <= packet->payload_packet_len) { - flow->protos.tls_quic.num_tls_signature_algorithms = size; - memcpy(flow->protos.tls_quic.client_signature_algorithms, - &packet->payload[s_offset], 2 /* 16 bit */ * size); +#ifdef TLS_HANDLE_SIGNATURE_ALGORITMS + if (s_offset + 2 * sa_size <= packet->payload_packet_len) { + flow->protos.tls_quic.num_tls_signature_algorithms = sa_size; + memcpy(flow->protos.tls_quic.client_signature_algorithms, + &packet->payload[s_offset], 2 /* 16 bit */ * sa_size); } #endif - for(i=0; i<tot_signature_algorithms_len && s_offset+i<total_len; i++) { - int rc = ndpi_snprintf(&ja3.client.signature_algorithms[i*2], sizeof(ja3.client.signature_algorithms)-i*2, "%02X", packet->payload[s_offset+i]); + ja.client.num_signature_algorithms = ndpi_min(sa_size, MAX_NUM_JA); + + for(i=0, id=0; i<tot_signature_algorithms_len && s_offset+i<total_len; i++) { + int rc = ndpi_snprintf(&ja.client.signature_algorithms_str[i*2], + sizeof(ja.client.signature_algorithms_str)-i*2, + "%02X", packet->payload[s_offset+i]); + ja.client.signature_algorithms[id++] = ntohs(*(u_int16_t*)&packet->payload[s_offset+i*2]); if(rc < 0) break; } @@ -2329,13 +2486,13 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, #endif if(i > 0 && i >= tot_signature_algorithms_len) { - ja3.client.signature_algorithms[i*2 - 1] = '\0'; + ja.client.signature_algorithms_str[i*2 - 1] = '\0'; } else { - ja3.client.signature_algorithms[i*2] = '\0'; + ja.client.signature_algorithms_str[i*2] = '\0'; } #ifdef DEBUG_TLS - printf("Client TLS [SIGNATURE_ALGORITHMS: %s]\n", ja3.client.signature_algorithms); + printf("Client TLS [SIGNATURE_ALGORITHMS: %s]\n", ja.client.signature_algorithms_str); #endif } else if(extension_id == 16 /* application_layer_protocol_negotiation */ && offset+extension_offset+1 < total_len) { @@ -2393,14 +2550,14 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, } } - alpn_str_len = ndpi_min(sizeof(ja3.client.alpn), (size_t)alpn_str_len); - memcpy(ja3.client.alpn, alpn_str, alpn_str_len); + alpn_str_len = ndpi_min(sizeof(ja.client.alpn), (size_t)alpn_str_len); + memcpy(ja.client.alpn, alpn_str, alpn_str_len); if(alpn_str_len > 0) - ja3.client.alpn[alpn_str_len - 1] = '\0'; + ja.client.alpn[alpn_str_len - 1] = '\0'; /* Replace , with - as in JA3 */ - for(i=0; ja3.client.alpn[i] != '\0'; i++) - if(ja3.client.alpn[i] == ',') ja3.client.alpn[i] = '-'; + for(i=0; ja.client.alpn[i] != '\0'; i++) + if(ja.client.alpn[i] == ',') ja.client.alpn[i] = '-'; } else if(extension_id == 43 /* supported versions */ && offset+extension_offset < total_len) { @@ -2416,7 +2573,6 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if(version_len == (extension_len-1)) { u_int8_t j; - u_int16_t supported_versions_offset = 0; s_offset++; @@ -2440,17 +2596,13 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, else version_str_len += rc; - rc = ndpi_snprintf(&ja3.client.supported_versions[supported_versions_offset], - sizeof(ja3.client.supported_versions)-supported_versions_offset, - "%s%04X", (j > 0) ? "-" : "", tls_version); - - if(rc > 0) - supported_versions_offset += rc; + if(ja.client.num_supported_versions < MAX_NUM_JA) + ja.client.supported_versions[ja.client.num_supported_versions++] = tls_version; } } #ifdef DEBUG_TLS - printf("Client TLS [SUPPORTED_VERSIONS: %s]\n", ja3.client.supported_versions); + printf("Client TLS [SUPPORTED_VERSIONS: %s]\n", ja.client.supported_versions_str); #endif if(flow->protos.tls_quic.tls_supported_versions == NULL) @@ -2583,51 +2735,52 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, #endif } /* while */ - if(!invalid_ja3) { + if(!invalid_ja) { + /* Compute JA3 client */ int rc; compute_ja3c: - ja3_str_len = ndpi_snprintf(ja3_str, JA_STR_LEN, "%u,", ja3.client.tls_handshake_version); + ja_str_len = ndpi_snprintf(ja_str, JA_STR_LEN, "%u,", ja.client.tls_handshake_version); - for(i=0; i<ja3.client.num_cipher; i++) { - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, "%s%u", - (i > 0) ? "-" : "", ja3.client.cipher[i]); - if((rc > 0) && (ja3_str_len + rc < JA_STR_LEN)) ja3_str_len += rc; else break; + for(i=0; i<ja.client.num_ciphers; i++) { + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, "%s%u", + (i > 0) ? "-" : "", ja.client.cipher[i]); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; else break; } - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, ","); - if((rc > 0) && (ja3_str_len + rc < JA_STR_LEN)) ja3_str_len += rc; + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, ","); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; /* ********** */ - for(i=0; i<ja3.client.num_tls_extension; i++) { - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, "%s%u", - (i > 0) ? "-" : "", ja3.client.tls_extension[i]); - if((rc > 0) && (ja3_str_len + rc < JA_STR_LEN)) ja3_str_len += rc; else break; + for(i=0; i<ja.client.num_tls_extensions; i++) { + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, "%s%u", + (i > 0) ? "-" : "", ja.client.tls_extension[i]); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; else break; } - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, ","); - if((rc > 0) && (ja3_str_len + rc < JA_STR_LEN)) ja3_str_len += rc; + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, ","); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; /* ********** */ - for(i=0; i<ja3.client.num_elliptic_curve; i++) { - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, "%s%u", - (i > 0) ? "-" : "", ja3.client.elliptic_curve[i]); - if((rc > 0) && (ja3_str_len + rc < JA_STR_LEN)) ja3_str_len += rc; else break; + for(i=0; i<ja.client.num_elliptic_curve; i++) { + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, "%s%u", + (i > 0) ? "-" : "", ja.client.elliptic_curve[i]); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; else break; } - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, ","); - if((rc > 0) && (ja3_str_len + rc < JA_STR_LEN)) ja3_str_len += rc; + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, ","); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; - for(i=0; i<ja3.client.num_elliptic_curve_point_format; i++) { - rc = ndpi_snprintf(&ja3_str[ja3_str_len], JA_STR_LEN-ja3_str_len, "%s%u", - (i > 0) ? "-" : "", ja3.client.elliptic_curve_point_format[i]); - if((rc > 0) && (ja3_str_len + rc < JA_STR_LEN)) ja3_str_len += rc; else break; + for(i=0; i<ja.client.num_elliptic_curve_point_format; i++) { + rc = ndpi_snprintf(&ja_str[ja_str_len], JA_STR_LEN-ja_str_len, "%s%u", + (i > 0) ? "-" : "", ja.client.elliptic_curve_point_format[i]); + if((rc > 0) && (ja_str_len + rc < JA_STR_LEN)) ja_str_len += rc; else break; } ndpi_MD5Init(&ctx); - ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); + ndpi_MD5Update(&ctx, (const unsigned char *)ja_str, strlen(ja_str)); ndpi_MD5Final(md5_hash, &ctx); for(i=0, j=0; i<16; i++) { @@ -2650,6 +2803,9 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if(rc1 == 0) ndpi_set_risk(ndpi_struct, flow, NDPI_MALICIOUS_JA3, flow->protos.tls_quic.ja3_client); } + + ndpi_compute_ja4(ndpi_struct, flow, quic_version, &ja); + /* End JA3/JA4 */ } /* Before returning to the caller we need to make a final check */ @@ -2672,14 +2828,14 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, ) { /* This is a bit suspicious */ ndpi_set_risk(ndpi_struct, flow, NDPI_TLS_MISSING_SNI, NULL); - + if(flow->protos.tls_quic.advertised_alpns != NULL) { char buf[256], *tmp, *item; snprintf(buf, sizeof(buf), "%s", flow->protos.tls_quic.advertised_alpns); item = strtok_r(buf, ",", &tmp); - + while(item != NULL) { if(item[0] == 'h') { /* Example 'h2' */ @@ -2690,7 +2846,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, } } } - + return(2 /* Client Certificate */); } else { #ifdef DEBUG_TLS diff --git a/src/lib/third_party/include/ndpi_sha256.h b/src/lib/third_party/include/ndpi_sha256.h new file mode 100644 index 000000000..0525f3fef --- /dev/null +++ b/src/lib/third_party/include/ndpi_sha256.h @@ -0,0 +1,35 @@ +/********************************************************************* + * Filename: sha256.h + * Author: Brad Conte (brad AT bradconte.com) + * Copyright: + * Disclaimer: This code is presented "as is" without any guarantees. + * Details: Defines the API for the corresponding SHA1 implementation. + *********************************************************************/ + +#ifndef SHA256_H +#define SHA256_H + +/*************************** HEADER FILES ***************************/ +#include <stddef.h> + +/****************************** MACROS ******************************/ +#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest + +/**************************** DATA TYPES ****************************/ +typedef unsigned char BYTE; // 8-bit byte +typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines + +typedef struct { + BYTE data[64]; + WORD datalen; + unsigned long long bitlen; + WORD state[8]; +} SHA256_CTX; + +/*********************** FUNCTION DECLARATIONS **********************/ + +void ndpi_sha256_init(SHA256_CTX *ctx); +void ndpi_sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); +void ndpi_sha256_final(SHA256_CTX *ctx, BYTE hash[]); + +#endif // SHA256_H diff --git a/src/lib/third_party/src/ndpi_sha256.c b/src/lib/third_party/src/ndpi_sha256.c new file mode 100644 index 000000000..3fd920bc6 --- /dev/null +++ b/src/lib/third_party/src/ndpi_sha256.c @@ -0,0 +1,160 @@ +/* https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c */ + +/********************************************************************* + * Filename: sha256.c + * Author: Brad Conte (brad AT bradconte.com) + * Copyright: + * Disclaimer: This code is presented "as is" without any guarantees. + * Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include <stdlib.h> +#include <memory.h> +#include "ndpi_sha256.h" + +/****************************** MACROS ******************************/ +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + +/**************************** VARIABLES *****************************/ +static const WORD k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +/*********************** FUNCTION DEFINITIONS ***********************/ +void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) +{ + WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void ndpi_sha256_init(SHA256_CTX *ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void ndpi_sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) +{ + WORD i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void ndpi_sha256_final(SHA256_CTX *ctx, BYTE hash[]) +{ + WORD i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = ctx->bitlen; + ctx->data[62] = ctx->bitlen >> 8; + ctx->data[61] = ctx->bitlen >> 16; + ctx->data[60] = ctx->bitlen >> 24; + ctx->data[59] = ctx->bitlen >> 32; + ctx->data[58] = ctx->bitlen >> 40; + ctx->data[57] = ctx->bitlen >> 48; + ctx->data[56] = ctx->bitlen >> 56; + sha256_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } +} |