Add CRC32 checksums to all message

Calculate CRC32 checksum of the whole ZRTP packet and add it at the
end of packet and verify the checksum when a packet is received.
If the verification fails, the packet is simply discarded
This commit is contained in:
Aaro Altonen 2020-02-02 08:22:58 +02:00
parent f62784cf27
commit ca669fc1b5
16 changed files with 164 additions and 34 deletions

View File

@ -217,3 +217,24 @@ void kvz_rtp::crypto::random::generate_random(uint8_t *out, size_t len)
/* do not block ever */
CryptoPP::OS_GenerateRandomBlock(false, out, len);
}
/* ***************** crc32 ***************** */
void kvz_rtp::crypto::crc32::get_crc32(uint8_t *input, size_t len, uint32_t *output)
{
CryptoPP::CRC32 crc32;
crc32.Update(input, len);
crc32.TruncatedFinal((uint8_t *)output, sizeof(uint32_t));
}
bool kvz_rtp::crypto::crc32::verify_crc32(uint8_t *input, size_t len, uint32_t old_crc)
{
CryptoPP::CRC32 crc32;
uint32_t new_crc;
crc32.Update(input, len);
crc32.TruncatedFinal((uint8_t *)&new_crc, sizeof(uint32_t));
return new_crc == old_crc;
}

View File

@ -8,6 +8,7 @@
#include "crypto/3rdparty/cryptopp/modes.h"
#include "crypto/3rdparty/cryptopp/osrng.h"
#include "crypto/3rdparty/cryptopp/sha.h"
#include "crypto/3rdparty/cryptopp/crc.h"
namespace kvz_rtp {
@ -120,5 +121,10 @@ namespace kvz_rtp {
namespace random {
void generate_random(uint8_t *out, size_t len);
};
namespace crc32 {
void get_crc32(uint8_t *input, size_t len, uint32_t *output);
bool verify_crc32(uint8_t *input, size_t len, uint32_t old_crc);
};
};
};

View File

@ -11,7 +11,7 @@
kvz_rtp::zrtp_msg::commit::commit(zrtp_session_t& session)
{
/* temporary storage for the full hmac hash */
uint8_t mac_full[32];
uint8_t mac_full[32] = { 0 };
LOG_DEBUG("Create ZRTP Commit message!");
@ -44,13 +44,17 @@ kvz_rtp::zrtp_msg::commit::commit(zrtp_session_t& session)
msg->auth_tag_type = session.auth_tag_type;
msg->key_agreement_type = session.key_agreement_type;
/* Calculate truncated HMAC-SHA256 for the Commit Message */
auto hmac_sha256 = kvz_rtp::crypto::hmac::sha256(session.hashes[1], 32);
hmac_sha256.update((uint8_t *)frame_, len_ - 8);
hmac_sha256.update((uint8_t *)frame_, len_ - 8 - 4);
hmac_sha256.final(mac_full);
memcpy(&msg->mac, mac_full, sizeof(uint64_t));
/* Calculate CRC32 for the whole ZRTP packet */
kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc);
/* Finally make a copy of the message and save it for later use */
session.l_msg.commit.first = len_;
session.l_msg.commit.second = (kvz_rtp::zrtp_msg::zrtp_commit *)new uint8_t[len_];

View File

@ -26,6 +26,7 @@ namespace kvz_rtp {
uint32_t hvi[8];
uint32_t mac[2];
uint32_t crc;
};
class commit {

View File

@ -35,6 +35,9 @@ kvz_rtp::zrtp_msg::confack::confack(zrtp_session_t& session)
msg->msg_start.length = len_ - sizeof(zrtp_header);
memcpy(&msg->msg_start.msgblock, ZRTP_CONFACK, 8);
/* Calculate CRC32 for the whole ZRTP packet */
kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc);
}
kvz_rtp::zrtp_msg::confack::~confack()

View File

@ -12,6 +12,7 @@ namespace kvz_rtp {
struct zrtp_confack {
zrtp_msg msg_start;
uint32_t crc;
};
class confack {

View File

@ -66,10 +66,14 @@ kvz_rtp::zrtp_msg::confirm::confirm(zrtp_session_t& session, int part)
aes_cfb->encrypt((uint8_t *)msg->hash, (uint8_t *)msg->hash, 40);
/* Calculate HMAC-SHA256 of the encrypted portion of the message */
hmac_sha256->update((uint8_t *)msg->hash, 40);
hmac_sha256->final(mac_full);
memcpy(&msg->confirm_mac, mac_full, sizeof(uint64_t));
/* Calculate CRC32 for the whole ZRTP packet */
kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc);
delete hmac_sha256;
delete aes_cfb;
}

View File

@ -6,6 +6,7 @@ namespace kvz_rtp {
namespace zrtp_msg {
struct zrtp_hello_ack;
struct zrtp_commit;
struct zrtp_hello;
struct zrtp_dh;

View File

@ -78,13 +78,16 @@ kvz_rtp::zrtp_msg::dh_key_exchange::dh_key_exchange(zrtp_session_t& session, int
/* public key */
memcpy(msg->pk, session.public_key, sizeof(session.public_key));
/* Finally calculate MAC code for the message */
/* Calculate truncated HMAC-SHA256 for the Commit Message */
hmac_sha256 = kvz_rtp::crypto::hmac::sha256(session.hashes[0], 32);
hmac_sha256.update((uint8_t *)frame_, len_ - 8 - 4);
hmac_sha256.final(mac_full);
memcpy(msg->mac, mac_full, 8);
/* Calculate CRC32 for the whole ZRTP packet */
kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc);
/* Finally make a copy of the message and save it for later use */
session.l_msg.dh.first = len_;
session.l_msg.dh.second = (kvz_rtp::zrtp_msg::zrtp_dh *)new uint8_t[len_];

View File

@ -8,6 +8,8 @@
namespace kvz_rtp {
typedef struct zrtp_session zrtp_session_t;
namespace zrtp_msg {
struct zrtp_dh {

View File

@ -18,17 +18,22 @@ kvz_rtp::zrtp_msg::hello::hello(zrtp_session_t& session)
/* We support only the mandatory algorithms etc. defined in RFC 6189
* so for us all the hash algos and key agreement types are set to zero */
size_t common_size = sizeof(zrtp_hello) - sizeof(zrtp_header);
size_t our_size = common_size;
/* size_t common_size = sizeof(zrtp_hello) - sizeof(zrtp_header); */
/* size_t our_size = common_size; */
/* assume remote supports everything so allocate space for all possible elements */
size_t their_size = common_size + 5 * 8 * sizeof(uint32_t);
/* size_t their_size = common_size + 5 * 8 * sizeof(uint32_t); */
frame_ = kvz_rtp::frame::alloc_zrtp_frame(our_size);
rframe_ = kvz_rtp::frame::alloc_zrtp_frame(their_size);
len_ = sizeof(zrtp_hello);
rlen_ = sizeof(zrtp_hello) + 5 * 8;
len_ = sizeof(kvz_rtp::frame::zrtp_frame) + our_size;
rlen_ = sizeof(kvz_rtp::frame::zrtp_frame) + their_size;
frame_ = kvz_rtp::frame::alloc_zrtp_frame(sizeof(zrtp_hello));
rframe_ = kvz_rtp::frame::alloc_zrtp_frame(sizeof(zrtp_hello) + 5 * 8);
memset(frame_, 0, sizeof(zrtp_hello));
memset(rframe_, 0, sizeof(zrtp_hello) + 5 * 8);
fprintf(stderr, "%zu\n", len_);
zrtp_hello *msg = (zrtp_hello *)frame_;
@ -38,7 +43,7 @@ kvz_rtp::zrtp_msg::hello::hello(zrtp_session_t& session)
msg->msg_start.header.seq = session.seq++;
msg->msg_start.magic = ZRTP_MSG_MAGIC;
msg->msg_start.length = our_size;
msg->msg_start.length = len_ - sizeof(kvz_rtp::frame::zrtp_frame);
memcpy(&msg->msg_start.msgblock, ZRTP_HELLO, 8);
memcpy(&msg->version, ZRTP_VERSION, 4);
@ -50,19 +55,23 @@ kvz_rtp::zrtp_msg::hello::hello(zrtp_session_t& session)
msg->s = 0;
msg->m = 0;
msg->p = 0;
msg->unused = 0;
/* msg->unused = 0; */
msg->hc = 0;
msg->ac = 0;
msg->kc = 0;
msg->sc = 0;
/* Calculate MAC for the Hello message (only the ZRTP message part) */
auto hmac_sha256 = kvz_rtp::crypto::hmac::sha256(session.hashes[2], 32);
hmac_sha256.update((uint8_t *)frame_, our_size - 8);
hmac_sha256.update((uint8_t *)frame_, 81);
hmac_sha256.final(mac_full);
memcpy(&msg->mac, mac_full, sizeof(uint64_t));
/* Calculate CRC32 of the whole packet (excluding crc) */
kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc);
/* Finally make a copy of the message and save it for later use */
session.l_msg.hello.first = len_;
session.l_msg.hello.second = (kvz_rtp::zrtp_msg::zrtp_hello *)new uint8_t[len_];
@ -73,6 +82,7 @@ kvz_rtp::zrtp_msg::hello::~hello()
{
LOG_DEBUG("Freeing ZRTP hello message...");
(void)kvz_rtp::frame::dealloc_frame(frame_);
(void)kvz_rtp::frame::dealloc_frame(rframe_);
}
rtp_error_t kvz_rtp::zrtp_msg::hello::send_msg(socket_t& socket, sockaddr_in& addr)

View File

@ -9,6 +9,7 @@
namespace kvz_rtp {
typedef struct capabilities zrtp_capab_t;
typedef struct zrtp_session zrtp_session_t;
namespace zrtp_msg {
@ -39,6 +40,7 @@ namespace kvz_rtp {
uint32_t sas_types[0];
uint64_t mac;
uint32_t crc;
};
class hello {

View File

@ -14,6 +14,8 @@ kvz_rtp::zrtp_msg::hello_ack::hello_ack()
zrtp_hello_ack *msg = (zrtp_hello_ack *)frame_;
memset(msg, 0, sizeof(zrtp_hello_ack));
msg->msg_start.header.version = 0;
msg->msg_start.header.magic = ZRTP_HEADER_MAGIC;
@ -21,6 +23,8 @@ kvz_rtp::zrtp_msg::hello_ack::hello_ack()
msg->msg_start.length = 3;
memcpy(&msg->msg_start.msgblock, ZRTP_HELLO_ACK, 8);
kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc);
}
kvz_rtp::zrtp_msg::hello_ack::~hello_ack()

View File

@ -9,8 +9,9 @@ namespace kvz_rtp {
namespace zrtp_msg {
struct zrtp_hello_ack {
PACKED_STRUCT(zrtp_hello_ack) {
zrtp_msg msg_start;
uint32_t crc;
};
class hello_ack {

View File

@ -12,7 +12,14 @@
#include "debug.hh"
#include "util.hh"
#include "crypto/crypto.hh"
#include "mzrtp/defines.hh"
#include "mzrtp/dh_kxchng.hh"
#include "mzrtp/commit.hh"
#include "mzrtp/confack.hh"
#include "mzrtp/confirm.hh"
#include "mzrtp/hello.hh"
#include "mzrtp/hello_ack.hh"
#include "mzrtp/receiver.hh"
using namespace kvz_rtp::zrtp_msg;
@ -77,36 +84,92 @@ int kvz_rtp::zrtp_msg::receiver::recv_msg(socket_t& socket, int flags)
switch (msg->msgblock) {
case ZRTP_MSG_HELLO:
LOG_DEBUG("Hello message received");
return ZRTP_FT_HELLO;
{
LOG_DEBUG("Hello message received, verify CRC32!");
zrtp_hello *hello = (zrtp_hello *)msg;
if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, hello->crc))
return -EOPNOTSUPP;
}
return ZRTP_FT_HELLO;
case ZRTP_MSG_HELLO_ACK:
LOG_DEBUG("HelloACK message received");
return ZRTP_FT_HELLO_ACK;
{
LOG_DEBUG("HelloACK message received, verify CRC32!");
zrtp_hello_ack *ha_msg = (zrtp_hello_ack *)msg;
if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, ha_msg->crc))
return -EOPNOTSUPP;
}
return ZRTP_FT_HELLO_ACK;
case ZRTP_MSG_COMMIT:
LOG_DEBUG("Commit message received");
return ZRTP_FT_COMMIT;
{
LOG_DEBUG("Commit message received, verify CRC32!");
zrtp_commit *commit = (zrtp_commit *)msg;
if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, commit->crc))
return -EOPNOTSUPP;
}
return ZRTP_FT_COMMIT;
case ZRTP_MSG_DH_PART1:
LOG_DEBUG("DH Part1 message received");
return ZRTP_FT_DH_PART1;
{
LOG_DEBUG("DH Part1 message received, verify CRC32!");
zrtp_dh *dh = (zrtp_dh *)msg;
if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, dh->crc))
return -EOPNOTSUPP;
}
return ZRTP_FT_DH_PART1;
case ZRTP_MSG_DH_PART2:
LOG_DEBUG("DH Part2 message received");
return ZRTP_FT_DH_PART2;
{
LOG_DEBUG("DH Part2 message received, verify CRC32!");
zrtp_dh *dh = (zrtp_dh *)msg;
if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, dh->crc))
return -EOPNOTSUPP;
}
return ZRTP_FT_DH_PART2;
case ZRTP_MSG_CONFIRM1:
LOG_DEBUG("Confirm1 message received");
return ZRTP_FT_CONFIRM1;
{
LOG_DEBUG("Confirm1 message received, verify CRC32!");
zrtp_confirm *dh = (zrtp_confirm *)msg;
if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, dh->crc))
return -EOPNOTSUPP;
}
return ZRTP_FT_CONFIRM1;
case ZRTP_MSG_CONFIRM2:
LOG_DEBUG("Confirm2 message received");
return ZRTP_FT_CONFIRM2;
{
LOG_DEBUG("Confirm2 message received, verify CRC32!");
zrtp_confirm *dh = (zrtp_confirm *)msg;
if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, dh->crc))
return -EOPNOTSUPP;
}
return ZRTP_FT_CONFIRM2;
case ZRTP_MSG_CONF2_ACK:
LOG_DEBUG("Conf2 ACK message received");
return ZRTP_FT_CONF2_ACK;
{
LOG_DEBUG("Conf2 ACK message received, verify CRC32!");
zrtp_confack *ca = (zrtp_confack *)msg;
if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, ca->crc))
return -EOPNOTSUPP;
}
return ZRTP_FT_CONF2_ACK;
case ZRTP_MSG_ERROR:
LOG_DEBUG("Error message received");

View File

@ -244,7 +244,7 @@ rtp_error_t kvz_rtp::zrtp::validate_session()
if (RTP_INVALID_VALUE == verify_hash(
(uint8_t *)hashes[1],
(uint8_t *)session_.r_msg.commit.second,
session_.r_msg.commit.first - 8,
session_.r_msg.commit.first - 8 - 4,
session_.remote_macs[2]
))
{
@ -307,8 +307,9 @@ rtp_error_t kvz_rtp::zrtp::begin_session()
for (i = 0; i < 20; ++i) {
set_timeout(rto);
if ((ret = hello.send_msg(socket_, addr_)) != RTP_OK)
if ((ret = hello.send_msg(socket_, addr_)) != RTP_OK) {
LOG_ERROR("Failed to send Hello message");
}
if ((type = receiver_.recv_msg(socket_, 0)) > 0) {
/* We received something interesting, either Hello message from remote in which case
@ -383,8 +384,9 @@ rtp_error_t kvz_rtp::zrtp::init_session()
for (int i = 0; i < 10; ++i) {
set_timeout(rto);
if ((ret = commit.send_msg(socket_, addr_)) != RTP_OK)
if ((ret = commit.send_msg(socket_, addr_)) != RTP_OK) {
LOG_ERROR("Failed to send Commit message!");
}
if ((type = receiver_.recv_msg(socket_, 0)) > 0) {
@ -471,8 +473,9 @@ rtp_error_t kvz_rtp::zrtp::dh_part2()
for (int i = 0; i < 10; ++i) {
set_timeout(rto);
if ((ret = dhpart.send_msg(socket_, addr_)) != RTP_OK)
if ((ret = dhpart.send_msg(socket_, addr_)) != RTP_OK) {
LOG_ERROR("Failed to send DHPart2 Message!");
}
if ((type = receiver_.recv_msg(socket_, 0)) > 0) {
if (type == ZRTP_FT_CONFIRM1) {
@ -571,6 +574,7 @@ rtp_error_t kvz_rtp::zrtp::init(uint32_t ssrc, socket_t& socket, sockaddr_in& ad
rtp_error_t ret = RTP_OK;
/* TODO: set all fields initially to zero */
memset(session_.hvi, 0, sizeof(session_.hvi));
generate_zid();
generate_secrets();