1/*
2 * aeskeywrap.c
3 * Perform RFC3394 AES-based key wrap and unwrap functions.
4 *
5 * Copyright (C) 2015, Broadcom Corporation
6 * All Rights Reserved.
7 *
8 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
9 * the contents of this file may not be disclosed to third parties, copied
10 * or duplicated in any form, in whole or in part, without the prior
11 * written permission of Broadcom Corporation.
12 *
13 * $Id: aeskeywrap.c 241182 2011-02-17 21:50:03Z $
14 */
15
16#include <typedefs.h>
17
18#ifdef BCMDRIVER
19#include <osl.h>
20#else
21#include <string.h>
22#endif	/* BCMDRIVER */
23
24#include <bcmcrypto/aes.h>
25#include <bcmcrypto/aeskeywrap.h>
26#include <bcmcrypto/rijndael-alg-fst.h>
27
28#ifdef BCMAESKEYWRAP_TEST
29#include <stdio.h>
30
31#define	dbg(args)	printf args
32
33void
34pinter(const char *label, const uint8 *A, const size_t il, const uint8 *R)
35{
36	unsigned int k;
37	printf("%s", label);
38	for (k = 0; k < AKW_BLOCK_LEN; k++)
39		printf("%02X", A[k]);
40	printf(" ");
41	for (k = 0; k < il; k++) {
42		printf("%02X", R[k]);
43		if (!((k+1)%AKW_BLOCK_LEN))
44			printf(" ");
45		}
46	printf("\n");
47}
48
49void
50pres(const char *label, const size_t len, const uint8 *data)
51{
52	unsigned int k;
53	printf("%lu %s", (unsigned long)len, label);
54	for (k = 0; k < len; k++) {
55		printf("%02x", data[k]);
56		if (!((k + 1) % AKW_BLOCK_LEN))
57			printf(" ");
58	}
59	printf("\n");
60}
61#else
62#define	dbg(args)
63#define pinter(label, A, il, R)
64#endif /* BCMAESKEYWRAP_TEST */
65
66static const uint8 aeskeywrapIV[] = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 };
67
68/* aes_wrap: perform AES-based keywrap function defined in RFC3394
69 *	return 0 on success, 1 on error
70 *	input is il bytes
71 *	output is (il+8) bytes
72 */
73int
74BCMROMFN(aes_wrap)(size_t kl, uint8 *key, size_t il, uint8 *input, uint8 *output)
75{
76	uint32 rk[4*(AES_MAXROUNDS+1)];
77	uint8 A[AES_BLOCK_SZ];
78	uint8 R[AKW_MAX_WRAP_LEN];
79	uint8 B[AES_BLOCK_SZ];
80	int n = (int)(il/AKW_BLOCK_LEN), i, j, k;
81
82	/* validate kl (must be valid AES key length)  */
83	if ((kl != 16) && (kl != 24) && (kl != 32)) {
84		dbg(("aes_wrap: invlaid key length %lu\n", (unsigned long)kl));
85		return (1);
86	}
87	if (il > AKW_MAX_WRAP_LEN) {
88		dbg(("aes_wrap: input length %lu too large\n", (unsigned long)il));
89		return (1);
90	}
91	if (il % AKW_BLOCK_LEN) {
92		dbg(("aes_wrap: input length %lu must be a multiple of block length\n",
93		     (unsigned long)il));
94		return (1);
95	}
96
97	dbg(("   Input:\n"));
98	dbg(("   KEK:        "));
99	for (k = 0; k < (int)kl; k++)
100		dbg(("%02X", key[k]));
101	dbg(("\n   Key Data:   "));
102	for (k = 0; k < (int)il; k++)
103		dbg(("%02X", input[k]));
104	dbg(("\n\n   Wrap: \n"));
105
106	rijndaelKeySetupEnc(rk, key, (int)AES_KEY_BITLEN(kl));
107
108	/* Set A = IV */
109	memcpy(A, aeskeywrapIV, AKW_BLOCK_LEN);
110	/* For i = 1 to n */
111	/*	R[i] = P[i] */
112	memcpy(R, input, il);
113
114	/* For j = 0 to 5 */
115	for (j = 0; j < 6; j++) {
116		/* For i = 1 to n */
117		for (i = 0; i < n; i++) {
118			dbg(("\n   %d\n", (n*j)+i+1));
119			pinter("   In   ", A, il, R);
120			/* B = AES(K, A | R[i]) */
121			memcpy(&A[AKW_BLOCK_LEN], &R[i*AKW_BLOCK_LEN], AKW_BLOCK_LEN);
122			aes_block_encrypt((int)AES_ROUNDS(kl), rk, A, B);
123
124			/* R[i] = LSB(64, B) */
125			memcpy(&R[i*AKW_BLOCK_LEN], &B[AKW_BLOCK_LEN], AKW_BLOCK_LEN);
126
127			/* A = MSB(64, B) ^ t where t = (n*j)+i */
128			memcpy(&A[0], &B[0], AKW_BLOCK_LEN);
129			pinter("   Enc  ", A, il, R);
130			A[AKW_BLOCK_LEN-1] ^= ((n*j)+i+1);
131			pinter("   XorT ", A, il, R);
132		}
133	}
134	/* Set C[0] = A */
135	memcpy(output, A, AKW_BLOCK_LEN);
136	/* For i = 1 to n */
137	/* 	C[i] = R[i] */
138	memcpy(&output[AKW_BLOCK_LEN], R, il);
139
140	return (0);
141}
142
143/* aes_unwrap: perform AES-based key unwrap function defined in RFC3394,
144 *	return 0 on success, 1 on error
145 *	input is il bytes
146 *	output is (il-8) bytes
147 */
148int
149BCMROMFN(aes_unwrap)(size_t kl, uint8 *key, size_t il, uint8 *input, uint8 *output)
150{
151	uint32 rk[4*(AES_MAXROUNDS+1)];
152	uint8 A[AES_BLOCK_SZ];
153	uint8 R[AKW_MAX_WRAP_LEN + AKW_BLOCK_LEN];
154	uint8 B[AES_BLOCK_SZ];
155	size_t ol = il - AKW_BLOCK_LEN;
156	int n = (int)(ol/AKW_BLOCK_LEN), i, j, k;
157
158	/* validate kl (must be valid AES key length)  */
159	if ((kl != 16) && (kl != 24) && (kl != 32)) {
160		dbg(("aes_wrap: invlaid key length %lu\n", (unsigned long)kl));
161		return (1);
162	}
163	if (il > (AKW_MAX_WRAP_LEN + AKW_BLOCK_LEN)) {
164		dbg(("aes_unwrap: input length %lu too large\n", (unsigned long)il));
165		return (1);
166	}
167	if (il % AKW_BLOCK_LEN) {
168		dbg(("aes_unwrap: input length %lu must be a multiple of block length\n",
169		     (unsigned long)il));
170		return (1);
171	}
172
173	dbg(("   Input:\n"));
174	dbg(("   KEK:        "));
175	for (k = 0; k < (int)kl; k++)
176		dbg(("%02X", key[k]));
177	dbg(("\n   Data:       "));
178	for (k = 0; k < (int)il; k++)
179		dbg(("%02X", input[k]));
180	dbg(("\n\n   Unwrap: \n"));
181
182	rijndaelKeySetupDec(rk, key, (int)AES_KEY_BITLEN(kl));
183
184	/* Set A = C[0] */
185	memcpy(A, input, AKW_BLOCK_LEN);
186
187	/* For i = 1 to n */
188	/*	R[i] = C[i] */
189	memcpy(R, &input[AKW_BLOCK_LEN], ol);
190
191	/* For j = 5 to 0 */
192	for (j = 5; j >= 0; j--) {
193		/* For i = n to 1 */
194		for (i = n - 1; i >= 0; i--) {
195			dbg(("\n   %d\n", (n*j)+i+1));
196			pinter("   In   ", A, ol, R);
197
198			/* B = AES - 1 (K, (A ^ t) | R[i]) where t = n * j + i */
199			A[AKW_BLOCK_LEN - 1] ^= ((n*j)+i+1);
200			pinter("   XorT ", A, ol, R);
201
202			memcpy(&A[AKW_BLOCK_LEN], &R[i*AKW_BLOCK_LEN], AKW_BLOCK_LEN);
203			aes_block_decrypt((int)AES_ROUNDS(kl), rk, A, B);
204
205			/* A = MSB(64, B) */
206			memcpy(&A[0], &B[0], AKW_BLOCK_LEN);
207
208			/* R[i] = LSB(64, B) */
209			memcpy(&R[i*AKW_BLOCK_LEN], &B[AKW_BLOCK_LEN], AKW_BLOCK_LEN);
210			pinter("   Dec  ", A, ol, R);
211		}
212	}
213	if (!memcmp(A, aeskeywrapIV, AKW_BLOCK_LEN)) {
214		/* For i = 1 to n */
215		/*	P[i] = R[i] */
216		memcpy(&output[0], R, ol);
217		return 0;
218	} else {
219		dbg(("aes_unwrap: IV mismatch in unwrapped data\n"));
220		return 1;
221	}
222}
223
224#ifdef BCMAESKEYWRAP_TEST
225#include "aeskeywrap_vectors.h"
226#define NUM_VECTORS  (sizeof(akw_vec)/sizeof(akw_vec[0]))
227#define NUM_WRAP_FAIL_VECTORS  \
228	(sizeof(akw_wrap_fail_vec)/sizeof(akw_wrap_fail_vec[0]))
229#define NUM_UNWRAP_FAIL_VECTORS  \
230	(sizeof(akw_unwrap_fail_vec)/sizeof(akw_unwrap_fail_vec[0]))
231
232int
233main(int argc, char **argv)
234{
235	uint8 output[AKW_MAX_WRAP_LEN+AKW_BLOCK_LEN];
236	uint8 input2[AKW_MAX_WRAP_LEN];
237	int retv, k, fail = 0;
238
239	for (k = 0; k < NUM_VECTORS; k++) {
240		retv = aes_wrap(akw_vec[k].kl, akw_vec[k].key, akw_vec[k].il,
241		                akw_vec[k].input, output);
242		pres("\n   AES Wrap: ", akw_vec[k].il+AKW_BLOCK_LEN, output);
243
244		if (retv) {
245			dbg(("%s: aes_wrap failed\n", *argv));
246			fail++;
247		}
248		if (memcmp(output, akw_vec[k].ref, akw_vec[k].il+AKW_BLOCK_LEN) != 0) {
249			dbg(("%s: aes_wrap failed\n", *argv));
250			fail++;
251		}
252
253		retv = aes_unwrap(akw_vec[k].kl, akw_vec[k].key, akw_vec[k].il + AKW_BLOCK_LEN,
254		                  output, input2);
255		pres("\n   AES Unwrap: ", akw_vec[k].il, input2);
256
257		if (retv) {
258			dbg(("%s: aes_unwrap failed\n", *argv));
259			fail++;
260		}
261		if (memcmp(akw_vec[k].input, input2, akw_vec[k].il) != 0) {
262			dbg(("%s: aes_unwrap failed\n", *argv));
263			fail++;
264		}
265	}
266
267	for (k = 0; k < NUM_WRAP_FAIL_VECTORS; k++) {
268		if (!aes_wrap(akw_wrap_fail_vec[k].kl, akw_wrap_fail_vec[k].key,
269		              akw_wrap_fail_vec[k].il, akw_wrap_fail_vec[k].input, output)) {
270			dbg(("%s: aes_wrap didn't detect failure case\n", *argv));
271			fail++;
272		}
273	}
274
275	for (k = 0; k < NUM_UNWRAP_FAIL_VECTORS; k++) {
276		if (!aes_unwrap(akw_unwrap_fail_vec[k].kl, akw_unwrap_fail_vec[k].key,
277		                akw_unwrap_fail_vec[k].il, akw_unwrap_fail_vec[k].input, input2)) {
278			dbg(("%s: aes_unwrap didn't detect failure case\n", *argv));
279			fail++;
280		}
281	}
282
283	dbg(("%s: %s\n", *argv, fail?"FAILED":"PASSED"));
284	return (fail);
285}
286#endif /* BCMAESKEYWRAP_TEST */
287