summaryrefslogtreecommitdiff
path: root/linux/net/ipsec/alg/ipsec_alg_aes.c
blob: c6b390281b91294e494f66017d6fe666d9270df3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
 * ipsec_alg AES cipher stubs
 *
 * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
 * 
 * $Id: ipsec_alg_aes.c,v 1.2 2004/03/22 21:53:19 as Exp $
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * Fixes by:
 * 	PK:	Pawel Krawczyk <kravietz@aba.krakow.pl>
 * Fixes list:
 * 	PK:	make XCBC comply with latest draft (keylength)
 *
 */
#include <linux/config.h>
#include <linux/version.h>

/*	
 *	special case: ipsec core modular with this static algo inside:
 *	must avoid MODULE magic for this file
 */
#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_AES
#undef MODULE
#endif

#include <linux/module.h>
#include <linux/init.h>

#include <linux/kernel.h> /* printk() */
#include <linux/errno.h>  /* error codes */
#include <linux/types.h>  /* size_t */
#include <linux/string.h>

/* Check if __exit is defined, if not null it */
#ifndef __exit
#define __exit
#endif

/*	Low freeswan header coupling	*/
#include "freeswan/ipsec_alg.h"
#include "libaes/aes_cbc.h"

#define CONFIG_IPSEC_ALG_AES_MAC 1

#define AES_CONTEXT_T aes_context
MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
static int debug=0;
MODULE_PARM(debug, "i");
static int test=0;
MODULE_PARM(test, "i");
static int excl=0;
MODULE_PARM(excl, "i");
static int keyminbits=0;
MODULE_PARM(keyminbits, "i");
static int keymaxbits=0;
MODULE_PARM(keymaxbits, "i");

#if CONFIG_IPSEC_ALG_AES_MAC
#include "libaes/aes_xcbc_mac.h"

/*	
 *	Not IANA number yet (draft-ietf-ipsec-ciph-aes-xcbc-mac-00.txt).
 *	We use 9 for non-modular algorithm and none for modular, thus
 *	forcing user to specify one on module load. -kravietz
 */
#ifdef MODULE
static int auth_id=0;
#else
static int auth_id=9;
#endif
MODULE_PARM(auth_id, "i");
#endif

#define ESP_AES			12	/* truely _constant_  :)  */

/* 128, 192 or 256 */
#define ESP_AES_KEY_SZ_MIN	16 	/* 128 bit secret key */
#define ESP_AES_KEY_SZ_MAX	32 	/* 256 bit secret key */
#define ESP_AES_CBC_BLK_LEN	16	/* AES-CBC block size */

/* Values according to draft-ietf-ipsec-ciph-aes-xcbc-mac-02.txt
 * -kravietz
 */
#define ESP_AES_MAC_KEY_SZ	16	/* 128 bit MAC key */
#define ESP_AES_MAC_BLK_LEN	16	/* 128 bit block */

static int _aes_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
	int ret;
	AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
	ret=AES_set_key(ctx, key, keysize)!=0? 0: -EINVAL;
	if (debug > 0)
		printk(KERN_DEBUG "klips_debug:_aes_set_key:"
				"ret=%d key_e=%p key=%p keysize=%d\n",
				ret, key_e, key, keysize);
	return ret;
}
static int _aes_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
	AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
	if (debug > 0)
		printk(KERN_DEBUG "klips_debug:_aes_cbc_encrypt:"
				"key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
				key_e, in, ilen, iv, encrypt);
	return AES_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
}
#if CONFIG_IPSEC_ALG_AES_MAC
static int _aes_mac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
	aes_context_mac *ctxm=(aes_context_mac *)key_a;
	return AES_xcbc_mac_set_key(ctxm, key, keylen)? 0 : -EINVAL;
}
static int _aes_mac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
	int ret;
	char hash_buf[16];
	aes_context_mac *ctxm=(aes_context_mac *)key_a;
	ret=AES_xcbc_mac_hash(ctxm, dat, len, hash_buf);
	memcpy(hash, hash_buf, hashlen);
	return ret;
}
static struct ipsec_alg_auth ipsec_alg_AES_MAC = {
	ixt_version:	IPSEC_ALG_VERSION,
	ixt_module:	THIS_MODULE,
	ixt_refcnt:	ATOMIC_INIT(0),
	ixt_alg_type:	IPSEC_ALG_TYPE_AUTH,
	ixt_alg_id: 	0,
	ixt_name: 	"aes_mac",
	ixt_blocksize:	ESP_AES_MAC_BLK_LEN,
	ixt_keyminbits:	ESP_AES_MAC_KEY_SZ*8,
	ixt_keymaxbits:	ESP_AES_MAC_KEY_SZ*8,
	ixt_a_keylen:	ESP_AES_MAC_KEY_SZ,
	ixt_a_ctx_size:	sizeof(aes_context_mac),
	ixt_a_hmac_set_key:	_aes_mac_set_key,
	ixt_a_hmac_hash:_aes_mac_hash,
};
#endif /* CONFIG_IPSEC_ALG_AES_MAC */
static struct ipsec_alg_enc ipsec_alg_AES = {
	ixt_version:	IPSEC_ALG_VERSION,
	ixt_module:	THIS_MODULE,
	ixt_refcnt:	ATOMIC_INIT(0),
	ixt_alg_type:	IPSEC_ALG_TYPE_ENCRYPT,
	ixt_alg_id: 	ESP_AES,
	ixt_name: 	"aes",
	ixt_blocksize:	ESP_AES_CBC_BLK_LEN, 
	ixt_keyminbits:	ESP_AES_KEY_SZ_MIN*8,
	ixt_keymaxbits:	ESP_AES_KEY_SZ_MAX*8,
	ixt_e_keylen:	ESP_AES_KEY_SZ_MAX,
	ixt_e_ctx_size:	sizeof(AES_CONTEXT_T),
	ixt_e_set_key:	_aes_set_key,
	ixt_e_cbc_encrypt:_aes_cbc_encrypt,
};
	
IPSEC_ALG_MODULE_INIT( ipsec_aes_init )
{
	int ret, test_ret;
	if (keyminbits)
		ipsec_alg_AES.ixt_keyminbits=keyminbits;
	if (keymaxbits) {
		ipsec_alg_AES.ixt_keymaxbits=keymaxbits;
		if (keymaxbits*8>ipsec_alg_AES.ixt_keymaxbits)
			ipsec_alg_AES.ixt_e_keylen=keymaxbits*8;
	}
	if (excl) ipsec_alg_AES.ixt_state |= IPSEC_ALG_ST_EXCL;
	ret=register_ipsec_alg_enc(&ipsec_alg_AES);
	printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n", 
			ipsec_alg_AES.ixt_alg_type, 
			ipsec_alg_AES.ixt_alg_id, 
			ipsec_alg_AES.ixt_name, 
			ret);
	if (ret==0 && test) {
		test_ret=ipsec_alg_test(
				ipsec_alg_AES.ixt_alg_type,
				ipsec_alg_AES.ixt_alg_id, 
				test);
		printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n", 
				ipsec_alg_AES.ixt_alg_type, 
				ipsec_alg_AES.ixt_alg_id, 
				test_ret);
	}
#if CONFIG_IPSEC_ALG_AES_MAC
	if (auth_id!=0){
		int ret;
		ipsec_alg_AES_MAC.ixt_alg_id=auth_id;
		ret=register_ipsec_alg_auth(&ipsec_alg_AES_MAC);
		printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n", 
				ipsec_alg_AES_MAC.ixt_alg_type, 
				ipsec_alg_AES_MAC.ixt_alg_id, 
				ipsec_alg_AES_MAC.ixt_name, 
				ret);
		if (ret==0 && test) {
			test_ret=ipsec_alg_test(
					ipsec_alg_AES_MAC.ixt_alg_type,
					ipsec_alg_AES_MAC.ixt_alg_id, 
					test);
			printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n", 
					ipsec_alg_AES_MAC.ixt_alg_type, 
					ipsec_alg_AES_MAC.ixt_alg_id, 
					test_ret);
		}
	} else {
		printk(KERN_DEBUG "klips_debug: experimental ipsec_alg_AES_MAC not registered [Ok] (auth_id=%d)\n", auth_id);
	}
#endif /* CONFIG_IPSEC_ALG_AES_MAC */
	return ret;
}
IPSEC_ALG_MODULE_EXIT( ipsec_aes_fini )
{
#if CONFIG_IPSEC_ALG_AES_MAC
	if (auth_id) unregister_ipsec_alg_auth(&ipsec_alg_AES_MAC);
#endif /* CONFIG_IPSEC_ALG_AES_MAC */
	unregister_ipsec_alg_enc(&ipsec_alg_AES);
	return;
}
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif

#if 0+NOT_YET
#ifndef MODULE
/*
 * 	This is intended for static module setups, currently
 * 	doesn't work for modular ipsec.o with static algos inside
 */
static int setup_keybits(const char *str)
{
	unsigned aux;
	char *end;

	aux = simple_strtoul(str,&end,0);
	if (aux != 128 && aux != 192 && aux != 256)
		return 0;
	keyminbits = aux;

	if (*end == 0 || *end != ',')
		return 1;
	str=end+1;
	aux = simple_strtoul(str, NULL, 0);
	if (aux != 128 && aux != 192 && aux != 256)
		return 0;
	if (aux >= keyminbits)
		keymaxbits = aux;
	return 1;
}
__setup("ipsec_aes_keybits=", setup_keybits);
#endif
#endif
EXPORT_NO_SYMBOLS;