[crypto] Add our own general-purpose cipher-block chaining routines
[people/asdlkf/gpxe.git] / src / crypto / axtls_aes.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <string.h>
20 #include <errno.h>
21 #include <byteswap.h>
22 #include <gpxe/crypto.h>
23 #include <gpxe/cbc.h>
24 #include <gpxe/aes.h>
25 #include "crypto/axtls/crypto.h"
26
27 /** @file
28  *
29  * AES algorithm
30  *
31  */
32
33 /** Basic AES blocksize */
34 #define AES_BLOCKSIZE 16
35
36 /****************************************************************************
37  *
38  * Basic AES algorithm (independent of mode of operation)
39  *
40  ****************************************************************************
41  */
42
43 /** AES context */
44 struct aes_context {
45         /** AES context for AXTLS */
46         AES_CTX axtls_ctx;
47         /** Cipher is being used for decrypting */
48         int decrypting;
49 };
50
51 /**
52  * Set key
53  *
54  * @v ctx               Context
55  * @v key               Key
56  * @v keylen            Key length
57  * @ret rc              Return status code
58  */
59 static int aes_setkey ( void *ctx, const void *key, size_t keylen ) {
60         struct aes_context *aes_ctx = ctx;
61         AES_MODE mode;
62         void *iv;
63
64         switch ( keylen ) {
65         case ( 128 / 8 ):
66                 mode = AES_MODE_128;
67                 break;
68         case ( 256 / 8 ):
69                 mode = AES_MODE_256;
70                 break;
71         default:
72                 return -EINVAL;
73         }
74
75         /* IV is not a relevant concept at this stage; use a dummy
76          * value that will have no side-effects.
77          */
78         iv = &aes_ctx->axtls_ctx.iv;
79
80         AES_set_key ( &aes_ctx->axtls_ctx, key, iv, mode );
81
82         aes_ctx->decrypting = 0;
83
84         return 0;
85 }
86
87 /**
88  * Set initialisation vector
89  *
90  * @v ctx               Context
91  * @v iv                Initialisation vector
92  */
93 static void aes_setiv ( void *ctx __unused, const void *iv __unused ) {
94         /* Nothing to do */
95 }
96
97 /**
98  * Call AXTLS' AES_encrypt() or AES_decrypt() functions
99  *
100  * @v axtls_ctx         AXTLS AES context
101  * @v src               Data to process
102  * @v dst               Buffer for output
103  * @v func              AXTLS AES function to call
104  */
105 static void aes_call_axtls ( AES_CTX *axtls_ctx, const void *src, void *dst,
106                              void ( * func ) ( const AES_CTX *axtls_ctx,
107                                                uint32_t *data ) ){
108         const uint32_t *srcl = src;
109         uint32_t *dstl = dst;
110         unsigned int i;
111
112         /* AXTLS' AES_encrypt() and AES_decrypt() functions both
113          * expect to deal with an array of four dwords in host-endian
114          * order.
115          */
116         for ( i = 0 ; i < 4 ; i++ )
117                 dstl[i] = ntohl ( srcl[i] );
118         func ( axtls_ctx, dstl );
119         for ( i = 0 ; i < 4 ; i++ )
120                 dstl[i] = htonl ( dstl[i] );
121 }
122
123 /**
124  * Encrypt data
125  *
126  * @v ctx               Context
127  * @v src               Data to encrypt
128  * @v dst               Buffer for encrypted data
129  * @v len               Length of data
130  */
131 static void aes_encrypt ( void *ctx, const void *src, void *dst,
132                           size_t len ) {
133         struct aes_context *aes_ctx = ctx;
134
135         assert ( len == AES_BLOCKSIZE );
136         if ( aes_ctx->decrypting )
137                 assert ( 0 );
138         aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_encrypt );
139 }
140
141 /**
142  * Decrypt data
143  *
144  * @v ctx               Context
145  * @v src               Data to decrypt
146  * @v dst               Buffer for decrypted data
147  * @v len               Length of data
148  */
149 static void aes_decrypt ( void *ctx, const void *src, void *dst,
150                           size_t len ) {
151         struct aes_context *aes_ctx = ctx;
152
153         assert ( len == AES_BLOCKSIZE );
154         if ( ! aes_ctx->decrypting ) {
155                 AES_convert_key ( &aes_ctx->axtls_ctx );
156                 aes_ctx->decrypting = 1;
157         }
158         aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_decrypt );
159 }
160
161 /** Basic AES algorithm */
162 static struct cipher_algorithm aes_algorithm = {
163         .name = "aes",
164         .ctxsize = sizeof ( struct aes_context ),
165         .blocksize = AES_BLOCKSIZE,
166         .setkey = aes_setkey,
167         .setiv = aes_setiv,
168         .encrypt = aes_encrypt,
169         .decrypt = aes_decrypt,
170 };
171
172 /****************************************************************************
173  *
174  * AES with cipher-block chaining (CBC)
175  *
176  ****************************************************************************
177  */
178
179 /** AES with CBC context */
180 struct aes_cbc_context {
181         /** AES context */
182         struct aes_context aes_ctx;
183         /** CBC context */
184         uint8_t cbc_ctx[AES_BLOCKSIZE];
185 };
186
187 /**
188  * Set key
189  *
190  * @v ctx               Context
191  * @v key               Key
192  * @v keylen            Key length
193  * @ret rc              Return status code
194  */
195 static int aes_cbc_setkey ( void *ctx, const void *key, size_t keylen ) {
196         struct aes_cbc_context *aes_cbc_ctx = ctx;
197
198         return cbc_setkey ( ctx, key, keylen, &aes_algorithm,
199                             &aes_cbc_ctx->cbc_ctx );
200 }
201
202 /**
203  * Set initialisation vector
204  *
205  * @v ctx               Context
206  * @v iv                Initialisation vector
207  */
208 static void aes_cbc_setiv ( void *ctx, const void *iv ) {
209         struct aes_cbc_context *aes_cbc_ctx = ctx;
210
211         cbc_setiv ( ctx, iv, &aes_algorithm, &aes_cbc_ctx->cbc_ctx );
212 }
213
214 /**
215  * Encrypt data
216  *
217  * @v ctx               Context
218  * @v src               Data to encrypt
219  * @v dst               Buffer for encrypted data
220  * @v len               Length of data
221  */
222 static void aes_cbc_encrypt ( void *ctx, const void *src, void *dst,
223                               size_t len ) {
224         struct aes_cbc_context *aes_cbc_ctx = ctx;
225
226         cbc_encrypt ( &aes_cbc_ctx->aes_ctx, src, dst, len,
227                       &aes_algorithm, &aes_cbc_ctx->cbc_ctx );
228 }
229
230 /**
231  * Decrypt data
232  *
233  * @v ctx               Context
234  * @v src               Data to decrypt
235  * @v dst               Buffer for decrypted data
236  * @v len               Length of data
237  */
238 static void aes_cbc_decrypt ( void *ctx, const void *src, void *dst,
239                               size_t len ) {
240         struct aes_cbc_context *aes_cbc_ctx = ctx;
241
242         cbc_decrypt ( &aes_cbc_ctx->aes_ctx, src, dst, len,
243                       &aes_algorithm, &aes_cbc_ctx->cbc_ctx );
244 }
245
246 /* AES with cipher-block chaining */
247 struct cipher_algorithm aes_cbc_algorithm = {
248         .name           = "aes_cbc",
249         .ctxsize        = sizeof ( struct aes_cbc_context ),
250         .blocksize      = AES_BLOCKSIZE,
251         .setkey         = aes_cbc_setkey,
252         .setiv          = aes_cbc_setiv,
253         .encrypt        = aes_cbc_encrypt,
254         .decrypt        = aes_cbc_decrypt,
255 };