diff options
Diffstat (limited to 'modules/gzrtp/srtp.cpp')
-rw-r--r-- | modules/gzrtp/srtp.cpp | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/modules/gzrtp/srtp.cpp b/modules/gzrtp/srtp.cpp new file mode 100644 index 0000000..9aaa4b3 --- /dev/null +++ b/modules/gzrtp/srtp.cpp @@ -0,0 +1,327 @@ +/** + * @file srtp.cpp GNU ZRTP: SRTP processing + * + * Copyright (C) 2010 - 2017 Creytiv.com + */ +#include <stdint.h> + +#include <re.h> +#include <baresip.h> + +#ifdef GZRTP_USE_RE_SRTP +#include <string.h> +#else +#include <srtp/CryptoContext.h> +#include <srtp/CryptoContextCtrl.h> +#include <srtp/SrtpHandler.h> +#endif + +#include "srtp.h" + + +Srtp::Srtp(int& err, const SrtpSecret_t *secrets, EnableSecurity part) + +{ + const uint8_t *key, *salt; + uint32_t key_len, salt_len; + + err = EPERM; + +#ifdef GZRTP_USE_RE_SRTP + m_srtp = NULL; +#else + m_cc = NULL; + m_cc_ctrl = NULL; +#endif + + if (part == ForSender) { + // To encrypt packets: intiator uses initiator keys, + // responder uses responder keys + if (secrets->role == Initiator) { + key = secrets->keyInitiator; + key_len = secrets->initKeyLen / 8; + salt = secrets->saltInitiator; + salt_len = secrets->initSaltLen / 8; + } + else { + key = secrets->keyResponder; + key_len = secrets->respKeyLen / 8; + salt = secrets->saltResponder; + salt_len = secrets->respSaltLen / 8; + } + } + else if (part == ForReceiver) { + // To decrypt packets: intiator uses responder keys, + // responder initiator keys + if (secrets->role == Initiator) { + key = secrets->keyResponder; + key_len = secrets->respKeyLen / 8; + salt = secrets->saltResponder; + salt_len = secrets->respSaltLen / 8; + } + else { + key = secrets->keyInitiator; + key_len = secrets->initKeyLen / 8; + salt = secrets->saltInitiator; + salt_len = secrets->initSaltLen / 8; + } + } + else { + err = EINVAL; + return; + } + +#ifdef GZRTP_USE_RE_SRTP + + uint8_t key_buf[32 + 14]; // max key + salt + enum srtp_suite suite; + struct srtp *st; + + if (secrets->symEncAlgorithm == Aes && + secrets->authAlgorithm == Sha1) { + + if (key_len == 16 && secrets->srtpAuthTagLen == 32) + suite = SRTP_AES_CM_128_HMAC_SHA1_32; + + else if (key_len == 16 && secrets->srtpAuthTagLen == 80) + suite = SRTP_AES_CM_128_HMAC_SHA1_80; + + else if (key_len == 32 && secrets->srtpAuthTagLen == 32) + suite = SRTP_AES_256_CM_HMAC_SHA1_32; + + else if (key_len == 32 && secrets->srtpAuthTagLen == 80) + suite = SRTP_AES_256_CM_HMAC_SHA1_80; + + else { + err = ENOTSUP; + return; + } + } + else { + err = ENOTSUP; + return; + } + + if (salt_len != 14) { + err = EINVAL; + return; + } + + memcpy(key_buf, key, key_len); + memcpy(key_buf + key_len, salt, salt_len); + + err = srtp_alloc(&st, suite, key_buf, key_len + salt_len, 0); + if (err) + return; + + m_auth_tag_len = secrets->srtpAuthTagLen / 8; + m_srtp = st; + + err = 0; +#else + + CryptoContext *cc = NULL; + CryptoContextCtrl *cc_ctrl = NULL; + int cipher; + int authn; + int auth_key_len; + + switch (secrets->authAlgorithm) { + case Sha1: + authn = SrtpAuthenticationSha1Hmac; + auth_key_len = 20; + break; + case Skein: + authn = SrtpAuthenticationSkeinHmac; + auth_key_len = 32; + break; + default: + err = ENOTSUP; + return; + } + + switch (secrets->symEncAlgorithm) { + case Aes: + cipher = SrtpEncryptionAESCM; + break; + case TwoFish: + cipher = SrtpEncryptionTWOCM; + break; + default: + err = ENOTSUP; + return; + } + + cc = new CryptoContext( + 0, // SSRC (used for lookup) + 0, // Roll-Over-Counter (ROC) + 0L, // keyderivation << 48, + cipher, // encryption algo + authn, // authtentication algo + (uint8_t *)key, // Master Key + key_len, // Master Key length + (uint8_t *)salt, // Master Salt + salt_len, // Master Salt length + key_len, // encryption keyl + auth_key_len, // authentication key len + salt_len, // session salt len + secrets->srtpAuthTagLen / 8); // authentication tag lenA + + cc_ctrl = new CryptoContextCtrl( + 0, // SSRC (used for lookup) + cipher, // encryption algo + authn, // authtentication algo + (uint8_t *)key, // Master Key + key_len, // Master Key length + (uint8_t *)salt, // Master Salt + salt_len, // Master Salt length + key_len, // encryption keyl + auth_key_len, // authentication key len + salt_len, // session salt len + secrets->srtpAuthTagLen / 8); // authentication tag lenA + + if (!cc || !cc_ctrl) { + delete cc; + delete cc_ctrl; + + err = ENOMEM; + return; + } + + cc->deriveSrtpKeys(0L); + cc_ctrl->deriveSrtcpKeys(); + + m_cc = cc; + m_cc_ctrl = cc_ctrl; + + err = 0; +#endif +} + + +Srtp::~Srtp() +{ +#ifdef GZRTP_USE_RE_SRTP + mem_deref(m_srtp); +#else + delete m_cc; + delete m_cc_ctrl; +#endif +} + + +int Srtp::protect_int(struct mbuf *mb, bool control) +{ + size_t len = mbuf_get_left(mb); + + int32_t extra = (mbuf_get_space(mb) > len)? + mbuf_get_space(mb) - len : 0; + +#ifdef GZRTP_USE_RE_SRTP + if (m_auth_tag_len + (control? 4 : 0) > extra) + return ENOMEM; + + if (control) + return srtcp_encrypt(m_srtp, mb); + else + return srtp_encrypt(m_srtp, mb); +#else + if (control) { + if (m_cc_ctrl->getTagLength() + 4 + + m_cc_ctrl->getMkiLength() > extra) + return ENOMEM; + } + else { + if (m_cc->getTagLength() + + m_cc->getMkiLength() > extra) + return ENOMEM; + } + + bool rc; + + if (control) + rc = SrtpHandler::protectCtrl(m_cc_ctrl, mbuf_buf(mb), + len, &len); + else + rc = SrtpHandler::protect(m_cc, mbuf_buf(mb), len, &len); + if (!rc) + return EPROTO; + + if (len > mbuf_get_space(mb)) { + // this should never happen + error_msg("zrtp: protect: length > space (%u > %u)\n", + len, mbuf_get_space(mb)); + abort(); + } + + mb->end = mb->pos + len; + + return 0; +#endif +} + + +int Srtp::protect(struct mbuf *mb) +{ + return protect_int(mb, false); +} + + +int Srtp::protect_ctrl(struct mbuf *mb) +{ + return protect_int(mb, true); +} + + +// return value: +// 0 - OK +// EBADMSG - SRTP/RTP packet decode error +// EAUTH - SRTP authentication failed +// EALREADY - SRTP replay check failed +// other errors +int Srtp::unprotect_int(struct mbuf *mb, bool control) +{ +#ifdef GZRTP_USE_RE_SRTP + if (control) + return srtcp_decrypt(m_srtp, mb); + else + return srtp_decrypt(m_srtp, mb); +#else + size_t len = mbuf_get_left(mb); + uint32_t rc; + int err; + + if (control) + rc = SrtpHandler::unprotectCtrl(m_cc_ctrl, mbuf_buf(mb), + len, &len); + else + rc = SrtpHandler::unprotect(m_cc, mbuf_buf(mb), + len, &len, NULL); + + switch (rc) { + case 1: err = 0; break; + case 0: err = EBADMSG; break; + case -1: err = EAUTH; break; + case -2: err = EALREADY; break; + default: err = EINVAL; + } + + if (!err) + mb->end = mb->pos + len; + + return err; +#endif +} + + +int Srtp::unprotect(struct mbuf *mb) +{ + return unprotect_int(mb, false); +} + + +int Srtp::unprotect_ctrl(struct mbuf *mb) +{ + return unprotect_int(mb, true); +} + |