2 * arch/ubicom32/crypto/sha1_ubicom32.c
3 * Ubicom32 implementation of the SHA1 Secure Hash Algorithm.
5 * (C) Copyright 2009, Ubicom, Inc.
7 * This file is part of the Ubicom32 Linux Kernel Port.
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
23 * Ubicom32 implementation derived from (with many thanks):
28 #include <linux/init.h>
29 #include <linux/module.h>
30 #include <linux/crypto.h>
31 #include <crypto/sha.h>
32 #include <asm/linkage.h>
34 #include "crypto_ubicom32.h"
35 #define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2
36 #define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION)
38 struct ubicom32_sha1_ctx
{
39 u64 count
; /* message length */
41 u8 buf
[2 * SHA1_BLOCK_SIZE
];
44 static inline void sha1_clear_2ws(u8
*buf
, int wc
)
47 "1: move.4 (%0)4++, #0 \n\t"
48 " move.4 (%0)4++, #0 \n\t"
49 " sub.4 %1, #2, %1 \n\t"
57 /* only wipe out count, state, and 1st half of buf - 9 bytes at most */
58 #define sha1_wipe_out(sctx) sha1_clear_2ws((u8 *)sctx, 2 + 5 + 16 - 2)
60 static inline void sha1_init_digest(u32
*digest
)
62 hw_crypto_set_ctrl(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1
);
64 " ; move digests to hash_output regs \n\t"
65 " move.4 0x70(%0), 0x0(%1) \n\t"
66 " move.4 0x74(%0), 0x4(%1) \n\t"
67 " move.4 0x78(%0), 0x8(%1) \n\t"
68 " move.4 0x7c(%0), 0xc(%1) \n\t"
69 " move.4 0x80(%0), 0x10(%1) \n\t"
71 : "a" (SEC_BASE
), "a" (digest
)
75 static inline void sha1_transform_feed(const u8
*in
)
78 " ; write the 1st 16 bytes \n\t"
79 " move.4 0x30(%0), 0x0(%1) \n\t"
80 " move.4 0x34(%0), 0x4(%1) \n\t"
81 " move.4 0x38(%0), 0x8(%1) \n\t"
82 " move.4 0x3c(%0), 0xc(%1) \n\t"
83 " move.4 0x40(%0), %1 \n\t"
84 " ; write the 2nd 16 bytes \n\t"
85 " move.4 0x30(%0), 0x10(%1) \n\t"
86 " move.4 0x34(%0), 0x14(%1) \n\t"
87 " move.4 0x38(%0), 0x18(%1) \n\t"
88 " move.4 0x3c(%0), 0x1c(%1) \n\t"
89 " move.4 0x40(%0), %1 \n\t"
90 " ; write the 3rd 16 bytes \n\t"
91 " move.4 0x30(%0), 0x20(%1) \n\t"
92 " move.4 0x34(%0), 0x24(%1) \n\t"
93 " move.4 0x38(%0), 0x28(%1) \n\t"
94 " move.4 0x3c(%0), 0x2c(%1) \n\t"
95 " move.4 0x40(%0), %1 \n\t"
96 " ; write the 4th 16 bytes \n\t"
97 " move.4 0x30(%0), 0x30(%1) \n\t"
98 " move.4 0x34(%0), 0x34(%1) \n\t"
99 " move.4 0x38(%0), 0x38(%1) \n\t"
100 " move.4 0x3c(%0), 0x3c(%1) \n\t"
101 " move.4 0x40(%0), %1 \n\t"
104 : "a"(SEC_BASE
), "a"(in
)
108 static inline void sha1_transform_wait(void)
111 " btst 0x04(%0), #0 \n\t"
119 static inline void sha1_output_digest(u32
*digest
)
122 " move.4 0x0(%1), 0x70(%0) \n\t"
123 " move.4 0x4(%1), 0x74(%0) \n\t"
124 " move.4 0x8(%1), 0x78(%0) \n\t"
125 " move.4 0xc(%1), 0x7c(%0) \n\t"
126 " move.4 0x10(%1), 0x80(%0) \n\t"
128 : "a" (SEC_BASE
), "a" (digest
)
132 static __ocm_text
void sha1_init(struct crypto_tfm
*tfm
)
134 struct ubicom32_sha1_ctx
*sctx
= crypto_tfm_ctx(tfm
);
136 sctx
->state
[0] = SHA1_H0
;
137 sctx
->state
[1] = SHA1_H1
;
138 sctx
->state
[2] = SHA1_H2
;
139 sctx
->state
[3] = SHA1_H3
;
140 sctx
->state
[4] = SHA1_H4
;
144 static void __ocm_text
sha1_update(struct crypto_tfm
*tfm
, const u8
*data
,
147 struct ubicom32_sha1_ctx
*sctx
= crypto_tfm_ctx(tfm
);
150 /* how much is already in the buffer? */
151 index
= sctx
->count
& 0x3f;
155 if (index
+ len
< SHA1_BLOCK_SIZE
) {
162 /* init digest set ctrl register too */
163 sha1_init_digest(sctx
->state
);
165 if (unlikely(index
== 0 && SEC_ALIGNED(data
))) {
167 #if CRYPTO_UBICOM32_LOOP_ASM
168 if (likely(len
>= SHA1_BLOCK_SIZE
)) {
169 register unsigned int cnt
= len
>> 6; // loop = len / 64;
170 sha1_transform_feed(data
);
171 data
+= SHA1_BLOCK_SIZE
;
173 /* cnt is pre-decremented in the loop */
175 "; while (--loop): work on 2nd block \n\t"
176 "1: add.4 %2, #-1, %2 \n\t"
179 " ; write the 1st 16 bytes \n\t"
180 " move.4 0x30(%1), (%0)4++ \n\t"
181 " move.4 0x34(%1), (%0)4++ \n\t"
182 " move.4 0x38(%1), (%0)4++ \n\t"
183 " move.4 0x3c(%1), (%0)4++ \n\t"
184 " ; can not kick off hw before it \n\t"
185 " ; is done with the prev block \n\t"
187 " btst 0x04(%1), #0 \n\t"
190 " ; tell hw to load 1st 16 bytes \n\t"
191 " move.4 0x40(%1), %2 \n\t"
193 " ; write the 2nd 16 bytes \n\t"
194 " move.4 0x30(%1), (%0)4++ \n\t"
195 " move.4 0x34(%1), (%0)4++ \n\t"
196 " move.4 0x38(%1), (%0)4++ \n\t"
197 " move.4 0x3c(%1), (%0)4++ \n\t"
198 " move.4 0x40(%1), %2 \n\t"
200 " ; write the 3rd 16 bytes \n\t"
201 " move.4 0x30(%1), (%0)4++ \n\t"
202 " move.4 0x34(%1), (%0)4++ \n\t"
203 " move.4 0x38(%1), (%0)4++ \n\t"
204 " move.4 0x3c(%1), (%0)4++ \n\t"
205 " move.4 0x40(%1), %2 \n\t"
207 " ; write the 4th 16 bytes \n\t"
208 " move.4 0x30(%1), (%0)4++ \n\t"
209 " move.4 0x34(%1), (%0)4++ \n\t"
210 " move.4 0x38(%1), (%0)4++ \n\t"
211 " move.4 0x3c(%1), (%0)4++ \n\t"
212 " move.4 0x40(%1), %2 \n\t"
214 "; no need flush, enough insts \n\t"
215 "; before next hw wait \n\t"
217 "; go back to loop \n\t"
220 "; wait hw for last block \n\t"
221 "5: btst 0x04(%1), #0 \n\t"
225 : "a"( SEC_BASE
), "d" (cnt
)
229 len
= len
& (64 - 1);
232 while (likely(len
>= SHA1_BLOCK_SIZE
)) {
233 sha1_transform_feed(data
);
234 data
+= SHA1_BLOCK_SIZE
;
235 len
-= SHA1_BLOCK_SIZE
;
236 sha1_transform_wait();
242 /* process one stored block */
244 clen
= SHA1_BLOCK_SIZE
- index
;
245 memcpy(sctx
->buf
+ index
, data
, clen
);
246 sha1_transform_feed(sctx
->buf
);
250 sha1_transform_wait();
253 if (likely(SEC_ALIGNED(data
))) {
257 /* process as many blocks as possible */
258 if (likely(len
>= SHA1_BLOCK_SIZE
)) {
259 memcpy(sctx
->buf
, data
, SHA1_BLOCK_SIZE
);
261 sha1_transform_feed(sctx
->buf
);
262 data
+= SHA1_BLOCK_SIZE
;
263 len
-= SHA1_BLOCK_SIZE
;
264 if (likely(len
>= SHA1_BLOCK_SIZE
)) {
265 memcpy(sctx
->buf
, data
, SHA1_BLOCK_SIZE
);
266 sha1_transform_wait();
269 /* it is the last block */
270 sha1_transform_wait();
276 sha1_output_digest(sctx
->state
);
282 memcpy(sctx
->buf
+ index
, data
, len
);
285 /* Add padding and return the message digest. */
286 static void __ocm_text
sha1_final(struct crypto_tfm
*tfm
, u8
*out
)
288 struct ubicom32_sha1_ctx
*sctx
= crypto_tfm_ctx(tfm
);
290 unsigned int index
, end
;
292 /* must perform manual padding */
293 index
= sctx
->count
& 0x3f;
294 end
= (index
< 56) ? SHA1_BLOCK_SIZE
: (2 * SHA1_BLOCK_SIZE
);
296 /* start pad with 1 */
297 sctx
->buf
[index
] = 0x80;
301 memset(sctx
->buf
+ index
, 0x00, end
- index
- 8);
303 /* append message length */
304 bits
= sctx
->count
<< 3 ;
305 SEC_COPY_2W(sctx
->buf
+ end
- 8, &bits
);
307 /* force to use the sctx->buf and ignore the partial buf */
308 sctx
->count
= sctx
->count
& ~0x3f;
309 sha1_update(tfm
, sctx
->buf
, end
);
311 /* copy digest to out */
312 SEC_COPY_5W(out
, sctx
->state
);
318 static struct crypto_alg alg
= {
320 .cra_driver_name
= "sha1-ubicom32",
321 .cra_priority
= CRYPTO_UBICOM32_PRIORITY
,
322 .cra_flags
= CRYPTO_ALG_TYPE_DIGEST
,
323 .cra_blocksize
= SHA1_BLOCK_SIZE
,
324 .cra_ctxsize
= sizeof(struct ubicom32_sha1_ctx
),
325 .cra_module
= THIS_MODULE
,
326 .cra_list
= LIST_HEAD_INIT(alg
.cra_list
),
329 .dia_digestsize
= SHA1_DIGEST_SIZE
,
330 .dia_init
= sha1_init
,
331 .dia_update
= sha1_update
,
332 .dia_final
= sha1_final
,
337 static int __init
init(void)
340 return crypto_register_alg(&alg
);
343 static void __exit
fini(void)
345 crypto_unregister_alg(&alg
);
351 MODULE_ALIAS("sha1");
353 MODULE_LICENSE("GPL");
354 MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");