Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved AES GCM encryption, changed IV length to 12 bytes. #2962

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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));
Fixed Show fixed Hide fixed
}

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));
Fixed Show fixed Hide fixed
}

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 @@ -2020,7 +2020,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 @@ -2057,7 +2057,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 @@ -2646,7 +2646,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 @@ -2693,7 +2693,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 @@ -6022,13 +6022,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 @@ -7762,7 +7764,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
Loading