731beaad0f66a8bdf92f65fc4888851d3ee8fe99
[openwrt/staging/hauke.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 <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <mbedtls/cipher.h>
12
13 int do_crypt(FILE *infile, FILE *outfile, const mbedtls_cipher_info_t *cipher_info,
14 const unsigned char *key, const unsigned char *iv, int enc, int padding)
15 {
16 mbedtls_cipher_context_t ctx;
17 unsigned char inbuf[1024], outbuf[1024 + MBEDTLS_MAX_BLOCK_LENGTH];
18 size_t inlen, outlen;
19 int ret = 0;
20 int step;
21
22 mbedtls_cipher_init(&ctx);
23 if ((ret = mbedtls_cipher_setup(&ctx, cipher_info))) {
24 fprintf(stderr, "Error: mbedtls_cipher_setup: %d\n", ret);
25 goto out;
26 }
27 step = iv ? 1024 : mbedtls_cipher_get_block_size(&ctx);
28 if ((ret = mbedtls_cipher_setkey(&ctx, key, (int) mbedtls_cipher_get_key_bitlen(&ctx),
29 enc ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT))) {
30 fprintf(stderr, "Error: mbedtls_cipher_setkey: %d\n", ret);
31 goto out;
32 }
33 if (iv && (ret = mbedtls_cipher_set_iv(&ctx, iv, cipher_info->iv_size))) {
34 fprintf(stderr, "Error: mbedtls_cipher_set_iv: %d\n", ret);
35 goto out;
36 }
37
38 if (cipher_info->block_size > 1) {
39 if (cipher_info->mode == MBEDTLS_MODE_CBC) {
40 if ((ret = mbedtls_cipher_set_padding_mode(&ctx,
41 padding ? MBEDTLS_PADDING_PKCS7
42 : MBEDTLS_PADDING_NONE))) {
43 fprintf(stderr, "Error: mbedtls_cipher_set_padding_mode: %d\n", ret);
44 goto out;
45 }
46 } else {
47 if (cipher_info->mode != MBEDTLS_MODE_CBC && padding) {
48 fprintf(stderr, "Error: mbedTLS only supports padding with CBC ciphers.\n");
49 goto out;
50 }
51 }
52 }
53
54 if ((ret = mbedtls_cipher_reset(&ctx))) {
55 fprintf(stderr, "Error: mbedtls_cipher_reset: %d\n", ret);
56 goto out;
57 }
58
59 for (;;) {
60 inlen = fread(inbuf, 1, step, infile);
61 if (inlen <= 0)
62 break;
63 if ((ret = mbedtls_cipher_update(&ctx, inbuf, inlen, outbuf, &outlen))) {
64 fprintf(stderr, "Error: mbedtls_cipher_update: %d\n", ret);
65 goto out;
66 }
67 fwrite(outbuf, 1, outlen, outfile);
68 }
69 if ((ret = mbedtls_cipher_finish(&ctx, outbuf, &outlen))) {
70 fprintf(stderr, "Error: mbedtls_cipher_finish: %d\n", ret);
71 goto out;
72 }
73 fwrite(outbuf, 1, outlen, outfile);
74
75 out:
76 mbedtls_cipher_free(&ctx);
77 return ret;
78 }
79
80 static void check_enc_dec(const int enc)
81 {
82 if (enc == -1)
83 return;
84 fprintf(stderr, "Error: both -d and -e were specified.\n");
85 exit(EXIT_FAILURE);
86 }
87
88 static void check_cipher(const mbedtls_cipher_info_t *cipher_info)
89 {
90 const int *list;
91
92 if (cipher_info == NULL) {
93 fprintf(stderr, "Error: invalid cipher: %s.\n", optarg);
94 fprintf(stderr, "Supported ciphers: \n");
95 for (list = mbedtls_cipher_list(); *list; list++) {
96 cipher_info = mbedtls_cipher_info_from_type(*list);
97 if (!cipher_info)
98 continue;
99 fprintf(stderr, "\t%s\n", cipher_info->name);
100 }
101 exit(EXIT_FAILURE);
102 }
103 }
104
105 static void show_usage(const char* name)
106 {
107 fprintf(stderr, "Usage: %s: [-d | -e] [-n] -k key [-i iv] [-c cipher]\n"
108 "-d = decrypt; -e = encrypt; -n = no padding\n", name);
109 }
110
111 char *hexstr2buf(const char *str, size_t *len)
112 {
113 char *buf;
114 size_t inlen = strlen(str);
115
116 *len = 0;
117 if (inlen % 2)
118 return NULL;
119
120 *len = inlen >> 1;
121 buf = malloc(*len);
122 for (size_t x = 0; x < *len; x++)
123 sscanf(str + x * 2, "%2hhx", buf + x);
124 return buf;
125 }
126
127 static char* upperstr(char *str) {
128 for (char *s = str; *s; s++)
129 *s = toupper((unsigned char) *s);
130 return str;
131 }
132
133 int main(int argc, char *argv[])
134 {
135 int enc = -1;
136 unsigned char *iv = NULL;
137 unsigned char *key = NULL;
138 size_t keylen = 0, ivlen = 0;
139 int opt;
140 int padding = 1;
141 const mbedtls_cipher_info_t *cipher_info =
142 mbedtls_cipher_info_from_type (MBEDTLS_CIPHER_AES_128_CBC);
143 int ret;
144
145 while ((opt = getopt(argc, argv, "c:dei:k:n")) != -1) {
146 switch (opt) {
147 case 'c':
148 cipher_info = mbedtls_cipher_info_from_string(upperstr(optarg));
149 check_cipher(cipher_info);
150 break;
151 case 'd':
152 check_enc_dec(enc);
153 enc = 0;
154 break;
155 case 'e':
156 check_enc_dec(enc);
157 enc = 1;
158 break;
159 case 'i':
160 iv = (unsigned char *) hexstr2buf((const char *)optarg, &ivlen);
161 if (iv == NULL) {
162 fprintf(stderr, "Error setting IV to %s. The IV should be encoded in hex.\n",
163 optarg);
164 exit(EINVAL);
165 }
166 break;
167 case 'k':
168 key = (unsigned char *) hexstr2buf((const char *)optarg, &keylen);
169 if (key == NULL) {
170 fprintf(stderr, "Error setting key to %s. The key should be encoded in hex.\n",
171 optarg);
172 exit(EINVAL);
173 }
174 break;
175 case 'n':
176 padding = 0;
177 break;
178 default:
179 show_usage(argv[0]);
180 exit(EINVAL);
181 }
182 }
183 if (cipher_info->iv_size) {
184 if (iv == NULL) {
185 fprintf(stderr, "Error: iv not set.\n");
186 show_usage(argv[0]);
187 exit(EXIT_FAILURE);
188 }
189 if (ivlen != cipher_info->iv_size) {
190 fprintf(stderr, "Error: IV must be %d bytes; given IV is %zd bytes.\n",
191 cipher_info->iv_size, ivlen);
192 exit(EXIT_FAILURE);
193 }
194 }
195 if (key == NULL) {
196 fprintf(stderr, "Error: key not set.\n");
197 show_usage(argv[0]);
198 exit(EXIT_FAILURE);
199 }
200 if (keylen != cipher_info->key_bitlen >> 3) {
201 fprintf(stderr, "Error: key must be %d bytes; given key is %zd bytes.\n",
202 cipher_info->key_bitlen >> 3, keylen);
203 exit(EXIT_FAILURE);
204 }
205 ret = do_crypt(stdin, stdout, cipher_info, key, iv, !!enc, padding);
206 if (iv)
207 memset(iv, 0, ivlen);
208 memset(key, 0, keylen);
209 free(iv);
210 free(key);
211 return ret;
212 }