Implement encryption/authentication handlers for SRTP
This commit is contained in:
parent
9060ec9859
commit
359e84076c
|
@ -127,21 +127,8 @@ namespace uvg_rtp {
|
|||
* Return RTP_MEMORY allocation failed */
|
||||
rtp_error_t init_user(int type, int flags, uint8_t *key, uint8_t *salt);
|
||||
|
||||
/* Encrypt the payload of "frame" using the private session key
|
||||
*
|
||||
* Return RTP_OK on success
|
||||
* Return RTP_INVALID_VALUE if "frame" is nullptr
|
||||
* Return RTP_NOT_INITIALIZED if SRTP has not been initialized */
|
||||
rtp_error_t encrypt(uvg_rtp::frame::rtp_frame *frame);
|
||||
|
||||
/* Encrypt the payload of "buffers" vector using the private session key
|
||||
* The payload that is encrypted is the last buffer of "buffers" and the
|
||||
* RTP header is the first" buffer of "buffers"
|
||||
*
|
||||
* Return RTP_OK on success
|
||||
* Return RTP_INVALID_VALUE if "frame" is nullptr
|
||||
* Return RTP_NOT_INITIALIZED if SRTP has not been initialized */
|
||||
rtp_error_t encrypt(std::vector<std::pair<size_t, uint8_t *>>& buffers);
|
||||
/* TODO: */
|
||||
rtp_error_t encrypt(uint32_t ssrc, uint16_t seq, uint8_t *buffer, size_t len);
|
||||
|
||||
/* Decrypt the payload payload of "frame" using the private session key
|
||||
*
|
||||
|
@ -159,6 +146,19 @@ namespace uvg_rtp {
|
|||
* Return RTP_OK on success
|
||||
* Return RTP_INVALID_VALUE if "frame" is nullptr or if authentication failed */
|
||||
rtp_error_t authenticate(uvg_rtp::frame::rtp_frame *frame);
|
||||
|
||||
/* Has RTP packet encryption been disabled? */
|
||||
bool use_null_cipher();
|
||||
|
||||
/* Has RTP packet authentication been enabled? */
|
||||
bool authenticate_rtp();
|
||||
|
||||
/* Get reference to the SRTP context (including session keys) */
|
||||
srtp_ctx_t& get_ctx();
|
||||
|
||||
/* Encrypt the payload and add authentication tag (if enabled) */
|
||||
static rtp_error_t send_packet_handler_buf(void *arg, ssize_t len, void *buf);
|
||||
static rtp_error_t send_packet_handler_vec(void *arg, std::vector<std::pair<size_t, uint8_t *>>& buffers);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -172,7 +172,7 @@ namespace uvg_rtp {
|
|||
rtp_error_t create_iv(uint8_t *out, uint32_t ssrc, uint64_t index, uint8_t *salt);
|
||||
|
||||
/* Internal encrypt method that takes only the necessary variables and encrypts "buffer" */
|
||||
rtp_error_t __encrypt(uint32_t ssrc, uint16_t seq, uint8_t *buffer, size_t len);
|
||||
/* rtp_error_t __encrypt(uint32_t ssrc, uint16_t seq, uint8_t *buffer, size_t len); */
|
||||
|
||||
/* Internal init method that initialize the SRTP context using values in key_ctx_.master */
|
||||
rtp_error_t __init(int type, int flags);
|
||||
|
|
|
@ -265,17 +265,6 @@ rtp_error_t uvg_rtp::socket::__sendtov(
|
|||
#ifdef __linux__
|
||||
int sent_bytes = 0;
|
||||
|
||||
#ifdef __RTP_CRYPTO__
|
||||
if (srtp_) {
|
||||
auto ret = srtp_->encrypt(buffers);
|
||||
|
||||
if (ret != RTP_OK) {
|
||||
LOG_ERROR("Failed to encrypt RTP packet!");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < buffers.size(); ++i) {
|
||||
chunks_[i].iov_len = buffers.at(i).first;
|
||||
chunks_[i].iov_base = buffers.at(i).second;
|
||||
|
|
143
src/srtp.cc
143
src/srtp.cc
|
@ -55,6 +55,44 @@ rtp_error_t uvg_rtp::srtp::create_iv(uint8_t *out, uint32_t ssrc, uint64_t index
|
|||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::srtp::encrypt(uint32_t ssrc, uint16_t seq, uint8_t *buffer, size_t len)
|
||||
{
|
||||
if (use_null_cipher_)
|
||||
return RTP_OK;
|
||||
|
||||
uint8_t iv[16] = { 0 };
|
||||
uint64_t index = (((uint64_t)srtp_ctx_.roc) << 16) + seq;
|
||||
|
||||
/* Sequence number has wrapped around, update Roll-over Counter */
|
||||
if (seq == 0xffff)
|
||||
srtp_ctx_.roc++;
|
||||
|
||||
if (create_iv(iv, ssrc, index, srtp_ctx_.key_ctx.local.salt_key) != RTP_OK) {
|
||||
LOG_ERROR("Failed to create IV, unable to encrypt the RTP packet!");
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
uvg_rtp::crypto::aes::ctr ctr(srtp_ctx_.key_ctx.local.enc_key, sizeof(srtp_ctx_.key_ctx.local.enc_key), iv);
|
||||
ctr.encrypt(buffer, buffer, len);
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
bool uvg_rtp::srtp::use_null_cipher()
|
||||
{
|
||||
return use_null_cipher_;
|
||||
}
|
||||
|
||||
bool uvg_rtp::srtp::authenticate_rtp()
|
||||
{
|
||||
return authenticate_rtp_;
|
||||
}
|
||||
|
||||
uvg_rtp::srtp_ctx_t& uvg_rtp::srtp::get_ctx()
|
||||
{
|
||||
return srtp_ctx_;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::srtp::__init(int type, int flags)
|
||||
{
|
||||
srtp_ctx_.roc = 0;
|
||||
|
@ -169,120 +207,65 @@ rtp_error_t uvg_rtp::srtp::init_user(int type, int flags, uint8_t *key, uint8_t
|
|||
return __init(type, flags);
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::srtp::__encrypt(uint32_t ssrc, uint16_t seq, uint8_t *buffer, size_t len)
|
||||
rtp_error_t uvg_rtp::srtp::send_packet_handler_buf(void *arg, ssize_t len, void *buf)
|
||||
{
|
||||
if (use_null_cipher_)
|
||||
auto srtp = (uvg_rtp::srtp *)arg;
|
||||
|
||||
if (srtp->use_null_cipher())
|
||||
return RTP_OK;
|
||||
|
||||
uint8_t iv[16] = { 0 };
|
||||
uint64_t index = (((uint64_t)srtp_ctx_.roc) << 16) + seq;
|
||||
auto ctx = srtp->get_ctx();
|
||||
auto frame = (uvg_rtp::frame::rtp_frame *)buf;
|
||||
auto index = (((uint64_t)ctx.roc) << 16) + ntohs(frame->header.seq);
|
||||
|
||||
/* Sequence number has wrapped around, update Roll-over Counter */
|
||||
if (seq == 0xffff)
|
||||
srtp_ctx_.roc++;
|
||||
if (ntohs(frame->header.seq) == 0xffff)
|
||||
ctx.roc++;
|
||||
|
||||
if (create_iv(iv, ssrc, index, key_ctx_.local.salt_key) != RTP_OK) {
|
||||
if (srtp->create_iv(iv, ntohl(frame->header.ssrc), index, ctx.key_ctx.local.salt_key) != RTP_OK) {
|
||||
LOG_ERROR("Failed to create IV, unable to encrypt the RTP packet!");
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
uvg_rtp::crypto::aes::ctr ctr(key_ctx_.local.enc_key, sizeof(key_ctx_.local.enc_key), iv);
|
||||
ctr.encrypt(buffer, buffer, len);
|
||||
uvg_rtp::crypto::aes::ctr ctr(ctx.key_ctx.local.enc_key, sizeof(ctx.key_ctx.local.enc_key), iv);
|
||||
ctr.encrypt((uint8_t *)buf, (uint8_t *)buf, len);
|
||||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::srtp::encrypt(uvg_rtp::frame::rtp_frame *frame)
|
||||
rtp_error_t uvg_rtp::srtp::send_packet_handler_vec(void *arg, std::vector<std::pair<size_t, uint8_t *>>& buffers)
|
||||
{
|
||||
/* TODO: authentication for complete RTP frame requires co-operation
|
||||
* with the allocator of that frame -> no good solution for that right now */
|
||||
auto srtp = (uvg_rtp::srtp *)arg;
|
||||
|
||||
return __encrypt(
|
||||
ntohl(frame->header.ssrc),
|
||||
ntohs(frame->header.seq),
|
||||
frame->payload,
|
||||
frame->payload_len
|
||||
);
|
||||
}
|
||||
if (srtp->use_null_cipher())
|
||||
return RTP_OK;
|
||||
|
||||
rtp_error_t uvg_rtp::srtp::encrypt(std::vector<std::pair<size_t, uint8_t *>>& buffers)
|
||||
{
|
||||
auto frame = (uvg_rtp::frame::rtp_frame *)buffers.at(0).second;
|
||||
auto rtp = buffers.at(buffers.size() - 1);
|
||||
uint64_t *digest = new uint64_t;
|
||||
auto frame = (uvg_rtp::frame::rtp_frame *)buffers.at(0).second;
|
||||
auto rtp = buffers.at(buffers.size() - 1);
|
||||
auto ctx = srtp->get_ctx();
|
||||
auto digest = new uint64_t;
|
||||
|
||||
rtp_error_t ret = __encrypt(
|
||||
rtp_error_t ret = srtp->encrypt(
|
||||
ntohl(frame->header.ssrc),
|
||||
ntohs(frame->header.seq),
|
||||
rtp.second,
|
||||
rtp.first
|
||||
);
|
||||
|
||||
if (!authenticate_rtp_)
|
||||
return ret;
|
||||
if (!srtp->authenticate_rtp())
|
||||
return RTP_OK;
|
||||
|
||||
/* create authentication tag for the packet and push it to the vector buffer */
|
||||
auto hmac_sha1 = uvg_rtp::crypto::hmac::sha1(key_ctx_.local.auth_key, AES_KEY_LENGTH);
|
||||
auto hmac_sha1 = uvg_rtp::crypto::hmac::sha1(ctx.key_ctx.local.auth_key, AES_KEY_LENGTH);
|
||||
|
||||
for (auto& buffer : buffers)
|
||||
hmac_sha1.update((uint8_t *)buffer.second, buffer.first);
|
||||
|
||||
hmac_sha1.update((uint8_t *)&srtp_ctx_.roc, sizeof(srtp_ctx_.roc));
|
||||
hmac_sha1.update((uint8_t *)&ctx.roc, sizeof(ctx.roc));
|
||||
hmac_sha1.final((uint8_t *)digest);
|
||||
|
||||
buffers.push_back(std::make_pair(sizeof(uint64_t), (uint8_t *)digest));
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::srtp::decrypt(uint8_t *buffer, size_t len)
|
||||
{
|
||||
if (use_null_cipher_)
|
||||
return RTP_OK;
|
||||
|
||||
uint8_t iv[16] = { 0 };
|
||||
auto hdr = (uvg_rtp::frame::rtp_header *)buffer;
|
||||
uint16_t seq = ntohs(hdr->seq);
|
||||
uint32_t ssrc = ntohl(hdr->ssrc);
|
||||
uint64_t index = (((uint64_t)srtp_ctx_.roc) << 16) + seq;
|
||||
uint64_t digest = 0;
|
||||
|
||||
/* Sequence number has wrapped around, update Roll-over Counter */
|
||||
if (seq == 0xffff)
|
||||
srtp_ctx_.roc++;
|
||||
|
||||
if (create_iv(iv, ssrc, index, key_ctx_.remote.salt_key) != RTP_OK) {
|
||||
LOG_ERROR("Failed to create IV, unable to encrypt the RTP packet!");
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
||||
uint8_t *payload = buffer + sizeof(uvg_rtp::frame::rtp_header);
|
||||
uvg_rtp::crypto::aes::ctr ctr(key_ctx_.remote.enc_key, sizeof(key_ctx_.remote.enc_key), iv);
|
||||
|
||||
/* exit early if RTP packet authentication is disabled... */
|
||||
if (!authenticate_rtp_) {
|
||||
ctr.decrypt(payload, payload, len - sizeof(uvg_rtp::frame::rtp_header));
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
/* ... otherwise calculate authentication tag for the packet
|
||||
* and compare it against the one we received */
|
||||
auto hmac_sha1 = uvg_rtp::crypto::hmac::sha1(key_ctx_.remote.auth_key, AES_KEY_LENGTH);
|
||||
|
||||
hmac_sha1.update((uint8_t *)buffer, len - AUTH_TAG_LENGTH);
|
||||
hmac_sha1.update((uint8_t *)&srtp_ctx_.roc, sizeof(srtp_ctx_.roc));
|
||||
hmac_sha1.final((uint8_t *)&digest);
|
||||
|
||||
if (memcmp(&digest, &buffer[len - AUTH_TAG_LENGTH], AUTH_TAG_LENGTH)) {
|
||||
LOG_ERROR("Authentication tag mismatch!");
|
||||
return RTP_AUTH_TAG_MISMATCH;
|
||||
}
|
||||
|
||||
size_t size_ = len - sizeof(uvg_rtp::frame::rtp_header) - 8;
|
||||
uint8_t *new_buffer = new uint8_t[size_];
|
||||
|
||||
ctr.decrypt(new_buffer, payload, size_);
|
||||
memset(payload, 0, len);
|
||||
memcpy(payload, new_buffer, size_);
|
||||
return RTP_OK;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue