Files
OpenUniFi/src/crypto.c
T
2026-07-10 15:44:09 +02:00

163 lines
5.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mbedtls/aes.h>
#include <mbedtls/gcm.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include "crypto.h"
/* ─── Hex / binary helpers ──────────────────────────────────────── */
void crypto_hex2bin(const char *hex, unsigned char *bin, size_t bin_len)
{
for (size_t i = 0; i < bin_len; i++) {
unsigned int b = 0;
sscanf(hex + i * 2, "%02x", &b);
bin[i] = (unsigned char)b;
}
}
void crypto_bin2hex(const unsigned char *bin, size_t bin_len, char *hex_out)
{
for (size_t i = 0; i < bin_len; i++)
sprintf(hex_out + i * 2, "%02x", bin[i]);
hex_out[bin_len * 2] = '\0';
}
/* ─── Random hex ────────────────────────────────────────────────── */
int crypto_random_hex(unsigned char *hex_out, int nbytes)
{
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
unsigned char buf[64];
int ret;
if (nbytes > 64) return -1;
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)"openuf", 6);
if (ret != 0) goto out;
ret = mbedtls_ctr_drbg_random(&ctr_drbg, buf, nbytes);
if (ret != 0) goto out;
crypto_bin2hex(buf, nbytes, (char *)hex_out);
ret = 0;
out:
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return ret;
}
/* ─── AES-128-CBC encrypt (PKCS#7 padding) ──────────────────────── */
int crypto_encrypt(const char *key_hex, const char *iv_hex,
const unsigned char *in, size_t in_len,
unsigned char *out)
{
unsigned char key[16], iv[16];
crypto_hex2bin(key_hex, key, 16);
crypto_hex2bin(iv_hex, iv, 16);
/* PKCS#7: pad to next 16-byte block */
size_t pad = 16 - (in_len % 16);
size_t padded = in_len + pad;
unsigned char *tmp = malloc(padded);
if (!tmp) return -1;
memcpy(tmp, in, in_len);
memset(tmp + in_len, (unsigned char)pad, pad);
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
if (mbedtls_aes_setkey_enc(&ctx, key, 128) != 0) {
mbedtls_aes_free(&ctx); free(tmp); return -1;
}
/* iv is modified in place by CBC use a copy */
unsigned char iv_copy[16];
memcpy(iv_copy, iv, 16);
int ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT,
padded, iv_copy, tmp, out);
mbedtls_aes_free(&ctx);
free(tmp);
return (ret == 0) ? (int)padded : -1;
}
/* ─── AES-128-CBC decrypt (PKCS#7 unpadding) ────────────────────── */
int crypto_decrypt(const char *key_hex, const char *iv_hex,
const unsigned char *in, size_t in_len,
unsigned char *out)
{
if (in_len == 0 || in_len % 16 != 0) return -1;
unsigned char key[16], iv[16];
crypto_hex2bin(key_hex, key, 16);
crypto_hex2bin(iv_hex, iv, 16);
unsigned char iv_copy[16];
memcpy(iv_copy, iv, 16);
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
if (mbedtls_aes_setkey_dec(&ctx, key, 128) != 0) {
mbedtls_aes_free(&ctx); return -1;
}
int ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT,
in_len, iv_copy, in, out);
mbedtls_aes_free(&ctx);
if (ret != 0) return -1;
/* Remove PKCS#7 padding */
unsigned char pad = out[in_len - 1];
if (pad == 0 || pad > 16) return -1;
return (int)(in_len - pad);
}
int crypto_gcm_encrypt(const char *key_hex, const char *iv_hex,
const unsigned char *aad, size_t aad_len,
const unsigned char *in, size_t in_len,
unsigned char *out, unsigned char tag[16])
{
unsigned char key[16], iv[16];
crypto_hex2bin(key_hex, key, sizeof(key));
crypto_hex2bin(iv_hex, iv, sizeof(iv));
mbedtls_gcm_context ctx;
mbedtls_gcm_init(&ctx);
int ret = mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
key, 128);
if (ret == 0)
ret = mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_ENCRYPT,
in_len, iv, sizeof(iv),
aad, aad_len, in, out, 16, tag);
mbedtls_gcm_free(&ctx);
return ret == 0 ? (int)in_len : -1;
}
int crypto_gcm_decrypt(const char *key_hex, const char *iv_hex,
const unsigned char *aad, size_t aad_len,
const unsigned char *in, size_t in_len,
const unsigned char tag[16], unsigned char *out)
{
unsigned char key[16], iv[16];
crypto_hex2bin(key_hex, key, sizeof(key));
crypto_hex2bin(iv_hex, iv, sizeof(iv));
mbedtls_gcm_context ctx;
mbedtls_gcm_init(&ctx);
int ret = mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
key, 128);
if (ret == 0)
ret = mbedtls_gcm_auth_decrypt(&ctx, in_len, iv, sizeof(iv),
aad, aad_len, tag, 16, in, out);
mbedtls_gcm_free(&ctx);
return ret == 0 ? (int)in_len : -1;
}