uencrypt: Fix mbedtls 3.6 compatibility
[openwrt/openwrt.git] / package / utils / uencrypt / src / uencrypt-mbedtls.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2 * Copyright (C) 2023 Eneas Ulir de Queiroz
3 */
4
5 #include <ctype.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include "uencrypt.h"
11
12 #if MBEDTLS_VERSION_NUMBER < 0x03010000 /* mbedtls 3.1.0 */
13 static inline mbedtls_cipher_mode_t mbedtls_cipher_info_get_mode(
14 const mbedtls_cipher_info_t *info)
15 {
16 if (info == NULL) {
17 return MBEDTLS_MODE_NONE;
18 } else {
19 return info->mode;
20 }
21 }
22
23 static inline size_t mbedtls_cipher_info_get_key_bitlen(
24 const mbedtls_cipher_info_t *info)
25 {
26 if (info == NULL) {
27 return 0;
28 } else {
29 return info->key_bitlen;
30 }
31 }
32
33 static inline const char *mbedtls_cipher_info_get_name(
34 const mbedtls_cipher_info_t *info)
35 {
36 if (info == NULL) {
37 return NULL;
38 } else {
39 return info->name;
40 }
41 }
42
43 static inline size_t mbedtls_cipher_info_get_iv_size(
44 const mbedtls_cipher_info_t *info)
45 {
46 if (info == NULL) {
47 return 0;
48 }
49
50 return info->iv_size;
51 }
52
53 static inline size_t mbedtls_cipher_info_get_block_size(
54 const mbedtls_cipher_info_t *info)
55 {
56 if (info == NULL) {
57 return 0;
58 }
59
60 return info->block_size;
61 }
62 #endif
63
64 unsigned char *hexstr2buf(const char *str, long *len)
65 {
66 unsigned char *buf;
67 long inlen = strlen(str);
68
69 *len = 0;
70 if (inlen % 2)
71 return NULL;
72
73 *len = inlen >> 1;
74 buf = malloc(*len);
75 for (long x = 0; x < *len; x++)
76 sscanf(str + x * 2, "%2hhx", buf + x);
77 return buf;
78 }
79
80 const cipher_t *get_default_cipher(void)
81 {
82 return mbedtls_cipher_info_from_type (MBEDTLS_CIPHER_AES_128_CBC);
83 }
84
85 static char* upperstr(char *str) {
86 for (char *s = str; *s; s++)
87 *s = toupper((unsigned char) *s);
88 return str;
89 }
90
91 const cipher_t *get_cipher_or_print_error(char *name)
92 {
93 const mbedtls_cipher_info_t *cipher;
94
95 cipher = mbedtls_cipher_info_from_string(upperstr(name));
96 if (cipher)
97 return cipher;
98
99 fprintf(stderr, "Error: invalid cipher: %s.\n", name);
100 fprintf(stderr, "Supported ciphers: \n");
101 for (const int *list = mbedtls_cipher_list(); *list; list++) {
102 cipher = mbedtls_cipher_info_from_type(*list);
103 if (!cipher)
104 continue;
105 fprintf(stderr, "\t%s\n", mbedtls_cipher_info_get_name(cipher));
106 }
107 return NULL;
108 }
109
110 int get_cipher_ivsize(const cipher_t *cipher)
111 {
112 const mbedtls_cipher_info_t *c = cipher;
113
114 return mbedtls_cipher_info_get_iv_size(c);
115 }
116
117 int get_cipher_keysize(const cipher_t *cipher)
118 {
119 const mbedtls_cipher_info_t *c = cipher;
120
121 return mbedtls_cipher_info_get_key_bitlen(c) >> 3;
122 }
123
124 ctx_t *create_ctx(const cipher_t *cipher, const unsigned char *key,
125 const unsigned char *iv, int enc, int padding)
126 {
127 mbedtls_cipher_context_t *ctx;
128 const mbedtls_cipher_info_t *cipher_info=cipher;
129 int ret;
130
131 ctx = malloc(sizeof (mbedtls_cipher_context_t));
132 if (!ctx) {
133 fprintf (stderr, "Error: create_ctx: out of memory.\n");
134 return NULL;
135 }
136
137 mbedtls_cipher_init(ctx);
138 ret = mbedtls_cipher_setup(ctx, cipher_info);
139 if (ret) {
140 fprintf(stderr, "Error: mbedtls_cipher_setup: %d\n", ret);
141 goto abort;
142 }
143 ret = mbedtls_cipher_setkey(ctx, key,
144 (int) mbedtls_cipher_get_key_bitlen(ctx),
145 enc ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT);
146 if (ret) {
147 fprintf(stderr, "Error: mbedtls_cipher_setkey: %d\n", ret);
148 goto abort;
149 }
150 if (iv) {
151 ret = mbedtls_cipher_set_iv(ctx, iv, mbedtls_cipher_get_iv_size(ctx));
152 if (ret) {
153 fprintf(stderr, "Error: mbedtls_cipher_set_iv: %d\n", ret);
154 goto abort;
155 }
156 }
157
158 if (mbedtls_cipher_info_get_mode(cipher_info) == MBEDTLS_MODE_CBC) {
159 ret = mbedtls_cipher_set_padding_mode(ctx, padding ?
160 MBEDTLS_PADDING_PKCS7 :
161 MBEDTLS_PADDING_NONE);
162 if (ret) {
163 fprintf(stderr, "Error: mbedtls_cipher_set_padding_mode: %d\n",
164 ret);
165 goto abort;
166 }
167 } else {
168 if (mbedtls_cipher_info_get_block_size(cipher_info) > 1 && padding) {
169 fprintf(stderr,
170 "Error: mbedTLS only allows padding with CBC ciphers.\n");
171 goto abort;
172 }
173 }
174
175 ret = mbedtls_cipher_reset(ctx);
176 if (ret) {
177 fprintf(stderr, "Error: mbedtls_cipher_reset: %d\n", ret);
178 goto abort;
179 }
180 return ctx;
181
182 abort:
183 free_ctx(ctx);
184 return NULL;
185 }
186
187 int do_crypt(FILE *infile, FILE *outfile, ctx_t *ctx)
188 {
189 unsigned char inbuf[CRYPT_BUF_SIZE];
190 unsigned char outbuf[CRYPT_BUF_SIZE + MBEDTLS_MAX_BLOCK_LENGTH];
191 size_t inlen, outlen, step;
192 int ret;
193
194 if (mbedtls_cipher_get_cipher_mode(ctx) == MBEDTLS_MODE_ECB) {
195 step = mbedtls_cipher_get_block_size(ctx);
196 if (step > CRYPT_BUF_SIZE) {
197 step = CRYPT_BUF_SIZE;
198 }
199 } else {
200 step = CRYPT_BUF_SIZE;
201 }
202
203 for (;;) {
204 inlen = fread(inbuf, 1, step, infile);
205 if (inlen <= 0)
206 break;
207 ret = mbedtls_cipher_update(ctx, inbuf, inlen, outbuf, &outlen);
208 if (ret) {
209 fprintf(stderr, "Error: mbedtls_cipher_update: %d\n", ret);
210 return ret;
211 }
212 ret = fwrite(outbuf, 1, outlen, outfile);
213 if (ret != outlen) {
214 fprintf(stderr, "Error: cipher_update short write.\n");
215 return ret - outlen;
216 }
217 }
218 ret = mbedtls_cipher_finish(ctx, outbuf, &outlen);
219 if (ret) {
220 fprintf(stderr, "Error: mbedtls_cipher_finish: %d\n", ret);
221 return ret;
222 }
223 ret = fwrite(outbuf, 1, outlen, outfile);
224 if (ret != outlen) {
225 fprintf(stderr, "Error: cipher_finish short write.\n");
226 return ret - outlen;
227 }
228
229 return 0;
230 }
231
232 void free_ctx(ctx_t *ctx)
233 {
234 if (ctx) {
235 mbedtls_cipher_free(ctx);
236 free(ctx);
237 }
238 }