diff options
Diffstat (limited to 'crypto/md4.c')
-rw-r--r-- | crypto/md4.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/crypto/md4.c b/crypto/md4.c new file mode 100644 index 000000000000..bef6a9e5ac9b --- /dev/null +++ b/crypto/md4.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * Cryptographic API. | ||
3 | * | ||
4 | * MD4 Message Digest Algorithm (RFC1320). | ||
5 | * | ||
6 | * Implementation derived from Andrew Tridgell and Steve French's | ||
7 | * CIFS MD4 implementation, and the cryptoapi implementation | ||
8 | * originally based on the public domain implementation written | ||
9 | * by Colin Plumb in 1993. | ||
10 | * | ||
11 | * Copyright (c) Andrew Tridgell 1997-1998. | ||
12 | * Modified by Steve French (sfrench@us.ibm.com) 2002 | ||
13 | * Copyright (c) Cryptoapi developers. | ||
14 | * Copyright (c) 2002 David S. Miller (davem@redhat.com) | ||
15 | * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | */ | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/crypto.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <asm/byteorder.h> | ||
28 | |||
29 | #define MD4_DIGEST_SIZE 16 | ||
30 | #define MD4_HMAC_BLOCK_SIZE 64 | ||
31 | #define MD4_BLOCK_WORDS 16 | ||
32 | #define MD4_HASH_WORDS 4 | ||
33 | |||
34 | struct md4_ctx { | ||
35 | u32 hash[MD4_HASH_WORDS]; | ||
36 | u32 block[MD4_BLOCK_WORDS]; | ||
37 | u64 byte_count; | ||
38 | }; | ||
39 | |||
40 | static inline u32 lshift(u32 x, unsigned int s) | ||
41 | { | ||
42 | x &= 0xFFFFFFFF; | ||
43 | return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); | ||
44 | } | ||
45 | |||
46 | static inline u32 F(u32 x, u32 y, u32 z) | ||
47 | { | ||
48 | return (x & y) | ((~x) & z); | ||
49 | } | ||
50 | |||
51 | static inline u32 G(u32 x, u32 y, u32 z) | ||
52 | { | ||
53 | return (x & y) | (x & z) | (y & z); | ||
54 | } | ||
55 | |||
56 | static inline u32 H(u32 x, u32 y, u32 z) | ||
57 | { | ||
58 | return x ^ y ^ z; | ||
59 | } | ||
60 | |||
61 | #define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s)) | ||
62 | #define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (u32)0x5A827999,s)) | ||
63 | #define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (u32)0x6ED9EBA1,s)) | ||
64 | |||
65 | /* XXX: this stuff can be optimized */ | ||
66 | static inline void le32_to_cpu_array(u32 *buf, unsigned int words) | ||
67 | { | ||
68 | while (words--) { | ||
69 | __le32_to_cpus(buf); | ||
70 | buf++; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static inline void cpu_to_le32_array(u32 *buf, unsigned int words) | ||
75 | { | ||
76 | while (words--) { | ||
77 | __cpu_to_le32s(buf); | ||
78 | buf++; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static void md4_transform(u32 *hash, u32 const *in) | ||
83 | { | ||
84 | u32 a, b, c, d; | ||
85 | |||
86 | a = hash[0]; | ||
87 | b = hash[1]; | ||
88 | c = hash[2]; | ||
89 | d = hash[3]; | ||
90 | |||
91 | ROUND1(a, b, c, d, in[0], 3); | ||
92 | ROUND1(d, a, b, c, in[1], 7); | ||
93 | ROUND1(c, d, a, b, in[2], 11); | ||
94 | ROUND1(b, c, d, a, in[3], 19); | ||
95 | ROUND1(a, b, c, d, in[4], 3); | ||
96 | ROUND1(d, a, b, c, in[5], 7); | ||
97 | ROUND1(c, d, a, b, in[6], 11); | ||
98 | ROUND1(b, c, d, a, in[7], 19); | ||
99 | ROUND1(a, b, c, d, in[8], 3); | ||
100 | ROUND1(d, a, b, c, in[9], 7); | ||
101 | ROUND1(c, d, a, b, in[10], 11); | ||
102 | ROUND1(b, c, d, a, in[11], 19); | ||
103 | ROUND1(a, b, c, d, in[12], 3); | ||
104 | ROUND1(d, a, b, c, in[13], 7); | ||
105 | ROUND1(c, d, a, b, in[14], 11); | ||
106 | ROUND1(b, c, d, a, in[15], 19); | ||
107 | |||
108 | ROUND2(a, b, c, d,in[ 0], 3); | ||
109 | ROUND2(d, a, b, c, in[4], 5); | ||
110 | ROUND2(c, d, a, b, in[8], 9); | ||
111 | ROUND2(b, c, d, a, in[12], 13); | ||
112 | ROUND2(a, b, c, d, in[1], 3); | ||
113 | ROUND2(d, a, b, c, in[5], 5); | ||
114 | ROUND2(c, d, a, b, in[9], 9); | ||
115 | ROUND2(b, c, d, a, in[13], 13); | ||
116 | ROUND2(a, b, c, d, in[2], 3); | ||
117 | ROUND2(d, a, b, c, in[6], 5); | ||
118 | ROUND2(c, d, a, b, in[10], 9); | ||
119 | ROUND2(b, c, d, a, in[14], 13); | ||
120 | ROUND2(a, b, c, d, in[3], 3); | ||
121 | ROUND2(d, a, b, c, in[7], 5); | ||
122 | ROUND2(c, d, a, b, in[11], 9); | ||
123 | ROUND2(b, c, d, a, in[15], 13); | ||
124 | |||
125 | ROUND3(a, b, c, d,in[ 0], 3); | ||
126 | ROUND3(d, a, b, c, in[8], 9); | ||
127 | ROUND3(c, d, a, b, in[4], 11); | ||
128 | ROUND3(b, c, d, a, in[12], 15); | ||
129 | ROUND3(a, b, c, d, in[2], 3); | ||
130 | ROUND3(d, a, b, c, in[10], 9); | ||
131 | ROUND3(c, d, a, b, in[6], 11); | ||
132 | ROUND3(b, c, d, a, in[14], 15); | ||
133 | ROUND3(a, b, c, d, in[1], 3); | ||
134 | ROUND3(d, a, b, c, in[9], 9); | ||
135 | ROUND3(c, d, a, b, in[5], 11); | ||
136 | ROUND3(b, c, d, a, in[13], 15); | ||
137 | ROUND3(a, b, c, d, in[3], 3); | ||
138 | ROUND3(d, a, b, c, in[11], 9); | ||
139 | ROUND3(c, d, a, b, in[7], 11); | ||
140 | ROUND3(b, c, d, a, in[15], 15); | ||
141 | |||
142 | hash[0] += a; | ||
143 | hash[1] += b; | ||
144 | hash[2] += c; | ||
145 | hash[3] += d; | ||
146 | } | ||
147 | |||
148 | static inline void md4_transform_helper(struct md4_ctx *ctx) | ||
149 | { | ||
150 | le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); | ||
151 | md4_transform(ctx->hash, ctx->block); | ||
152 | } | ||
153 | |||
154 | static void md4_init(void *ctx) | ||
155 | { | ||
156 | struct md4_ctx *mctx = ctx; | ||
157 | |||
158 | mctx->hash[0] = 0x67452301; | ||
159 | mctx->hash[1] = 0xefcdab89; | ||
160 | mctx->hash[2] = 0x98badcfe; | ||
161 | mctx->hash[3] = 0x10325476; | ||
162 | mctx->byte_count = 0; | ||
163 | } | ||
164 | |||
165 | static void md4_update(void *ctx, const u8 *data, unsigned int len) | ||
166 | { | ||
167 | struct md4_ctx *mctx = ctx; | ||
168 | const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); | ||
169 | |||
170 | mctx->byte_count += len; | ||
171 | |||
172 | if (avail > len) { | ||
173 | memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), | ||
174 | data, len); | ||
175 | return; | ||
176 | } | ||
177 | |||
178 | memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), | ||
179 | data, avail); | ||
180 | |||
181 | md4_transform_helper(mctx); | ||
182 | data += avail; | ||
183 | len -= avail; | ||
184 | |||
185 | while (len >= sizeof(mctx->block)) { | ||
186 | memcpy(mctx->block, data, sizeof(mctx->block)); | ||
187 | md4_transform_helper(mctx); | ||
188 | data += sizeof(mctx->block); | ||
189 | len -= sizeof(mctx->block); | ||
190 | } | ||
191 | |||
192 | memcpy(mctx->block, data, len); | ||
193 | } | ||
194 | |||
195 | static void md4_final(void *ctx, u8 *out) | ||
196 | { | ||
197 | struct md4_ctx *mctx = ctx; | ||
198 | const unsigned int offset = mctx->byte_count & 0x3f; | ||
199 | char *p = (char *)mctx->block + offset; | ||
200 | int padding = 56 - (offset + 1); | ||
201 | |||
202 | *p++ = 0x80; | ||
203 | if (padding < 0) { | ||
204 | memset(p, 0x00, padding + sizeof (u64)); | ||
205 | md4_transform_helper(mctx); | ||
206 | p = (char *)mctx->block; | ||
207 | padding = 56; | ||
208 | } | ||
209 | |||
210 | memset(p, 0, padding); | ||
211 | mctx->block[14] = mctx->byte_count << 3; | ||
212 | mctx->block[15] = mctx->byte_count >> 29; | ||
213 | le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - | ||
214 | sizeof(u64)) / sizeof(u32)); | ||
215 | md4_transform(mctx->hash, mctx->block); | ||
216 | cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); | ||
217 | memcpy(out, mctx->hash, sizeof(mctx->hash)); | ||
218 | memset(mctx, 0, sizeof(*mctx)); | ||
219 | } | ||
220 | |||
221 | static struct crypto_alg alg = { | ||
222 | .cra_name = "md4", | ||
223 | .cra_flags = CRYPTO_ALG_TYPE_DIGEST, | ||
224 | .cra_blocksize = MD4_HMAC_BLOCK_SIZE, | ||
225 | .cra_ctxsize = sizeof(struct md4_ctx), | ||
226 | .cra_module = THIS_MODULE, | ||
227 | .cra_list = LIST_HEAD_INIT(alg.cra_list), | ||
228 | .cra_u = { .digest = { | ||
229 | .dia_digestsize = MD4_DIGEST_SIZE, | ||
230 | .dia_init = md4_init, | ||
231 | .dia_update = md4_update, | ||
232 | .dia_final = md4_final } } | ||
233 | }; | ||
234 | |||
235 | static int __init init(void) | ||
236 | { | ||
237 | return crypto_register_alg(&alg); | ||
238 | } | ||
239 | |||
240 | static void __exit fini(void) | ||
241 | { | ||
242 | crypto_unregister_alg(&alg); | ||
243 | } | ||
244 | |||
245 | module_init(init); | ||
246 | module_exit(fini); | ||
247 | |||
248 | MODULE_LICENSE("GPL"); | ||
249 | MODULE_DESCRIPTION("MD4 Message Digest Algorithm"); | ||
250 | |||