aboutsummaryrefslogtreecommitdiff
path: root/lib/libmpa/mpa_random.c
blob: 4f4e2da466a178bf4ea06032509829fa4e9aef80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// SPDX-License-Identifier: BSD-2-Clause
/*
 * Copyright (c) 2014, STMicroelectronics International N.V.
 */
#include "mpa.h"
#include <tee_api_types.h>

/*
 * This code is compiled for both kernel and user mode. How to obtain
 * random differs since the RNG resides in kernel mode.
 */
#ifdef __KERNEL__
#include <crypto/crypto.h>

static TEE_Result get_rng_array(void *buf, size_t blen)
{
	return crypto_rng_read(buf, blen);
}
#else
#include "utee_syscalls.h"

static TEE_Result get_rng_array(void *buf, size_t blen)
{
	return utee_cryp_random_number_generate(buf, blen);
}
#endif

static uint8_t get_random_byte(void)
{
	uint8_t buf;
	while (get_rng_array(&buf, 1) != TEE_SUCCESS)
	;

	return buf;
}

/*------------------------------------------------------------
 *
 *  mpa_get_random
 *
 */
void mpa_get_random(mpanum dest, mpanum limit)
{
	int done = 0;

	mpa_wipe(dest);
	if (__mpanum_alloced(dest) < __mpanum_size(limit))
		dest->size = __mpanum_alloced(dest);
	else
		dest->size = __mpanum_size(limit);
	while (!done) {
		for (int idx = 0; idx < dest->size; idx++) {
			mpa_word_t w = 0;
			for (int j = 0; j < BYTES_PER_WORD; j++)
				w = (w << 8) ^ get_random_byte();
			dest->d[idx] = w;
		}
		if (dest->size < __mpanum_size(limit)) {
			done = 1;
		} else {
			mpa_word_t hbi =
			    (mpa_word_t) mpa_highest_bit_index(limit);
			/* 1 <= hbi <= WORD_SIZE */
			hbi = (hbi % WORD_SIZE) + 1;
			if (hbi < WORD_SIZE) {
				hbi = (1 << hbi) - 1;
				dest->d[dest->size - 1] &= hbi;
			}
			done = (mpa_cmp(dest, limit) < 0) ? 1 : 0;
		}
	}
}

int mpa_get_random_digits(mpanum dest, mpa_usize_t size)
{
	mpa_wipe(dest);

	if (size > __mpanum_alloced(dest))
		return 0;

	dest->size = size;

	if (get_rng_array(&dest->d, WORDS_TO_BYTES(__mpanum_size(dest))))
		return 0;

	return __mpanum_size(dest);
}