| --- a/Makefile.am |
| +++ b/Makefile.am |
| @@ -193,6 +193,16 @@ EXTRA_bin_kcapi_rng_DEPENDENCIES = libto |
| |
| SCAN_FILES += $(bin_kcapi_rng_SOURCES) |
| man_MANS += apps/kcapi-rng.1 |
| + |
| +bin_PROGRAMS += bin/kcapi-drbg |
| + |
| +bin_kcapi_drbg_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/lib/ |
| +bin_kcapi_drbg_LDFLAGS = $(COMMON_LDFLAGS) |
| +bin_kcapi_drbg_LDADD = libkcapi.la |
| +bin_kcapi_drbg_SOURCES = apps/kcapi-drbg.c apps/app-internal.c |
| +EXTRA_bin_kcapi_rng_DEPENDENCIES = libtool |
| + |
| +SCAN_FILES += $(bin_kcapi_drbg_SOURCES) |
| endif |
| |
| if ENABLE_KCAPI_ENCAPP |
| --- /dev/null |
| +++ b/apps/kcapi-drbg.c |
| @@ -0,0 +1,273 @@ |
| +// SPDX-License-Identifier: BSD-2-Clause |
| +/* |
| + * Copyright (C) 2023, MediaTek Inc. All rights reserved. |
| + */ |
| + |
| +#define _GNU_SOURCE |
| +#include <unistd.h> |
| +#include <sys/syscall.h> |
| +#include <errno.h> |
| +#include <limits.h> |
| +#include <stdint.h> |
| +#include <sys/types.h> |
| +#include <sys/stat.h> |
| +#include <fcntl.h> |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| +#include <getopt.h> |
| + |
| +#include <kcapi.h> |
| + |
| +#include "app-internal.h" |
| + |
| +/* For efficiency reasons, this should be identical to algif_rng.c:MAXSIZE. */ |
| +#define KCAPI_RNG_BUFSIZE 2048 |
| + |
| +static struct kcapi_handle *rng = NULL; |
| +static char *rng_name = NULL; |
| +static bool hexout = false; |
| +static unsigned char* entropy = NULL; |
| +static unsigned char* nonce = NULL; |
| +static unsigned char* per = NULL; |
| +static unsigned char* additional_1 = NULL; |
| +static unsigned char* additional_2 = NULL; |
| +static uint32_t entropy_len = 0; |
| +static uint32_t nonce_len = 0; |
| +static uint32_t per_len = 0; |
| +static uint32_t add1_len = 0; |
| +static uint32_t add2_len = 0; |
| + |
| + |
| + |
| +static unsigned char* hextobin(char* hexstr, uint32_t *ret_len) { |
| + uint32_t len = strlen(hexstr); |
| + size_t i = 0; |
| + char *pos = hexstr; |
| + unsigned char *ret = (unsigned char*) malloc((len + 1) / 2); |
| + |
| + for (i = 0; i < (len + 1) / 2; i++) { |
| + if(i == 0 && (len % 2) == 1) { |
| + sscanf(pos, "%1hhx", &ret[i]); |
| + pos += 1; |
| + } else { |
| + sscanf(pos, "%2hhx", &ret[i]); |
| + pos += 2; |
| + } |
| + } |
| + *ret_len = (len + 1) / 2; |
| + |
| + return ret; |
| +} |
| + |
| +static void uninit() { |
| + memset(entropy, 0, entropy_len); |
| + memset(nonce, 0, nonce_len); |
| + memset(per, 0, per_len); |
| + memset(additional_1, 0, add1_len); |
| + memset(additional_2, 0, add2_len); |
| + if(entropy) |
| + free(entropy); |
| + if(nonce) |
| + free(nonce); |
| + if(per) |
| + free(per); |
| +} |
| + |
| +static void usage(void) |
| +{ |
| + fprintf(stderr, "\nKernel Crypto API DRBG\n"); |
| + fprintf(stderr, "Usage:\n"); |
| + fprintf(stderr, "\t-b --bytes <BYTES>\tNumber of bytes to generate (required option)\n"); |
| + fprintf(stderr, "\t-r --rng name <RNGNAME>\tDRNG name as advertised in /proc/crypto(require option))\n"); |
| + fprintf(stderr, "\t-e --entropy <RNGNAME>\tDRBG entropy(require option))\n"); |
| + fprintf(stderr, "\t-n --nonce <RNGNAME>\tDRBG nonce(require option))\n"); |
| + fprintf(stderr, "\t-p --personaliztion string <RNGNAME>\tDRBG personaliztion string(require option))\n"); |
| + fprintf(stderr, "\t --hex\t\tThe random number is returned in hexadecimal\n"); |
| + fprintf(stderr, "\t\t\t\tnotation\n"); |
| + fprintf(stderr, "\t-h --help\t\tThis help information\n"); |
| + |
| + uninit(); |
| + exit(1); |
| +} |
| + |
| +static int parse_opts(int argc, char *argv[], size_t *outlen) |
| +{ |
| + int c = 0; |
| + size_t bytes = 0; |
| + |
| + while (1) { |
| + int opt_index = 0; |
| + static struct option opts[] = { |
| + {"entropy", required_argument, 0, 'e'}, |
| + {"nonce", required_argument, 0, 'n'}, |
| + {"bytes", required_argument, 0, 'b'}, |
| + {"rng_name", required_argument, 0, 'r'}, |
| + {"personal_strng ", required_argument, 0, 'p'}, |
| + {"help", no_argument, 0, 'h'}, |
| + {"hex", no_argument, 0, 0}, |
| + {"additionalinput1 ", required_argument, 0, 'a'}, |
| + {"additionalinput2 ", required_argument, 0, 'c'}, |
| + {0, 0, 0, 0} |
| + }; |
| + c = getopt_long(argc, argv, "e:n:b:r:p:ha:c:", opts, &opt_index); |
| + if (-1 == c) |
| + break; |
| + switch (c) { |
| + case 0: |
| + switch (opt_index) { |
| + case 0: |
| + entropy = hextobin(optarg, &entropy_len); |
| + break; |
| + case 1: |
| + nonce = hextobin(optarg, &nonce_len); |
| + break; |
| + case 2: |
| + bytes = strtoul(optarg, NULL, 10); |
| + if (bytes == ULONG_MAX) { |
| + usage(); |
| + return -EINVAL; |
| + } |
| + break; |
| + case 3: |
| + rng_name = optarg; |
| + break; |
| + case 4: |
| + per = hextobin(optarg, &per_len); |
| + break; |
| + case 5: |
| + usage(); |
| + break; |
| + case 6: |
| + hexout = true; |
| + break; |
| + case 7: |
| + additional_1 = hextobin(optarg, &add1_len); |
| + break; |
| + case 8: |
| + additional_2 = hextobin(optarg, &add2_len); |
| + break; |
| + default: |
| + usage(); |
| + } |
| + break; |
| + case 'e': |
| + entropy = hextobin(optarg, &entropy_len); |
| + break; |
| + case 'n': |
| + nonce = hextobin(optarg, &nonce_len); |
| + break; |
| + case 'b': |
| + bytes = strtoul(optarg, NULL, 10); |
| + if (bytes == ULONG_MAX) { |
| + usage(); |
| + return -EINVAL; |
| + } |
| + break; |
| + case 'r': |
| + rng_name = optarg; |
| + break; |
| + case 'p': |
| + per = hextobin(optarg, &per_len); |
| + break; |
| + case 'a': |
| + additional_1 = hextobin(optarg, &add1_len); |
| + break; |
| + case 'c': |
| + additional_2 = hextobin(optarg, &add2_len); |
| + break; |
| + default: |
| + usage(); |
| + } |
| + } |
| + if (!bytes || !nonce || !entropy || !rng_name) |
| + usage(); |
| + |
| + *outlen = (size_t)bytes; |
| + return 0; |
| +} |
| + |
| +int main(int argc, char *argv[]) |
| +{ |
| + ssize_t ret = 0; |
| + uint8_t buf[KCAPI_RNG_BUFSIZE] __aligned(KCAPI_APP_ALIGN); |
| + uint8_t *seedbuf = buf; |
| + uint32_t seedsize = 0; |
| + size_t outlen = 0; |
| + unsigned char *ent = NULL; |
| + int count = 2; |
| + |
| + ret = parse_opts(argc, argv, &outlen); |
| + if (ret) |
| + return (int)ret; |
| + |
| + ret = kcapi_rng_init(&rng, rng_name, 0); |
| + if (ret) |
| + return (int)ret; |
| + |
| + seedsize = kcapi_rng_seedsize(rng); |
| + |
| + ent = (unsigned char*)malloc(entropy_len + nonce_len + per_len); |
| + memset(ent, 0, entropy_len + nonce_len + per_len); |
| + memcpy(ent, entropy, entropy_len); |
| + memcpy(ent + entropy_len, nonce, nonce_len); |
| + memcpy(ent + entropy_len + nonce_len, per, per_len); |
| + |
| + kcapi_rng_setentropy(rng, ent, entropy_len + nonce_len + per_len); |
| + |
| + ret = kcapi_rng_seed(rng, seedbuf, seedsize); |
| + if (ret) |
| + goto out; |
| + |
| + while(count --) { |
| + size_t len = outlen; |
| + while (len) { |
| + size_t todo = (len < KCAPI_RNG_BUFSIZE) ? |
| + len : KCAPI_RNG_BUFSIZE; |
| + |
| + if(count == 1 && additional_1) { |
| + kcapi_rng_setaddtl(rng, additional_1, add1_len); |
| + } else if(count == 0 && additional_2 ){ |
| + kcapi_rng_setaddtl(rng, additional_2, add2_len); |
| + } |
| + |
| + ret = kcapi_rng_generate(rng, buf, todo); |
| + if (ret < 0) |
| + goto out; |
| + |
| + if ((uint32_t)ret == 0) { |
| + ret = -EFAULT; |
| + goto out; |
| + } |
| + |
| + if(count == 0) { |
| + if (hexout) { |
| + char hexbuf[2 * KCAPI_RNG_BUFSIZE]; |
| + |
| + bin2hex(buf, (size_t)ret, hexbuf, sizeof(hexbuf), 0); |
| + fwrite(hexbuf, 2 * (size_t)ret, 1, stdout); |
| + } else { |
| + fwrite(buf, (size_t)ret, 1, stdout); |
| + } |
| + } |
| + len -= (size_t)ret; |
| + } |
| + } |
| + |
| + ret = 0; |
| +out: |
| + if (rng) |
| + kcapi_rng_destroy(rng); |
| + kcapi_memset_secure(buf, 0, sizeof(buf)); |
| + |
| + if (seedbuf && (seedbuf != buf)) { |
| + kcapi_memset_secure(seedbuf, 0, seedsize); |
| + free(seedbuf); |
| + } |
| + |
| + uninit(); |
| + if(!ent) |
| + free(ent); |
| + |
| + return (int)ret; |
| +} |