34851261b79d0dcdf9de7be01235f9f180144517
[openwrt/staging/pepe2k.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 unsigned char *hexstr2buf(const char *str, long *len)
13 {
14 unsigned char *buf;
15 long inlen = strlen(str);
16
17 *len = 0;
18 if (inlen % 2)
19 return NULL;
20
21 *len = inlen >> 1;
22 buf = malloc(*len);
23 for (long x = 0; x < *len; x++)
24 sscanf(str + x * 2, "%2hhx", buf + x);
25 return buf;
26 }
27
28 const cipher_t *get_default_cipher(void)
29 {
30 return mbedtls_cipher_info_from_type (MBEDTLS_CIPHER_AES_128_CBC);
31 }
32
33 static char* upperstr(char *str) {
34 for (char *s = str; *s; s++)
35 *s = toupper((unsigned char) *s);
36 return str;
37 }
38
39 const cipher_t *get_cipher_or_print_error(char *name)
40 {
41 const mbedtls_cipher_info_t *cipher;
42
43 cipher = mbedtls_cipher_info_from_string(upperstr(name));
44 if (cipher)
45 return cipher;
46
47 fprintf(stderr, "Error: invalid cipher: %s.\n", name);
48 fprintf(stderr, "Supported ciphers: \n");
49 for (const int *list = mbedtls_cipher_list(); *list; list++) {
50 cipher = mbedtls_cipher_info_from_type(*list);
51 if (!cipher)
52 continue;
53 fprintf(stderr, "\t%s\n", cipher->name);
54 }
55 return NULL;
56 }
57
58 int get_cipher_ivsize(const cipher_t *cipher)
59 {
60 const mbedtls_cipher_info_t *c = cipher;
61
62 return c->iv_size;
63 }
64
65 int get_cipher_keysize(const cipher_t *cipher)
66 {
67 const mbedtls_cipher_info_t *c = cipher;
68
69 return c->key_bitlen >> 3;
70 }
71
72 ctx_t *create_ctx(const cipher_t *cipher, const unsigned char *key,
73 const unsigned char *iv, int enc, int padding)
74 {
75 mbedtls_cipher_context_t *ctx;
76 const mbedtls_cipher_info_t *cipher_info=cipher;
77 int ret;
78
79 ctx = malloc(sizeof (mbedtls_cipher_context_t));
80 if (!ctx) {
81 fprintf (stderr, "Error: create_ctx: out of memory.\n");
82 return NULL;
83 }
84
85 mbedtls_cipher_init(ctx);
86 ret = mbedtls_cipher_setup(ctx, cipher_info);
87 if (ret) {
88 fprintf(stderr, "Error: mbedtls_cipher_setup: %d\n", ret);
89 goto abort;
90 }
91 ret = mbedtls_cipher_setkey(ctx, key,
92 (int) mbedtls_cipher_get_key_bitlen(ctx),
93 enc ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT);
94 if (ret) {
95 fprintf(stderr, "Error: mbedtls_cipher_setkey: %d\n", ret);
96 goto abort;
97 }
98 if (iv) {
99 ret = mbedtls_cipher_set_iv(ctx, iv, mbedtls_cipher_get_iv_size(ctx));
100 if (ret) {
101 fprintf(stderr, "Error: mbedtls_cipher_set_iv: %d\n", ret);
102 goto abort;
103 }
104 }
105
106 if (cipher_info->mode == MBEDTLS_MODE_CBC) {
107 ret = mbedtls_cipher_set_padding_mode(ctx, padding ?
108 MBEDTLS_PADDING_PKCS7 :
109 MBEDTLS_PADDING_NONE);
110 if (ret) {
111 fprintf(stderr, "Error: mbedtls_cipher_set_padding_mode: %d\n",
112 ret);
113 goto abort;
114 }
115 } else {
116 if (cipher_info->block_size > 1 && padding) {
117 fprintf(stderr,
118 "Error: mbedTLS only allows padding with CBC ciphers.\n");
119 goto abort;
120 }
121 }
122
123 ret = mbedtls_cipher_reset(ctx);
124 if (ret) {
125 fprintf(stderr, "Error: mbedtls_cipher_reset: %d\n", ret);
126 goto abort;
127 }
128 return ctx;
129
130 abort:
131 free_ctx(ctx);
132 return NULL;
133 }
134
135 int do_crypt(FILE *infile, FILE *outfile, ctx_t *ctx)
136 {
137 unsigned char inbuf[CRYPT_BUF_SIZE];
138 unsigned char outbuf[CRYPT_BUF_SIZE + MBEDTLS_MAX_BLOCK_LENGTH];
139 size_t inlen, outlen, step;
140 int ret;
141
142 if (mbedtls_cipher_get_cipher_mode(ctx) == MBEDTLS_MODE_ECB) {
143 step = mbedtls_cipher_get_block_size(ctx);
144 if (step > CRYPT_BUF_SIZE) {
145 step = CRYPT_BUF_SIZE;
146 }
147 } else {
148 step = CRYPT_BUF_SIZE;
149 }
150
151 for (;;) {
152 inlen = fread(inbuf, 1, step, infile);
153 if (inlen <= 0)
154 break;
155 ret = mbedtls_cipher_update(ctx, inbuf, inlen, outbuf, &outlen);
156 if (ret) {
157 fprintf(stderr, "Error: mbedtls_cipher_update: %d\n", ret);
158 return ret;
159 }
160 ret = fwrite(outbuf, 1, outlen, outfile);
161 if (ret != outlen) {
162 fprintf(stderr, "Error: cipher_update short write.\n");
163 return ret - outlen;
164 }
165 }
166 ret = mbedtls_cipher_finish(ctx, outbuf, &outlen);
167 if (ret) {
168 fprintf(stderr, "Error: mbedtls_cipher_finish: %d\n", ret);
169 return ret;
170 }
171 ret = fwrite(outbuf, 1, outlen, outfile);
172 if (ret != outlen) {
173 fprintf(stderr, "Error: cipher_finish short write.\n");
174 return ret - outlen;
175 }
176
177 return 0;
178 }
179
180 void free_ctx(ctx_t *ctx)
181 {
182 if (ctx) {
183 mbedtls_cipher_free(ctx);
184 free(ctx);
185 }
186 }