linux/arch/arm/crypto/sha1_glue.c
<<
>>
Prefs
   1/*
   2 * Cryptographic API.
   3 * Glue code for the SHA1 Secure Hash Algorithm assembler implementation
   4 *
   5 * This file is based on sha1_generic.c and sha1_ssse3_glue.c
   6 *
   7 * Copyright (c) Alan Smithee.
   8 * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
   9 * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
  10 * Copyright (c) Mathias Krause <minipli@googlemail.com>
  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 */
  18
  19#include <crypto/internal/hash.h>
  20#include <linux/init.h>
  21#include <linux/module.h>
  22#include <linux/cryptohash.h>
  23#include <linux/types.h>
  24#include <crypto/sha.h>
  25#include <asm/byteorder.h>
  26
  27struct SHA1_CTX {
  28        uint32_t h0,h1,h2,h3,h4;
  29        u64 count;
  30        u8 data[SHA1_BLOCK_SIZE];
  31};
  32
  33asmlinkage void sha1_block_data_order(struct SHA1_CTX *digest,
  34                const unsigned char *data, unsigned int rounds);
  35
  36
  37static int sha1_init(struct shash_desc *desc)
  38{
  39        struct SHA1_CTX *sctx = shash_desc_ctx(desc);
  40        memset(sctx, 0, sizeof(*sctx));
  41        sctx->h0 = SHA1_H0;
  42        sctx->h1 = SHA1_H1;
  43        sctx->h2 = SHA1_H2;
  44        sctx->h3 = SHA1_H3;
  45        sctx->h4 = SHA1_H4;
  46        return 0;
  47}
  48
  49
  50static int __sha1_update(struct SHA1_CTX *sctx, const u8 *data,
  51                               unsigned int len, unsigned int partial)
  52{
  53        unsigned int done = 0;
  54
  55        sctx->count += len;
  56
  57        if (partial) {
  58                done = SHA1_BLOCK_SIZE - partial;
  59                memcpy(sctx->data + partial, data, done);
  60                sha1_block_data_order(sctx, sctx->data, 1);
  61        }
  62
  63        if (len - done >= SHA1_BLOCK_SIZE) {
  64                const unsigned int rounds = (len - done) / SHA1_BLOCK_SIZE;
  65                sha1_block_data_order(sctx, data + done, rounds);
  66                done += rounds * SHA1_BLOCK_SIZE;
  67        }
  68
  69        memcpy(sctx->data, data + done, len - done);
  70        return 0;
  71}
  72
  73
  74static int sha1_update(struct shash_desc *desc, const u8 *data,
  75                             unsigned int len)
  76{
  77        struct SHA1_CTX *sctx = shash_desc_ctx(desc);
  78        unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
  79        int res;
  80
  81        /* Handle the fast case right here */
  82        if (partial + len < SHA1_BLOCK_SIZE) {
  83                sctx->count += len;
  84                memcpy(sctx->data + partial, data, len);
  85                return 0;
  86        }
  87        res = __sha1_update(sctx, data, len, partial);
  88        return res;
  89}
  90
  91
  92/* Add padding and return the message digest. */
  93static int sha1_final(struct shash_desc *desc, u8 *out)
  94{
  95        struct SHA1_CTX *sctx = shash_desc_ctx(desc);
  96        unsigned int i, index, padlen;
  97        __be32 *dst = (__be32 *)out;
  98        __be64 bits;
  99        static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, };
 100
 101        bits = cpu_to_be64(sctx->count << 3);
 102
 103        /* Pad out to 56 mod 64 and append length */
 104        index = sctx->count % SHA1_BLOCK_SIZE;
 105        padlen = (index < 56) ? (56 - index) : ((SHA1_BLOCK_SIZE+56) - index);
 106        /* We need to fill a whole block for __sha1_update() */
 107        if (padlen <= 56) {
 108                sctx->count += padlen;
 109                memcpy(sctx->data + index, padding, padlen);
 110        } else {
 111                __sha1_update(sctx, padding, padlen, index);
 112        }
 113        __sha1_update(sctx, (const u8 *)&bits, sizeof(bits), 56);
 114
 115        /* Store state in digest */
 116        for (i = 0; i < 5; i++)
 117                dst[i] = cpu_to_be32(((u32 *)sctx)[i]);
 118
 119        /* Wipe context */
 120        memset(sctx, 0, sizeof(*sctx));
 121        return 0;
 122}
 123
 124
 125static int sha1_export(struct shash_desc *desc, void *out)
 126{
 127        struct SHA1_CTX *sctx = shash_desc_ctx(desc);
 128        memcpy(out, sctx, sizeof(*sctx));
 129        return 0;
 130}
 131
 132
 133static int sha1_import(struct shash_desc *desc, const void *in)
 134{
 135        struct SHA1_CTX *sctx = shash_desc_ctx(desc);
 136        memcpy(sctx, in, sizeof(*sctx));
 137        return 0;
 138}
 139
 140
 141static struct shash_alg alg = {
 142        .digestsize     =       SHA1_DIGEST_SIZE,
 143        .init           =       sha1_init,
 144        .update         =       sha1_update,
 145        .final          =       sha1_final,
 146        .export         =       sha1_export,
 147        .import         =       sha1_import,
 148        .descsize       =       sizeof(struct SHA1_CTX),
 149        .statesize      =       sizeof(struct SHA1_CTX),
 150        .base           =       {
 151                .cra_name       =       "sha1",
 152                .cra_driver_name=       "sha1-asm",
 153                .cra_priority   =       150,
 154                .cra_flags      =       CRYPTO_ALG_TYPE_SHASH,
 155                .cra_blocksize  =       SHA1_BLOCK_SIZE,
 156                .cra_module     =       THIS_MODULE,
 157        }
 158};
 159
 160
 161static int __init sha1_mod_init(void)
 162{
 163        return crypto_register_shash(&alg);
 164}
 165
 166
 167static void __exit sha1_mod_fini(void)
 168{
 169        crypto_unregister_shash(&alg);
 170}
 171
 172
 173module_init(sha1_mod_init);
 174module_exit(sha1_mod_fini);
 175
 176MODULE_LICENSE("GPL");
 177MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm (ARM)");
 178MODULE_ALIAS("sha1");
 179MODULE_AUTHOR("David McCullough <ucdevel@gmail.com>");
 180