Skip to content

Commit

Permalink
[core] Improved AES GCM encryption, changed GCM IV length to 12 bytes (
Browse files Browse the repository at this point in the history
…#2962).

SRT version raised to 1.5.4.
  • Loading branch information
maxsharabayko authored Jul 30, 2024
1 parent 2af8706 commit 5819ade
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 63 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#

cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR)
set (SRT_VERSION 1.5.3)
set (SRT_VERSION 1.5.4)

set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/scripts")
include(haiUtil) # needed for set_version_variables
Expand Down
78 changes: 40 additions & 38 deletions haicrypt/cryspr.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ written by
CRYSPR/4SRT Initial implementation.
*****************************************************************************/

#ifndef _WIN32
#include <arpa/inet.h> /* htonl */
#endif

#include "hcrypt.h"
#include "cryspr.h"

Expand Down Expand Up @@ -429,6 +433,8 @@ static int crysprFallback_MsEncrypt(

/* Auth tag produced by AES GCM. */
unsigned char tag[HAICRYPT_AUTHTAG_MAX];
/* Additional authenticated data used by AES-GCM. */
unsigned char aad[HAICRYPT_AAD_MAX];

/*
* Get buffer room from the internal circular output buffer.
Expand All @@ -452,33 +458,30 @@ static int crysprFallback_MsEncrypt(
/* Get input packet index (in network order) */
hcrypt_Pki pki = hcryptMsg_GetPki(ctx->msg_info, in_data[0].pfx, 1);

/*
* Compute the Initial Vector
* IV (128-bit):
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | 0s | pki | ctr |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* XOR
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | nonce +
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*
* pki (32-bit): packet index
* ctr (16-bit): block counter
* nonce (112-bit): number used once (salt)
*/
hcrypt_SetCtrIV((unsigned char *)&pki, ctx->salt, iv);

if (ctx->mode == HCRYPT_CTX_MODE_AESGCM)
{
const int iret = cryspr_cb->cryspr->aes_gcm_cipher(true, aes_key, iv, in_data[0].pfx, pfx_len, in_data[0].payload, in_data[0].len,
const bool old_aead = ctx->use_gcm_153; // SRT v1.5.2 to v1.5.3.
if (old_aead)
{
hcrypt_SetCtrIV((unsigned char*)&pki, ctx->salt, iv);
memcpy(aad, in_data[0].pfx, sizeof(aad));
}
else
{
hcrypt_SetGcmIV((unsigned char*)&pki, ctx->salt, iv);

for (size_t i = 0; i < sizeof(aad) / 4; ++i)
*((uint32_t*)aad + i) = htonl(*((uint32_t*)in_data[0].pfx + i));
}

const int iret = cryspr_cb->cryspr->aes_gcm_cipher(true, aes_key, iv, aad, sizeof(aad), in_data[0].payload, in_data[0].len,
&out_msg[pfx_len], tag);
if (iret) {
return(iret);
}
}
else {
hcrypt_SetCtrIV((unsigned char *)&pki, ctx->salt, iv);
#if CRYSPR_HAS_AESCTR
cryspr_cb->cryspr->aes_ctr_cipher(true, aes_key, iv, in_data[0].payload, in_data[0].len,
&out_msg[pfx_len]);
Expand Down Expand Up @@ -599,35 +602,34 @@ static int crysprFallback_MsDecrypt(CRYSPR_cb *cryspr_cb, hcrypt_Ctx *ctx,
/* Get input packet index (in network order) */
hcrypt_Pki pki = hcryptMsg_GetPki(ctx->msg_info, in_data[0].pfx, 1);

/*
* Compute the Initial Vector
* IV (128-bit):
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | 0s | pki | ctr |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* XOR
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | nonce +
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*
* pki (32-bit): packet index
* ctr (16-bit): block counter
* nonce (112-bit): number used once (salt)
*/
hcrypt_SetCtrIV((unsigned char *)&pki, ctx->salt, iv);

if (ctx->mode == HCRYPT_CTX_MODE_AESGCM)
{
/* Additional authenticated data used by AES-GCM. */
unsigned char aad[HAICRYPT_AAD_MAX];
const bool old_aead = ctx->use_gcm_153; // SRT v1.5.2 to v1.5.3.
if (old_aead)
{
hcrypt_SetCtrIV((unsigned char*)&pki, ctx->salt, iv);
memcpy(aad, in_data[0].pfx, sizeof(aad));
}
else
{
hcrypt_SetGcmIV((unsigned char*)&pki, ctx->salt, iv);

for (size_t i = 0; i < sizeof(aad) / 4; ++i)
*((uint32_t*)aad + i) = htonl(*((uint32_t*)in_data[0].pfx + i));
}

unsigned char* tag = in_data[0].payload + in_data[0].len - HAICRYPT_AUTHTAG_MAX;
int liret = cryspr_cb->cryspr->aes_gcm_cipher(false, aes_key, iv, in_data[0].pfx, ctx->msg_info->pfx_len, in_data[0].payload, in_data[0].len - HAICRYPT_AUTHTAG_MAX,
int liret = cryspr_cb->cryspr->aes_gcm_cipher(false, aes_key, iv, aad, sizeof(aad), in_data[0].payload, in_data[0].len - HAICRYPT_AUTHTAG_MAX,
out_txt, tag);
if (liret) {
return(liret);
}
out_len = in_data[0].len - HAICRYPT_AUTHTAG_MAX;
}
else {
hcrypt_SetCtrIV((unsigned char*)&pki, ctx->salt, iv);
#if CRYSPR_HAS_AESCTR
cryspr_cb->cryspr->aes_ctr_cipher(false, aes_key, iv, in_data[0].payload, in_data[0].len,
out_txt);
Expand Down
2 changes: 2 additions & 0 deletions haicrypt/haicrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ HaiCrypt_Cryspr HaiCryptCryspr_Get_Instance (void); /* Return a default crys
#define HAICRYPT_KEY_MAX_SZ 32 /* MAX key */
#define HAICRYPT_SECRET_MAX_SZ (HAICRYPT_PWD_MAX_SZ > HAICRYPT_KEY_MAX_SZ ? HAICRYPT_PWD_MAX_SZ : HAICRYPT_KEY_MAX_SZ)
#define HAICRYPT_AUTHTAG_MAX 16 /* maximum length of the auth tag (e.g. GCM) */
#define HAICRYPT_AAD_MAX 16 /* maximum length of the additional authenticated data (GCM mode) */

#define HAICRYPT_SALT_SZ 16

Expand Down Expand Up @@ -96,6 +97,7 @@ typedef struct hcrypt_Session_str* HaiCrypt_Handle;
int HaiCrypt_SetLogLevel(int level, int logfa);

int HaiCrypt_Create(const HaiCrypt_Cfg *cfg, HaiCrypt_Handle *phhc);
int HaiCrypt_UpdateGcm153(HaiCrypt_Handle hhc, unsigned use_gcm_153);
int HaiCrypt_Clone(HaiCrypt_Handle hhcSrc, HaiCrypt_CryptoDir tx, HaiCrypt_Handle *phhc);
int HaiCrypt_Close(HaiCrypt_Handle hhc);
int HaiCrypt_Tx_GetBuf(HaiCrypt_Handle hhc, size_t data_len, unsigned char **in_p);
Expand Down
12 changes: 12 additions & 0 deletions haicrypt/hcrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,18 @@ int HaiCrypt_Create(const HaiCrypt_Cfg *cfg, HaiCrypt_Handle *phhc)
return(0);
}

int HaiCrypt_UpdateGcm153(HaiCrypt_Handle hhc, unsigned use_gcm_153)
{
ASSERT(hhc != NULL);
hcrypt_Session* crypto = hhc;
if (!crypto)
return (-1);

crypto->ctx_pair[0].use_gcm_153 = use_gcm_153;
crypto->ctx_pair[1].use_gcm_153 = use_gcm_153;
return (0);
}

int HaiCrypt_ExtractConfig(HaiCrypt_Handle hhcSrc, HaiCrypt_Cfg* pcfg)
{
hcrypt_Session *crypto = (hcrypt_Session *)hhcSrc;
Expand Down
19 changes: 19 additions & 0 deletions haicrypt/hcrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,25 @@ typedef struct hcrypt_Session_str {
hcrypt_XorStream(&(iv)[0], (nonce), 112/8); \
} while(0)

/* HaiCrypt-TP GCM mode IV (96-bit) - SRT 1.5.4:
* 0 1 2 3 4 5 6 7 8 9 10 11
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | 0s | pki |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* XOR
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | nonce +
* +---+---+---+---+---+---+---+---+---+---+---+---+
*
* pki (32-bit): packet index
* nonce (96-bit): number used once (salt)
*/
#define hcrypt_SetGcmIV(pki, nonce, iv) do { \
memset(&(iv)[0], 0, 96/8); \
memcpy(&(iv)[8], (pki), HCRYPT_PKI_SZ); \
hcrypt_XorStream(&(iv)[0], (nonce), 96/8); \
} while(0)

#define hcrypt_XorStream(dst, strm, len) do { \
int __XORSTREAMi; \
for (__XORSTREAMi = 0 \
Expand Down
1 change: 1 addition & 0 deletions haicrypt/hcrypt_ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef struct tag_hcrypt_Ctx {
#define HCRYPT_CTX_MODE_AESCBC 3 /* Cipher-block chaining mode */
#define HCRYPT_CTX_MODE_AESGCM 4 /* AES GCM authenticated encryption */
unsigned mode;
bool use_gcm_153; /* AES-GCM compatibility mode (SRT v1.5.3 and earlier) */

struct {
size_t key_len;
Expand Down
2 changes: 1 addition & 1 deletion haicrypt/hcrypt_ctx_rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ int hcryptCtx_Rx_Init(hcrypt_Session *crypto, hcrypt_Ctx *ctx, const HaiCrypt_Cf
ctx->mode = (cfg->flags & HAICRYPT_CFG_F_GCM) ? HCRYPT_CTX_MODE_AESGCM : HCRYPT_CTX_MODE_AESCTR;
}
ctx->status = HCRYPT_CTX_S_INIT;

ctx->msg_info = crypto->msg_info;
ctx->use_gcm_153 = false; // Default initialization.

if (cfg && hcryptCtx_SetSecret(crypto, ctx, &cfg->secret)) {
return(-1);
Expand Down
3 changes: 1 addition & 2 deletions haicrypt/hcrypt_ctx_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ int hcryptCtx_Tx_Init(hcrypt_Session *crypto, hcrypt_Ctx *ctx, const HaiCrypt_Cf

ctx->mode = (cfg->flags & HAICRYPT_CFG_F_GCM) ? HCRYPT_CTX_MODE_AESGCM : HCRYPT_CTX_MODE_AESCTR;
ctx->status = HCRYPT_CTX_S_INIT;

ctx->use_gcm_153 = false; // Default initialization.
ctx->msg_info = crypto->msg_info;

if (hcryptCtx_SetSecret(crypto, ctx, &cfg->secret)) {
Expand Down Expand Up @@ -184,7 +184,6 @@ int hcryptCtx_Tx_Refresh(hcrypt_Session *crypto)
ASSERT(HCRYPT_CTX_S_SARDY <= new_ctx->status);

/* Keep same KEK, configuration, and salt */
// memcpy(&new_ctx->aes_kek, &ctx->aes_kek, sizeof(new_ctx->aes_kek));
memcpy(&new_ctx->cfg, &ctx->cfg, sizeof(new_ctx->cfg));

new_ctx->salt_len = ctx->salt_len;
Expand Down
14 changes: 8 additions & 6 deletions srtcore/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2021,7 +2021,7 @@ bool srt::CUDT::processSrtMsg(const CPacket *ctrlpkt)
{
uint32_t srtdata_out[SRTDATA_MAXSIZE];
size_t len_out = 0;
res = m_pCryptoControl->processSrtMsg_KMREQ(srtdata, len, CUDT::HS_VERSION_UDT4,
res = m_pCryptoControl->processSrtMsg_KMREQ(srtdata, len, CUDT::HS_VERSION_UDT4, m_uPeerSrtVersion,
(srtdata_out), (len_out));
if (res == SRT_CMD_KMRSP)
{
Expand Down Expand Up @@ -2058,7 +2058,7 @@ bool srt::CUDT::processSrtMsg(const CPacket *ctrlpkt)
case SRT_CMD_KMRSP:
{
// KMRSP doesn't expect any following action
m_pCryptoControl->processSrtMsg_KMRSP(srtdata, len, CUDT::HS_VERSION_UDT4);
m_pCryptoControl->processSrtMsg_KMRSP(srtdata, len, m_uPeerSrtVersion);
return true; // nothing to do
}

Expand Down Expand Up @@ -2647,7 +2647,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,
return false;
}

int res = m_pCryptoControl->processSrtMsg_KMREQ(begin + 1, bytelen, HS_VERSION_SRT1,
int res = m_pCryptoControl->processSrtMsg_KMREQ(begin + 1, bytelen, HS_VERSION_SRT1, m_uPeerSrtVersion,
(out_data), (*pw_len));
if (res != SRT_CMD_KMRSP)
{
Expand Down Expand Up @@ -2694,7 +2694,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,
}
else if (cmd == SRT_CMD_KMRSP)
{
int res = m_pCryptoControl->processSrtMsg_KMRSP(begin + 1, bytelen, HS_VERSION_SRT1);
int res = m_pCryptoControl->processSrtMsg_KMRSP(begin + 1, bytelen, m_uPeerSrtVersion);
if (m_config.bEnforcedEnc && res == -1)
{
if (m_pCryptoControl->m_SndKmState == SRT_KM_S_BADSECRET)
Expand Down Expand Up @@ -6023,13 +6023,15 @@ bool srt::CUDT::createCrypter(HandshakeSide side, bool bidirectional)
// they have outdated values.
m_pCryptoControl->setCryptoSecret(m_config.CryptoSecret);

const bool useGcm153 = m_uPeerSrtVersion <= SrtVersion(1, 5, 3);

if (bidirectional || m_config.bDataSender)
{
HLOGC(rslog.Debug, log << CONID() << "createCrypter: setting RCV/SND KeyLen=" << m_config.iSndCryptoKeyLen);
m_pCryptoControl->setCryptoKeylen(m_config.iSndCryptoKeyLen);
}

return m_pCryptoControl->init(side, m_config, bidirectional);
return m_pCryptoControl->init(side, m_config, bidirectional, useGcm153);
}

SRT_REJECT_REASON srt::CUDT::setupCC()
Expand Down Expand Up @@ -7763,7 +7765,7 @@ bool srt::CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg)
// - m_dCWndSize
m_tdSendInterval = microseconds_from((int64_t)m_CongCtl->pktSndPeriod_us());
const double cgwindow = m_CongCtl->cgWindowSize();
m_iCongestionWindow = cgwindow;
m_iCongestionWindow = (int) cgwindow;
#if ENABLE_HEAVY_LOGGING
HLOGC(rslog.Debug,
log << CONID() << "updateCC: updated values from congctl: interval=" << FormatDuration<DUNIT_US>(m_tdSendInterval)
Expand Down
30 changes: 23 additions & 7 deletions srtcore/crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void srt::CCryptoControl::createFakeSndContext()
int srt::CCryptoControl::processSrtMsg_KMREQ(
const uint32_t* srtdata SRT_ATR_UNUSED,
size_t bytelen SRT_ATR_UNUSED,
int hsv SRT_ATR_UNUSED,
int hsv SRT_ATR_UNUSED, unsigned srtv SRT_ATR_UNUSED,
uint32_t pw_srtdata_out[], size_t& w_srtlen)
{
//Receiver
Expand Down Expand Up @@ -172,6 +172,8 @@ int srt::CCryptoControl::processSrtMsg_KMREQ(
(m_iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO && kmdata[HCRYPT_MSG_KM_OFS_CIPHER] == HCRYPT_CIPHER_AES_GCM) ||
(m_iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM);

m_bUseGcm153 = srtv <= SrtVersion(1, 5, 3);

// What we have to do:
// If encryption is on (we know that by having m_KmSecret nonempty), create
// the crypto context (if bidirectional, create for both sending and receiving).
Expand Down Expand Up @@ -331,6 +333,13 @@ int srt::CCryptoControl::processSrtMsg_KMREQ(
HLOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: NOT REPLAYING the key update to TX CRYPTO CTX.");
}

#ifdef SRT_ENABLE_ENCRYPTION
if (m_hRcvCrypto != NULL)
HaiCrypt_UpdateGcm153(m_hRcvCrypto, m_bUseGcm153);
if (m_hSndCrypto != NULL)
HaiCrypt_UpdateGcm153(m_hSndCrypto, m_bUseGcm153);
#endif

return SRT_CMD_KMRSP;

HSv4_ErrorReport:
Expand Down Expand Up @@ -359,7 +368,7 @@ int srt::CCryptoControl::processSrtMsg_KMREQ(
return SRT_CMD_KMRSP;
}

int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, int /* XXX unused? hsv*/)
int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, unsigned srtv)
{
/* All 32-bit msg fields (if present) swapped on reception
* But HaiCrypt expect network order message
Expand All @@ -371,9 +380,6 @@ int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len

int retstatus = -1;

// Unused?
//bool bidirectional = hsv > CUDT::HS_VERSION_UDT4;

// Since now, when CCryptoControl::decrypt() encounters an error, it will print it, ONCE,
// until the next KMREQ is received as a key regeneration.
m_bErrorReported = false;
Expand Down Expand Up @@ -459,6 +465,14 @@ int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len
}
HLOGC(cnlog.Debug, log << "processSrtMsg_KMRSP: key[0]: len=" << m_SndKmMsg[0].MsgLen << " retry=" << m_SndKmMsg[0].iPeerRetry
<< "; key[1]: len=" << m_SndKmMsg[1].MsgLen << " retry=" << m_SndKmMsg[1].iPeerRetry);

m_bUseGcm153 = srtv <= SrtVersion(1, 5, 3);
#ifdef SRT_ENABLE_ENCRYPTION
if (m_hRcvCrypto != NULL)
HaiCrypt_UpdateGcm153(m_hRcvCrypto, m_bUseGcm153);
if (m_hSndCrypto != NULL)
HaiCrypt_UpdateGcm153(m_hSndCrypto, m_bUseGcm153);
#endif
}

LOGP(cnlog.Note, FormatKmMessage("processSrtMsg_KMRSP", SRT_CMD_KMRSP, len));
Expand Down Expand Up @@ -593,6 +607,7 @@ srt::CCryptoControl::CCryptoControl(SRTSOCKET id)
, m_KmRefreshRatePkt(0)
, m_KmPreAnnouncePkt(0)
, m_iCryptoMode(CSrtConfig::CIPHER_MODE_AUTO)
, m_bUseGcm153(false)
, m_bErrorReported(false)
{
m_KmSecret.len = 0;
Expand All @@ -606,7 +621,7 @@ srt::CCryptoControl::CCryptoControl(SRTSOCKET id)
m_hRcvCrypto = NULL;
}

bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool bidirectional SRT_ATR_UNUSED)
bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool bidirectional SRT_ATR_UNUSED, bool bUseGcm153 SRT_ATR_UNUSED)
{
// NOTE: initiator creates m_hSndCrypto. When bidirectional,
// it creates also m_hRcvCrypto with the same key length.
Expand All @@ -620,6 +635,7 @@ bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool b
// Set UNSECURED state as default
m_RcvKmState = SRT_KM_S_UNSECURED;
m_iCryptoMode = cfg.iCryptoMode;
m_bUseGcm153 = bUseGcm153;

#ifdef SRT_ENABLE_ENCRYPTION
if (!cfg.bTSBPD && m_iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO)
Expand Down Expand Up @@ -807,7 +823,7 @@ srt::EncryptionStatus srt::CCryptoControl::encrypt(CPacket& w_packet SRT_ATR_UNU
{
return ENCS_FAILED;
}
else if ( rc > 0 )
else if (rc > 0)
{
// XXX what happens if the encryption is said to be "succeeded",
// but the length is 0? Shouldn't this be treated as unwanted?
Expand Down
Loading

0 comments on commit 5819ade

Please sign in to comment.