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