1 /*
2 * Cryptographic API.
3 *
4 * MD5 Message Digest Algorithm (RFC1321).
5 *
6 * Adapted for OCTEON by Aaro Koskinen <aaro.koskinen@iki.fi>.
7 *
8 * Based on crypto/md5.c, which is:
9 *
10 * Derived from cryptoapi implementation, originally based on the
11 * public domain implementation written by Colin Plumb in 1993.
12 *
13 * Copyright (c) Cryptoapi developers.
14 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
15 *
16 * This program is free software; you can redistribute it and/or modify it
17 * under the terms of the GNU General Public License as published by the Free
18 * Software Foundation; either version 2 of the License, or (at your option)
19 * any later version.
20 */
21
22 #include <asm/octeon/crypto.h>
23 #include <asm/octeon/octeon.h>
24 #include <crypto/internal/hash.h>
25 #include <crypto/md5.h>
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/string.h>
29 #include <linux/unaligned.h>
30
31 struct octeon_md5_state {
32 __le32 hash[MD5_HASH_WORDS];
33 u64 byte_count;
34 };
35
36 /*
37 * We pass everything as 64-bit. OCTEON can handle misaligned data.
38 */
39
octeon_md5_store_hash(struct octeon_md5_state * ctx)40 static void octeon_md5_store_hash(struct octeon_md5_state *ctx)
41 {
42 u64 *hash = (u64 *)ctx->hash;
43
44 write_octeon_64bit_hash_dword(hash[0], 0);
45 write_octeon_64bit_hash_dword(hash[1], 1);
46 }
47
octeon_md5_read_hash(struct octeon_md5_state * ctx)48 static void octeon_md5_read_hash(struct octeon_md5_state *ctx)
49 {
50 u64 *hash = (u64 *)ctx->hash;
51
52 hash[0] = read_octeon_64bit_hash_dword(0);
53 hash[1] = read_octeon_64bit_hash_dword(1);
54 }
55
octeon_md5_transform(const void * _block)56 static void octeon_md5_transform(const void *_block)
57 {
58 const u64 *block = _block;
59
60 write_octeon_64bit_block_dword(block[0], 0);
61 write_octeon_64bit_block_dword(block[1], 1);
62 write_octeon_64bit_block_dword(block[2], 2);
63 write_octeon_64bit_block_dword(block[3], 3);
64 write_octeon_64bit_block_dword(block[4], 4);
65 write_octeon_64bit_block_dword(block[5], 5);
66 write_octeon_64bit_block_dword(block[6], 6);
67 octeon_md5_start(block[7]);
68 }
69
octeon_md5_init(struct shash_desc * desc)70 static int octeon_md5_init(struct shash_desc *desc)
71 {
72 struct octeon_md5_state *mctx = shash_desc_ctx(desc);
73
74 mctx->hash[0] = cpu_to_le32(MD5_H0);
75 mctx->hash[1] = cpu_to_le32(MD5_H1);
76 mctx->hash[2] = cpu_to_le32(MD5_H2);
77 mctx->hash[3] = cpu_to_le32(MD5_H3);
78 mctx->byte_count = 0;
79
80 return 0;
81 }
82
octeon_md5_update(struct shash_desc * desc,const u8 * data,unsigned int len)83 static int octeon_md5_update(struct shash_desc *desc, const u8 *data,
84 unsigned int len)
85 {
86 struct octeon_md5_state *mctx = shash_desc_ctx(desc);
87 struct octeon_cop2_state state;
88 unsigned long flags;
89
90 mctx->byte_count += len;
91 flags = octeon_crypto_enable(&state);
92 octeon_md5_store_hash(mctx);
93
94 do {
95 octeon_md5_transform(data);
96 data += MD5_HMAC_BLOCK_SIZE;
97 len -= MD5_HMAC_BLOCK_SIZE;
98 } while (len >= MD5_HMAC_BLOCK_SIZE);
99
100 octeon_md5_read_hash(mctx);
101 octeon_crypto_disable(&state, flags);
102 mctx->byte_count -= len;
103 return len;
104 }
105
octeon_md5_finup(struct shash_desc * desc,const u8 * src,unsigned int offset,u8 * out)106 static int octeon_md5_finup(struct shash_desc *desc, const u8 *src,
107 unsigned int offset, u8 *out)
108 {
109 struct octeon_md5_state *mctx = shash_desc_ctx(desc);
110 int padding = 56 - (offset + 1);
111 struct octeon_cop2_state state;
112 u32 block[MD5_BLOCK_WORDS];
113 unsigned long flags;
114 char *p;
115
116 p = memcpy(block, src, offset);
117 p += offset;
118 *p++ = 0x80;
119
120 flags = octeon_crypto_enable(&state);
121 octeon_md5_store_hash(mctx);
122
123 if (padding < 0) {
124 memset(p, 0x00, padding + sizeof(u64));
125 octeon_md5_transform(block);
126 p = (char *)block;
127 padding = 56;
128 }
129
130 memset(p, 0, padding);
131 mctx->byte_count += offset;
132 block[14] = mctx->byte_count << 3;
133 block[15] = mctx->byte_count >> 29;
134 cpu_to_le32_array(block + 14, 2);
135 octeon_md5_transform(block);
136
137 octeon_md5_read_hash(mctx);
138 octeon_crypto_disable(&state, flags);
139
140 memzero_explicit(block, sizeof(block));
141 memcpy(out, mctx->hash, sizeof(mctx->hash));
142
143 return 0;
144 }
145
octeon_md5_export(struct shash_desc * desc,void * out)146 static int octeon_md5_export(struct shash_desc *desc, void *out)
147 {
148 struct octeon_md5_state *ctx = shash_desc_ctx(desc);
149 union {
150 u8 *u8;
151 u32 *u32;
152 u64 *u64;
153 } p = { .u8 = out };
154 int i;
155
156 for (i = 0; i < MD5_HASH_WORDS; i++)
157 put_unaligned(le32_to_cpu(ctx->hash[i]), p.u32++);
158 put_unaligned(ctx->byte_count, p.u64);
159 return 0;
160 }
161
octeon_md5_import(struct shash_desc * desc,const void * in)162 static int octeon_md5_import(struct shash_desc *desc, const void *in)
163 {
164 struct octeon_md5_state *ctx = shash_desc_ctx(desc);
165 union {
166 const u8 *u8;
167 const u32 *u32;
168 const u64 *u64;
169 } p = { .u8 = in };
170 int i;
171
172 for (i = 0; i < MD5_HASH_WORDS; i++)
173 ctx->hash[i] = cpu_to_le32(get_unaligned(p.u32++));
174 ctx->byte_count = get_unaligned(p.u64);
175 return 0;
176 }
177
178 static struct shash_alg alg = {
179 .digestsize = MD5_DIGEST_SIZE,
180 .init = octeon_md5_init,
181 .update = octeon_md5_update,
182 .finup = octeon_md5_finup,
183 .export = octeon_md5_export,
184 .import = octeon_md5_import,
185 .statesize = MD5_STATE_SIZE,
186 .descsize = sizeof(struct octeon_md5_state),
187 .base = {
188 .cra_name = "md5",
189 .cra_driver_name= "octeon-md5",
190 .cra_priority = OCTEON_CR_OPCODE_PRIORITY,
191 .cra_flags = CRYPTO_AHASH_ALG_BLOCK_ONLY,
192 .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
193 .cra_module = THIS_MODULE,
194 }
195 };
196
md5_mod_init(void)197 static int __init md5_mod_init(void)
198 {
199 if (!octeon_has_crypto())
200 return -ENOTSUPP;
201 return crypto_register_shash(&alg);
202 }
203
md5_mod_fini(void)204 static void __exit md5_mod_fini(void)
205 {
206 crypto_unregister_shash(&alg);
207 }
208
209 module_init(md5_mod_init);
210 module_exit(md5_mod_fini);
211
212 MODULE_LICENSE("GPL");
213 MODULE_DESCRIPTION("MD5 Message Digest Algorithm (OCTEON)");
214 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
215