uencrypt: add support for mbedtls
[openwrt/staging/jow.git] / package / utils / uencrypt / src / uencrypt-openssl.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2 * Copyright (C) 2022-2023 Eneas Ulir de Queiroz
3 */
4
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10
11 #ifdef USE_WOLFSSL
12 # include <wolfssl/options.h>
13 # include <wolfssl/openssl/evp.h>
14 #else
15 # include <openssl/evp.h>
16 #endif
17
18 int do_crypt(FILE *infile, FILE *outfile, const EVP_CIPHER *cipher, const unsigned char *key,
19 const unsigned char *iv, int enc, int padding)
20 {
21 EVP_CIPHER_CTX *ctx;
22 unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
23 int inlen, outlen;
24
25 ctx = EVP_CIPHER_CTX_new();
26 EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc);
27 EVP_CIPHER_CTX_set_padding(ctx, padding);
28
29 for (;;) {
30 inlen = fread(inbuf, 1, 1024, infile);
31 if (inlen <= 0)
32 break;
33 if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
34 EVP_CIPHER_CTX_free(ctx);
35 return -1;
36 }
37 fwrite(outbuf, 1, outlen, outfile);
38 }
39 if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
40 EVP_CIPHER_CTX_free(ctx);
41 return -1;
42 }
43 fwrite(outbuf, 1, outlen, outfile);
44
45 EVP_CIPHER_CTX_free(ctx);
46 return 0;
47 }
48
49 static void check_enc_dec(const int enc)
50 {
51 if (enc == -1)
52 return;
53 fprintf(stderr, "Error: both -d and -e were specified.\n");
54 exit(EXIT_FAILURE);
55 }
56
57 #ifndef USE_WOLFSSL
58 static void print_ciphers(const OBJ_NAME *name,void *arg) {
59 fprintf(arg, "\t%s\n", name->name);
60 }
61 #endif
62
63 static void check_cipher(const EVP_CIPHER *cipher)
64 {
65 if (cipher == NULL) {
66 fprintf(stderr, "Error: invalid cipher: %s.\n", optarg);
67 #ifndef USE_WOLFSSL
68 fprintf(stderr, "Supported ciphers: \n");
69 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, print_ciphers, stderr);
70 #endif
71 exit(EXIT_FAILURE);
72 }
73 }
74
75 static void show_usage(const char* name)
76 {
77 fprintf(stderr, "Usage: %s: [-d | -e] [-n] -k key [-i iv] [-c cipher]\n"
78 "-d = decrypt; -e = encrypt; -n = no padding\n", name);
79 }
80
81 int main(int argc, char *argv[])
82 {
83 int enc = -1;
84 unsigned char *iv = NULL;
85 unsigned char *key = NULL;
86 long ivlen = 0, keylen = 0;
87 int cipher_ivlen, cipher_keylen;
88 int opt;
89 int padding = 1;
90 const EVP_CIPHER *cipher = EVP_aes_128_cbc();
91 int ret;
92
93 while ((opt = getopt(argc, argv, "c:dei:k:n")) != -1) {
94 switch (opt) {
95 case 'c':
96 cipher = EVP_get_cipherbyname(optarg);
97 check_cipher(cipher);
98 break;
99 case 'd':
100 check_enc_dec(enc);
101 enc = 0;
102 break;
103 case 'e':
104 check_enc_dec(enc);
105 enc = 1;
106 break;
107 case 'i':
108 iv = OPENSSL_hexstr2buf((const char *)optarg, &ivlen);
109 if (iv == NULL) {
110 fprintf(stderr, "Error setting IV to %s. The IV should be encoded in hex.\n",
111 optarg);
112 exit(EINVAL);
113 }
114 break;
115 case 'k':
116 key = OPENSSL_hexstr2buf((const char *)optarg, &keylen);
117 if (key == NULL) {
118 fprintf(stderr, "Error setting key to %s. The key should be encoded in hex.\n",
119 optarg);
120 exit(EINVAL);
121 }
122 break;
123 case 'n':
124 padding = 0;
125 break;
126 default:
127 show_usage(argv[0]);
128 exit(EINVAL);
129 }
130 }
131 if (key == NULL) {
132 fprintf(stderr, "Error: key not set.\n");
133 show_usage(argv[0]);
134 exit(EXIT_FAILURE);
135 }
136 if ((cipher_keylen = EVP_CIPHER_key_length(cipher)) != keylen) {
137 fprintf(stderr, "Error: key must be %d bytes; given key is %ld bytes.\n",
138 cipher_keylen, keylen);
139 exit(EXIT_FAILURE);
140 }
141 if ((cipher_ivlen = EVP_CIPHER_iv_length(cipher))) {
142 if (iv == NULL) {
143 fprintf(stderr, "Error: IV not set.\n");
144 show_usage(argv[0]);
145 exit(EXIT_FAILURE);
146 }
147 if (cipher_ivlen != ivlen) {
148 fprintf(stderr, "Error: IV must be %d bytes; given IV is %ld bytes.\n",
149 cipher_ivlen, ivlen);
150 exit(EXIT_FAILURE);
151 }
152 }
153 ret = do_crypt(stdin, stdout, cipher, key, iv, !!enc, padding);
154 if (ret)
155 fprintf(stderr, "Error during crypt operation.\n");
156 OPENSSL_free(iv);
157 OPENSSL_free(key);
158 return ret;
159 }