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