hcrypt.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. * SRT - Secure, Reliable, Transport
  3. * Copyright (c) 2018 Haivision Systems Inc.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. */
  10. /*****************************************************************************
  11. written by
  12. Haivision Systems Inc.
  13. 2011-06-23 (jdube)
  14. HaiCrypt initial implementation.
  15. 2014-03-11 (jdube)
  16. Adaptation for SRT.
  17. *****************************************************************************/
  18. #include <stdio.h> /* snprintf */
  19. #include <stdlib.h> /* NULL, malloc, free */
  20. #include <string.h> /* memcpy, memset */
  21. #ifdef _WIN32
  22. #include <winsock2.h>
  23. #include <ws2tcpip.h>
  24. #else
  25. #include <sys/time.h> /* timerclear */
  26. #endif
  27. #include "hcrypt.h"
  28. #if ENABLE_HAICRYPT_LOGGING
  29. void HaiCrypt_DumpConfig(const HaiCrypt_Cfg* cfg);
  30. #else
  31. #define HaiCrypt_DumpConfig(x) (void)0
  32. #endif
  33. static hcrypt_Session* sHaiCrypt_PrepareHandle(const HaiCrypt_Cfg* cfg, HaiCrypt_CryptoDir tx)
  34. {
  35. hcrypt_Session *crypto;
  36. unsigned char *mem_buf;
  37. size_t mem_siz, inbuf_siz;
  38. HaiCrypt_DumpConfig(cfg);
  39. HCRYPT_PRINTKEY(cfg->secret.str, cfg->secret.len, "cfgkey");
  40. inbuf_siz = 0;
  41. inbuf_siz = hcryptMsg_PaddedLen(cfg->data_max_len, 128/8);
  42. /* Allocate crypto session control struct */
  43. mem_siz = sizeof(hcrypt_Session) // structure
  44. + inbuf_siz;
  45. crypto = malloc(mem_siz);
  46. if (NULL == crypto) {
  47. HCRYPT_LOG(LOG_ERR, "%s\n", "malloc failed");
  48. return NULL;
  49. }
  50. mem_buf = (unsigned char *)crypto;
  51. mem_buf += sizeof(*crypto);
  52. memset(crypto, 0, sizeof(*crypto));
  53. if (inbuf_siz) {
  54. crypto->inbuf = mem_buf;
  55. crypto->inbuf_siz = inbuf_siz;
  56. }
  57. crypto->cryspr = cfg->cryspr;
  58. crypto->cfg.data_max_len = cfg->data_max_len;
  59. /* Setup transport packet info */
  60. switch (cfg->xport) {
  61. case HAICRYPT_XPT_SRT:
  62. crypto->se = HCRYPT_SE_TSSRT;
  63. crypto->msg_info = hcryptMsg_SRT_MsgInfo();
  64. break;
  65. default:
  66. HCRYPT_LOG(LOG_ERR, "invalid xport: %d\n", cfg->xport);
  67. free(crypto);
  68. return NULL;
  69. }
  70. timerclear(&crypto->km.tx_last);
  71. crypto->km.tx_period.tv_sec = cfg->km_tx_period_ms / 1000;
  72. crypto->km.tx_period.tv_usec = (cfg->km_tx_period_ms % 1000) * 1000;
  73. crypto->km.refresh_rate = cfg->km_refresh_rate_pkt;
  74. crypto->km.pre_announce = cfg->km_pre_announce_pkt;
  75. /* Indentify each context */
  76. crypto->ctx_pair[0].flags = HCRYPT_MSG_F_eSEK | (tx ? HCRYPT_CTX_F_ENCRYPT : 0);
  77. crypto->ctx_pair[1].flags = HCRYPT_MSG_F_oSEK | (tx ? HCRYPT_CTX_F_ENCRYPT : 0);
  78. /* Point to each other */
  79. crypto->ctx_pair[0].alt = &crypto->ctx_pair[1];
  80. crypto->ctx_pair[1].alt = &crypto->ctx_pair[0];
  81. crypto->cryspr_cb = crypto->cryspr->open(crypto->cryspr, cfg->data_max_len);
  82. if (NULL == crypto->cryspr_cb) {
  83. free(crypto);
  84. return NULL;
  85. }
  86. return crypto;
  87. }
  88. int HaiCrypt_Create(const HaiCrypt_Cfg *cfg, HaiCrypt_Handle *phhc)
  89. {
  90. ASSERT(cfg != NULL);
  91. ASSERT(phhc != NULL);
  92. hcrypt_Session *crypto;
  93. HaiCrypt_CryptoDir tx = (HaiCrypt_CryptoDir)(HAICRYPT_CFG_F_TX & cfg->flags);
  94. *phhc = NULL;
  95. HCRYPT_LOG_INIT();
  96. //Test log
  97. HCRYPT_LOG(LOG_INFO, "creating crypto context(flags=0x%x)\n", cfg->flags);
  98. if (!(HAICRYPT_CFG_F_CRYPTO & cfg->flags)) {
  99. HCRYPT_LOG(LOG_INFO, "no supported flags set (0x%x)\n", cfg->flags);
  100. return(-1);
  101. } else if ((16 != cfg->key_len) /* SEK length */
  102. && (24 != cfg->key_len)
  103. && (32 != cfg->key_len)) {
  104. HCRYPT_LOG(LOG_ERR, "invalid key length (%d). Expected: 16, 24, 32\n", (int)cfg->key_len);
  105. return(-1);
  106. } else if ((HAICRYPT_SECTYP_PASSPHRASE == cfg->secret.typ)
  107. && ((0 == cfg->secret.len) || (sizeof(cfg->secret.str) < cfg->secret.len))) { /* KEK length */
  108. HCRYPT_LOG(LOG_ERR, "invalid secret passphrase length (%d)\n", (int)cfg->secret.len);
  109. return(-1);
  110. } else if ((HAICRYPT_SECTYP_PRESHARED == cfg->secret.typ)
  111. && (cfg->key_len > cfg->secret.len)) {
  112. HCRYPT_LOG(LOG_ERR, "preshared secret length (%d) smaller than key length (%d)\n",
  113. (int)cfg->secret.len, (int)cfg->key_len);
  114. return(-1);
  115. } else if (NULL == cfg->cryspr) {
  116. HCRYPT_LOG(LOG_ERR, "%s\n", "no cryspr specified");
  117. return(-1);
  118. } else if (0 == cfg->data_max_len) {
  119. HCRYPT_LOG(LOG_ERR, "%s\n", "no data_max_len specified");
  120. return(-1);
  121. }
  122. crypto = sHaiCrypt_PrepareHandle(cfg, tx);
  123. if (!crypto)
  124. return -1;
  125. if (tx) { /* Encoder */
  126. /* Configure initial context */
  127. if (hcryptCtx_Tx_Init(crypto, &crypto->ctx_pair[0], cfg)
  128. || hcryptCtx_Tx_Init(crypto, &crypto->ctx_pair[1], cfg)) {
  129. free(crypto);
  130. return(-1);
  131. }
  132. /* Generate keys for first (default) context */
  133. if (hcryptCtx_Tx_Rekey(crypto, &crypto->ctx_pair[0])) {
  134. free(crypto);
  135. return(-1);
  136. }
  137. crypto->ctx = &crypto->ctx_pair[0];
  138. crypto->ctx->flags |= (HCRYPT_CTX_F_ANNOUNCE | HCRYPT_CTX_F_TTSEND);
  139. crypto->ctx->status = HCRYPT_CTX_S_ACTIVE;
  140. } else { /* Decoder */
  141. /* Configure contexts */
  142. if (hcryptCtx_Rx_Init(crypto, &crypto->ctx_pair[0], cfg)
  143. || hcryptCtx_Rx_Init(crypto, &crypto->ctx_pair[1], cfg)) {
  144. free(crypto);
  145. return(-1);
  146. }
  147. }
  148. *phhc = (void *)crypto;
  149. return(0);
  150. }
  151. int HaiCrypt_ExtractConfig(HaiCrypt_Handle hhcSrc, HaiCrypt_Cfg* pcfg)
  152. {
  153. hcrypt_Session *crypto = (hcrypt_Session *)hhcSrc;
  154. hcrypt_Ctx* ctx = crypto->ctx;
  155. if (!ctx)
  156. {
  157. // Fall back to the first of the pair;
  158. // Should this be not initialized, ignore it.
  159. ctx = &crypto->ctx_pair[0];
  160. // We assume that when ctx != NULL, it is active or keyed anyway.
  161. if (ctx->status != HCRYPT_CTX_S_KEYED && ctx->status != HCRYPT_CTX_S_ACTIVE)
  162. return -1;
  163. }
  164. pcfg->flags = HAICRYPT_CFG_F_CRYPTO;
  165. if ((ctx->flags & HCRYPT_CTX_F_ENCRYPT) == HCRYPT_CTX_F_ENCRYPT)
  166. pcfg->flags |= HAICRYPT_CFG_F_TX;
  167. if (ctx->mode == HCRYPT_CTX_MODE_AESGCM)
  168. pcfg->flags |= HAICRYPT_CFG_F_GCM;
  169. /* Set this explicitly - this use of this library is SRT only. */
  170. pcfg->xport = HAICRYPT_XPT_SRT;
  171. pcfg->cryspr = crypto->cryspr;
  172. pcfg->key_len = ctx->cfg.key_len;
  173. if (pcfg->key_len == 0) // not initialized - usual in RX
  174. {
  175. pcfg->key_len = ctx->sek_len;
  176. }
  177. pcfg->data_max_len = crypto->cfg.data_max_len;
  178. pcfg->km_tx_period_ms = 0;//No HaiCrypt KM inject period, handled in SRT;
  179. pcfg->km_refresh_rate_pkt = crypto->km.refresh_rate;
  180. pcfg->km_pre_announce_pkt = crypto->km.pre_announce;
  181. /* As SRT is using only the PASSPHRASE type, never PRESHARED,
  182. * this is so assumed here, although there are completely no
  183. * premises as to which is currently used by the hhcSrc.
  184. */
  185. pcfg->secret.typ = HAICRYPT_SECTYP_PASSPHRASE;
  186. pcfg->secret.len = ctx->cfg.pwd_len;
  187. memcpy(pcfg->secret.str, ctx->cfg.pwd, pcfg->secret.len);
  188. return 0;
  189. }
  190. int HaiCrypt_Clone(HaiCrypt_Handle hhcSrc, HaiCrypt_CryptoDir tx, HaiCrypt_Handle *phhc)
  191. {
  192. hcrypt_Session *cryptoSrc = (hcrypt_Session *)hhcSrc;
  193. hcrypt_Session *cryptoClone;
  194. unsigned char *mem_buf;
  195. size_t mem_siz, inbuf_siz;
  196. *phhc = NULL;
  197. ASSERT(NULL != hhcSrc);
  198. HCRYPT_LOG(LOG_INFO, "%s\n", "creating CLONED crypto context");
  199. if (tx) {
  200. HaiCrypt_Cfg crypto_config;
  201. if (-1 == HaiCrypt_ExtractConfig(hhcSrc, &crypto_config))
  202. return -1;
  203. /*
  204. * Just invert the direction written in flags and use the
  205. * standard way of creating the context, as you already have a config.
  206. */
  207. crypto_config.flags |= HAICRYPT_CFG_F_TX;
  208. cryptoClone = sHaiCrypt_PrepareHandle(&crypto_config, tx);
  209. if (!cryptoClone)
  210. return -1;
  211. /* Configure initial context */
  212. if (hcryptCtx_Tx_Init(cryptoClone, &cryptoClone->ctx_pair[0], &crypto_config)
  213. || hcryptCtx_Tx_Init(cryptoClone, &cryptoClone->ctx_pair[1], &crypto_config)) {
  214. free(cryptoClone);
  215. return(-1);
  216. }
  217. /* Clone keys for first (default) context from the source RX crypto */
  218. if (hcryptCtx_Tx_CloneKey(cryptoClone, &cryptoClone->ctx_pair[0], cryptoSrc)) {
  219. free(cryptoClone);
  220. return(-1);
  221. }
  222. cryptoClone->ctx = &cryptoClone->ctx_pair[0];
  223. cryptoClone->ctx->flags |= (HCRYPT_CTX_F_ANNOUNCE | HCRYPT_CTX_F_TTSEND);
  224. cryptoClone->ctx->status = HCRYPT_CTX_S_ACTIVE;
  225. } else { /* Receiver */
  226. /*
  227. * If cryspr has no special input buffer alignment requirement,
  228. * handle it in the crypto session.
  229. */
  230. inbuf_siz = cryptoSrc->inbuf_siz ;
  231. /* Allocate crypto session control struct */
  232. mem_siz = sizeof(hcrypt_Session) // structure
  233. + inbuf_siz;
  234. cryptoClone = malloc(mem_siz);
  235. if (NULL == cryptoClone) {
  236. HCRYPT_LOG(LOG_ERR, "%s\n", "malloc failed");
  237. return(-1);
  238. }
  239. mem_buf = (unsigned char *)cryptoClone;
  240. mem_buf += sizeof(*cryptoClone);
  241. memcpy(cryptoClone, cryptoSrc, sizeof(*cryptoClone));
  242. if (inbuf_siz) {
  243. cryptoClone->inbuf = mem_buf;
  244. mem_buf += inbuf_siz;
  245. }
  246. timerclear(&cryptoClone->km.tx_last);
  247. /* Adjust pointers pointing into cryproSrc after copy
  248. msg_info and crysprs are extern statics so this is ok*/
  249. cryptoClone->ctx_pair[0].alt = &cryptoClone->ctx_pair[1];
  250. cryptoClone->ctx_pair[1].alt = &cryptoClone->ctx_pair[0];
  251. /* create a new cryspr (OpenSSL) context */
  252. cryptoClone->cryspr_cb = cryptoClone->cryspr->open(cryptoClone->cryspr, cryptoClone->cfg.data_max_len);
  253. if (NULL == cryptoClone->cryspr_cb) {
  254. //shred
  255. free(cryptoClone);
  256. return(-1);
  257. }
  258. /* Configure contexts. Note that GCM mode has been already copied from the source context. */
  259. if (hcryptCtx_Rx_Init(cryptoClone, &cryptoClone->ctx_pair[0], NULL)
  260. || hcryptCtx_Rx_Init(cryptoClone, &cryptoClone->ctx_pair[1], NULL)) {
  261. free(cryptoClone);
  262. return(-1);
  263. }
  264. /* Clear salt to force later regeneration of KEK as AES decrypting key,
  265. copyed one is encrypting key */
  266. cryptoClone->ctx_pair[0].flags &= ~HCRYPT_CTX_F_ENCRYPT;
  267. cryptoClone->ctx_pair[1].flags &= ~HCRYPT_CTX_F_ENCRYPT;
  268. memset(cryptoClone->ctx_pair[0].salt, 0, sizeof(cryptoClone->ctx_pair[0].salt));
  269. cryptoClone->ctx_pair[0].salt_len = 0;
  270. }
  271. *phhc = (void *)cryptoClone;
  272. return(0);
  273. }
  274. int HaiCrypt_Close(HaiCrypt_Handle hhc)
  275. {
  276. hcrypt_Session *crypto = (hcrypt_Session *)hhc;
  277. int rc = -1;
  278. if (crypto) {
  279. if (crypto->cryspr && crypto->cryspr->close) crypto->cryspr->close(crypto->cryspr_cb);
  280. free(crypto);
  281. rc = 0;
  282. }
  283. HCRYPT_LOG_EXIT();
  284. return rc;
  285. }
  286. int HaiCrypt_IsAESGCM_Supported(void)
  287. {
  288. #if CRYSPR_HAS_AESGCM
  289. return 1;
  290. #else
  291. return 0;
  292. #endif
  293. }