162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Cryptographic API. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * MD5 Message Digest Algorithm (RFC1321). 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Adapted for OCTEON by Aaro Koskinen <aaro.koskinen@iki.fi>. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on crypto/md5.c, which is: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Derived from cryptoapi implementation, originally based on the 1162306a36Sopenharmony_ci * public domain implementation written by Colin Plumb in 1993. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Copyright (c) Cryptoapi developers. 1462306a36Sopenharmony_ci * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 1762306a36Sopenharmony_ci * under the terms of the GNU General Public License as published by the Free 1862306a36Sopenharmony_ci * Software Foundation; either version 2 of the License, or (at your option) 1962306a36Sopenharmony_ci * any later version. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <crypto/md5.h> 2362306a36Sopenharmony_ci#include <linux/init.h> 2462306a36Sopenharmony_ci#include <linux/types.h> 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/string.h> 2762306a36Sopenharmony_ci#include <asm/byteorder.h> 2862306a36Sopenharmony_ci#include <asm/octeon/octeon.h> 2962306a36Sopenharmony_ci#include <crypto/internal/hash.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "octeon-crypto.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * We pass everything as 64-bit. OCTEON can handle misaligned data. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void octeon_md5_store_hash(struct md5_state *ctx) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci u64 *hash = (u64 *)ctx->hash; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci write_octeon_64bit_hash_dword(hash[0], 0); 4262306a36Sopenharmony_ci write_octeon_64bit_hash_dword(hash[1], 1); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic void octeon_md5_read_hash(struct md5_state *ctx) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci u64 *hash = (u64 *)ctx->hash; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci hash[0] = read_octeon_64bit_hash_dword(0); 5062306a36Sopenharmony_ci hash[1] = read_octeon_64bit_hash_dword(1); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void octeon_md5_transform(const void *_block) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci const u64 *block = _block; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci write_octeon_64bit_block_dword(block[0], 0); 5862306a36Sopenharmony_ci write_octeon_64bit_block_dword(block[1], 1); 5962306a36Sopenharmony_ci write_octeon_64bit_block_dword(block[2], 2); 6062306a36Sopenharmony_ci write_octeon_64bit_block_dword(block[3], 3); 6162306a36Sopenharmony_ci write_octeon_64bit_block_dword(block[4], 4); 6262306a36Sopenharmony_ci write_octeon_64bit_block_dword(block[5], 5); 6362306a36Sopenharmony_ci write_octeon_64bit_block_dword(block[6], 6); 6462306a36Sopenharmony_ci octeon_md5_start(block[7]); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int octeon_md5_init(struct shash_desc *desc) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct md5_state *mctx = shash_desc_ctx(desc); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci mctx->hash[0] = MD5_H0; 7262306a36Sopenharmony_ci mctx->hash[1] = MD5_H1; 7362306a36Sopenharmony_ci mctx->hash[2] = MD5_H2; 7462306a36Sopenharmony_ci mctx->hash[3] = MD5_H3; 7562306a36Sopenharmony_ci cpu_to_le32_array(mctx->hash, 4); 7662306a36Sopenharmony_ci mctx->byte_count = 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int octeon_md5_update(struct shash_desc *desc, const u8 *data, 8262306a36Sopenharmony_ci unsigned int len) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct md5_state *mctx = shash_desc_ctx(desc); 8562306a36Sopenharmony_ci const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); 8662306a36Sopenharmony_ci struct octeon_cop2_state state; 8762306a36Sopenharmony_ci unsigned long flags; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci mctx->byte_count += len; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (avail > len) { 9262306a36Sopenharmony_ci memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), 9362306a36Sopenharmony_ci data, len); 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, 9862306a36Sopenharmony_ci avail); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci flags = octeon_crypto_enable(&state); 10162306a36Sopenharmony_ci octeon_md5_store_hash(mctx); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci octeon_md5_transform(mctx->block); 10462306a36Sopenharmony_ci data += avail; 10562306a36Sopenharmony_ci len -= avail; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci while (len >= sizeof(mctx->block)) { 10862306a36Sopenharmony_ci octeon_md5_transform(data); 10962306a36Sopenharmony_ci data += sizeof(mctx->block); 11062306a36Sopenharmony_ci len -= sizeof(mctx->block); 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci octeon_md5_read_hash(mctx); 11462306a36Sopenharmony_ci octeon_crypto_disable(&state, flags); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci memcpy(mctx->block, data, len); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int octeon_md5_final(struct shash_desc *desc, u8 *out) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct md5_state *mctx = shash_desc_ctx(desc); 12462306a36Sopenharmony_ci const unsigned int offset = mctx->byte_count & 0x3f; 12562306a36Sopenharmony_ci char *p = (char *)mctx->block + offset; 12662306a36Sopenharmony_ci int padding = 56 - (offset + 1); 12762306a36Sopenharmony_ci struct octeon_cop2_state state; 12862306a36Sopenharmony_ci unsigned long flags; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci *p++ = 0x80; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci flags = octeon_crypto_enable(&state); 13362306a36Sopenharmony_ci octeon_md5_store_hash(mctx); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (padding < 0) { 13662306a36Sopenharmony_ci memset(p, 0x00, padding + sizeof(u64)); 13762306a36Sopenharmony_ci octeon_md5_transform(mctx->block); 13862306a36Sopenharmony_ci p = (char *)mctx->block; 13962306a36Sopenharmony_ci padding = 56; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci memset(p, 0, padding); 14362306a36Sopenharmony_ci mctx->block[14] = mctx->byte_count << 3; 14462306a36Sopenharmony_ci mctx->block[15] = mctx->byte_count >> 29; 14562306a36Sopenharmony_ci cpu_to_le32_array(mctx->block + 14, 2); 14662306a36Sopenharmony_ci octeon_md5_transform(mctx->block); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci octeon_md5_read_hash(mctx); 14962306a36Sopenharmony_ci octeon_crypto_disable(&state, flags); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci memcpy(out, mctx->hash, sizeof(mctx->hash)); 15262306a36Sopenharmony_ci memset(mctx, 0, sizeof(*mctx)); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int octeon_md5_export(struct shash_desc *desc, void *out) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct md5_state *ctx = shash_desc_ctx(desc); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci memcpy(out, ctx, sizeof(*ctx)); 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int octeon_md5_import(struct shash_desc *desc, const void *in) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct md5_state *ctx = shash_desc_ctx(desc); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci memcpy(ctx, in, sizeof(*ctx)); 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic struct shash_alg alg = { 17462306a36Sopenharmony_ci .digestsize = MD5_DIGEST_SIZE, 17562306a36Sopenharmony_ci .init = octeon_md5_init, 17662306a36Sopenharmony_ci .update = octeon_md5_update, 17762306a36Sopenharmony_ci .final = octeon_md5_final, 17862306a36Sopenharmony_ci .export = octeon_md5_export, 17962306a36Sopenharmony_ci .import = octeon_md5_import, 18062306a36Sopenharmony_ci .descsize = sizeof(struct md5_state), 18162306a36Sopenharmony_ci .statesize = sizeof(struct md5_state), 18262306a36Sopenharmony_ci .base = { 18362306a36Sopenharmony_ci .cra_name = "md5", 18462306a36Sopenharmony_ci .cra_driver_name= "octeon-md5", 18562306a36Sopenharmony_ci .cra_priority = OCTEON_CR_OPCODE_PRIORITY, 18662306a36Sopenharmony_ci .cra_blocksize = MD5_HMAC_BLOCK_SIZE, 18762306a36Sopenharmony_ci .cra_module = THIS_MODULE, 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int __init md5_mod_init(void) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci if (!octeon_has_crypto()) 19462306a36Sopenharmony_ci return -ENOTSUPP; 19562306a36Sopenharmony_ci return crypto_register_shash(&alg); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void __exit md5_mod_fini(void) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci crypto_unregister_shash(&alg); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cimodule_init(md5_mod_init); 20462306a36Sopenharmony_cimodule_exit(md5_mod_fini); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 20762306a36Sopenharmony_ciMODULE_DESCRIPTION("MD5 Message Digest Algorithm (OCTEON)"); 20862306a36Sopenharmony_ciMODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>"); 209