3 * Perform RFC3394 AES-based key wrap and unwrap functions.
5 * Copyright (C) 2010, Broadcom Corporation
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.
13 * $Id: aeskeywrap.c,v 1.31 2009-04-21 01:06:59 Exp $
22 extern void bcopy(const void *src
, void *dst
, int len
);
23 extern int bcmp(const void *b1
, const void *b2
, int len
);
26 #define bcopy(src, dst, len) memcpy((dst), (src), (len))
27 #define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
29 #include <stddef.h> /* for size_t */
30 #endif /* BCMDRIVER */
32 #include <bcmcrypto/aes.h>
33 #include <bcmcrypto/aeskeywrap.h>
34 #include <bcmcrypto/rijndael-alg-fst.h>
36 #ifdef BCMAESKEYWRAP_TEST
39 #define dbg(args) printf args
41 void pinter(const char *label
, const uint8
*A
, const size_t il
, const uint8
*R
)
45 for (k
= 0; k
< AKW_BLOCK_LEN
; k
++)
48 for (k
= 0; k
< il
; k
++) {
50 if (!((k
+1)%AKW_BLOCK_LEN
))
56 void pres(const char *label
, const size_t len
, const uint8
*data
)
59 printf("%lu %s", (unsigned long)len
, label
);
60 for (k
= 0; k
< len
; k
++) {
61 printf("%02x", data
[k
]);
62 if (!((k
+ 1) % AKW_BLOCK_LEN
))
69 #define pinter(label, A, il, R)
70 #endif /* BCMAESKEYWRAP_TEST */
72 static const uint8 aeskeywrapIV
[] = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 };
74 /* aes_wrap: perform AES-based keywrap function defined in RFC3394
75 * return 0 on success, 1 on error
77 * output is (il+8) bytes
80 BCMROMFN(aes_wrap
)(size_t kl
, uint8
*key
, size_t il
, uint8
*input
, uint8
*output
)
82 uint32 rk
[4*(AES_MAXROUNDS
+1)];
83 uint8 A
[AES_BLOCK_SZ
];
84 uint8 R
[AKW_MAX_WRAP_LEN
];
85 uint8 B
[AES_BLOCK_SZ
];
86 int n
= (int)(il
/AKW_BLOCK_LEN
), i
, j
, k
;
88 /* validate kl (must be valid AES key length) */
89 if ((kl
!= 16) && (kl
!= 24) && (kl
!= 32)) {
90 dbg(("aes_wrap: invlaid key length %lu\n", (unsigned long)kl
));
93 if (il
> AKW_MAX_WRAP_LEN
) {
94 dbg(("aes_wrap: input length %lu too large\n", (unsigned long)il
));
97 if (il
% AKW_BLOCK_LEN
) {
98 dbg(("aes_wrap: input length %lu must be a multiple of block length\n",
105 for (k
= 0; k
< (int)kl
; k
++)
106 dbg(("%02X", key
[k
]));
107 dbg(("\n Key Data: "));
108 for (k
= 0; k
< (int)il
; k
++)
109 dbg(("%02X", input
[k
]));
110 dbg(("\n\n Wrap: \n"));
112 rijndaelKeySetupEnc(rk
, key
, (int)AES_KEY_BITLEN(kl
));
115 bcopy(aeskeywrapIV
, A
, AKW_BLOCK_LEN
);
121 for (j
= 0; j
< 6; j
++) {
123 for (i
= 0; i
< n
; i
++) {
124 dbg(("\n %d\n", (n
*j
)+i
+1));
125 pinter(" In ", A
, il
, R
);
126 /* B = AES(K, A | R[i]) */
127 bcopy(&R
[i
*AKW_BLOCK_LEN
], &A
[AKW_BLOCK_LEN
], AKW_BLOCK_LEN
);
128 aes_block_encrypt((int)AES_ROUNDS(kl
), rk
, A
, B
);
130 /* R[i] = LSB(64, B) */
131 bcopy(&B
[AKW_BLOCK_LEN
], &R
[i
*AKW_BLOCK_LEN
], AKW_BLOCK_LEN
);
133 /* A = MSB(64, B) ^ t where t = (n*j)+i */
134 bcopy(&B
[0], &A
[0], AKW_BLOCK_LEN
);
135 pinter(" Enc ", A
, il
, R
);
136 A
[AKW_BLOCK_LEN
-1] ^= ((n
*j
)+i
+1);
137 pinter(" XorT ", A
, il
, R
);
141 bcopy(A
, output
, AKW_BLOCK_LEN
);
144 bcopy(R
, &output
[AKW_BLOCK_LEN
], il
);
149 /* aes_unwrap: perform AES-based key unwrap function defined in RFC3394,
150 * return 0 on success, 1 on error
152 * output is (il-8) bytes
155 BCMROMFN(aes_unwrap
)(size_t kl
, uint8
*key
, size_t il
, uint8
*input
, uint8
*output
)
157 uint32 rk
[4*(AES_MAXROUNDS
+1)];
158 uint8 A
[AES_BLOCK_SZ
];
159 uint8 R
[AKW_MAX_WRAP_LEN
+ AKW_BLOCK_LEN
];
160 uint8 B
[AES_BLOCK_SZ
];
161 size_t ol
= il
- AKW_BLOCK_LEN
;
162 int n
= (int)(ol
/AKW_BLOCK_LEN
), i
, j
, k
;
164 /* validate kl (must be valid AES key length) */
165 if ((kl
!= 16) && (kl
!= 24) && (kl
!= 32)) {
166 dbg(("aes_wrap: invlaid key length %lu\n", (unsigned long)kl
));
169 if (il
> (AKW_MAX_WRAP_LEN
+ AKW_BLOCK_LEN
)) {
170 dbg(("aes_unwrap: input length %lu too large\n", (unsigned long)il
));
173 if (il
% AKW_BLOCK_LEN
) {
174 dbg(("aes_unwrap: input length %lu must be a multiple of block length\n",
181 for (k
= 0; k
< (int)kl
; k
++)
182 dbg(("%02X", key
[k
]));
184 for (k
= 0; k
< (int)il
; k
++)
185 dbg(("%02X", input
[k
]));
186 dbg(("\n\n Unwrap: \n"));
188 rijndaelKeySetupDec(rk
, key
, (int)AES_KEY_BITLEN(kl
));
191 bcopy(input
, A
, AKW_BLOCK_LEN
);
195 bcopy(&input
[AKW_BLOCK_LEN
], R
, ol
);
198 for (j
= 5; j
>= 0; j
--) {
200 for (i
= n
- 1; i
>= 0; i
--) {
201 dbg(("\n %d\n", (n
*j
)+i
+1));
202 pinter(" In ", A
, ol
, R
);
204 /* B = AES - 1 (K, (A ^ t) | R[i]) where t = n * j + i */
205 A
[AKW_BLOCK_LEN
- 1] ^= ((n
*j
)+i
+1);
206 pinter(" XorT ", A
, ol
, R
);
208 bcopy(&R
[i
*AKW_BLOCK_LEN
], &A
[AKW_BLOCK_LEN
], AKW_BLOCK_LEN
);
209 aes_block_decrypt((int)AES_ROUNDS(kl
), rk
, A
, B
);
212 bcopy(&B
[0], &A
[0], AKW_BLOCK_LEN
);
214 /* R[i] = LSB(64, B) */
215 bcopy(&B
[AKW_BLOCK_LEN
], &R
[i
*AKW_BLOCK_LEN
], AKW_BLOCK_LEN
);
216 pinter(" Dec ", A
, ol
, R
);
219 if (!bcmp(A
, aeskeywrapIV
, AKW_BLOCK_LEN
)) {
222 bcopy(R
, &output
[0], ol
);
225 dbg(("aes_unwrap: IV mismatch in unwrapped data\n"));
230 #ifdef BCMAESKEYWRAP_TEST
231 #include "aeskeywrap_vectors.h"
232 #define NUM_VECTORS (sizeof(akw_vec)/sizeof(akw_vec[0]))
233 #define NUM_WRAP_FAIL_VECTORS \
234 (sizeof(akw_wrap_fail_vec)/sizeof(akw_wrap_fail_vec[0]))
235 #define NUM_UNWRAP_FAIL_VECTORS \
236 (sizeof(akw_unwrap_fail_vec)/sizeof(akw_unwrap_fail_vec[0]))
238 int main(int argc
, char **argv
)
240 uint8 output
[AKW_MAX_WRAP_LEN
+AKW_BLOCK_LEN
];
241 uint8 input2
[AKW_MAX_WRAP_LEN
];
242 int retv
, k
, fail
= 0;
244 for (k
= 0; k
< NUM_VECTORS
; k
++) {
245 retv
= aes_wrap(akw_vec
[k
].kl
, akw_vec
[k
].key
, akw_vec
[k
].il
,
246 akw_vec
[k
].input
, output
);
247 pres("\n AES Wrap: ", akw_vec
[k
].il
+AKW_BLOCK_LEN
, output
);
250 dbg(("%s: aes_wrap failed\n", *argv
));
253 if (bcmp(output
, akw_vec
[k
].ref
, akw_vec
[k
].il
+AKW_BLOCK_LEN
) != 0) {
254 dbg(("%s: aes_wrap failed\n", *argv
));
258 retv
= aes_unwrap(akw_vec
[k
].kl
, akw_vec
[k
].key
, akw_vec
[k
].il
+ AKW_BLOCK_LEN
,
260 pres("\n AES Unwrap: ", akw_vec
[k
].il
, input2
);
263 dbg(("%s: aes_unwrap failed\n", *argv
));
266 if (bcmp(akw_vec
[k
].input
, input2
, akw_vec
[k
].il
) != 0) {
267 dbg(("%s: aes_unwrap failed\n", *argv
));
272 for (k
= 0; k
< NUM_WRAP_FAIL_VECTORS
; k
++) {
273 if (!aes_wrap(akw_wrap_fail_vec
[k
].kl
, akw_wrap_fail_vec
[k
].key
,
274 akw_wrap_fail_vec
[k
].il
, akw_wrap_fail_vec
[k
].input
, output
)) {
275 dbg(("%s: aes_wrap didn't detect failure case\n", *argv
));
280 for (k
= 0; k
< NUM_UNWRAP_FAIL_VECTORS
; k
++) {
281 if (!aes_unwrap(akw_unwrap_fail_vec
[k
].kl
, akw_unwrap_fail_vec
[k
].key
,
282 akw_unwrap_fail_vec
[k
].il
, akw_unwrap_fail_vec
[k
].input
, input2
)) {
283 dbg(("%s: aes_unwrap didn't detect failure case\n", *argv
));
288 dbg(("%s: %s\n", *argv
, fail
?"FAILED":"PASSED"));
291 #endif /* BCMAESKEYWRAP_TEST */