Skip to content

Commit

Permalink
crypto: sha512 - implement base layer for SHA-512
Browse files Browse the repository at this point in the history
To reduce the number of copies of boilerplate code throughout
the tree, this patch implements generic glue for the SHA-512
algorithm. This allows a specific arch or hardware implementation
to only implement the special handling that it needs.

The users need to supply an implementation of

  void (sha512_block_fn)(struct sha512_state *sst, u8 const *src, int blocks)

and pass it to the SHA-512 base functions. For easy casting between the
prototype above and existing block functions that take a 'u64 state[]'
as their first argument, the 'state' member of struct sha512_state is
moved to the base of the struct.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
Ard Biesheuvel authored and Herbert Xu committed Apr 10, 2015
1 parent 11b8d5e commit b84a2a0
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 1 deletion.
2 changes: 1 addition & 1 deletion include/crypto/sha.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ struct sha256_state {
};

struct sha512_state {
u64 count[2];
u64 state[SHA512_DIGEST_SIZE / 8];
u64 count[2];
u8 buf[SHA512_BLOCK_SIZE];
};

Expand Down
131 changes: 131 additions & 0 deletions include/crypto/sha512_base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* sha512_base.h - core logic for SHA-512 implementations
*
* Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#include <crypto/internal/hash.h>
#include <crypto/sha.h>
#include <linux/crypto.h>
#include <linux/module.h>

#include <asm/unaligned.h>

typedef void (sha512_block_fn)(struct sha512_state *sst, u8 const *src,
int blocks);

static inline int sha384_base_init(struct shash_desc *desc)
{
struct sha512_state *sctx = shash_desc_ctx(desc);

sctx->state[0] = SHA384_H0;
sctx->state[1] = SHA384_H1;
sctx->state[2] = SHA384_H2;
sctx->state[3] = SHA384_H3;
sctx->state[4] = SHA384_H4;
sctx->state[5] = SHA384_H5;
sctx->state[6] = SHA384_H6;
sctx->state[7] = SHA384_H7;
sctx->count[0] = sctx->count[1] = 0;

return 0;
}

static inline int sha512_base_init(struct shash_desc *desc)
{
struct sha512_state *sctx = shash_desc_ctx(desc);

sctx->state[0] = SHA512_H0;
sctx->state[1] = SHA512_H1;
sctx->state[2] = SHA512_H2;
sctx->state[3] = SHA512_H3;
sctx->state[4] = SHA512_H4;
sctx->state[5] = SHA512_H5;
sctx->state[6] = SHA512_H6;
sctx->state[7] = SHA512_H7;
sctx->count[0] = sctx->count[1] = 0;

return 0;
}

static inline int sha512_base_do_update(struct shash_desc *desc,
const u8 *data,
unsigned int len,
sha512_block_fn *block_fn)
{
struct sha512_state *sctx = shash_desc_ctx(desc);
unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;

sctx->count[0] += len;
if (sctx->count[0] < len)
sctx->count[1]++;

if (unlikely((partial + len) >= SHA512_BLOCK_SIZE)) {
int blocks;

if (partial) {
int p = SHA512_BLOCK_SIZE - partial;

memcpy(sctx->buf + partial, data, p);
data += p;
len -= p;

block_fn(sctx, sctx->buf, 1);
}

blocks = len / SHA512_BLOCK_SIZE;
len %= SHA512_BLOCK_SIZE;

if (blocks) {
block_fn(sctx, data, blocks);
data += blocks * SHA512_BLOCK_SIZE;
}
partial = 0;
}
if (len)
memcpy(sctx->buf + partial, data, len);

return 0;
}

static inline int sha512_base_do_finalize(struct shash_desc *desc,
sha512_block_fn *block_fn)
{
const int bit_offset = SHA512_BLOCK_SIZE - sizeof(__be64[2]);
struct sha512_state *sctx = shash_desc_ctx(desc);
__be64 *bits = (__be64 *)(sctx->buf + bit_offset);
unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;

sctx->buf[partial++] = 0x80;
if (partial > bit_offset) {
memset(sctx->buf + partial, 0x0, SHA512_BLOCK_SIZE - partial);
partial = 0;

block_fn(sctx, sctx->buf, 1);
}

memset(sctx->buf + partial, 0x0, bit_offset - partial);
bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61);
bits[1] = cpu_to_be64(sctx->count[0] << 3);
block_fn(sctx, sctx->buf, 1);

return 0;
}

static inline int sha512_base_finish(struct shash_desc *desc, u8 *out)
{
unsigned int digest_size = crypto_shash_digestsize(desc->tfm);
struct sha512_state *sctx = shash_desc_ctx(desc);
__be64 *digest = (__be64 *)out;
int i;

for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be64))
put_unaligned_be64(sctx->state[i], digest++);

*sctx = (struct sha512_state){};
return 0;
}

0 comments on commit b84a2a0

Please sign in to comment.