xref: /rk3399_rockchip-uboot/lib/rsa/rsa-mod-exp.c (revision 7497bc3daedf41ef8f2b1d53121d70c50bbb59e0)
1fc2f4246SRuchika Gupta /*
2fc2f4246SRuchika Gupta  * Copyright (c) 2013, Google Inc.
3fc2f4246SRuchika Gupta  *
4fc2f4246SRuchika Gupta  * SPDX-License-Identifier:	GPL-2.0+
5fc2f4246SRuchika Gupta  */
6fc2f4246SRuchika Gupta 
7fc2f4246SRuchika Gupta #ifndef USE_HOSTCC
8fc2f4246SRuchika Gupta #include <common.h>
9fc2f4246SRuchika Gupta #include <fdtdec.h>
10fc2f4246SRuchika Gupta #include <asm/types.h>
11fc2f4246SRuchika Gupta #include <asm/byteorder.h>
121221ce45SMasahiro Yamada #include <linux/errno.h>
13fc2f4246SRuchika Gupta #include <asm/types.h>
14fc2f4246SRuchika Gupta #include <asm/unaligned.h>
15fc2f4246SRuchika Gupta #else
16fc2f4246SRuchika Gupta #include "fdt_host.h"
17fc2f4246SRuchika Gupta #include "mkimage.h"
18fc2f4246SRuchika Gupta #include <fdt_support.h>
19fc2f4246SRuchika Gupta #endif
20fc2f4246SRuchika Gupta #include <u-boot/rsa.h>
21fc2f4246SRuchika Gupta #include <u-boot/rsa-mod-exp.h>
22fc2f4246SRuchika Gupta 
23fc2f4246SRuchika Gupta #define UINT64_MULT32(v, multby)  (((uint64_t)(v)) * ((uint32_t)(multby)))
24fc2f4246SRuchika Gupta 
25fc2f4246SRuchika Gupta #define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a)
26fc2f4246SRuchika Gupta #define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a))
27fc2f4246SRuchika Gupta 
28fc2f4246SRuchika Gupta /* Default public exponent for backward compatibility */
29fc2f4246SRuchika Gupta #define RSA_DEFAULT_PUBEXP	65537
30fc2f4246SRuchika Gupta 
31fc2f4246SRuchika Gupta /**
32fc2f4246SRuchika Gupta  * subtract_modulus() - subtract modulus from the given value
33fc2f4246SRuchika Gupta  *
34fc2f4246SRuchika Gupta  * @key:	Key containing modulus to subtract
35fc2f4246SRuchika Gupta  * @num:	Number to subtract modulus from, as little endian word array
36fc2f4246SRuchika Gupta  */
subtract_modulus(const struct rsa_public_key * key,uint32_t num[])37fc2f4246SRuchika Gupta static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
38fc2f4246SRuchika Gupta {
39fc2f4246SRuchika Gupta 	int64_t acc = 0;
40fc2f4246SRuchika Gupta 	uint i;
41fc2f4246SRuchika Gupta 
42fc2f4246SRuchika Gupta 	for (i = 0; i < key->len; i++) {
43fc2f4246SRuchika Gupta 		acc += (uint64_t)num[i] - key->modulus[i];
44fc2f4246SRuchika Gupta 		num[i] = (uint32_t)acc;
45fc2f4246SRuchika Gupta 		acc >>= 32;
46fc2f4246SRuchika Gupta 	}
47fc2f4246SRuchika Gupta }
48fc2f4246SRuchika Gupta 
49fc2f4246SRuchika Gupta /**
50fc2f4246SRuchika Gupta  * greater_equal_modulus() - check if a value is >= modulus
51fc2f4246SRuchika Gupta  *
52fc2f4246SRuchika Gupta  * @key:	Key containing modulus to check
53fc2f4246SRuchika Gupta  * @num:	Number to check against modulus, as little endian word array
54fc2f4246SRuchika Gupta  * @return 0 if num < modulus, 1 if num >= modulus
55fc2f4246SRuchika Gupta  */
greater_equal_modulus(const struct rsa_public_key * key,uint32_t num[])56fc2f4246SRuchika Gupta static int greater_equal_modulus(const struct rsa_public_key *key,
57fc2f4246SRuchika Gupta 				 uint32_t num[])
58fc2f4246SRuchika Gupta {
59fc2f4246SRuchika Gupta 	int i;
60fc2f4246SRuchika Gupta 
61fc2f4246SRuchika Gupta 	for (i = (int)key->len - 1; i >= 0; i--) {
62fc2f4246SRuchika Gupta 		if (num[i] < key->modulus[i])
63fc2f4246SRuchika Gupta 			return 0;
64fc2f4246SRuchika Gupta 		if (num[i] > key->modulus[i])
65fc2f4246SRuchika Gupta 			return 1;
66fc2f4246SRuchika Gupta 	}
67fc2f4246SRuchika Gupta 
68fc2f4246SRuchika Gupta 	return 1;  /* equal */
69fc2f4246SRuchika Gupta }
70fc2f4246SRuchika Gupta 
71fc2f4246SRuchika Gupta /**
72fc2f4246SRuchika Gupta  * montgomery_mul_add_step() - Perform montgomery multiply-add step
73fc2f4246SRuchika Gupta  *
74fc2f4246SRuchika Gupta  * Operation: montgomery result[] += a * b[] / n0inv % modulus
75fc2f4246SRuchika Gupta  *
76fc2f4246SRuchika Gupta  * @key:	RSA key
77fc2f4246SRuchika Gupta  * @result:	Place to put result, as little endian word array
78fc2f4246SRuchika Gupta  * @a:		Multiplier
79fc2f4246SRuchika Gupta  * @b:		Multiplicand, as little endian word array
80fc2f4246SRuchika Gupta  */
montgomery_mul_add_step(const struct rsa_public_key * key,uint32_t result[],const uint32_t a,const uint32_t b[])81fc2f4246SRuchika Gupta static void montgomery_mul_add_step(const struct rsa_public_key *key,
82fc2f4246SRuchika Gupta 		uint32_t result[], const uint32_t a, const uint32_t b[])
83fc2f4246SRuchika Gupta {
84fc2f4246SRuchika Gupta 	uint64_t acc_a, acc_b;
85fc2f4246SRuchika Gupta 	uint32_t d0;
86fc2f4246SRuchika Gupta 	uint i;
87fc2f4246SRuchika Gupta 
88fc2f4246SRuchika Gupta 	acc_a = (uint64_t)a * b[0] + result[0];
89fc2f4246SRuchika Gupta 	d0 = (uint32_t)acc_a * key->n0inv;
90fc2f4246SRuchika Gupta 	acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
91fc2f4246SRuchika Gupta 	for (i = 1; i < key->len; i++) {
92fc2f4246SRuchika Gupta 		acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
93fc2f4246SRuchika Gupta 		acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
94fc2f4246SRuchika Gupta 				(uint32_t)acc_a;
95fc2f4246SRuchika Gupta 		result[i - 1] = (uint32_t)acc_b;
96fc2f4246SRuchika Gupta 	}
97fc2f4246SRuchika Gupta 
98fc2f4246SRuchika Gupta 	acc_a = (acc_a >> 32) + (acc_b >> 32);
99fc2f4246SRuchika Gupta 
100fc2f4246SRuchika Gupta 	result[i - 1] = (uint32_t)acc_a;
101fc2f4246SRuchika Gupta 
102fc2f4246SRuchika Gupta 	if (acc_a >> 32)
103fc2f4246SRuchika Gupta 		subtract_modulus(key, result);
104fc2f4246SRuchika Gupta }
105fc2f4246SRuchika Gupta 
106fc2f4246SRuchika Gupta /**
107fc2f4246SRuchika Gupta  * montgomery_mul() - Perform montgomery mutitply
108fc2f4246SRuchika Gupta  *
109fc2f4246SRuchika Gupta  * Operation: montgomery result[] = a[] * b[] / n0inv % modulus
110fc2f4246SRuchika Gupta  *
111fc2f4246SRuchika Gupta  * @key:	RSA key
112fc2f4246SRuchika Gupta  * @result:	Place to put result, as little endian word array
113fc2f4246SRuchika Gupta  * @a:		Multiplier, as little endian word array
114fc2f4246SRuchika Gupta  * @b:		Multiplicand, as little endian word array
115fc2f4246SRuchika Gupta  */
montgomery_mul(const struct rsa_public_key * key,uint32_t result[],uint32_t a[],const uint32_t b[])116fc2f4246SRuchika Gupta static void montgomery_mul(const struct rsa_public_key *key,
117fc2f4246SRuchika Gupta 		uint32_t result[], uint32_t a[], const uint32_t b[])
118fc2f4246SRuchika Gupta {
119fc2f4246SRuchika Gupta 	uint i;
120fc2f4246SRuchika Gupta 
121fc2f4246SRuchika Gupta 	for (i = 0; i < key->len; ++i)
122fc2f4246SRuchika Gupta 		result[i] = 0;
123fc2f4246SRuchika Gupta 	for (i = 0; i < key->len; ++i)
124fc2f4246SRuchika Gupta 		montgomery_mul_add_step(key, result, a[i], b);
125fc2f4246SRuchika Gupta }
126fc2f4246SRuchika Gupta 
127fc2f4246SRuchika Gupta /**
128fc2f4246SRuchika Gupta  * num_pub_exponent_bits() - Number of bits in the public exponent
129fc2f4246SRuchika Gupta  *
130fc2f4246SRuchika Gupta  * @key:	RSA key
131fc2f4246SRuchika Gupta  * @num_bits:	Storage for the number of public exponent bits
132fc2f4246SRuchika Gupta  */
num_public_exponent_bits(const struct rsa_public_key * key,int * num_bits)133fc2f4246SRuchika Gupta static int num_public_exponent_bits(const struct rsa_public_key *key,
134fc2f4246SRuchika Gupta 		int *num_bits)
135fc2f4246SRuchika Gupta {
136fc2f4246SRuchika Gupta 	uint64_t exponent;
137fc2f4246SRuchika Gupta 	int exponent_bits;
138fc2f4246SRuchika Gupta 	const uint max_bits = (sizeof(exponent) * 8);
139fc2f4246SRuchika Gupta 
140fc2f4246SRuchika Gupta 	exponent = key->exponent;
141fc2f4246SRuchika Gupta 	exponent_bits = 0;
142fc2f4246SRuchika Gupta 
143fc2f4246SRuchika Gupta 	if (!exponent) {
144fc2f4246SRuchika Gupta 		*num_bits = exponent_bits;
145fc2f4246SRuchika Gupta 		return 0;
146fc2f4246SRuchika Gupta 	}
147fc2f4246SRuchika Gupta 
148fc2f4246SRuchika Gupta 	for (exponent_bits = 1; exponent_bits < max_bits + 1; ++exponent_bits)
149fc2f4246SRuchika Gupta 		if (!(exponent >>= 1)) {
150fc2f4246SRuchika Gupta 			*num_bits = exponent_bits;
151fc2f4246SRuchika Gupta 			return 0;
152fc2f4246SRuchika Gupta 		}
153fc2f4246SRuchika Gupta 
154fc2f4246SRuchika Gupta 	return -EINVAL;
155fc2f4246SRuchika Gupta }
156fc2f4246SRuchika Gupta 
157fc2f4246SRuchika Gupta /**
158fc2f4246SRuchika Gupta  * is_public_exponent_bit_set() - Check if a bit in the public exponent is set
159fc2f4246SRuchika Gupta  *
160fc2f4246SRuchika Gupta  * @key:	RSA key
161fc2f4246SRuchika Gupta  * @pos:	The bit position to check
162fc2f4246SRuchika Gupta  */
is_public_exponent_bit_set(const struct rsa_public_key * key,int pos)163fc2f4246SRuchika Gupta static int is_public_exponent_bit_set(const struct rsa_public_key *key,
164fc2f4246SRuchika Gupta 		int pos)
165fc2f4246SRuchika Gupta {
166fc2f4246SRuchika Gupta 	return key->exponent & (1ULL << pos);
167fc2f4246SRuchika Gupta }
168fc2f4246SRuchika Gupta 
169fc2f4246SRuchika Gupta /**
170fc2f4246SRuchika Gupta  * pow_mod() - in-place public exponentiation
171fc2f4246SRuchika Gupta  *
172fc2f4246SRuchika Gupta  * @key:	RSA key
173fc2f4246SRuchika Gupta  * @inout:	Big-endian word array containing value and result
174fc2f4246SRuchika Gupta  */
pow_mod(const struct rsa_public_key * key,uint32_t * inout)175fc2f4246SRuchika Gupta static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
176fc2f4246SRuchika Gupta {
177fc2f4246SRuchika Gupta 	uint32_t *result, *ptr;
178fc2f4246SRuchika Gupta 	uint i;
179fc2f4246SRuchika Gupta 	int j, k;
180fc2f4246SRuchika Gupta 
181fc2f4246SRuchika Gupta 	/* Sanity check for stack size - key->len is in 32-bit words */
182fc2f4246SRuchika Gupta 	if (key->len > RSA_MAX_KEY_BITS / 32) {
183fc2f4246SRuchika Gupta 		debug("RSA key words %u exceeds maximum %d\n", key->len,
184fc2f4246SRuchika Gupta 		      RSA_MAX_KEY_BITS / 32);
185fc2f4246SRuchika Gupta 		return -EINVAL;
186fc2f4246SRuchika Gupta 	}
187fc2f4246SRuchika Gupta 
188fc2f4246SRuchika Gupta 	uint32_t val[key->len], acc[key->len], tmp[key->len];
189fc2f4246SRuchika Gupta 	uint32_t a_scaled[key->len];
190fc2f4246SRuchika Gupta 	result = tmp;  /* Re-use location. */
191fc2f4246SRuchika Gupta 
192fc2f4246SRuchika Gupta 	/* Convert from big endian byte array to little endian word array. */
193fc2f4246SRuchika Gupta 	for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
194fc2f4246SRuchika Gupta 		val[i] = get_unaligned_be32(ptr);
195fc2f4246SRuchika Gupta 
196fc2f4246SRuchika Gupta 	if (0 != num_public_exponent_bits(key, &k))
197fc2f4246SRuchika Gupta 		return -EINVAL;
198fc2f4246SRuchika Gupta 
199fc2f4246SRuchika Gupta 	if (k < 2) {
200fc2f4246SRuchika Gupta 		debug("Public exponent is too short (%d bits, minimum 2)\n",
201fc2f4246SRuchika Gupta 		      k);
202fc2f4246SRuchika Gupta 		return -EINVAL;
203fc2f4246SRuchika Gupta 	}
204fc2f4246SRuchika Gupta 
205fc2f4246SRuchika Gupta 	if (!is_public_exponent_bit_set(key, 0)) {
206fc2f4246SRuchika Gupta 		debug("LSB of RSA public exponent must be set.\n");
207fc2f4246SRuchika Gupta 		return -EINVAL;
208fc2f4246SRuchika Gupta 	}
209fc2f4246SRuchika Gupta 
210fc2f4246SRuchika Gupta 	/* the bit at e[k-1] is 1 by definition, so start with: C := M */
211fc2f4246SRuchika Gupta 	montgomery_mul(key, acc, val, key->rr); /* acc = a * RR / R mod n */
212fc2f4246SRuchika Gupta 	/* retain scaled version for intermediate use */
213fc2f4246SRuchika Gupta 	memcpy(a_scaled, acc, key->len * sizeof(a_scaled[0]));
214fc2f4246SRuchika Gupta 
215fc2f4246SRuchika Gupta 	for (j = k - 2; j > 0; --j) {
216fc2f4246SRuchika Gupta 		montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
217fc2f4246SRuchika Gupta 
218fc2f4246SRuchika Gupta 		if (is_public_exponent_bit_set(key, j)) {
219fc2f4246SRuchika Gupta 			/* acc = tmp * val / R mod n */
220fc2f4246SRuchika Gupta 			montgomery_mul(key, acc, tmp, a_scaled);
221fc2f4246SRuchika Gupta 		} else {
222fc2f4246SRuchika Gupta 			/* e[j] == 0, copy tmp back to acc for next operation */
223fc2f4246SRuchika Gupta 			memcpy(acc, tmp, key->len * sizeof(acc[0]));
224fc2f4246SRuchika Gupta 		}
225fc2f4246SRuchika Gupta 	}
226fc2f4246SRuchika Gupta 
227fc2f4246SRuchika Gupta 	/* the bit at e[0] is always 1 */
228fc2f4246SRuchika Gupta 	montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
229fc2f4246SRuchika Gupta 	montgomery_mul(key, acc, tmp, val); /* acc = tmp * a / R mod M */
230fc2f4246SRuchika Gupta 	memcpy(result, acc, key->len * sizeof(result[0]));
231fc2f4246SRuchika Gupta 
232fc2f4246SRuchika Gupta 	/* Make sure result < mod; result is at most 1x mod too large. */
233fc2f4246SRuchika Gupta 	if (greater_equal_modulus(key, result))
234fc2f4246SRuchika Gupta 		subtract_modulus(key, result);
235fc2f4246SRuchika Gupta 
236fc2f4246SRuchika Gupta 	/* Convert to bigendian byte array */
237fc2f4246SRuchika Gupta 	for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
238fc2f4246SRuchika Gupta 		put_unaligned_be32(result[i], ptr);
239fc2f4246SRuchika Gupta 	return 0;
240fc2f4246SRuchika Gupta }
241fc2f4246SRuchika Gupta 
rsa_convert_big_endian(uint32_t * dst,const uint32_t * src,int len)242fc2f4246SRuchika Gupta static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
243fc2f4246SRuchika Gupta {
244fc2f4246SRuchika Gupta 	int i;
245fc2f4246SRuchika Gupta 
246fc2f4246SRuchika Gupta 	for (i = 0; i < len; i++)
247fc2f4246SRuchika Gupta 		dst[i] = fdt32_to_cpu(src[len - 1 - i]);
248fc2f4246SRuchika Gupta }
249fc2f4246SRuchika Gupta 
rsa_mod_exp_sw(const uint8_t * sig,uint32_t sig_len,struct key_prop * prop,uint8_t * out)250fc2f4246SRuchika Gupta int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len,
251fc2f4246SRuchika Gupta 		struct key_prop *prop, uint8_t *out)
252fc2f4246SRuchika Gupta {
253*a8f564c3SJoseph Chen #ifndef USE_HOSTCC
254*a8f564c3SJoseph Chen 	__cacheline_aligned uint64_t tmp;
255*a8f564c3SJoseph Chen #else
256*a8f564c3SJoseph Chen 	uint64_t tmp;
257*a8f564c3SJoseph Chen #endif
258fc2f4246SRuchika Gupta 	struct rsa_public_key key;
259fc2f4246SRuchika Gupta 	int ret;
260fc2f4246SRuchika Gupta 
261fc2f4246SRuchika Gupta 	if (!prop) {
262fc2f4246SRuchika Gupta 		debug("%s: Skipping invalid prop", __func__);
263fc2f4246SRuchika Gupta 		return -EBADF;
264fc2f4246SRuchika Gupta 	}
265fc2f4246SRuchika Gupta 	key.n0inv = prop->n0inv;
266fc2f4246SRuchika Gupta 	key.len = prop->num_bits;
267fc2f4246SRuchika Gupta 
268*a8f564c3SJoseph Chen 	if (!prop->public_exponent) {
269fc2f4246SRuchika Gupta 		key.exponent = RSA_DEFAULT_PUBEXP;
270*a8f564c3SJoseph Chen 	} else {
271*a8f564c3SJoseph Chen 		/*
272*a8f564c3SJoseph Chen 		 * it seems fdt64_to_cpu() input param address must be 8-bytes
273*a8f564c3SJoseph Chen 		 * align, otherwise it brings a data-abort. No root cause was
274*a8f564c3SJoseph Chen 		 * found.
275*a8f564c3SJoseph Chen 		 *
276*a8f564c3SJoseph Chen 		 * workaround it this a tmp value.
277*a8f564c3SJoseph Chen 		 */
278*a8f564c3SJoseph Chen 		memcpy((void *)&tmp, prop->public_exponent, sizeof(uint64_t));
279*a8f564c3SJoseph Chen 		key.exponent = fdt64_to_cpu(tmp);
280*a8f564c3SJoseph Chen 	}
281fc2f4246SRuchika Gupta 
282fc2f4246SRuchika Gupta 	if (!key.len || !prop->modulus || !prop->rr) {
283fc2f4246SRuchika Gupta 		debug("%s: Missing RSA key info", __func__);
284fc2f4246SRuchika Gupta 		return -EFAULT;
285fc2f4246SRuchika Gupta 	}
286fc2f4246SRuchika Gupta 
287fc2f4246SRuchika Gupta 	/* Sanity check for stack size */
288fc2f4246SRuchika Gupta 	if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
289fc2f4246SRuchika Gupta 		debug("RSA key bits %u outside allowed range %d..%d\n",
290fc2f4246SRuchika Gupta 		      key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
291fc2f4246SRuchika Gupta 		return -EFAULT;
292fc2f4246SRuchika Gupta 	}
293fc2f4246SRuchika Gupta 	key.len /= sizeof(uint32_t) * 8;
294fc2f4246SRuchika Gupta 	uint32_t key1[key.len], key2[key.len];
295fc2f4246SRuchika Gupta 
296fc2f4246SRuchika Gupta 	key.modulus = key1;
297fc2f4246SRuchika Gupta 	key.rr = key2;
298fc2f4246SRuchika Gupta 	rsa_convert_big_endian(key.modulus, (uint32_t *)prop->modulus, key.len);
299fc2f4246SRuchika Gupta 	rsa_convert_big_endian(key.rr, (uint32_t *)prop->rr, key.len);
300fc2f4246SRuchika Gupta 	if (!key.modulus || !key.rr) {
301fc2f4246SRuchika Gupta 		debug("%s: Out of memory", __func__);
302fc2f4246SRuchika Gupta 		return -ENOMEM;
303fc2f4246SRuchika Gupta 	}
304fc2f4246SRuchika Gupta 
305fc2f4246SRuchika Gupta 	uint32_t buf[sig_len / sizeof(uint32_t)];
306fc2f4246SRuchika Gupta 
307fc2f4246SRuchika Gupta 	memcpy(buf, sig, sig_len);
308fc2f4246SRuchika Gupta 
309fc2f4246SRuchika Gupta 	ret = pow_mod(&key, buf);
310fc2f4246SRuchika Gupta 	if (ret)
311fc2f4246SRuchika Gupta 		return ret;
312fc2f4246SRuchika Gupta 
313fc2f4246SRuchika Gupta 	memcpy(out, buf, sig_len);
314fc2f4246SRuchika Gupta 
315fc2f4246SRuchika Gupta 	return 0;
316fc2f4246SRuchika Gupta }
317