/** * @file srtp.cpp GNU ZRTP: SRTP processing * * Copyright (C) 2010 - 2017 Creytiv.com */ #include #include #include #ifdef GZRTP_USE_RE_SRTP #include #else #include #include #include #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); }