OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | /****************************************************************************** |
2 | ** |
||
3 | ** FILE NAME : ifxmips_sha1_hmac.c |
||
4 | ** PROJECT : IFX UEIP |
||
5 | ** MODULES : DEU Module for UEIP |
||
6 | ** DATE : September 8, 2009 |
||
7 | ** AUTHOR : Mohammad Firdaus |
||
8 | ** DESCRIPTION : Data Encryption Unit Driver |
||
9 | ** COPYRIGHT : Copyright (c) 2009 |
||
10 | ** Infineon Technologies AG |
||
11 | ** Am Campeon 1-12, 85579 Neubiberg, Germany |
||
12 | ** |
||
13 | ** This program is free software; you can redistribute it and/or modify |
||
14 | ** it under the terms of the GNU General Public License as published by |
||
15 | ** the Free Software Foundation; either version 2 of the License, or |
||
16 | ** (at your option) any later version. |
||
17 | ** |
||
18 | ** HISTORY |
||
19 | ** $Date $Author $Comment |
||
20 | ** 08,Sept 2009 Mohammad Firdaus Initial UEIP release |
||
21 | ** 21,March 2011 Mohammad Firdaus Changes for Kernel 2.6.32 and IPSec integration |
||
22 | *******************************************************************************/ |
||
23 | /*! |
||
24 | \defgroup IFX_DEU IFX_DEU_DRIVERS |
||
25 | \ingroup API |
||
26 | \brief ifx deu driver module |
||
27 | */ |
||
28 | |||
29 | /*! |
||
30 | \file ifxmips_sha1_hmac.c |
||
31 | \ingroup IFX_DEU |
||
32 | \brief SHA1-HMAC deu driver file |
||
33 | */ |
||
34 | |||
35 | /*! |
||
36 | \defgroup IFX_SHA1_HMAC_FUNCTIONS IFX_SHA1_HMAC_FUNCTIONS |
||
37 | \ingroup IFX_DEU |
||
38 | \brief ifx sha1 hmac functions |
||
39 | */ |
||
40 | |||
41 | |||
42 | /* Project header */ |
||
43 | #include <linux/init.h> |
||
44 | #include <linux/module.h> |
||
45 | #include <linux/mm.h> |
||
46 | #include <linux/crypto.h> |
||
47 | #include <linux/cryptohash.h> |
||
48 | #include <crypto/internal/hash.h> |
||
49 | #include <linux/types.h> |
||
50 | #include <linux/scatterlist.h> |
||
51 | #include <asm/byteorder.h> |
||
52 | #include <linux/delay.h> |
||
53 | |||
54 | #if defined(CONFIG_AR9) |
||
55 | #include "ifxmips_deu_ar9.h" |
||
56 | #elif defined(CONFIG_VR9) || defined(CONFIG_AR10) |
||
57 | #include "ifxmips_deu_vr9.h" |
||
58 | #else |
||
59 | #error "Plaform Unknwon!" |
||
60 | #endif |
||
61 | |||
62 | #define SHA1_DIGEST_SIZE 20 |
||
63 | #define SHA1_HMAC_BLOCK_SIZE 64 |
||
64 | #define SHA1_HMAC_DBN_TEMP_SIZE 1024 // size in dword, needed for dbn workaround |
||
65 | #define HASH_START IFX_HASH_CON |
||
66 | |||
67 | #define SHA1_HMAC_MAX_KEYLEN 64 |
||
68 | |||
69 | static spinlock_t lock; |
||
70 | #define CRTCL_SECT_INIT spin_lock_init(&lock) |
||
71 | #define CRTCL_SECT_START spin_lock_irqsave(&lock, flag) |
||
72 | #define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag) |
||
73 | |||
74 | #ifdef CRYPTO_DEBUG |
||
75 | extern char debug_level; |
||
76 | #define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args); |
||
77 | #else |
||
78 | #define DPRINTF(level, format, args...) |
||
79 | #endif |
||
80 | |||
81 | struct sha1_hmac_ctx { |
||
82 | int keylen; |
||
83 | |||
84 | u8 buffer[SHA1_HMAC_BLOCK_SIZE]; |
||
85 | u8 key[SHA1_HMAC_MAX_KEYLEN]; |
||
86 | u32 state[5]; |
||
87 | u32 dbn; |
||
88 | u64 count; |
||
89 | |||
90 | }; |
||
91 | |||
92 | static u32 temp[SHA1_HMAC_DBN_TEMP_SIZE]; |
||
93 | |||
94 | extern int disable_deudma; |
||
95 | |||
96 | /*! \fn static void sha1_hmac_transform(struct crypto_tfm *tfm, u32 const *in) |
||
97 | * \ingroup IFX_SHA1_HMAC_FUNCTIONS |
||
98 | * \brief save input block to context |
||
99 | * \param tfm linux crypto algo transform |
||
100 | * \param in 64-byte block of input |
||
101 | */ |
||
102 | static int sha1_hmac_transform(struct shash_desc *desc, u32 const *in) |
||
103 | { |
||
104 | struct sha1_hmac_ctx *sctx = crypto_shash_ctx(desc->tfm); |
||
105 | |||
106 | memcpy(&temp[sctx->dbn<<4], in, 64); //dbn workaround |
||
107 | sctx->dbn += 1; |
||
108 | |||
109 | if ( (sctx->dbn<<4) > SHA1_HMAC_DBN_TEMP_SIZE ) |
||
110 | { |
||
111 | printk("SHA1_HMAC_DBN_TEMP_SIZE exceeded\n"); |
||
112 | } |
||
113 | |||
114 | return 0; |
||
115 | } |
||
116 | |||
117 | /*! \fn int sha1_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) |
||
118 | * \ingroup IFX_SHA1_HMAC_FUNCTIONS |
||
119 | * \brief sets sha1 hmac key |
||
120 | * \param tfm linux crypto algo transform |
||
121 | * \param key input key |
||
122 | * \param keylen key length greater than 64 bytes IS NOT SUPPORTED |
||
123 | */ |
||
124 | static int sha1_hmac_setkey(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) |
||
125 | { |
||
126 | struct sha1_hmac_ctx *sctx = crypto_shash_ctx(tfm); |
||
127 | volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START; |
||
128 | |||
129 | if (keylen > SHA1_HMAC_MAX_KEYLEN) { |
||
130 | printk("Key length exceeds maximum key length\n"); |
||
131 | return -EINVAL; |
||
132 | } |
||
133 | |||
134 | //printk("Setting keys of len: %d\n", keylen); |
||
135 | |||
136 | hashs->KIDX |= 0x80000000; //reset keys back to 0 |
||
137 | memcpy(&sctx->key, key, keylen); |
||
138 | sctx->keylen = keylen; |
||
139 | |||
140 | return 0; |
||
141 | |||
142 | } |
||
143 | |||
144 | |||
145 | /*! \fn int sha1_hmac_setkey_hw(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) |
||
146 | * \ingroup IFX_SHA1_HMAC_FUNCTIONS |
||
147 | * \brief sets sha1 hmac key into hw registers |
||
148 | * \param tfm linux crypto algo transform |
||
149 | * \param key input key |
||
150 | * \param keylen key length greater than 64 bytes IS NOT SUPPORTED |
||
151 | */ |
||
152 | static int sha1_hmac_setkey_hw(const u8 *key, unsigned int keylen) |
||
153 | { |
||
154 | volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START; |
||
155 | int i, j; |
||
156 | unsigned long flag; |
||
157 | u32 *in_key = (u32 *)key; |
||
158 | |||
159 | j = 0; |
||
160 | |||
161 | CRTCL_SECT_START; |
||
162 | for (i = 0; i < keylen; i+=4) |
||
163 | { |
||
164 | hash->KIDX = j; |
||
165 | asm("sync"); |
||
166 | hash->KEY = *((u32 *) in_key + j); |
||
167 | j++; |
||
168 | } |
||
169 | |||
170 | CRTCL_SECT_END; |
||
171 | return 0; |
||
172 | } |
||
173 | |||
174 | /*! \fn void sha1_hmac_init(struct crypto_tfm *tfm) |
||
175 | * \ingroup IFX_SHA1_HMAC_FUNCTIONS |
||
176 | * \brief initialize sha1 hmac context |
||
177 | * \param tfm linux crypto algo transform |
||
178 | */ |
||
179 | static int sha1_hmac_init(struct shash_desc *desc) |
||
180 | { |
||
181 | struct sha1_hmac_ctx *sctx = crypto_shash_ctx(desc->tfm); |
||
182 | |||
183 | //printk("debug ln: %d, fn: %s\n", __LINE__, __func__); |
||
184 | sctx->dbn = 0; //dbn workaround |
||
185 | sha1_hmac_setkey_hw(sctx->key, sctx->keylen); |
||
186 | |||
187 | return 0; |
||
188 | } |
||
189 | |||
190 | /*! \fn static void sha1_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) |
||
191 | * \ingroup IFX_SHA1_HMAC_FUNCTIONS |
||
192 | * \brief on-the-fly sha1 hmac computation |
||
193 | * \param tfm linux crypto algo transform |
||
194 | * \param data input data |
||
195 | * \param len size of input data |
||
196 | */ |
||
197 | static int sha1_hmac_update(struct shash_desc *desc, const u8 *data, |
||
198 | unsigned int len) |
||
199 | { |
||
200 | struct sha1_hmac_ctx *sctx = crypto_shash_ctx(desc->tfm); |
||
201 | unsigned int i, j; |
||
202 | |||
203 | j = (sctx->count >> 3) & 0x3f; |
||
204 | sctx->count += len << 3; |
||
205 | // printk("sctx->count = %d\n", sctx->count); |
||
206 | |||
207 | if ((j + len) > 63) { |
||
208 | memcpy (&sctx->buffer[j], data, (i = 64 - j)); |
||
209 | sha1_hmac_transform (desc, (const u32 *)sctx->buffer); |
||
210 | for (; i + 63 < len; i += 64) { |
||
211 | sha1_hmac_transform (desc, (const u32 *)&data[i]); |
||
212 | } |
||
213 | |||
214 | j = 0; |
||
215 | } |
||
216 | else |
||
217 | i = 0; |
||
218 | |||
219 | memcpy (&sctx->buffer[j], &data[i], len - i); |
||
220 | return 0; |
||
221 | } |
||
222 | |||
223 | /*! \fn static void sha1_hmac_final(struct crypto_tfm *tfm, u8 *out) |
||
224 | * \ingroup IFX_SHA1_HMAC_FUNCTIONS |
||
225 | * \brief ompute final sha1 hmac value |
||
226 | * \param tfm linux crypto algo transform |
||
227 | * \param out final sha1 hmac output value |
||
228 | */ |
||
229 | static int sha1_hmac_final(struct shash_desc *desc, u8 *out) |
||
230 | { |
||
231 | //struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); |
||
232 | struct sha1_hmac_ctx *sctx = crypto_shash_ctx(desc->tfm); |
||
233 | u32 index, padlen; |
||
234 | u64 t; |
||
235 | u8 bits[8] = { 0, }; |
||
236 | static const u8 padding[64] = { 0x80, }; |
||
237 | volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START; |
||
238 | unsigned long flag; |
||
239 | int i = 0; |
||
240 | int dbn; |
||
241 | u32 *in = &temp[0]; |
||
242 | |||
243 | t = sctx->count + 512; // need to add 512 bit of the IPAD operation |
||
244 | bits[7] = 0xff & t; |
||
245 | t >>= 8; |
||
246 | bits[6] = 0xff & t; |
||
247 | t >>= 8; |
||
248 | bits[5] = 0xff & t; |
||
249 | t >>= 8; |
||
250 | bits[4] = 0xff & t; |
||
251 | t >>= 8; |
||
252 | bits[3] = 0xff & t; |
||
253 | t >>= 8; |
||
254 | bits[2] = 0xff & t; |
||
255 | t >>= 8; |
||
256 | bits[1] = 0xff & t; |
||
257 | t >>= 8; |
||
258 | bits[0] = 0xff & t; |
||
259 | |||
260 | /* Pad out to 56 mod 64 */ |
||
261 | index = (sctx->count >> 3) & 0x3f; |
||
262 | padlen = (index < 56) ? (56 - index) : ((64 + 56) - index); |
||
263 | sha1_hmac_update (desc, padding, padlen); |
||
264 | |||
265 | /* Append length */ |
||
266 | sha1_hmac_update (desc, bits, sizeof bits); |
||
267 | |||
268 | CRTCL_SECT_START; |
||
269 | |||
270 | hashs->DBN = sctx->dbn; |
||
271 | |||
272 | //for vr9 change, ENDI = 1 |
||
273 | *IFX_HASH_CON = HASH_CON_VALUE; |
||
274 | |||
275 | //wait for processing |
||
276 | while (hashs->controlr.BSY) { |
||
277 | // this will not take long |
||
278 | } |
||
279 | |||
280 | for (dbn = 0; dbn < sctx->dbn; dbn++) |
||
281 | { |
||
282 | for (i = 0; i < 16; i++) { |
||
283 | hashs->MR = in[i]; |
||
284 | }; |
||
285 | |||
286 | hashs->controlr.GO = 1; |
||
287 | asm("sync"); |
||
288 | |||
289 | //wait for processing |
||
290 | while (hashs->controlr.BSY) { |
||
291 | // this will not take long |
||
292 | } |
||
293 | |||
294 | in += 16; |
||
295 | } |
||
296 | |||
297 | |||
298 | #if 1 |
||
299 | //wait for digest ready |
||
300 | while (! hashs->controlr.DGRY) { |
||
301 | // this will not take long |
||
302 | } |
||
303 | #endif |
||
304 | |||
305 | *((u32 *) out + 0) = hashs->D1R; |
||
306 | *((u32 *) out + 1) = hashs->D2R; |
||
307 | *((u32 *) out + 2) = hashs->D3R; |
||
308 | *((u32 *) out + 3) = hashs->D4R; |
||
309 | *((u32 *) out + 4) = hashs->D5R; |
||
310 | |||
311 | memset(&sctx->buffer[0], 0, SHA1_HMAC_BLOCK_SIZE); |
||
312 | sctx->count = 0; |
||
313 | |||
314 | //printk("debug ln: %d, fn: %s\n", __LINE__, __func__); |
||
315 | CRTCL_SECT_END; |
||
316 | |||
317 | |||
318 | return 0; |
||
319 | |||
320 | } |
||
321 | |||
322 | /* |
||
323 | * \brief SHA1-HMAC function mappings |
||
324 | */ |
||
325 | static struct shash_alg ifxdeu_sha1_hmac_alg = { |
||
326 | .digestsize = SHA1_DIGEST_SIZE, |
||
327 | .init = sha1_hmac_init, |
||
328 | .update = sha1_hmac_update, |
||
329 | .final = sha1_hmac_final, |
||
330 | .setkey = sha1_hmac_setkey, |
||
331 | .descsize = sizeof(struct sha1_hmac_ctx), |
||
332 | .base = { |
||
333 | .cra_name = "hmac(sha1)", |
||
334 | .cra_driver_name= "ifxdeu-sha1_hmac", |
||
335 | .cra_priority = 400, |
||
336 | .cra_ctxsize = sizeof(struct sha1_hmac_ctx), |
||
337 | .cra_flags = CRYPTO_ALG_TYPE_DIGEST, |
||
338 | .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, |
||
339 | .cra_module = THIS_MODULE, |
||
340 | } |
||
341 | |||
342 | }; |
||
343 | |||
344 | |||
345 | /*! \fn int ifxdeu_init_sha1_hmac (void) |
||
346 | * \ingroup IFX_SHA1_HMAC_FUNCTIONS |
||
347 | * \brief initialize sha1 hmac driver |
||
348 | */ |
||
349 | int ifxdeu_init_sha1_hmac (void) |
||
350 | { |
||
351 | int ret = -ENOSYS; |
||
352 | |||
353 | |||
354 | |||
355 | if ((ret = crypto_register_shash(&ifxdeu_sha1_hmac_alg))) |
||
356 | goto sha1_err; |
||
357 | |||
358 | CRTCL_SECT_INIT; |
||
359 | |||
360 | printk (KERN_NOTICE "IFX DEU SHA1_HMAC initialized%s.\n", disable_deudma ? "" : " (DMA)"); |
||
361 | return ret; |
||
362 | |||
363 | sha1_err: |
||
364 | printk(KERN_ERR "IFX DEU SHA1_HMAC initialization failed!\n"); |
||
365 | return ret; |
||
366 | } |
||
367 | |||
368 | /*! \fn void ifxdeu_fini_sha1_hmac (void) |
||
369 | * \ingroup IFX_SHA1_HMAC_FUNCTIONS |
||
370 | * \brief unregister sha1 hmac driver |
||
371 | */ |
||
372 | void ifxdeu_fini_sha1_hmac (void) |
||
373 | { |
||
374 | |||
375 | crypto_unregister_shash(&ifxdeu_sha1_hmac_alg); |
||
376 | |||
377 | |||
378 | } |
||
379 |