2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16 * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
17 * Copyright (C) 2009 Mohammad Firdaus
21 \defgroup IFX_DEU IFX_DEU_DRIVERS
23 \brief ifx deu driver module
29 \brief MD5 encryption deu driver file
33 \defgroup IFX_MD5_FUNCTIONS IFX_MD5_FUNCTIONS
35 \brief ifx deu MD5 functions
38 /*Project header files */
39 #include <linux/init.h>
40 #include <linux/module.h>
41 #include <linux/string.h>
42 #include <linux/crypto.h>
43 #include <linux/types.h>
44 #include <asm/byteorder.h>
45 #include "ifxmips_deu.h"
47 #define MD5_DIGEST_SIZE 16
48 #define MD5_HMAC_BLOCK_SIZE 64
49 #define MD5_BLOCK_WORDS 16
50 #define MD5_HASH_WORDS 4
51 #define HASH_START IFX_HASH_CON
53 static spinlock_t lock
;
54 #define CRTCL_SECT_INIT spin_lock_init(&lock)
55 #define CRTCL_SECT_START spin_lock_irqsave(&lock, flag)
56 #define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag)
59 u32 hash
[MD5_HASH_WORDS
];
60 u32 block
[MD5_BLOCK_WORDS
];
64 extern int disable_deudma
;
66 /*! \fn static u32 endian_swap(u32 input)
67 * \ingroup IFX_MD5_FUNCTIONS
68 * \brief perform dword level endian swap
69 * \param input value of dword that requires to be swapped
71 static u32
endian_swap(u32 input
)
73 u8
*ptr
= (u8
*)&input
;
75 return ((ptr
[3] << 24) | (ptr
[2] << 16) | (ptr
[1] << 8) | ptr
[0]);
78 /*! \fn static void md5_transform(u32 *hash, u32 const *in)
79 * \ingroup IFX_MD5_FUNCTIONS
80 * \brief main interface to md5 hardware
81 * \param hash current hash value
82 * \param in 64-byte block of input
84 static void md5_transform(u32
*hash
, u32
const *in
)
87 volatile struct deu_hash_t
*hashs
= (struct deu_hash_t
*) HASH_START
;
92 for (i
= 0; i
< 16; i
++) {
93 hashs
->MR
= endian_swap(in
[i
]);
97 while (hashs
->controlr
.BSY
) {
98 // this will not take long
104 /*! \fn static inline void md5_transform_helper(struct md5_ctx *ctx)
105 * \ingroup IFX_MD5_FUNCTIONS
106 * \brief interfacing function for md5_transform()
107 * \param ctx crypto context
109 static inline void md5_transform_helper(struct md5_ctx
*ctx
)
111 //le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
112 md5_transform(ctx
->hash
, ctx
->block
);
115 /*! \fn static void md5_init(struct crypto_tfm *tfm)
116 * \ingroup IFX_MD5_FUNCTIONS
117 * \brief initialize md5 hardware
118 * \param tfm linux crypto algo transform
120 static void md5_init(struct crypto_tfm
*tfm
)
122 struct md5_ctx
*mctx
= crypto_tfm_ctx(tfm
);
123 volatile struct deu_hash_t
*hash
= (struct deu_hash_t
*) HASH_START
;
125 hash
->controlr
.SM
= 1;
126 hash
->controlr
.ALGO
= 1; // 1 = md5 0 = sha1
127 hash
->controlr
.INIT
= 1; // Initialize the hash operation by writing a '1' to the INIT bit.
129 mctx
->byte_count
= 0;
132 /*! \fn static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
133 * \ingroup IFX_MD5_FUNCTIONS
134 * \brief on-the-fly md5 computation
135 * \param tfm linux crypto algo transform
136 * \param data input data
137 * \param len size of input data
139 static void md5_update(struct crypto_tfm
*tfm
, const u8
*data
, unsigned int len
)
141 struct md5_ctx
*mctx
= crypto_tfm_ctx(tfm
);
142 const u32 avail
= sizeof(mctx
->block
) - (mctx
->byte_count
& 0x3f);
144 mctx
->byte_count
+= len
;
147 memcpy((char *)mctx
->block
+ (sizeof(mctx
->block
) - avail
),
152 memcpy((char *)mctx
->block
+ (sizeof(mctx
->block
) - avail
),
155 md5_transform_helper(mctx
);
159 while (len
>= sizeof(mctx
->block
)) {
160 memcpy(mctx
->block
, data
, sizeof(mctx
->block
));
161 md5_transform_helper(mctx
);
162 data
+= sizeof(mctx
->block
);
163 len
-= sizeof(mctx
->block
);
166 memcpy(mctx
->block
, data
, len
);
169 /*! \fn static void md5_final(struct crypto_tfm *tfm, u8 *out)
170 * \ingroup IFX_MD5_FUNCTIONS
171 * \brief compute final md5 value
172 * \param tfm linux crypto algo transform
173 * \param out final md5 output value
175 static void md5_final(struct crypto_tfm
*tfm
, u8
*out
)
177 struct md5_ctx
*mctx
= crypto_tfm_ctx(tfm
);
178 const unsigned int offset
= mctx
->byte_count
& 0x3f;
179 char *p
= (char *)mctx
->block
+ offset
;
180 int padding
= 56 - (offset
+ 1);
181 volatile struct deu_hash_t
*hashs
= (struct deu_hash_t
*) HASH_START
;
186 memset(p
, 0x00, padding
+ sizeof (u64
));
187 md5_transform_helper(mctx
);
188 p
= (char *)mctx
->block
;
192 memset(p
, 0, padding
);
193 mctx
->block
[14] = endian_swap(mctx
->byte_count
<< 3);
194 mctx
->block
[15] = endian_swap(mctx
->byte_count
>> 29);
197 le32_to_cpu_array(mctx
->block
, (sizeof(mctx
->block
) -
198 sizeof(u64
)) / sizeof(u32
));
201 md5_transform(mctx
->hash
, mctx
->block
);
205 *((u32
*) out
+ 0) = endian_swap (hashs
->D1R
);
206 *((u32
*) out
+ 1) = endian_swap (hashs
->D2R
);
207 *((u32
*) out
+ 2) = endian_swap (hashs
->D3R
);
208 *((u32
*) out
+ 3) = endian_swap (hashs
->D4R
);
213 memset(mctx
, 0, sizeof(*mctx
));
217 * \brief MD5 function mappings
219 static struct crypto_alg ifxdeu_md5_alg
= {
221 .cra_driver_name
= "ifxdeu-md5",
222 .cra_flags
= CRYPTO_ALG_TYPE_DIGEST
,
223 .cra_blocksize
= MD5_HMAC_BLOCK_SIZE
,
224 .cra_ctxsize
= sizeof(struct md5_ctx
),
225 .cra_module
= THIS_MODULE
,
226 .cra_list
= LIST_HEAD_INIT(ifxdeu_md5_alg
.cra_list
),
227 .cra_u
= { .digest
= {
228 .dia_digestsize
= MD5_DIGEST_SIZE
,
229 .dia_init
= md5_init
,
230 .dia_update
= md5_update
,
231 .dia_final
= md5_final
} }
234 /*! \fn int __init ifxdeu_init_md5 (void)
235 * \ingroup IFX_MD5_FUNCTIONS
236 * \brief initialize md5 driver
238 int __init
ifxdeu_init_md5 (void)
242 if ((ret
= crypto_register_alg(&ifxdeu_md5_alg
)))
247 printk (KERN_NOTICE
"IFX DEU MD5 initialized%s.\n", disable_deudma
? "" : " (DMA)");
251 printk(KERN_ERR
"IFX DEU MD5 initialization failed!\n");
255 /*! \fn void __exit ifxdeu_fini_md5 (void)
256 * \ingroup IFX_MD5_FUNCTIONS
257 * \brief unregister md5 driver
260 void __exit
ifxdeu_fini_md5 (void)
262 crypto_unregister_alg (&ifxdeu_md5_alg
);