123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- /*
- * SRT - Secure, Reliable, Transport
- * Copyright (c) 2018 Haivision Systems Inc.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- */
- /*****************************************************************************
- written by
- Haivision Systems Inc.
- 2011-06-23 (jdube)
- HaiCrypt initial implementation.
- 2014-03-11 (jdube)
- Adaptation for SRT.
- *****************************************************************************/
- #include <stdio.h> /* snprintf */
- #include <stdlib.h> /* NULL, malloc, free */
- #include <string.h> /* memcpy, memset */
- #ifdef _WIN32
- #include <winsock2.h>
- #include <ws2tcpip.h>
- #else
- #include <sys/time.h> /* timerclear */
- #endif
- #include "hcrypt.h"
- #if ENABLE_HAICRYPT_LOGGING
- void HaiCrypt_DumpConfig(const HaiCrypt_Cfg* cfg);
- #else
- #define HaiCrypt_DumpConfig(x) (void)0
- #endif
- static hcrypt_Session* sHaiCrypt_PrepareHandle(const HaiCrypt_Cfg* cfg, HaiCrypt_CryptoDir tx)
- {
- hcrypt_Session *crypto;
- unsigned char *mem_buf;
- size_t mem_siz, inbuf_siz;
- HaiCrypt_DumpConfig(cfg);
- HCRYPT_PRINTKEY(cfg->secret.str, cfg->secret.len, "cfgkey");
- inbuf_siz = 0;
- inbuf_siz = hcryptMsg_PaddedLen(cfg->data_max_len, 128/8);
- /* Allocate crypto session control struct */
- mem_siz = sizeof(hcrypt_Session) // structure
- + inbuf_siz;
- crypto = malloc(mem_siz);
- if (NULL == crypto) {
- HCRYPT_LOG(LOG_ERR, "%s\n", "malloc failed");
- return NULL;
- }
- mem_buf = (unsigned char *)crypto;
- mem_buf += sizeof(*crypto);
- memset(crypto, 0, sizeof(*crypto));
- if (inbuf_siz) {
- crypto->inbuf = mem_buf;
- crypto->inbuf_siz = inbuf_siz;
- }
- crypto->cryspr = cfg->cryspr;
- crypto->cfg.data_max_len = cfg->data_max_len;
- /* Setup transport packet info */
- switch (cfg->xport) {
- case HAICRYPT_XPT_SRT:
- crypto->se = HCRYPT_SE_TSSRT;
- crypto->msg_info = hcryptMsg_SRT_MsgInfo();
- break;
- default:
- HCRYPT_LOG(LOG_ERR, "invalid xport: %d\n", cfg->xport);
- free(crypto);
- return NULL;
- }
- timerclear(&crypto->km.tx_last);
- crypto->km.tx_period.tv_sec = cfg->km_tx_period_ms / 1000;
- crypto->km.tx_period.tv_usec = (cfg->km_tx_period_ms % 1000) * 1000;
- crypto->km.refresh_rate = cfg->km_refresh_rate_pkt;
- crypto->km.pre_announce = cfg->km_pre_announce_pkt;
- /* Indentify each context */
- crypto->ctx_pair[0].flags = HCRYPT_MSG_F_eSEK | (tx ? HCRYPT_CTX_F_ENCRYPT : 0);
- crypto->ctx_pair[1].flags = HCRYPT_MSG_F_oSEK | (tx ? HCRYPT_CTX_F_ENCRYPT : 0);
- /* Point to each other */
- crypto->ctx_pair[0].alt = &crypto->ctx_pair[1];
- crypto->ctx_pair[1].alt = &crypto->ctx_pair[0];
- crypto->cryspr_cb = crypto->cryspr->open(crypto->cryspr, cfg->data_max_len);
- if (NULL == crypto->cryspr_cb) {
- free(crypto);
- return NULL;
- }
- return crypto;
- }
- int HaiCrypt_Create(const HaiCrypt_Cfg *cfg, HaiCrypt_Handle *phhc)
- {
- ASSERT(cfg != NULL);
- ASSERT(phhc != NULL);
- hcrypt_Session *crypto;
- HaiCrypt_CryptoDir tx = (HaiCrypt_CryptoDir)(HAICRYPT_CFG_F_TX & cfg->flags);
- *phhc = NULL;
- HCRYPT_LOG_INIT();
- //Test log
- HCRYPT_LOG(LOG_INFO, "creating crypto context(flags=0x%x)\n", cfg->flags);
- if (!(HAICRYPT_CFG_F_CRYPTO & cfg->flags)) {
- HCRYPT_LOG(LOG_INFO, "no supported flags set (0x%x)\n", cfg->flags);
- return(-1);
- } else if ((16 != cfg->key_len) /* SEK length */
- && (24 != cfg->key_len)
- && (32 != cfg->key_len)) {
- HCRYPT_LOG(LOG_ERR, "invalid key length (%d). Expected: 16, 24, 32\n", (int)cfg->key_len);
- return(-1);
- } else if ((HAICRYPT_SECTYP_PASSPHRASE == cfg->secret.typ)
- && ((0 == cfg->secret.len) || (sizeof(cfg->secret.str) < cfg->secret.len))) { /* KEK length */
- HCRYPT_LOG(LOG_ERR, "invalid secret passphrase length (%d)\n", (int)cfg->secret.len);
- return(-1);
- } else if ((HAICRYPT_SECTYP_PRESHARED == cfg->secret.typ)
- && (cfg->key_len > cfg->secret.len)) {
- HCRYPT_LOG(LOG_ERR, "preshared secret length (%d) smaller than key length (%d)\n",
- (int)cfg->secret.len, (int)cfg->key_len);
- return(-1);
- } else if (NULL == cfg->cryspr) {
- HCRYPT_LOG(LOG_ERR, "%s\n", "no cryspr specified");
- return(-1);
- } else if (0 == cfg->data_max_len) {
- HCRYPT_LOG(LOG_ERR, "%s\n", "no data_max_len specified");
- return(-1);
- }
- crypto = sHaiCrypt_PrepareHandle(cfg, tx);
- if (!crypto)
- return -1;
- if (tx) { /* Encoder */
- /* Configure initial context */
- if (hcryptCtx_Tx_Init(crypto, &crypto->ctx_pair[0], cfg)
- || hcryptCtx_Tx_Init(crypto, &crypto->ctx_pair[1], cfg)) {
- free(crypto);
- return(-1);
- }
- /* Generate keys for first (default) context */
- if (hcryptCtx_Tx_Rekey(crypto, &crypto->ctx_pair[0])) {
- free(crypto);
- return(-1);
- }
- crypto->ctx = &crypto->ctx_pair[0];
- crypto->ctx->flags |= (HCRYPT_CTX_F_ANNOUNCE | HCRYPT_CTX_F_TTSEND);
- crypto->ctx->status = HCRYPT_CTX_S_ACTIVE;
- } else { /* Decoder */
- /* Configure contexts */
- if (hcryptCtx_Rx_Init(crypto, &crypto->ctx_pair[0], cfg)
- || hcryptCtx_Rx_Init(crypto, &crypto->ctx_pair[1], cfg)) {
- free(crypto);
- return(-1);
- }
- }
- *phhc = (void *)crypto;
- return(0);
- }
- int HaiCrypt_ExtractConfig(HaiCrypt_Handle hhcSrc, HaiCrypt_Cfg* pcfg)
- {
- hcrypt_Session *crypto = (hcrypt_Session *)hhcSrc;
- hcrypt_Ctx* ctx = crypto->ctx;
- if (!ctx)
- {
- // Fall back to the first of the pair;
- // Should this be not initialized, ignore it.
- ctx = &crypto->ctx_pair[0];
- // We assume that when ctx != NULL, it is active or keyed anyway.
- if (ctx->status != HCRYPT_CTX_S_KEYED && ctx->status != HCRYPT_CTX_S_ACTIVE)
- return -1;
- }
- pcfg->flags = HAICRYPT_CFG_F_CRYPTO;
- if ((ctx->flags & HCRYPT_CTX_F_ENCRYPT) == HCRYPT_CTX_F_ENCRYPT)
- pcfg->flags |= HAICRYPT_CFG_F_TX;
-
- if (ctx->mode == HCRYPT_CTX_MODE_AESGCM)
- pcfg->flags |= HAICRYPT_CFG_F_GCM;
- /* Set this explicitly - this use of this library is SRT only. */
- pcfg->xport = HAICRYPT_XPT_SRT;
- pcfg->cryspr = crypto->cryspr;
- pcfg->key_len = ctx->cfg.key_len;
- if (pcfg->key_len == 0) // not initialized - usual in RX
- {
- pcfg->key_len = ctx->sek_len;
- }
- pcfg->data_max_len = crypto->cfg.data_max_len;
- pcfg->km_tx_period_ms = 0;//No HaiCrypt KM inject period, handled in SRT;
- pcfg->km_refresh_rate_pkt = crypto->km.refresh_rate;
- pcfg->km_pre_announce_pkt = crypto->km.pre_announce;
- /* As SRT is using only the PASSPHRASE type, never PRESHARED,
- * this is so assumed here, although there are completely no
- * premises as to which is currently used by the hhcSrc.
- */
- pcfg->secret.typ = HAICRYPT_SECTYP_PASSPHRASE;
- pcfg->secret.len = ctx->cfg.pwd_len;
- memcpy(pcfg->secret.str, ctx->cfg.pwd, pcfg->secret.len);
- return 0;
- }
- int HaiCrypt_Clone(HaiCrypt_Handle hhcSrc, HaiCrypt_CryptoDir tx, HaiCrypt_Handle *phhc)
- {
- hcrypt_Session *cryptoSrc = (hcrypt_Session *)hhcSrc;
- hcrypt_Session *cryptoClone;
- unsigned char *mem_buf;
- size_t mem_siz, inbuf_siz;
- *phhc = NULL;
- ASSERT(NULL != hhcSrc);
- HCRYPT_LOG(LOG_INFO, "%s\n", "creating CLONED crypto context");
- if (tx) {
- HaiCrypt_Cfg crypto_config;
- if (-1 == HaiCrypt_ExtractConfig(hhcSrc, &crypto_config))
- return -1;
- /*
- * Just invert the direction written in flags and use the
- * standard way of creating the context, as you already have a config.
- */
- crypto_config.flags |= HAICRYPT_CFG_F_TX;
- cryptoClone = sHaiCrypt_PrepareHandle(&crypto_config, tx);
- if (!cryptoClone)
- return -1;
- /* Configure initial context */
- if (hcryptCtx_Tx_Init(cryptoClone, &cryptoClone->ctx_pair[0], &crypto_config)
- || hcryptCtx_Tx_Init(cryptoClone, &cryptoClone->ctx_pair[1], &crypto_config)) {
- free(cryptoClone);
- return(-1);
- }
- /* Clone keys for first (default) context from the source RX crypto */
- if (hcryptCtx_Tx_CloneKey(cryptoClone, &cryptoClone->ctx_pair[0], cryptoSrc)) {
- free(cryptoClone);
- return(-1);
- }
- cryptoClone->ctx = &cryptoClone->ctx_pair[0];
- cryptoClone->ctx->flags |= (HCRYPT_CTX_F_ANNOUNCE | HCRYPT_CTX_F_TTSEND);
- cryptoClone->ctx->status = HCRYPT_CTX_S_ACTIVE;
- } else { /* Receiver */
- /*
- * If cryspr has no special input buffer alignment requirement,
- * handle it in the crypto session.
- */
- inbuf_siz = cryptoSrc->inbuf_siz ;
- /* Allocate crypto session control struct */
- mem_siz = sizeof(hcrypt_Session) // structure
- + inbuf_siz;
- cryptoClone = malloc(mem_siz);
- if (NULL == cryptoClone) {
- HCRYPT_LOG(LOG_ERR, "%s\n", "malloc failed");
- return(-1);
- }
- mem_buf = (unsigned char *)cryptoClone;
- mem_buf += sizeof(*cryptoClone);
- memcpy(cryptoClone, cryptoSrc, sizeof(*cryptoClone));
- if (inbuf_siz) {
- cryptoClone->inbuf = mem_buf;
- mem_buf += inbuf_siz;
- }
- timerclear(&cryptoClone->km.tx_last);
- /* Adjust pointers pointing into cryproSrc after copy
- msg_info and crysprs are extern statics so this is ok*/
- cryptoClone->ctx_pair[0].alt = &cryptoClone->ctx_pair[1];
- cryptoClone->ctx_pair[1].alt = &cryptoClone->ctx_pair[0];
- /* create a new cryspr (OpenSSL) context */
- cryptoClone->cryspr_cb = cryptoClone->cryspr->open(cryptoClone->cryspr, cryptoClone->cfg.data_max_len);
- if (NULL == cryptoClone->cryspr_cb) {
- //shred
- free(cryptoClone);
- return(-1);
- }
- /* Configure contexts. Note that GCM mode has been already copied from the source context. */
- if (hcryptCtx_Rx_Init(cryptoClone, &cryptoClone->ctx_pair[0], NULL)
- || hcryptCtx_Rx_Init(cryptoClone, &cryptoClone->ctx_pair[1], NULL)) {
- free(cryptoClone);
- return(-1);
- }
- /* Clear salt to force later regeneration of KEK as AES decrypting key,
- copyed one is encrypting key */
- cryptoClone->ctx_pair[0].flags &= ~HCRYPT_CTX_F_ENCRYPT;
- cryptoClone->ctx_pair[1].flags &= ~HCRYPT_CTX_F_ENCRYPT;
- memset(cryptoClone->ctx_pair[0].salt, 0, sizeof(cryptoClone->ctx_pair[0].salt));
- cryptoClone->ctx_pair[0].salt_len = 0;
- }
- *phhc = (void *)cryptoClone;
- return(0);
- }
- int HaiCrypt_Close(HaiCrypt_Handle hhc)
- {
- hcrypt_Session *crypto = (hcrypt_Session *)hhc;
- int rc = -1;
- if (crypto) {
- if (crypto->cryspr && crypto->cryspr->close) crypto->cryspr->close(crypto->cryspr_cb);
- free(crypto);
- rc = 0;
- }
- HCRYPT_LOG_EXIT();
- return rc;
- }
- int HaiCrypt_IsAESGCM_Supported(void)
- {
- #if CRYSPR_HAS_AESGCM
- return 1;
- #else
- return 0;
- #endif
- }
|