1*433d6423SLionel Sambuc /* rijndael-api.c - Rijndael encryption programming interface.
2*433d6423SLionel Sambuc * Author: Kees J. Bot
3*433d6423SLionel Sambuc * 3 Nov 2000
4*433d6423SLionel Sambuc * Heavily based on the original API code by Antoon Bosselaers,
5*433d6423SLionel Sambuc * Vincent Rijmen, and Paulo Barreto, but with a different interface.
6*433d6423SLionel Sambuc *
7*433d6423SLionel Sambuc * Read this code top to bottom, not all comments are repeated.
8*433d6423SLionel Sambuc */
9*433d6423SLionel Sambuc
10*433d6423SLionel Sambuc #include <stdlib.h>
11*433d6423SLionel Sambuc #include <string.h>
12*433d6423SLionel Sambuc #include <sys/types.h>
13*433d6423SLionel Sambuc
14*433d6423SLionel Sambuc #include "rijndael-alg.h"
15*433d6423SLionel Sambuc #include "rijndael-api.h"
16*433d6423SLionel Sambuc
17*433d6423SLionel Sambuc /* Map a byte (?) address to a word address or vv. */
18*433d6423SLionel Sambuc #define W(a) ((word32 *) (a))
19*433d6423SLionel Sambuc #define B(a) ((word8 *) (a))
20*433d6423SLionel Sambuc
21*433d6423SLionel Sambuc #if STRICT_ALIGN
22*433d6423SLionel Sambuc /* This machine checks alignment religiously. (The code is not proper with
23*433d6423SLionel Sambuc * respect to alignment. We need a compiler that doesn't muck about with byte
24*433d6423SLionel Sambuc * arrays that follow words in structs, and that places automatic variables
25*433d6423SLionel Sambuc * at word boundaries if not odd-sized. Most compilers are this nice.)
26*433d6423SLionel Sambuc */
27*433d6423SLionel Sambuc
28*433d6423SLionel Sambuc #define aligned(a) (((unsigned) (a) & 3) == 0)
29*433d6423SLionel Sambuc #define aligned2(a1, a2) aligned((unsigned) (a1) | (unsigned) (a2))
30*433d6423SLionel Sambuc
blockcpy(void * dst,const void * src)31*433d6423SLionel Sambuc static void blockcpy(void *dst, const void *src)
32*433d6423SLionel Sambuc {
33*433d6423SLionel Sambuc int i= 0;
34*433d6423SLionel Sambuc
35*433d6423SLionel Sambuc do {
36*433d6423SLionel Sambuc B(dst)[i+0] = B(src)[i+0];
37*433d6423SLionel Sambuc B(dst)[i+1] = B(src)[i+1];
38*433d6423SLionel Sambuc B(dst)[i+2] = B(src)[i+2];
39*433d6423SLionel Sambuc B(dst)[i+3] = B(src)[i+3];
40*433d6423SLionel Sambuc } while ((i += 4) < 16);
41*433d6423SLionel Sambuc }
42*433d6423SLionel Sambuc
43*433d6423SLionel Sambuc #else /* !STRICT_ALIGN */
44*433d6423SLionel Sambuc /* This machine doesn't mind misaligned accesses much. */
45*433d6423SLionel Sambuc
46*433d6423SLionel Sambuc #define aligned(a) ((void) (a), 1)
47*433d6423SLionel Sambuc #define aligned2(a1, a2) ((void) (a1), (void) (a2), 1)
48*433d6423SLionel Sambuc
49*433d6423SLionel Sambuc #if __GNUC__
50*433d6423SLionel Sambuc __inline
51*433d6423SLionel Sambuc #endif
blockcpy(void * dst,const void * src)52*433d6423SLionel Sambuc static void blockcpy(void *dst, const void *src)
53*433d6423SLionel Sambuc {
54*433d6423SLionel Sambuc W(dst)[0] = W(src)[0];
55*433d6423SLionel Sambuc W(dst)[1] = W(src)[1];
56*433d6423SLionel Sambuc W(dst)[2] = W(src)[2];
57*433d6423SLionel Sambuc W(dst)[3] = W(src)[3];
58*433d6423SLionel Sambuc }
59*433d6423SLionel Sambuc
60*433d6423SLionel Sambuc #endif /* !STRICT_ALIGN */
61*433d6423SLionel Sambuc
62*433d6423SLionel Sambuc #define between(a, c, z) ((unsigned) (c) - (a) <= (unsigned) (z) - (a))
63*433d6423SLionel Sambuc
rijndael_makekey(rd_keyinstance * key,size_t keylen,const void * keymaterial)64*433d6423SLionel Sambuc int rijndael_makekey(rd_keyinstance *key,
65*433d6423SLionel Sambuc size_t keylen, const void *keymaterial)
66*433d6423SLionel Sambuc {
67*433d6423SLionel Sambuc word8 k[MAXKC][4];
68*433d6423SLionel Sambuc
69*433d6423SLionel Sambuc /* Initialize key schedule: */
70*433d6423SLionel Sambuc if (keylen == RD_KEY_HEX) {
71*433d6423SLionel Sambuc const word8 *kp;
72*433d6423SLionel Sambuc int c, b;
73*433d6423SLionel Sambuc
74*433d6423SLionel Sambuc kp= keymaterial;
75*433d6423SLionel Sambuc keylen= 0;
76*433d6423SLionel Sambuc
77*433d6423SLionel Sambuc for (;;) {
78*433d6423SLionel Sambuc c= *kp++;
79*433d6423SLionel Sambuc if (between('0', c, '9')) b= (c - '0' + 0x0) << 4;
80*433d6423SLionel Sambuc else
81*433d6423SLionel Sambuc if (between('a', c, 'f')) b= (c - 'a' + 0xa) << 4;
82*433d6423SLionel Sambuc else
83*433d6423SLionel Sambuc if (between('A', c, 'F')) b= (c - 'A' + 0xA) << 4;
84*433d6423SLionel Sambuc else break;
85*433d6423SLionel Sambuc
86*433d6423SLionel Sambuc c= *kp++;
87*433d6423SLionel Sambuc if (between('0', c, '9')) b |= (c - '0' + 0x0);
88*433d6423SLionel Sambuc else
89*433d6423SLionel Sambuc if (between('a', c, 'f')) b |= (c - 'a' + 0xa);
90*433d6423SLionel Sambuc else
91*433d6423SLionel Sambuc if (between('A', c, 'F')) b |= (c - 'A' + 0xA);
92*433d6423SLionel Sambuc else break;
93*433d6423SLionel Sambuc
94*433d6423SLionel Sambuc if (keylen >= 256/8) return RD_BAD_KEY_MAT;
95*433d6423SLionel Sambuc k[keylen/4][keylen%4] = b;
96*433d6423SLionel Sambuc keylen++;
97*433d6423SLionel Sambuc }
98*433d6423SLionel Sambuc if (c != 0) return RD_BAD_KEY_MAT;
99*433d6423SLionel Sambuc
100*433d6423SLionel Sambuc if (keylen != 128/8 && keylen != 192/8 && keylen != 256/8) {
101*433d6423SLionel Sambuc return RD_BAD_KEY_MAT;
102*433d6423SLionel Sambuc }
103*433d6423SLionel Sambuc } else {
104*433d6423SLionel Sambuc if (keylen != 128/8 && keylen != 192/8 && keylen != 256/8) {
105*433d6423SLionel Sambuc return RD_BAD_KEY_MAT;
106*433d6423SLionel Sambuc }
107*433d6423SLionel Sambuc memcpy(k, keymaterial, keylen);
108*433d6423SLionel Sambuc }
109*433d6423SLionel Sambuc
110*433d6423SLionel Sambuc key->rounds= keylen * 8 / 32 + 6;
111*433d6423SLionel Sambuc
112*433d6423SLionel Sambuc rijndael_KeySched(k, key->encsched, key->rounds);
113*433d6423SLionel Sambuc memcpy(key->decsched, key->encsched, sizeof(key->decsched));
114*433d6423SLionel Sambuc rijndael_KeyEncToDec(key->decsched, key->rounds);
115*433d6423SLionel Sambuc
116*433d6423SLionel Sambuc return 0;
117*433d6423SLionel Sambuc }
118*433d6423SLionel Sambuc
rijndael_ecb_encrypt(rd_keyinstance * key,const void * input,void * output,size_t length,void * dummyIV)119*433d6423SLionel Sambuc ssize_t rijndael_ecb_encrypt(rd_keyinstance *key,
120*433d6423SLionel Sambuc const void *input, void *output, size_t length, void *dummyIV)
121*433d6423SLionel Sambuc {
122*433d6423SLionel Sambuc /* Encrypt blocks of data in Electronic Codebook mode. */
123*433d6423SLionel Sambuc const word8 *inp= input;
124*433d6423SLionel Sambuc word8 *outp= output;
125*433d6423SLionel Sambuc size_t i, nr_blocks, extra;
126*433d6423SLionel Sambuc word32 in[4], out[4];
127*433d6423SLionel Sambuc word8 t;
128*433d6423SLionel Sambuc
129*433d6423SLionel Sambuc /* Compute the number of whole blocks, and the extra bytes beyond the
130*433d6423SLionel Sambuc * last block. Those extra bytes, if any, are encrypted by stealing
131*433d6423SLionel Sambuc * enough bytes from the previous encrypted block to make a whole block.
132*433d6423SLionel Sambuc * This is done by encrypting the last block, exchanging the first few
133*433d6423SLionel Sambuc * encrypted bytes with the extra bytes, and encrypting the last whole
134*433d6423SLionel Sambuc * block again.
135*433d6423SLionel Sambuc */
136*433d6423SLionel Sambuc nr_blocks= length / 16;
137*433d6423SLionel Sambuc if ((extra= (length % 16)) > 0) {
138*433d6423SLionel Sambuc if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
139*433d6423SLionel Sambuc nr_blocks--;
140*433d6423SLionel Sambuc }
141*433d6423SLionel Sambuc
142*433d6423SLionel Sambuc /* Encrypt a number of blocks. */
143*433d6423SLionel Sambuc if (aligned2(inp, outp)) {
144*433d6423SLionel Sambuc for (i= 0; i < nr_blocks; i++) {
145*433d6423SLionel Sambuc rijndael_Encrypt(inp, outp, key->encsched, key->rounds);
146*433d6423SLionel Sambuc inp += 16;
147*433d6423SLionel Sambuc outp += 16;
148*433d6423SLionel Sambuc }
149*433d6423SLionel Sambuc } else {
150*433d6423SLionel Sambuc for (i= 0; i < nr_blocks; i++) {
151*433d6423SLionel Sambuc blockcpy(in, inp);
152*433d6423SLionel Sambuc rijndael_Encrypt(in, out, key->encsched, key->rounds);
153*433d6423SLionel Sambuc blockcpy(outp, out);
154*433d6423SLionel Sambuc inp += 16;
155*433d6423SLionel Sambuc outp += 16;
156*433d6423SLionel Sambuc }
157*433d6423SLionel Sambuc }
158*433d6423SLionel Sambuc
159*433d6423SLionel Sambuc /* Encrypt extra bytes by stealing from the last full block. */
160*433d6423SLionel Sambuc if (extra > 0) {
161*433d6423SLionel Sambuc blockcpy(in, inp);
162*433d6423SLionel Sambuc rijndael_Encrypt(in, out, key->encsched, key->rounds);
163*433d6423SLionel Sambuc for (i= 0; i < extra; i++) {
164*433d6423SLionel Sambuc t= B(out)[i];
165*433d6423SLionel Sambuc B(out)[i] = inp[16 + i];
166*433d6423SLionel Sambuc outp[16 + i] = t;
167*433d6423SLionel Sambuc }
168*433d6423SLionel Sambuc rijndael_Encrypt(out, out, key->encsched, key->rounds);
169*433d6423SLionel Sambuc blockcpy(outp, out);
170*433d6423SLionel Sambuc }
171*433d6423SLionel Sambuc return length;
172*433d6423SLionel Sambuc }
173*433d6423SLionel Sambuc
rijndael_ecb_decrypt(rd_keyinstance * key,const void * input,void * output,size_t length,void * dummyIV)174*433d6423SLionel Sambuc ssize_t rijndael_ecb_decrypt(rd_keyinstance *key,
175*433d6423SLionel Sambuc const void *input, void *output, size_t length, void *dummyIV)
176*433d6423SLionel Sambuc {
177*433d6423SLionel Sambuc /* Decrypt blocks of data in Electronic Codebook mode. */
178*433d6423SLionel Sambuc const word8 *inp= input;
179*433d6423SLionel Sambuc word8 *outp= output;
180*433d6423SLionel Sambuc size_t i, nr_blocks, extra;
181*433d6423SLionel Sambuc word32 in[4], out[4];
182*433d6423SLionel Sambuc word8 t;
183*433d6423SLionel Sambuc
184*433d6423SLionel Sambuc nr_blocks= length / 16;
185*433d6423SLionel Sambuc if ((extra= (length % 16)) > 0) {
186*433d6423SLionel Sambuc if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
187*433d6423SLionel Sambuc nr_blocks--;
188*433d6423SLionel Sambuc }
189*433d6423SLionel Sambuc
190*433d6423SLionel Sambuc /* Decrypt a number of blocks. */
191*433d6423SLionel Sambuc if (aligned2(inp, outp)) {
192*433d6423SLionel Sambuc for (i= 0; i < nr_blocks; i++) {
193*433d6423SLionel Sambuc rijndael_Decrypt(inp, outp, key->decsched, key->rounds);
194*433d6423SLionel Sambuc inp += 16;
195*433d6423SLionel Sambuc outp += 16;
196*433d6423SLionel Sambuc }
197*433d6423SLionel Sambuc } else {
198*433d6423SLionel Sambuc for (i= 0; i < nr_blocks; i++) {
199*433d6423SLionel Sambuc blockcpy(in, inp);
200*433d6423SLionel Sambuc rijndael_Decrypt(in, out, key->decsched, key->rounds);
201*433d6423SLionel Sambuc blockcpy(outp, out);
202*433d6423SLionel Sambuc inp += 16;
203*433d6423SLionel Sambuc outp += 16;
204*433d6423SLionel Sambuc }
205*433d6423SLionel Sambuc }
206*433d6423SLionel Sambuc
207*433d6423SLionel Sambuc /* Decrypt extra bytes that stole from the last full block. */
208*433d6423SLionel Sambuc if (extra > 0) {
209*433d6423SLionel Sambuc blockcpy(in, inp);
210*433d6423SLionel Sambuc rijndael_Decrypt(in, out, key->decsched, key->rounds);
211*433d6423SLionel Sambuc for (i= 0; i < extra; i++) {
212*433d6423SLionel Sambuc t= B(out)[i];
213*433d6423SLionel Sambuc B(out)[i] = inp[16 + i];
214*433d6423SLionel Sambuc outp[16 + i] = t;
215*433d6423SLionel Sambuc }
216*433d6423SLionel Sambuc rijndael_Decrypt(out, out, key->decsched, key->rounds);
217*433d6423SLionel Sambuc blockcpy(outp, out);
218*433d6423SLionel Sambuc }
219*433d6423SLionel Sambuc return length;
220*433d6423SLionel Sambuc }
221*433d6423SLionel Sambuc
rijndael_cbc_encrypt(rd_keyinstance * key,const void * input,void * output,size_t length,void * IV)222*433d6423SLionel Sambuc ssize_t rijndael_cbc_encrypt(rd_keyinstance *key,
223*433d6423SLionel Sambuc const void *input, void *output, size_t length, void *IV)
224*433d6423SLionel Sambuc {
225*433d6423SLionel Sambuc /* Encrypt blocks of data in Cypher Block Chaining mode. */
226*433d6423SLionel Sambuc const word8 *inp= input;
227*433d6423SLionel Sambuc word8 *outp= output;
228*433d6423SLionel Sambuc size_t i, nr_blocks, extra;
229*433d6423SLionel Sambuc word32 in[4], out[4], iv[4], *ivp;
230*433d6423SLionel Sambuc word8 t;
231*433d6423SLionel Sambuc
232*433d6423SLionel Sambuc nr_blocks= length / 16;
233*433d6423SLionel Sambuc if ((extra= (length % 16)) > 0) {
234*433d6423SLionel Sambuc if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
235*433d6423SLionel Sambuc nr_blocks--;
236*433d6423SLionel Sambuc }
237*433d6423SLionel Sambuc
238*433d6423SLionel Sambuc /* Each input block is first XORed with the previous encryption result.
239*433d6423SLionel Sambuc * The "Initialization Vector" is used to XOR the first block with.
240*433d6423SLionel Sambuc * When done the last crypted block is stored back as the new IV to be
241*433d6423SLionel Sambuc * used for another call to this function.
242*433d6423SLionel Sambuc */
243*433d6423SLionel Sambuc ivp= aligned(IV) ? IV : (blockcpy(iv, IV), iv);
244*433d6423SLionel Sambuc
245*433d6423SLionel Sambuc if (aligned2(inp, outp)) {
246*433d6423SLionel Sambuc for (i= 0; i < nr_blocks; i++) {
247*433d6423SLionel Sambuc in[0] = W(inp)[0] ^ ivp[0];
248*433d6423SLionel Sambuc in[1] = W(inp)[1] ^ ivp[1];
249*433d6423SLionel Sambuc in[2] = W(inp)[2] ^ ivp[2];
250*433d6423SLionel Sambuc in[3] = W(inp)[3] ^ ivp[3];
251*433d6423SLionel Sambuc rijndael_Encrypt(in, outp, key->encsched, key->rounds);
252*433d6423SLionel Sambuc ivp= W(outp);
253*433d6423SLionel Sambuc inp += 16;
254*433d6423SLionel Sambuc outp += 16;
255*433d6423SLionel Sambuc }
256*433d6423SLionel Sambuc } else {
257*433d6423SLionel Sambuc for (i= 0; i < nr_blocks; i++) {
258*433d6423SLionel Sambuc blockcpy(in, inp);
259*433d6423SLionel Sambuc in[0] ^= ivp[0];
260*433d6423SLionel Sambuc in[1] ^= ivp[1];
261*433d6423SLionel Sambuc in[2] ^= ivp[2];
262*433d6423SLionel Sambuc in[3] ^= ivp[3];
263*433d6423SLionel Sambuc rijndael_Encrypt(in, out, key->encsched, key->rounds);
264*433d6423SLionel Sambuc blockcpy(outp, out);
265*433d6423SLionel Sambuc ivp= out;
266*433d6423SLionel Sambuc inp += 16;
267*433d6423SLionel Sambuc outp += 16;
268*433d6423SLionel Sambuc }
269*433d6423SLionel Sambuc }
270*433d6423SLionel Sambuc if (extra > 0) {
271*433d6423SLionel Sambuc blockcpy(in, inp);
272*433d6423SLionel Sambuc in[0] ^= ivp[0];
273*433d6423SLionel Sambuc in[1] ^= ivp[1];
274*433d6423SLionel Sambuc in[2] ^= ivp[2];
275*433d6423SLionel Sambuc in[3] ^= ivp[3];
276*433d6423SLionel Sambuc rijndael_Encrypt(in, out, key->encsched, key->rounds);
277*433d6423SLionel Sambuc for (i= 0; i < extra; i++) {
278*433d6423SLionel Sambuc t= B(out)[i];
279*433d6423SLionel Sambuc B(out)[i] ^= inp[16 + i];
280*433d6423SLionel Sambuc outp[16 + i] = t;
281*433d6423SLionel Sambuc }
282*433d6423SLionel Sambuc rijndael_Encrypt(out, out, key->encsched, key->rounds);
283*433d6423SLionel Sambuc blockcpy(outp, out);
284*433d6423SLionel Sambuc ivp= out;
285*433d6423SLionel Sambuc }
286*433d6423SLionel Sambuc blockcpy(IV, ivp); /* Store last IV back. */
287*433d6423SLionel Sambuc return length;
288*433d6423SLionel Sambuc }
289*433d6423SLionel Sambuc
rijndael_cbc_decrypt(rd_keyinstance * key,const void * input,void * output,size_t length,void * IV)290*433d6423SLionel Sambuc ssize_t rijndael_cbc_decrypt(rd_keyinstance *key,
291*433d6423SLionel Sambuc const void *input, void *output, size_t length, void *IV)
292*433d6423SLionel Sambuc {
293*433d6423SLionel Sambuc /* Decrypt blocks of data in Cypher Block Chaining mode. */
294*433d6423SLionel Sambuc const word8 *inp= input;
295*433d6423SLionel Sambuc word8 *outp= output;
296*433d6423SLionel Sambuc size_t i, nr_blocks, extra;
297*433d6423SLionel Sambuc word32 in[4], out[4], iv[4];
298*433d6423SLionel Sambuc word8 t;
299*433d6423SLionel Sambuc
300*433d6423SLionel Sambuc nr_blocks= length / 16;
301*433d6423SLionel Sambuc if ((extra= (length % 16)) > 0) {
302*433d6423SLionel Sambuc if (nr_blocks == 0) return RD_BAD_BLOCK_LENGTH;
303*433d6423SLionel Sambuc nr_blocks--;
304*433d6423SLionel Sambuc }
305*433d6423SLionel Sambuc
306*433d6423SLionel Sambuc blockcpy(iv, IV);
307*433d6423SLionel Sambuc
308*433d6423SLionel Sambuc if (aligned2(inp, outp)) {
309*433d6423SLionel Sambuc for (i= 0; i < nr_blocks; i++) {
310*433d6423SLionel Sambuc rijndael_Decrypt(inp, out, key->decsched, key->rounds);
311*433d6423SLionel Sambuc out[0] ^= iv[0];
312*433d6423SLionel Sambuc out[1] ^= iv[1];
313*433d6423SLionel Sambuc out[2] ^= iv[2];
314*433d6423SLionel Sambuc out[3] ^= iv[3];
315*433d6423SLionel Sambuc iv[0] = W(inp)[0];
316*433d6423SLionel Sambuc iv[1] = W(inp)[1];
317*433d6423SLionel Sambuc iv[2] = W(inp)[2];
318*433d6423SLionel Sambuc iv[3] = W(inp)[3];
319*433d6423SLionel Sambuc W(outp)[0] = out[0];
320*433d6423SLionel Sambuc W(outp)[1] = out[1];
321*433d6423SLionel Sambuc W(outp)[2] = out[2];
322*433d6423SLionel Sambuc W(outp)[3] = out[3];
323*433d6423SLionel Sambuc inp += 16;
324*433d6423SLionel Sambuc outp += 16;
325*433d6423SLionel Sambuc }
326*433d6423SLionel Sambuc } else {
327*433d6423SLionel Sambuc for (i= 0; i < nr_blocks; i++) {
328*433d6423SLionel Sambuc blockcpy(in, inp);
329*433d6423SLionel Sambuc rijndael_Decrypt(in, out, key->decsched, key->rounds);
330*433d6423SLionel Sambuc out[0] ^= iv[0];
331*433d6423SLionel Sambuc out[1] ^= iv[1];
332*433d6423SLionel Sambuc out[2] ^= iv[2];
333*433d6423SLionel Sambuc out[3] ^= iv[3];
334*433d6423SLionel Sambuc iv[0] = in[0];
335*433d6423SLionel Sambuc iv[1] = in[1];
336*433d6423SLionel Sambuc iv[2] = in[2];
337*433d6423SLionel Sambuc iv[3] = in[3];
338*433d6423SLionel Sambuc blockcpy(outp, out);
339*433d6423SLionel Sambuc inp += 16;
340*433d6423SLionel Sambuc outp += 16;
341*433d6423SLionel Sambuc }
342*433d6423SLionel Sambuc }
343*433d6423SLionel Sambuc if (extra > 0) {
344*433d6423SLionel Sambuc blockcpy(in, inp);
345*433d6423SLionel Sambuc blockcpy(IV, in);
346*433d6423SLionel Sambuc rijndael_Decrypt(in, out, key->decsched, key->rounds);
347*433d6423SLionel Sambuc for (i= 0; i < extra; i++) {
348*433d6423SLionel Sambuc t= B(out)[i] ^ inp[16 + i];
349*433d6423SLionel Sambuc B(out)[i] = inp[16 + i];
350*433d6423SLionel Sambuc outp[16 + i] = t;
351*433d6423SLionel Sambuc }
352*433d6423SLionel Sambuc rijndael_Decrypt(out, out, key->decsched, key->rounds);
353*433d6423SLionel Sambuc out[0] ^= iv[0];
354*433d6423SLionel Sambuc out[1] ^= iv[1];
355*433d6423SLionel Sambuc out[2] ^= iv[2];
356*433d6423SLionel Sambuc out[3] ^= iv[3];
357*433d6423SLionel Sambuc blockcpy(outp, out);
358*433d6423SLionel Sambuc } else {
359*433d6423SLionel Sambuc blockcpy(IV, iv);
360*433d6423SLionel Sambuc }
361*433d6423SLionel Sambuc return length;
362*433d6423SLionel Sambuc }
363*433d6423SLionel Sambuc
rijndael_cfb1_encrypt(rd_keyinstance * key,const void * input,void * output,size_t length,void * IV)364*433d6423SLionel Sambuc ssize_t rijndael_cfb1_encrypt(rd_keyinstance *key,
365*433d6423SLionel Sambuc const void *input, void *output, size_t length, void *IV)
366*433d6423SLionel Sambuc {
367*433d6423SLionel Sambuc /* Encrypt blocks of data in Cypher Feedback mode, 1 bit at a time. */
368*433d6423SLionel Sambuc const word8 *inp= input;
369*433d6423SLionel Sambuc word8 *outp= output;
370*433d6423SLionel Sambuc word8 t;
371*433d6423SLionel Sambuc size_t i;
372*433d6423SLionel Sambuc int b;
373*433d6423SLionel Sambuc word32 iv[4], civ[4];
374*433d6423SLionel Sambuc
375*433d6423SLionel Sambuc blockcpy(iv, IV);
376*433d6423SLionel Sambuc
377*433d6423SLionel Sambuc for (i= 0; i < length; i++) {
378*433d6423SLionel Sambuc t= *inp++;
379*433d6423SLionel Sambuc for (b= 0; b < 8; b++) {
380*433d6423SLionel Sambuc rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
381*433d6423SLionel Sambuc t ^= (B(civ)[0] & 0x80) >> b;
382*433d6423SLionel Sambuc B(iv)[ 0] = (B(iv)[ 0] << 1) | (B(iv)[ 1] >> 7);
383*433d6423SLionel Sambuc B(iv)[ 1] = (B(iv)[ 1] << 1) | (B(iv)[ 2] >> 7);
384*433d6423SLionel Sambuc B(iv)[ 2] = (B(iv)[ 2] << 1) | (B(iv)[ 3] >> 7);
385*433d6423SLionel Sambuc B(iv)[ 3] = (B(iv)[ 3] << 1) | (B(iv)[ 4] >> 7);
386*433d6423SLionel Sambuc B(iv)[ 4] = (B(iv)[ 4] << 1) | (B(iv)[ 5] >> 7);
387*433d6423SLionel Sambuc B(iv)[ 5] = (B(iv)[ 5] << 1) | (B(iv)[ 6] >> 7);
388*433d6423SLionel Sambuc B(iv)[ 6] = (B(iv)[ 6] << 1) | (B(iv)[ 7] >> 7);
389*433d6423SLionel Sambuc B(iv)[ 7] = (B(iv)[ 7] << 1) | (B(iv)[ 8] >> 7);
390*433d6423SLionel Sambuc B(iv)[ 8] = (B(iv)[ 8] << 1) | (B(iv)[ 9] >> 7);
391*433d6423SLionel Sambuc B(iv)[ 9] = (B(iv)[ 9] << 1) | (B(iv)[10] >> 7);
392*433d6423SLionel Sambuc B(iv)[10] = (B(iv)[10] << 1) | (B(iv)[11] >> 7);
393*433d6423SLionel Sambuc B(iv)[11] = (B(iv)[11] << 1) | (B(iv)[12] >> 7);
394*433d6423SLionel Sambuc B(iv)[12] = (B(iv)[12] << 1) | (B(iv)[13] >> 7);
395*433d6423SLionel Sambuc B(iv)[13] = (B(iv)[13] << 1) | (B(iv)[14] >> 7);
396*433d6423SLionel Sambuc B(iv)[14] = (B(iv)[14] << 1) | (B(iv)[15] >> 7);
397*433d6423SLionel Sambuc B(iv)[15] = (B(iv)[15] << 1) | ((t >> (7-b)) & 1);
398*433d6423SLionel Sambuc }
399*433d6423SLionel Sambuc *outp++ = t;
400*433d6423SLionel Sambuc }
401*433d6423SLionel Sambuc blockcpy(IV, iv);
402*433d6423SLionel Sambuc return length;
403*433d6423SLionel Sambuc }
404*433d6423SLionel Sambuc
rijndael_cfb1_decrypt(rd_keyinstance * key,const void * input,void * output,size_t length,void * IV)405*433d6423SLionel Sambuc ssize_t rijndael_cfb1_decrypt(rd_keyinstance *key,
406*433d6423SLionel Sambuc const void *input, void *output, size_t length, void *IV)
407*433d6423SLionel Sambuc {
408*433d6423SLionel Sambuc /* Decrypt blocks of data in Cypher Feedback mode, 1 bit at a time. */
409*433d6423SLionel Sambuc const word8 *inp= input;
410*433d6423SLionel Sambuc word8 *outp= output;
411*433d6423SLionel Sambuc word8 t;
412*433d6423SLionel Sambuc size_t i;
413*433d6423SLionel Sambuc int b;
414*433d6423SLionel Sambuc word32 iv[4], civ[4];
415*433d6423SLionel Sambuc
416*433d6423SLionel Sambuc blockcpy(iv, IV);
417*433d6423SLionel Sambuc
418*433d6423SLionel Sambuc for (i= 0; i < length; i++) {
419*433d6423SLionel Sambuc t= *inp++;
420*433d6423SLionel Sambuc for (b= 0; b < 8; b++) {
421*433d6423SLionel Sambuc rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
422*433d6423SLionel Sambuc B(iv)[ 0] = (B(iv)[ 0] << 1) | (B(iv)[ 1] >> 7);
423*433d6423SLionel Sambuc B(iv)[ 1] = (B(iv)[ 1] << 1) | (B(iv)[ 2] >> 7);
424*433d6423SLionel Sambuc B(iv)[ 2] = (B(iv)[ 2] << 1) | (B(iv)[ 3] >> 7);
425*433d6423SLionel Sambuc B(iv)[ 3] = (B(iv)[ 3] << 1) | (B(iv)[ 4] >> 7);
426*433d6423SLionel Sambuc B(iv)[ 4] = (B(iv)[ 4] << 1) | (B(iv)[ 5] >> 7);
427*433d6423SLionel Sambuc B(iv)[ 5] = (B(iv)[ 5] << 1) | (B(iv)[ 6] >> 7);
428*433d6423SLionel Sambuc B(iv)[ 6] = (B(iv)[ 6] << 1) | (B(iv)[ 7] >> 7);
429*433d6423SLionel Sambuc B(iv)[ 7] = (B(iv)[ 7] << 1) | (B(iv)[ 8] >> 7);
430*433d6423SLionel Sambuc B(iv)[ 8] = (B(iv)[ 8] << 1) | (B(iv)[ 9] >> 7);
431*433d6423SLionel Sambuc B(iv)[ 9] = (B(iv)[ 9] << 1) | (B(iv)[10] >> 7);
432*433d6423SLionel Sambuc B(iv)[10] = (B(iv)[10] << 1) | (B(iv)[11] >> 7);
433*433d6423SLionel Sambuc B(iv)[11] = (B(iv)[11] << 1) | (B(iv)[12] >> 7);
434*433d6423SLionel Sambuc B(iv)[12] = (B(iv)[12] << 1) | (B(iv)[13] >> 7);
435*433d6423SLionel Sambuc B(iv)[13] = (B(iv)[13] << 1) | (B(iv)[14] >> 7);
436*433d6423SLionel Sambuc B(iv)[14] = (B(iv)[14] << 1) | (B(iv)[15] >> 7);
437*433d6423SLionel Sambuc B(iv)[15] = (B(iv)[15] << 1) | ((t >> (7-b)) & 1);
438*433d6423SLionel Sambuc t ^= (B(civ)[0] & 0x80) >> b;
439*433d6423SLionel Sambuc }
440*433d6423SLionel Sambuc *outp++ = t;
441*433d6423SLionel Sambuc }
442*433d6423SLionel Sambuc blockcpy(IV, iv);
443*433d6423SLionel Sambuc return length;
444*433d6423SLionel Sambuc }
445*433d6423SLionel Sambuc
rijndael_cfb8_encrypt(rd_keyinstance * key,const void * input,void * output,size_t length,void * IV)446*433d6423SLionel Sambuc ssize_t rijndael_cfb8_encrypt(rd_keyinstance *key,
447*433d6423SLionel Sambuc const void *input, void *output, size_t length, void *IV)
448*433d6423SLionel Sambuc {
449*433d6423SLionel Sambuc /* Encrypt blocks of data in Cypher Feedback mode, 8 bits at a time. */
450*433d6423SLionel Sambuc const word8 *inp= input;
451*433d6423SLionel Sambuc word8 *outp= output;
452*433d6423SLionel Sambuc word8 t;
453*433d6423SLionel Sambuc size_t i;
454*433d6423SLionel Sambuc word32 iv[4], civ[4];
455*433d6423SLionel Sambuc
456*433d6423SLionel Sambuc blockcpy(iv, IV);
457*433d6423SLionel Sambuc
458*433d6423SLionel Sambuc for (i= 0; i < length; i++) {
459*433d6423SLionel Sambuc t= *inp++;
460*433d6423SLionel Sambuc rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
461*433d6423SLionel Sambuc t ^= B(civ)[0];
462*433d6423SLionel Sambuc B(iv)[ 0] = B(iv)[ 1];
463*433d6423SLionel Sambuc B(iv)[ 1] = B(iv)[ 2];
464*433d6423SLionel Sambuc B(iv)[ 2] = B(iv)[ 3];
465*433d6423SLionel Sambuc B(iv)[ 3] = B(iv)[ 4];
466*433d6423SLionel Sambuc B(iv)[ 4] = B(iv)[ 5];
467*433d6423SLionel Sambuc B(iv)[ 5] = B(iv)[ 6];
468*433d6423SLionel Sambuc B(iv)[ 6] = B(iv)[ 7];
469*433d6423SLionel Sambuc B(iv)[ 7] = B(iv)[ 8];
470*433d6423SLionel Sambuc B(iv)[ 8] = B(iv)[ 9];
471*433d6423SLionel Sambuc B(iv)[ 9] = B(iv)[10];
472*433d6423SLionel Sambuc B(iv)[10] = B(iv)[11];
473*433d6423SLionel Sambuc B(iv)[11] = B(iv)[12];
474*433d6423SLionel Sambuc B(iv)[12] = B(iv)[13];
475*433d6423SLionel Sambuc B(iv)[13] = B(iv)[14];
476*433d6423SLionel Sambuc B(iv)[14] = B(iv)[15];
477*433d6423SLionel Sambuc B(iv)[15] = t;
478*433d6423SLionel Sambuc *outp++ = t;
479*433d6423SLionel Sambuc }
480*433d6423SLionel Sambuc blockcpy(IV, iv);
481*433d6423SLionel Sambuc return length;
482*433d6423SLionel Sambuc }
483*433d6423SLionel Sambuc
rijndael_cfb8_decrypt(rd_keyinstance * key,const void * input,void * output,size_t length,void * IV)484*433d6423SLionel Sambuc ssize_t rijndael_cfb8_decrypt(rd_keyinstance *key,
485*433d6423SLionel Sambuc const void *input, void *output, size_t length, void *IV)
486*433d6423SLionel Sambuc {
487*433d6423SLionel Sambuc /* Decrypt blocks of data in Cypher Feedback mode, 1 byte at a time. */
488*433d6423SLionel Sambuc const word8 *inp= input;
489*433d6423SLionel Sambuc word8 *outp= output;
490*433d6423SLionel Sambuc word8 t;
491*433d6423SLionel Sambuc size_t i;
492*433d6423SLionel Sambuc word32 iv[4], civ[4];
493*433d6423SLionel Sambuc
494*433d6423SLionel Sambuc blockcpy(iv, IV);
495*433d6423SLionel Sambuc
496*433d6423SLionel Sambuc for (i= 0; i < length; i++) {
497*433d6423SLionel Sambuc t= *inp++;
498*433d6423SLionel Sambuc rijndael_Encrypt(iv, civ, key->encsched, key->rounds);
499*433d6423SLionel Sambuc B(iv)[ 0] = B(iv)[ 1];
500*433d6423SLionel Sambuc B(iv)[ 1] = B(iv)[ 2];
501*433d6423SLionel Sambuc B(iv)[ 2] = B(iv)[ 3];
502*433d6423SLionel Sambuc B(iv)[ 3] = B(iv)[ 4];
503*433d6423SLionel Sambuc B(iv)[ 4] = B(iv)[ 5];
504*433d6423SLionel Sambuc B(iv)[ 5] = B(iv)[ 6];
505*433d6423SLionel Sambuc B(iv)[ 6] = B(iv)[ 7];
506*433d6423SLionel Sambuc B(iv)[ 7] = B(iv)[ 8];
507*433d6423SLionel Sambuc B(iv)[ 8] = B(iv)[ 9];
508*433d6423SLionel Sambuc B(iv)[ 9] = B(iv)[10];
509*433d6423SLionel Sambuc B(iv)[10] = B(iv)[11];
510*433d6423SLionel Sambuc B(iv)[11] = B(iv)[12];
511*433d6423SLionel Sambuc B(iv)[12] = B(iv)[13];
512*433d6423SLionel Sambuc B(iv)[13] = B(iv)[14];
513*433d6423SLionel Sambuc B(iv)[14] = B(iv)[15];
514*433d6423SLionel Sambuc B(iv)[15] = t;
515*433d6423SLionel Sambuc t ^= B(civ)[0];
516*433d6423SLionel Sambuc *outp++ = t;
517*433d6423SLionel Sambuc }
518*433d6423SLionel Sambuc blockcpy(IV, iv);
519*433d6423SLionel Sambuc return length;
520*433d6423SLionel Sambuc }
521*433d6423SLionel Sambuc
rijndael_pad(void * input,size_t length)522*433d6423SLionel Sambuc ssize_t rijndael_pad(void *input, size_t length)
523*433d6423SLionel Sambuc {
524*433d6423SLionel Sambuc /* Adds at most one block of RFC-2040 style padding to the input to make
525*433d6423SLionel Sambuc * it a whole number of blocks for easier encryption. To be used if the
526*433d6423SLionel Sambuc * input may be less then one block in size, otherwise let the encryption
527*433d6423SLionel Sambuc * routines use cypher stealing. The input buffer should allow enough
528*433d6423SLionel Sambuc * space for the padding. The new length of the input is returned.
529*433d6423SLionel Sambuc */
530*433d6423SLionel Sambuc word8 *inp= input;
531*433d6423SLionel Sambuc size_t padlen;
532*433d6423SLionel Sambuc
533*433d6423SLionel Sambuc /* Add padding up until the next block boundary. */
534*433d6423SLionel Sambuc padlen= 16 - (length % 16);
535*433d6423SLionel Sambuc memset(inp + length, padlen, padlen);
536*433d6423SLionel Sambuc return length + padlen;
537*433d6423SLionel Sambuc }
538*433d6423SLionel Sambuc
rijndael_unpad(const void * input,size_t length)539*433d6423SLionel Sambuc ssize_t rijndael_unpad(const void *input, size_t length)
540*433d6423SLionel Sambuc {
541*433d6423SLionel Sambuc /* Remove RFC-2040 style padding after decryption. The true length of
542*433d6423SLionel Sambuc * the input is returned, or the usual errors if the padding is incorrect.
543*433d6423SLionel Sambuc */
544*433d6423SLionel Sambuc const word8 *inp= input;
545*433d6423SLionel Sambuc size_t i, padlen;
546*433d6423SLionel Sambuc
547*433d6423SLionel Sambuc if (length == 0 || (length % 16) != 0) return RD_BAD_BLOCK_LENGTH;
548*433d6423SLionel Sambuc padlen = inp[length-1];
549*433d6423SLionel Sambuc if (padlen <= 0 || padlen > 16) return RD_BAD_DATA;
550*433d6423SLionel Sambuc for (i= 2; i <= padlen; i++) {
551*433d6423SLionel Sambuc if (inp[length-i] != padlen) return RD_BAD_DATA;
552*433d6423SLionel Sambuc }
553*433d6423SLionel Sambuc return length - padlen;
554*433d6423SLionel Sambuc }
555*433d6423SLionel Sambuc
556*433d6423SLionel Sambuc #ifdef INTERMEDIATE_VALUE_KAT
557*433d6423SLionel Sambuc
cipherEncryptUpdateRounds(rd_keyinstance * key,const void * input,void * output,int rounds)558*433d6423SLionel Sambuc void cipherEncryptUpdateRounds(rd_keyinstance *key,
559*433d6423SLionel Sambuc const void *input, void *output, int rounds)
560*433d6423SLionel Sambuc {
561*433d6423SLionel Sambuc /* Encrypt a block only a specified number of rounds. */
562*433d6423SLionel Sambuc word8 block[4][4];
563*433d6423SLionel Sambuc
564*433d6423SLionel Sambuc blockcpy(block, input);
565*433d6423SLionel Sambuc
566*433d6423SLionel Sambuc rijndaelEncryptRound(block, key->encsched, key->rounds, rounds);
567*433d6423SLionel Sambuc
568*433d6423SLionel Sambuc blockcpy(output, block);
569*433d6423SLionel Sambuc }
570*433d6423SLionel Sambuc
cipherDecryptUpdateRounds(rd_keyinstance * key,const void * input,void * output,int rounds)571*433d6423SLionel Sambuc void cipherDecryptUpdateRounds(rd_keyinstance *key,
572*433d6423SLionel Sambuc const void *input, void *output, int rounds)
573*433d6423SLionel Sambuc {
574*433d6423SLionel Sambuc /* Decrypt a block only a specified number of rounds. */
575*433d6423SLionel Sambuc word8 block[4][4];
576*433d6423SLionel Sambuc
577*433d6423SLionel Sambuc blockcpy(block, input);
578*433d6423SLionel Sambuc
579*433d6423SLionel Sambuc rijndaelDecryptRound(block, key->decsched, key->rounds, rounds);
580*433d6423SLionel Sambuc
581*433d6423SLionel Sambuc blockcpy(output, block);
582*433d6423SLionel Sambuc }
583*433d6423SLionel Sambuc #endif /* INTERMEDIATE_VALUE_KAT */
584*433d6423SLionel Sambuc
585*433d6423SLionel Sambuc /*
586*433d6423SLionel Sambuc * $PchId: rijndael_api.c,v 1.2 2001/01/10 22:01:20 philip Exp $
587*433d6423SLionel Sambuc */
588