]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Cryptographic API. | |
3 | * | |
4 | * MD5 Message Digest Algorithm (RFC1321). | |
5 | * | |
6 | * Derived from cryptoapi implementation, originally based on the | |
7 | * public domain implementation written by Colin Plumb in 1993. | |
8 | * | |
9 | * Copyright (c) Cryptoapi developers. | |
10 | * Copyright (c) 2002 James Morris <[email protected]> | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by the Free | |
14 | * Software Foundation; either version 2 of the License, or (at your option) | |
15 | * any later version. | |
16 | * | |
17 | */ | |
14b75ba7 | 18 | #include <crypto/internal/hash.h> |
7d6f75eb | 19 | #include <crypto/md5.h> |
1da177e4 LT |
20 | #include <linux/init.h> |
21 | #include <linux/module.h> | |
22 | #include <linux/string.h> | |
06ace7a9 | 23 | #include <linux/types.h> |
bc0b96b5 | 24 | #include <linux/cryptohash.h> |
1da177e4 LT |
25 | #include <asm/byteorder.h> |
26 | ||
1da177e4 LT |
27 | /* XXX: this stuff can be optimized */ |
28 | static inline void le32_to_cpu_array(u32 *buf, unsigned int words) | |
29 | { | |
30 | while (words--) { | |
31 | __le32_to_cpus(buf); | |
32 | buf++; | |
33 | } | |
34 | } | |
35 | ||
36 | static inline void cpu_to_le32_array(u32 *buf, unsigned int words) | |
37 | { | |
38 | while (words--) { | |
39 | __cpu_to_le32s(buf); | |
40 | buf++; | |
41 | } | |
42 | } | |
43 | ||
7d6f75eb | 44 | static inline void md5_transform_helper(struct md5_state *ctx) |
1da177e4 LT |
45 | { |
46 | le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); | |
47 | md5_transform(ctx->hash, ctx->block); | |
48 | } | |
49 | ||
14b75ba7 | 50 | static int md5_init(struct shash_desc *desc) |
1da177e4 | 51 | { |
7d6f75eb | 52 | struct md5_state *mctx = shash_desc_ctx(desc); |
1da177e4 LT |
53 | |
54 | mctx->hash[0] = 0x67452301; | |
55 | mctx->hash[1] = 0xefcdab89; | |
56 | mctx->hash[2] = 0x98badcfe; | |
57 | mctx->hash[3] = 0x10325476; | |
58 | mctx->byte_count = 0; | |
14b75ba7 AKR |
59 | |
60 | return 0; | |
1da177e4 LT |
61 | } |
62 | ||
14b75ba7 | 63 | static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len) |
1da177e4 | 64 | { |
7d6f75eb | 65 | struct md5_state *mctx = shash_desc_ctx(desc); |
1da177e4 LT |
66 | const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); |
67 | ||
68 | mctx->byte_count += len; | |
69 | ||
70 | if (avail > len) { | |
71 | memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), | |
72 | data, len); | |
14b75ba7 | 73 | return 0; |
1da177e4 LT |
74 | } |
75 | ||
76 | memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), | |
77 | data, avail); | |
78 | ||
79 | md5_transform_helper(mctx); | |
80 | data += avail; | |
81 | len -= avail; | |
82 | ||
83 | while (len >= sizeof(mctx->block)) { | |
84 | memcpy(mctx->block, data, sizeof(mctx->block)); | |
85 | md5_transform_helper(mctx); | |
86 | data += sizeof(mctx->block); | |
87 | len -= sizeof(mctx->block); | |
88 | } | |
89 | ||
90 | memcpy(mctx->block, data, len); | |
14b75ba7 AKR |
91 | |
92 | return 0; | |
1da177e4 LT |
93 | } |
94 | ||
14b75ba7 | 95 | static int md5_final(struct shash_desc *desc, u8 *out) |
1da177e4 | 96 | { |
7d6f75eb | 97 | struct md5_state *mctx = shash_desc_ctx(desc); |
1da177e4 LT |
98 | const unsigned int offset = mctx->byte_count & 0x3f; |
99 | char *p = (char *)mctx->block + offset; | |
100 | int padding = 56 - (offset + 1); | |
101 | ||
102 | *p++ = 0x80; | |
103 | if (padding < 0) { | |
104 | memset(p, 0x00, padding + sizeof (u64)); | |
105 | md5_transform_helper(mctx); | |
106 | p = (char *)mctx->block; | |
107 | padding = 56; | |
108 | } | |
109 | ||
110 | memset(p, 0, padding); | |
111 | mctx->block[14] = mctx->byte_count << 3; | |
112 | mctx->block[15] = mctx->byte_count >> 29; | |
113 | le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - | |
114 | sizeof(u64)) / sizeof(u32)); | |
115 | md5_transform(mctx->hash, mctx->block); | |
116 | cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); | |
117 | memcpy(out, mctx->hash, sizeof(mctx->hash)); | |
118 | memset(mctx, 0, sizeof(*mctx)); | |
14b75ba7 AKR |
119 | |
120 | return 0; | |
1da177e4 LT |
121 | } |
122 | ||
7d6f75eb MV |
123 | static int md5_export(struct shash_desc *desc, void *out) |
124 | { | |
125 | struct md5_state *ctx = shash_desc_ctx(desc); | |
126 | ||
127 | memcpy(out, ctx, sizeof(*ctx)); | |
128 | return 0; | |
129 | } | |
130 | ||
131 | static int md5_import(struct shash_desc *desc, const void *in) | |
132 | { | |
133 | struct md5_state *ctx = shash_desc_ctx(desc); | |
134 | ||
135 | memcpy(ctx, in, sizeof(*ctx)); | |
136 | return 0; | |
137 | } | |
138 | ||
14b75ba7 AKR |
139 | static struct shash_alg alg = { |
140 | .digestsize = MD5_DIGEST_SIZE, | |
141 | .init = md5_init, | |
142 | .update = md5_update, | |
143 | .final = md5_final, | |
7d6f75eb MV |
144 | .export = md5_export, |
145 | .import = md5_import, | |
146 | .descsize = sizeof(struct md5_state), | |
eebb111f | 147 | .statesize = sizeof(struct md5_state), |
14b75ba7 AKR |
148 | .base = { |
149 | .cra_name = "md5", | |
150 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, | |
151 | .cra_blocksize = MD5_HMAC_BLOCK_SIZE, | |
152 | .cra_module = THIS_MODULE, | |
153 | } | |
1da177e4 LT |
154 | }; |
155 | ||
3af5b90b | 156 | static int __init md5_mod_init(void) |
1da177e4 | 157 | { |
14b75ba7 | 158 | return crypto_register_shash(&alg); |
1da177e4 LT |
159 | } |
160 | ||
3af5b90b | 161 | static void __exit md5_mod_fini(void) |
1da177e4 | 162 | { |
14b75ba7 | 163 | crypto_unregister_shash(&alg); |
1da177e4 LT |
164 | } |
165 | ||
3af5b90b KB |
166 | module_init(md5_mod_init); |
167 | module_exit(md5_mod_fini); | |
1da177e4 LT |
168 | |
169 | MODULE_LICENSE("GPL"); | |
170 | MODULE_DESCRIPTION("MD5 Message Digest Algorithm"); | |
5d26a105 | 171 | MODULE_ALIAS_CRYPTO("md5"); |