UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
openssl_encrypt.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2013-2024 CESNET
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
51
52#include <assert.h> // for assert
53#include <stdint.h> // for uint32_t
54#include <stdlib.h> // for free, abort, calloc
55#include <string.h> // for NULL, memcpy, strcmp, strlen
56
57#ifdef HAVE_CONFIG_H
58#include "config.h"
59#endif
60
61#ifdef HAVE_WOLFSSL
62#define OPENSSL_EXTRA
63#define WC_NO_HARDEN
64#include <wolfssl/options.h>
65#include <wolfssl/openssl/aes.h>
66#include <wolfssl/openssl/err.h>
67#include <wolfssl/openssl/evp.h>
68#include <wolfssl/openssl/rand.h>
69#else
70#include <openssl/aes.h>
71#include <openssl/err.h>
72#include <openssl/evp.h>
73#include <openssl/rand.h>
74#endif
75
76#include "compat/strings.h" // for strncasecmp
77#include "crypto/crc.h"
78#include "crypto/md5.h"
79#include "debug.h"
80#include "lib_common.h"
81#include "utils/color_out.h" // for color_printf, TBOLD
82#include "utils/macros.h" // for STR_LEN, snprintf_ch
83
84#define DEFAULT_CIPHER_MODE MODE_AES128_GCM
85#define GCM_TAG_LEN 16
86#define MOD_NAME "[encrypt] "
87
89 EVP_CIPHER_CTX *ctx;
90 const EVP_CIPHER *cipher;
92 unsigned char key_hash[16];
93};
94
95const struct {
97 const char *name;
98 const EVP_CIPHER *(*get_cipher)(void);
99} ciphers[] = {
100#if defined HAVE_EVP_AES_128_CFB128
101 { MODE_AES128_CFB, "cfb", EVP_aes_128_cfb128 },
102#endif
103#if defined HAVE_EVP_AES_128_CTR
104 { MODE_AES128_CTR, "ctr", EVP_aes_128_ctr },
105#endif
106#if defined HAVE_EVP_AES_128_ECB
107 { MODE_AES128_ECB, "ecb", EVP_aes_128_ecb },
108#endif
109 { MODE_AES128_CBC, "cbc", EVP_aes_128_cbc },
110
111 { MODE_AES128_GCM, "gcm", EVP_aes_128_gcm },
113
114const void *get_cipher(enum openssl_mode mode) {
115 for (unsigned i = 0; i < sizeof ciphers / sizeof ciphers[0]; ++i) {
116 if (ciphers[i].mode == mode) {
117 return ciphers[i].get_cipher();
118 }
119 }
120 return NULL;
121}
122
123static void
124usage(void)
125{
126 color_printf("Usage:\n");
127 color_printf("\t" TBOLD("-e <passphrase>[:cipher=<c>]") "\n");
128 color_printf("\nAvailable ciphers:\n");
129 for (unsigned i = 0; i < sizeof ciphers / sizeof ciphers[0]; ++i) {
130 color_printf("\t- " TBOLD("%s") "\n", ciphers[i].name);
131 }
132}
133
134static enum openssl_mode
136{
137 char *tok = strstr(str, ":cipher=");
138 assert(tok != NULL);
139 char *cipher = strchr(tok, '=') + 1;
140 *tok = '\0';
141 for (unsigned i = 0; i < sizeof ciphers / sizeof ciphers[0]; ++i) {
142 if (strcasecmp(ciphers[i].name, cipher) == 0) {
143 return ciphers[i].mode;
144 }
145 }
146 MSG(ERROR, "Unknown/unsuppoted/not compiled cipher %s!\n", cipher);
147 return MODE_AES128_NONE;
148}
149
150static int
151openssl_encrypt_init(struct openssl_encrypt **state, const char *passphrase)
152{
154
155 struct openssl_encrypt *s = (struct openssl_encrypt *)
156 calloc(1, sizeof(struct openssl_encrypt));
157
158 if (strcmp(passphrase, "help") == 0) {
159 usage();
160 return 1;
161 }
162
163 char pass[STR_LEN];
164 snprintf_ch(pass, "%s", passphrase);
165
166 if (strstr(passphrase, ":cipher=")) {
168 }
169
170 MD5CTX context;
171
172 MD5Init(&context);
173 MD5Update(&context, (const unsigned char *) pass,
174 strlen(pass));
175 MD5Final(s->key_hash, &context);
176
177 s->cipher = get_cipher(mode);
178 if (s->cipher == NULL) {
179 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cipher %d not available!\n", (int) mode);
180 free(s);
181 return -1;
182 }
183
184 s->ctx = EVP_CIPHER_CTX_new();
185 s->mode = mode;
186 log_msg(LOG_LEVEL_INFO, MOD_NAME "Encryption set to mode %d\n", (int) mode);
187
188 *state = s;
189 return 0;
190}
191
193{
194 EVP_CIPHER_CTX_free(s->ctx);
195 free(s);
196}
197
198#define CHECK(action, errmsg) do { int rc = action; if (rc != 1) { log_msg(LOG_LEVEL_ERROR, MOD_NAME errmsg ": %s\n", ERR_error_string(ERR_get_error(), NULL)); return 0; } } while(0)
199
200static int openssl_encrypt(struct openssl_encrypt *encryption,
201 char *plaintext, int data_len, char *aad, int aad_len, char *ciphertext)
202{
203 memcpy(ciphertext, &data_len, sizeof(uint32_t));
204 int total_len = sizeof(uint32_t);
205
206 unsigned char ivec[16];
207 if (RAND_bytes(ivec, 8) < 0) {
208 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot generate random bytes!\n");
209 return 0;
210 }
211 memcpy(ciphertext + total_len, ivec, sizeof ivec);
212 total_len += sizeof ivec;
213
214 CHECK(EVP_CipherInit(encryption->ctx, encryption->cipher, encryption->key_hash, ivec, 1), "Cannot initialize cipher");
215 /* Set IV length if default 12 bytes (96 bits) is not appropriate */
216 CHECK(EVP_CIPHER_CTX_ctrl(encryption->ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof ivec, NULL), "set IV len");
217 int out_len = 0;
218 if (encryption->mode == MODE_AES128_GCM) {
219 if (aad_len > 0) {
220 EVP_EncryptUpdate(encryption->ctx, NULL, &out_len, (unsigned char *) aad, aad_len);
221 }
222 }
223 CHECK(EVP_CipherUpdate(encryption->ctx, (unsigned char *) ciphertext + total_len, &out_len, (unsigned char *) plaintext, data_len), "EVP_CipherUpdate");
224 total_len += out_len;
225 if (encryption->mode != MODE_AES128_GCM) {
226 uint32_t crc = crc32buf(aad, aad_len);
227 crc = crc32buf_with_oldcrc(plaintext, data_len, crc);
228 CHECK(EVP_CipherUpdate(encryption->ctx, (unsigned char *) ciphertext + total_len, &out_len, (unsigned char *) &crc, sizeof crc), "EVP_CipherUpdate CRC");
229 total_len += out_len;
230 }
231 CHECK(EVP_CipherFinal(encryption->ctx, (unsigned char *) ciphertext + total_len, &out_len), "EVP_CipherFinal");
232 total_len += out_len;
233 if (encryption->mode == MODE_AES128_GCM) {
234 CHECK(EVP_CIPHER_CTX_ctrl(encryption->ctx, EVP_CTRL_GCM_GET_TAG, GCM_TAG_LEN, ciphertext + total_len), "GCM get tag");
235 total_len += GCM_TAG_LEN;
236 }
237
238 return total_len;
239}
240
242{
243 return sizeof(uint32_t) /* data_len */ +
244 16 /* nonce + counter */ + (s->mode == MODE_AES128_GCM ? GCM_TAG_LEN : sizeof(uint32_t) /* crc */)
245 + (s->mode == MODE_AES128_ECB ? 15 : 0 /* padding */);
246}
247
248static enum openssl_mode
250{
251 return encryption->mode;
252}
253
261
263
void ** state
int color_printf(const char *format,...)
#define TBOLD(x)
Definition color_out.h:70
uint32_t crc32buf(const char *buf, size_t len)
Definition crc_32.c:176
uint32_t crc32buf_with_oldcrc(const char *buf, size_t len, uint32_t oldcrc)
Definition crc_32.c:162
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define MSG(l, fmt,...)
Definition debug.h:96
@ LIBRARY_CLASS_UNDEFINED
Definition lib_common.h:74
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define snprintf_ch(str,...)
shortcut for snprintf(var, sizeof var...), var must be a char array
Definition macros.h:101
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134
void MD5Update(MD5CTX *context, const unsigned char *input, unsigned int inputLen)
Definition md5.c:249
void MD5Final(unsigned char digest[16], MD5CTX *context)
Definition md5.c:295
void MD5Init(MD5CTX *context)
Definition md5.c:229
const struct @17 ciphers[]
static enum openssl_mode get_cipher_from_str(char *str)
static int openssl_encrypt_init(struct openssl_encrypt **state, const char *passphrase)
enum openssl_mode mode
#define DEFAULT_CIPHER_MODE
#define GCM_TAG_LEN
const char * name
static enum openssl_mode openssl_get_cipher(struct openssl_encrypt *encryption)
static int openssl_encrypt(struct openssl_encrypt *encryption, char *plaintext, int data_len, char *aad, int aad_len, char *ciphertext)
static int openssl_get_overhead(struct openssl_encrypt *s)
#define MOD_NAME
static void openssl_encrypt_destroy(struct openssl_encrypt *s)
static const struct openssl_encrypt_info functions
static void usage(void)
#define CHECK(action, errmsg)
const EVP_CIPHER *(* get_cipher)(void)
#define OPENSSL_ENCRYPT_ABI_VERSION
openssl_mode
only GCM provides autenticity, other modes only check integrity (CRC)
@ MODE_AES128_NONE
@ MODE_AES128_CFB
@ MODE_AES128_CTR
@ MODE_AES128_ECB
@ MODE_AES128_CBC
@ MODE_AES128_GCM
Definition md5.h:34
const EVP_CIPHER * cipher
enum openssl_mode mode
EVP_CIPHER_CTX * ctx
unsigned char key_hash[16]