OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /****************************************************************************** |
2 | ** |
||
3 | ** FILE NAME : ifxmips_md5.c |
||
4 | ** PROJECT : IFX UEIP |
||
5 | ** MODULES : DEU Module for UEIP |
||
6 | ** |
||
7 | ** DATE : September 8, 2009 |
||
8 | ** AUTHOR : Mohammad Firdaus |
||
9 | ** DESCRIPTION : Data Encryption Unit Driver |
||
10 | ** COPYRIGHT : Copyright (c) 2009 |
||
11 | ** Infineon Technologies AG |
||
12 | ** Am Campeon 1-12, 85579 Neubiberg, Germany |
||
13 | ** |
||
14 | ** This program is free software; you can redistribute it and/or modify |
||
15 | ** it under the terms of the GNU General Public License as published by |
||
16 | ** the Free Software Foundation; either version 2 of the License, or |
||
17 | ** (at your option) any later version. |
||
18 | ** |
||
19 | ** HISTORY |
||
20 | ** $Date $Author $Comment |
||
21 | ** 08,Sept 2009 Mohammad Firdaus Initial UEIP release |
||
22 | *******************************************************************************/ |
||
23 | /*! |
||
24 | \defgroup IFX_DEU IFX_DEU_DRIVERS |
||
25 | \ingroup API |
||
26 | \brief ifx deu driver module |
||
27 | */ |
||
28 | |||
29 | /*! |
||
30 | \file ifxmips_md5.c |
||
31 | \ingroup IFX_DEU |
||
32 | \brief MD5 encryption deu driver file |
||
33 | */ |
||
34 | |||
35 | /*! |
||
36 | \defgroup IFX_MD5_FUNCTIONS IFX_MD5_FUNCTIONS |
||
37 | \ingroup IFX_DEU |
||
38 | \brief ifx deu MD5 functions |
||
39 | */ |
||
40 | |||
41 | /*Project header files */ |
||
42 | #include <linux/init.h> |
||
43 | #include <linux/module.h> |
||
44 | #include <linux/string.h> |
||
45 | #include <linux/crypto.h> |
||
46 | #include <linux/types.h> |
||
47 | #include <crypto/internal/hash.h> |
||
48 | #include <asm/byteorder.h> |
||
49 | |||
50 | /* Project header */ |
||
51 | #if defined(CONFIG_DANUBE) |
||
52 | #include "ifxmips_deu_danube.h" |
||
53 | #elif defined(CONFIG_AR9) |
||
54 | #include "ifxmips_deu_ar9.h" |
||
55 | #elif defined(CONFIG_VR9) || defined(CONFIG_AR10) |
||
56 | #include "ifxmips_deu_vr9.h" |
||
57 | #else |
||
58 | #error "Plaform Unknwon!" |
||
59 | #endif |
||
60 | |||
61 | #define MD5_DIGEST_SIZE 16 |
||
62 | #define MD5_HMAC_BLOCK_SIZE 64 |
||
63 | #define MD5_BLOCK_WORDS 16 |
||
64 | #define MD5_HASH_WORDS 4 |
||
65 | #define HASH_START IFX_HASH_CON |
||
66 | |||
67 | static spinlock_t lock; |
||
68 | #define CRTCL_SECT_INIT spin_lock_init(&lock) |
||
69 | #define CRTCL_SECT_START spin_lock_irqsave(&lock, flag) |
||
70 | #define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag) |
||
71 | |||
72 | //#define CRYPTO_DEBUG |
||
73 | #ifdef CRYPTO_DEBUG |
||
74 | extern char debug_level; |
||
75 | #define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args); |
||
76 | #else |
||
77 | #define DPRINTF(level, format, args...) |
||
78 | #endif |
||
79 | |||
80 | struct md5_ctx { |
||
81 | int started; |
||
82 | u32 hash[MD5_HASH_WORDS]; |
||
83 | u32 block[MD5_BLOCK_WORDS]; |
||
84 | u64 byte_count; |
||
85 | }; |
||
86 | |||
87 | extern int disable_deudma; |
||
88 | |||
89 | /*! \fn static u32 endian_swap(u32 input) |
||
90 | * \ingroup IFX_MD5_FUNCTIONS |
||
91 | * \brief perform dword level endian swap |
||
92 | * \param input value of dword that requires to be swapped |
||
93 | */ |
||
94 | static u32 endian_swap(u32 input) |
||
95 | { |
||
96 | u8 *ptr = (u8 *)&input; |
||
97 | |||
98 | return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); |
||
99 | } |
||
100 | |||
101 | /*! \fn static void md5_transform(u32 *hash, u32 const *in) |
||
102 | * \ingroup IFX_MD5_FUNCTIONS |
||
103 | * \brief main interface to md5 hardware |
||
104 | * \param hash current hash value |
||
105 | * \param in 64-byte block of input |
||
106 | */ |
||
107 | static void md5_transform(struct md5_ctx *mctx, u32 *hash, u32 const *in) |
||
108 | { |
||
109 | int i; |
||
110 | volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START; |
||
111 | unsigned long flag; |
||
112 | |||
113 | CRTCL_SECT_START; |
||
114 | |||
115 | if (mctx->started) { |
||
116 | hashs->D1R = endian_swap(*((u32 *) hash + 0)); |
||
117 | hashs->D2R = endian_swap(*((u32 *) hash + 1)); |
||
118 | hashs->D3R = endian_swap(*((u32 *) hash + 2)); |
||
119 | hashs->D4R = endian_swap(*((u32 *) hash + 3)); |
||
120 | } |
||
121 | |||
122 | for (i = 0; i < 16; i++) { |
||
123 | hashs->MR = endian_swap(in[i]); |
||
124 | // printk("in[%d]: %08x\n", i, endian_swap(in[i])); |
||
125 | }; |
||
126 | |||
127 | //wait for processing |
||
128 | while (hashs->controlr.BSY) { |
||
129 | // this will not take long |
||
130 | } |
||
131 | |||
132 | *((u32 *) hash + 0) = endian_swap (hashs->D1R); |
||
133 | *((u32 *) hash + 1) = endian_swap (hashs->D2R); |
||
134 | *((u32 *) hash + 2) = endian_swap (hashs->D3R); |
||
135 | *((u32 *) hash + 3) = endian_swap (hashs->D4R); |
||
136 | |||
137 | mctx->started = 1; |
||
138 | |||
139 | CRTCL_SECT_END; |
||
140 | } |
||
141 | |||
142 | /*! \fn static inline void md5_transform_helper(struct md5_ctx *ctx) |
||
143 | * \ingroup IFX_MD5_FUNCTIONS |
||
144 | * \brief interfacing function for md5_transform() |
||
145 | * \param ctx crypto context |
||
146 | */ |
||
147 | static inline void md5_transform_helper(struct md5_ctx *ctx) |
||
148 | { |
||
149 | //le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); |
||
150 | md5_transform(ctx, ctx->hash, ctx->block); |
||
151 | } |
||
152 | |||
153 | /*! \fn static void md5_init(struct crypto_tfm *tfm) |
||
154 | * \ingroup IFX_MD5_FUNCTIONS |
||
155 | * \brief initialize md5 hardware |
||
156 | * \param tfm linux crypto algo transform |
||
157 | */ |
||
158 | static int md5_init(struct shash_desc *desc) |
||
159 | { |
||
160 | struct md5_ctx *mctx = shash_desc_ctx(desc); |
||
161 | volatile struct deu_hash_t *hash = (struct deu_hash_t *) HASH_START; |
||
162 | |||
163 | hash->controlr.ENDI = 0; |
||
164 | hash->controlr.SM = 1; |
||
165 | hash->controlr.ALGO = 1; // 1 = md5 0 = sha1 |
||
166 | hash->controlr.INIT = 1; // Initialize the hash operation by writing a '1' to the INIT bit. |
||
167 | |||
168 | mctx->byte_count = 0; |
||
169 | mctx->started = 0; |
||
170 | return 0; |
||
171 | } |
||
172 | |||
173 | /*! \fn static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) |
||
174 | * \ingroup IFX_MD5_FUNCTIONS |
||
175 | * \brief on-the-fly md5 computation |
||
176 | * \param tfm linux crypto algo transform |
||
177 | * \param data input data |
||
178 | * \param len size of input data |
||
179 | */ |
||
180 | static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len) |
||
181 | { |
||
182 | struct md5_ctx *mctx = shash_desc_ctx(desc); |
||
183 | const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); |
||
184 | |||
185 | mctx->byte_count += len; |
||
186 | |||
187 | if (avail > len) { |
||
188 | memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), |
||
189 | data, len); |
||
190 | return 0; |
||
191 | } |
||
192 | |||
193 | memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), |
||
194 | data, avail); |
||
195 | |||
196 | md5_transform_helper(mctx); |
||
197 | data += avail; |
||
198 | len -= avail; |
||
199 | |||
200 | while (len >= sizeof(mctx->block)) { |
||
201 | memcpy(mctx->block, data, sizeof(mctx->block)); |
||
202 | md5_transform_helper(mctx); |
||
203 | data += sizeof(mctx->block); |
||
204 | len -= sizeof(mctx->block); |
||
205 | } |
||
206 | |||
207 | memcpy(mctx->block, data, len); |
||
208 | return 0; |
||
209 | } |
||
210 | |||
211 | /*! \fn static void md5_final(struct crypto_tfm *tfm, u8 *out) |
||
212 | * \ingroup IFX_MD5_FUNCTIONS |
||
213 | * \brief compute final md5 value |
||
214 | * \param tfm linux crypto algo transform |
||
215 | * \param out final md5 output value |
||
216 | */ |
||
217 | static int md5_final(struct shash_desc *desc, u8 *out) |
||
218 | { |
||
219 | struct md5_ctx *mctx = shash_desc_ctx(desc); |
||
220 | const unsigned int offset = mctx->byte_count & 0x3f; |
||
221 | char *p = (char *)mctx->block + offset; |
||
222 | int padding = 56 - (offset + 1); |
||
223 | volatile struct deu_hash_t *hashs = (struct deu_hash_t *) HASH_START; |
||
224 | unsigned long flag; |
||
225 | |||
226 | *p++ = 0x80; |
||
227 | if (padding < 0) { |
||
228 | memset(p, 0x00, padding + sizeof (u64)); |
||
229 | md5_transform_helper(mctx); |
||
230 | p = (char *)mctx->block; |
||
231 | padding = 56; |
||
232 | } |
||
233 | |||
234 | memset(p, 0, padding); |
||
235 | mctx->block[14] = endian_swap(mctx->byte_count << 3); |
||
236 | mctx->block[15] = endian_swap(mctx->byte_count >> 29); |
||
237 | |||
238 | #if 0 |
||
239 | le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - |
||
240 | sizeof(u64)) / sizeof(u32)); |
||
241 | #endif |
||
242 | |||
243 | md5_transform(mctx, mctx->hash, mctx->block); |
||
244 | |||
245 | CRTCL_SECT_START; |
||
246 | |||
247 | *((u32 *) out + 0) = endian_swap (hashs->D1R); |
||
248 | *((u32 *) out + 1) = endian_swap (hashs->D2R); |
||
249 | *((u32 *) out + 2) = endian_swap (hashs->D3R); |
||
250 | *((u32 *) out + 3) = endian_swap (hashs->D4R); |
||
251 | |||
252 | CRTCL_SECT_END; |
||
253 | |||
254 | // Wipe context |
||
255 | memset(mctx, 0, sizeof(*mctx)); |
||
256 | |||
257 | return 0; |
||
258 | } |
||
259 | |||
260 | /* |
||
261 | * \brief MD5 function mappings |
||
262 | */ |
||
263 | static struct shash_alg ifxdeu_md5_alg = { |
||
264 | .digestsize = MD5_DIGEST_SIZE, |
||
265 | .init = md5_init, |
||
266 | .update = md5_update, |
||
267 | .final = md5_final, |
||
268 | .descsize = sizeof(struct md5_ctx), |
||
269 | .base = { |
||
270 | .cra_name = "md5", |
||
271 | .cra_driver_name= "ifxdeu-md5", |
||
272 | .cra_priority = 300, |
||
273 | .cra_flags = CRYPTO_ALG_TYPE_DIGEST, |
||
274 | .cra_blocksize = MD5_HMAC_BLOCK_SIZE, |
||
275 | .cra_module = THIS_MODULE, |
||
276 | } |
||
277 | }; |
||
278 | |||
279 | /*! \fn int ifxdeu_init_md5 (void) |
||
280 | * \ingroup IFX_MD5_FUNCTIONS |
||
281 | * \brief initialize md5 driver |
||
282 | */ |
||
283 | int ifxdeu_init_md5 (void) |
||
284 | { |
||
285 | int ret = -ENOSYS; |
||
286 | |||
287 | |||
288 | if ((ret = crypto_register_shash(&ifxdeu_md5_alg))) |
||
289 | goto md5_err; |
||
290 | |||
291 | CRTCL_SECT_INIT; |
||
292 | |||
293 | printk (KERN_NOTICE "IFX DEU MD5 initialized%s.\n", disable_deudma ? "" : " (DMA)"); |
||
294 | return ret; |
||
295 | |||
296 | md5_err: |
||
297 | printk(KERN_ERR "IFX DEU MD5 initialization failed!\n"); |
||
298 | return ret; |
||
299 | } |
||
300 | |||
301 | /*! \fn void ifxdeu_fini_md5 (void) |
||
302 | * \ingroup IFX_MD5_FUNCTIONS |
||
303 | * \brief unregister md5 driver |
||
304 | */ |
||
305 | |||
306 | void ifxdeu_fini_md5 (void) |
||
307 | { |
||
308 | crypto_unregister_shash(&ifxdeu_md5_alg); |
||
309 | |||
310 | } |
||
311 |