diff --git a/include/header_encryption.h b/include/header_encryption.h index b84554a..0e8a708 100644 --- a/include/header_encryption.h +++ b/include/header_encryption.h @@ -18,8 +18,8 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, - char * community_name, he_context_t * ctx); - + char * community_name, he_context_t * ctx, + he_context_t * ctx_iv, uint16_t * checksum); int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx, he_context_t * ctx_iv, uint16_t checksum); diff --git a/src/edge_utils.c b/src/edge_utils.c index 825962c..e65b7df 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -1594,11 +1594,18 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { traceEvent(TRACE_DEBUG, "### Rx N2N UDP (%d) from %s", (signed int)recvlen, sock_to_cstr(sockbuf1, &sender)); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) - if( packet_header_decrypt (udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx) == 0) { + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + uint16_t checksum = 0; + if( packet_header_decrypt (udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, &checksum) == 0) { traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header."); return; } + if (checksum != pearson_hash_16 (udp_buf, recvlen)) { + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to checksum error."); + return; + } + } /* hexdump(udp_buf, recvlen); */ diff --git a/src/header_encryption.c b/src/header_encryption.c index 7bd9ae4..d7b1616 100644 --- a/src/header_encryption.c +++ b/src/header_encryption.c @@ -24,7 +24,8 @@ /* ********************************************************************** */ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, - char * community_name, he_context_t * ctx) { + char * community_name, he_context_t * ctx, + he_context_t * ctx_iv, uint16_t * checksum) { // assemble IV // the last four are ASCII "n2n!" and do not get overwritten @@ -34,6 +35,10 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, // to full 128 bit IV memcpy (iv, packet, 12); + // extract checksum (last 16 bit) blended in IV + speck_he_iv_decrypt (packet, (speck_context_t*)ctx_iv); + *checksum = be16toh (((uint16_t*)packet)[5]); + // try community name as possible key and check for magic bytes uint32_t magic = 0x6E326E00; // ="n2n_" uint32_t test_magic; diff --git a/src/sn.c b/src/sn.c index a7f508e..608a31c 100644 --- a/src/sn.c +++ b/src/sn.c @@ -491,7 +491,13 @@ static int process_udp(n2n_sn_t * sss, /* skip the definitely unencrypted communities */ if (comm->header_encryption == HEADER_ENCRYPTION_NONE) continue; - if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx)) ) { + uint16_t checksum = 0; + if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx, + comm->header_iv_ctx, &checksum)) ) { + if (checksum != pearson_hash_16 (udp_buf, udp_size)) { + traceEvent(TRACE_DEBUG, "process_udp dropped packet due to checksum error."); + return -1; + } if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) { traceEvent (TRACE_INFO, "process_udp locked community '%s' to using " "encrypted headers.", comm->community); @@ -650,7 +656,7 @@ static int process_udp(n2n_sn_t * sss, /* Re-encode the header. */ encode_REGISTER(encbuf, &encx, &cmn2, ®); -// !!! does this ever happen? does REGISTER ever come with a payload ??? !!! + /* Copy the original payload unchanged */ encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); } else { diff --git a/src/sn_utils.c b/src/sn_utils.c index fc7ba03..c732f40 100644 --- a/src/sn_utils.c +++ b/src/sn_utils.c @@ -417,7 +417,13 @@ static int process_udp(n2n_sn_t * sss, /* skip the definitely unencrypted communities */ if (comm->header_encryption == HEADER_ENCRYPTION_NONE) continue; - if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx)) ) { + uint16_t checksum = 0; + if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx, + comm->header_iv_ctx, &checksum)) ) { + if (checksum != pearson_hash_16 (udp_buf, udp_size)) { + traceEvent(TRACE_DEBUG, "process_udp dropped packet due to checksum error."); + return -1; + } if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) { traceEvent (TRACE_INFO, "process_udp locked community '%s' to using " "encrypted headers.", comm->community); @@ -577,7 +583,7 @@ static int process_udp(n2n_sn_t * sss, /* Re-encode the header. */ encode_REGISTER(encbuf, &encx, &cmn2, ®); -// !!! does this ever happen? does REGISTER ever come with a payload ??? !!! + /* Copy the original payload unchanged */ encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); } else {