openwrt/package/utils/uencrypt/src/uencrypt-mbedtls.c
Hauke Mehrtens 6c80f34c07 uencrypt: Fix mbedtls 3.6 compatibility
This makes it compile with mbedtls 3.6.0.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
2024-04-28 21:42:18 +02:00

239 lines
5.4 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright (C) 2023 Eneas Ulir de Queiroz
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "uencrypt.h"
#if MBEDTLS_VERSION_NUMBER < 0x03010000 /* mbedtls 3.1.0 */
static inline mbedtls_cipher_mode_t mbedtls_cipher_info_get_mode(
const mbedtls_cipher_info_t *info)
{
if (info == NULL) {
return MBEDTLS_MODE_NONE;
} else {
return info->mode;
}
}
static inline size_t mbedtls_cipher_info_get_key_bitlen(
const mbedtls_cipher_info_t *info)
{
if (info == NULL) {
return 0;
} else {
return info->key_bitlen;
}
}
static inline const char *mbedtls_cipher_info_get_name(
const mbedtls_cipher_info_t *info)
{
if (info == NULL) {
return NULL;
} else {
return info->name;
}
}
static inline size_t mbedtls_cipher_info_get_iv_size(
const mbedtls_cipher_info_t *info)
{
if (info == NULL) {
return 0;
}
return info->iv_size;
}
static inline size_t mbedtls_cipher_info_get_block_size(
const mbedtls_cipher_info_t *info)
{
if (info == NULL) {
return 0;
}
return info->block_size;
}
#endif
unsigned char *hexstr2buf(const char *str, long *len)
{
unsigned char *buf;
long inlen = strlen(str);
*len = 0;
if (inlen % 2)
return NULL;
*len = inlen >> 1;
buf = malloc(*len);
for (long x = 0; x < *len; x++)
sscanf(str + x * 2, "%2hhx", buf + x);
return buf;
}
const cipher_t *get_default_cipher(void)
{
return mbedtls_cipher_info_from_type (MBEDTLS_CIPHER_AES_128_CBC);
}
static char* upperstr(char *str) {
for (char *s = str; *s; s++)
*s = toupper((unsigned char) *s);
return str;
}
const cipher_t *get_cipher_or_print_error(char *name)
{
const mbedtls_cipher_info_t *cipher;
cipher = mbedtls_cipher_info_from_string(upperstr(name));
if (cipher)
return cipher;
fprintf(stderr, "Error: invalid cipher: %s.\n", name);
fprintf(stderr, "Supported ciphers: \n");
for (const int *list = mbedtls_cipher_list(); *list; list++) {
cipher = mbedtls_cipher_info_from_type(*list);
if (!cipher)
continue;
fprintf(stderr, "\t%s\n", mbedtls_cipher_info_get_name(cipher));
}
return NULL;
}
int get_cipher_ivsize(const cipher_t *cipher)
{
const mbedtls_cipher_info_t *c = cipher;
return mbedtls_cipher_info_get_iv_size(c);
}
int get_cipher_keysize(const cipher_t *cipher)
{
const mbedtls_cipher_info_t *c = cipher;
return mbedtls_cipher_info_get_key_bitlen(c) >> 3;
}
ctx_t *create_ctx(const cipher_t *cipher, const unsigned char *key,
const unsigned char *iv, int enc, int padding)
{
mbedtls_cipher_context_t *ctx;
const mbedtls_cipher_info_t *cipher_info=cipher;
int ret;
ctx = malloc(sizeof (mbedtls_cipher_context_t));
if (!ctx) {
fprintf (stderr, "Error: create_ctx: out of memory.\n");
return NULL;
}
mbedtls_cipher_init(ctx);
ret = mbedtls_cipher_setup(ctx, cipher_info);
if (ret) {
fprintf(stderr, "Error: mbedtls_cipher_setup: %d\n", ret);
goto abort;
}
ret = mbedtls_cipher_setkey(ctx, key,
(int) mbedtls_cipher_get_key_bitlen(ctx),
enc ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT);
if (ret) {
fprintf(stderr, "Error: mbedtls_cipher_setkey: %d\n", ret);
goto abort;
}
if (iv) {
ret = mbedtls_cipher_set_iv(ctx, iv, mbedtls_cipher_get_iv_size(ctx));
if (ret) {
fprintf(stderr, "Error: mbedtls_cipher_set_iv: %d\n", ret);
goto abort;
}
}
if (mbedtls_cipher_info_get_mode(cipher_info) == MBEDTLS_MODE_CBC) {
ret = mbedtls_cipher_set_padding_mode(ctx, padding ?
MBEDTLS_PADDING_PKCS7 :
MBEDTLS_PADDING_NONE);
if (ret) {
fprintf(stderr, "Error: mbedtls_cipher_set_padding_mode: %d\n",
ret);
goto abort;
}
} else {
if (mbedtls_cipher_info_get_block_size(cipher_info) > 1 && padding) {
fprintf(stderr,
"Error: mbedTLS only allows padding with CBC ciphers.\n");
goto abort;
}
}
ret = mbedtls_cipher_reset(ctx);
if (ret) {
fprintf(stderr, "Error: mbedtls_cipher_reset: %d\n", ret);
goto abort;
}
return ctx;
abort:
free_ctx(ctx);
return NULL;
}
int do_crypt(FILE *infile, FILE *outfile, ctx_t *ctx)
{
unsigned char inbuf[CRYPT_BUF_SIZE];
unsigned char outbuf[CRYPT_BUF_SIZE + MBEDTLS_MAX_BLOCK_LENGTH];
size_t inlen, outlen, step;
int ret;
if (mbedtls_cipher_get_cipher_mode(ctx) == MBEDTLS_MODE_ECB) {
step = mbedtls_cipher_get_block_size(ctx);
if (step > CRYPT_BUF_SIZE) {
step = CRYPT_BUF_SIZE;
}
} else {
step = CRYPT_BUF_SIZE;
}
for (;;) {
inlen = fread(inbuf, 1, step, infile);
if (inlen <= 0)
break;
ret = mbedtls_cipher_update(ctx, inbuf, inlen, outbuf, &outlen);
if (ret) {
fprintf(stderr, "Error: mbedtls_cipher_update: %d\n", ret);
return ret;
}
ret = fwrite(outbuf, 1, outlen, outfile);
if (ret != outlen) {
fprintf(stderr, "Error: cipher_update short write.\n");
return ret - outlen;
}
}
ret = mbedtls_cipher_finish(ctx, outbuf, &outlen);
if (ret) {
fprintf(stderr, "Error: mbedtls_cipher_finish: %d\n", ret);
return ret;
}
ret = fwrite(outbuf, 1, outlen, outfile);
if (ret != outlen) {
fprintf(stderr, "Error: cipher_finish short write.\n");
return ret - outlen;
}
return 0;
}
void free_ctx(ctx_t *ctx)
{
if (ctx) {
mbedtls_cipher_free(ctx);
free(ctx);
}
}