mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 07:31:15 +00:00
crypto: hash: Add software hash DM driver
Add purely software-implmented drivers to support multiple hash operations including CRC, MD5, and SHA family. This driver is based on the new hash uclass. Signed-off-by: Chia-Wei Wang <chiawei_wang@aspeedtech.com>
This commit is contained in:
parent
4deaff791c
commit
e5d870fa1e
3 changed files with 313 additions and 0 deletions
|
@ -3,3 +3,14 @@ config DM_HASH
|
|||
depends on DM
|
||||
help
|
||||
If you want to use driver model for Hash, say Y.
|
||||
|
||||
config HASH_SOFTWARE
|
||||
bool "Enable driver for Hash in software"
|
||||
depends on DM_HASH
|
||||
depends on MD5
|
||||
depends on SHA1
|
||||
depends on SHA256
|
||||
depends on SHA512_ALGO
|
||||
help
|
||||
Enable driver for hashing operations in software. Currently
|
||||
it support multiple hash algorithm including CRC/MD5/SHA.
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
# Copyright (c) 2021 ASPEED Technology Inc.
|
||||
|
||||
obj-$(CONFIG_DM_HASH) += hash-uclass.o
|
||||
obj-$(CONFIG_HASH_SOFTWARE) += hash_sw.o
|
||||
|
|
301
drivers/crypto/hash/hash_sw.c
Normal file
301
drivers/crypto/hash/hash_sw.c
Normal file
|
@ -0,0 +1,301 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2021 ASPEED Technology Inc.
|
||||
* Author: ChiaWei Wang <chiawei_wang@aspeedtech.com>
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
#include <watchdog.h>
|
||||
#include <u-boot/hash.h>
|
||||
#include <u-boot/crc.h>
|
||||
#include <u-boot/md5.h>
|
||||
#include <u-boot/sha1.h>
|
||||
#include <u-boot/sha256.h>
|
||||
#include <u-boot/sha512.h>
|
||||
|
||||
/* CRC16-CCITT */
|
||||
static void hash_init_crc16_ccitt(void *ctx)
|
||||
{
|
||||
*((uint16_t *)ctx) = 0;
|
||||
}
|
||||
|
||||
static void hash_update_crc16_ccitt(void *ctx, const void *ibuf, uint32_t ilen)
|
||||
{
|
||||
*((uint16_t *)ctx) = crc16_ccitt(*((uint16_t *)ctx), ibuf, ilen);
|
||||
}
|
||||
|
||||
static void hash_finish_crc16_ccitt(void *ctx, void *obuf)
|
||||
{
|
||||
*((uint16_t *)obuf) = *((uint16_t *)ctx);
|
||||
}
|
||||
|
||||
/* CRC32 */
|
||||
static void hash_init_crc32(void *ctx)
|
||||
{
|
||||
*((uint32_t *)ctx) = 0;
|
||||
}
|
||||
|
||||
static void hash_update_crc32(void *ctx, const void *ibuf, uint32_t ilen)
|
||||
{
|
||||
*((uint32_t *)ctx) = crc32(*((uint32_t *)ctx), ibuf, ilen);
|
||||
}
|
||||
|
||||
static void hash_finish_crc32(void *ctx, void *obuf)
|
||||
{
|
||||
*((uint32_t *)obuf) = *((uint32_t *)ctx);
|
||||
}
|
||||
|
||||
/* MD5 */
|
||||
static void hash_init_md5(void *ctx)
|
||||
{
|
||||
MD5Init((struct MD5Context *)ctx);
|
||||
}
|
||||
|
||||
static void hash_update_md5(void *ctx, const void *ibuf, uint32_t ilen)
|
||||
{
|
||||
MD5Update((struct MD5Context *)ctx, ibuf, ilen);
|
||||
}
|
||||
|
||||
static void hash_finish_md5(void *ctx, void *obuf)
|
||||
{
|
||||
MD5Final(obuf, (struct MD5Context *)ctx);
|
||||
}
|
||||
|
||||
/* SHA1 */
|
||||
static void hash_init_sha1(void *ctx)
|
||||
{
|
||||
sha1_starts((sha1_context *)ctx);
|
||||
}
|
||||
|
||||
static void hash_update_sha1(void *ctx, const void *ibuf, uint32_t ilen)
|
||||
{
|
||||
sha1_update((sha1_context *)ctx, ibuf, ilen);
|
||||
}
|
||||
|
||||
static void hash_finish_sha1(void *ctx, void *obuf)
|
||||
{
|
||||
sha1_finish((sha1_context *)ctx, obuf);
|
||||
}
|
||||
|
||||
/* SHA256 */
|
||||
static void hash_init_sha256(void *ctx)
|
||||
{
|
||||
sha256_starts((sha256_context *)ctx);
|
||||
}
|
||||
|
||||
static void hash_update_sha256(void *ctx, const void *ibuf, uint32_t ilen)
|
||||
{
|
||||
sha256_update((sha256_context *)ctx, ibuf, ilen);
|
||||
}
|
||||
|
||||
static void hash_finish_sha256(void *ctx, void *obuf)
|
||||
{
|
||||
sha256_finish((sha256_context *)ctx, obuf);
|
||||
}
|
||||
|
||||
/* SHA384 */
|
||||
static void hash_init_sha384(void *ctx)
|
||||
{
|
||||
sha384_starts((sha512_context *)ctx);
|
||||
}
|
||||
|
||||
static void hash_update_sha384(void *ctx, const void *ibuf, uint32_t ilen)
|
||||
{
|
||||
sha384_update((sha512_context *)ctx, ibuf, ilen);
|
||||
}
|
||||
|
||||
static void hash_finish_sha384(void *ctx, void *obuf)
|
||||
{
|
||||
sha384_finish((sha512_context *)ctx, obuf);
|
||||
}
|
||||
|
||||
/* SHA512 */
|
||||
static void hash_init_sha512(void *ctx)
|
||||
{
|
||||
sha512_starts((sha512_context *)ctx);
|
||||
}
|
||||
|
||||
static void hash_update_sha512(void *ctx, const void *ibuf, uint32_t ilen)
|
||||
{
|
||||
sha512_update((sha512_context *)ctx, ibuf, ilen);
|
||||
}
|
||||
|
||||
static void hash_finish_sha512(void *ctx, void *obuf)
|
||||
{
|
||||
sha512_finish((sha512_context *)ctx, obuf);
|
||||
}
|
||||
|
||||
struct sw_hash_ctx {
|
||||
enum HASH_ALGO algo;
|
||||
uint8_t algo_ctx[];
|
||||
};
|
||||
|
||||
struct sw_hash_impl {
|
||||
void (*init)(void *ctx);
|
||||
void (*update)(void *ctx, const void *ibuf, uint32_t ilen);
|
||||
void (*finish)(void *ctx, void *obuf);
|
||||
uint32_t ctx_alloc_sz;
|
||||
};
|
||||
|
||||
static struct sw_hash_impl sw_hash_impl[HASH_ALGO_NUM] = {
|
||||
[HASH_ALGO_CRC16_CCITT] = {
|
||||
.init = hash_init_crc16_ccitt,
|
||||
.update = hash_update_crc16_ccitt,
|
||||
.finish = hash_finish_crc16_ccitt,
|
||||
.ctx_alloc_sz = sizeof(uint16_t),
|
||||
},
|
||||
|
||||
[HASH_ALGO_CRC32] = {
|
||||
.init = hash_init_crc32,
|
||||
.update = hash_update_crc32,
|
||||
.finish = hash_finish_crc32,
|
||||
.ctx_alloc_sz = sizeof(uint32_t),
|
||||
},
|
||||
|
||||
[HASH_ALGO_MD5] = {
|
||||
.init = hash_init_md5,
|
||||
.update = hash_update_md5,
|
||||
.finish = hash_finish_md5,
|
||||
.ctx_alloc_sz = sizeof(struct MD5Context),
|
||||
},
|
||||
|
||||
[HASH_ALGO_SHA1] = {
|
||||
.init = hash_init_sha1,
|
||||
.update = hash_update_sha1,
|
||||
.finish = hash_finish_sha1,
|
||||
.ctx_alloc_sz = sizeof(sha1_context),
|
||||
},
|
||||
|
||||
[HASH_ALGO_SHA256] = {
|
||||
.init = hash_init_sha256,
|
||||
.update = hash_update_sha256,
|
||||
.finish = hash_finish_sha256,
|
||||
.ctx_alloc_sz = sizeof(sha256_context),
|
||||
},
|
||||
|
||||
[HASH_ALGO_SHA384] = {
|
||||
.init = hash_init_sha384,
|
||||
.update = hash_update_sha384,
|
||||
.finish = hash_finish_sha384,
|
||||
.ctx_alloc_sz = sizeof(sha512_context),
|
||||
},
|
||||
|
||||
[HASH_ALGO_SHA512] = {
|
||||
.init = hash_init_sha512,
|
||||
.update = hash_update_sha512,
|
||||
.finish = hash_finish_sha512,
|
||||
.ctx_alloc_sz = sizeof(sha512_context),
|
||||
},
|
||||
};
|
||||
|
||||
static int sw_hash_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp)
|
||||
{
|
||||
struct sw_hash_ctx *hash_ctx;
|
||||
struct sw_hash_impl *hash_impl = &sw_hash_impl[algo];
|
||||
|
||||
hash_ctx = malloc(sizeof(hash_ctx->algo) + hash_impl->ctx_alloc_sz);
|
||||
if (!hash_ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
hash_ctx->algo = algo;
|
||||
|
||||
hash_impl->init(hash_ctx->algo_ctx);
|
||||
|
||||
*ctxp = hash_ctx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sw_hash_update(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
|
||||
{
|
||||
struct sw_hash_ctx *hash_ctx = ctx;
|
||||
struct sw_hash_impl *hash_impl = &sw_hash_impl[hash_ctx->algo];
|
||||
|
||||
hash_impl->update(hash_ctx->algo_ctx, ibuf, ilen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sw_hash_finish(struct udevice *dev, void *ctx, void *obuf)
|
||||
{
|
||||
struct sw_hash_ctx *hash_ctx = ctx;
|
||||
struct sw_hash_impl *hash_impl = &sw_hash_impl[hash_ctx->algo];
|
||||
|
||||
hash_impl->finish(hash_ctx->algo_ctx, obuf);
|
||||
|
||||
free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sw_hash_digest_wd(struct udevice *dev, enum HASH_ALGO algo,
|
||||
const void *ibuf, const uint32_t ilen,
|
||||
void *obuf, uint32_t chunk_sz)
|
||||
{
|
||||
int rc;
|
||||
void *ctx;
|
||||
const void *cur, *end;
|
||||
uint32_t chunk;
|
||||
|
||||
rc = sw_hash_init(dev, algo, &ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (CONFIG_IS_ENABLED(HW_WATCHDOG) || CONFIG_IS_ENABLED(WATCHDOG)) {
|
||||
cur = ibuf;
|
||||
end = ibuf + ilen;
|
||||
|
||||
while (cur < end) {
|
||||
chunk = end - cur;
|
||||
if (chunk > chunk_sz)
|
||||
chunk = chunk_sz;
|
||||
|
||||
rc = sw_hash_update(dev, ctx, cur, chunk);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
cur += chunk;
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
} else {
|
||||
rc = sw_hash_update(dev, ctx, ibuf, ilen);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = sw_hash_finish(dev, ctx, obuf);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sw_hash_digest(struct udevice *dev, enum HASH_ALGO algo,
|
||||
const void *ibuf, const uint32_t ilen,
|
||||
void *obuf)
|
||||
{
|
||||
/* re-use the watchdog version with input length as the chunk_sz */
|
||||
return sw_hash_digest_wd(dev, algo, ibuf, ilen, obuf, ilen);
|
||||
}
|
||||
|
||||
static const struct hash_ops hash_ops_sw = {
|
||||
.hash_init = sw_hash_init,
|
||||
.hash_update = sw_hash_update,
|
||||
.hash_finish = sw_hash_finish,
|
||||
.hash_digest_wd = sw_hash_digest_wd,
|
||||
.hash_digest = sw_hash_digest,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(hash_sw) = {
|
||||
.name = "hash_sw",
|
||||
.id = UCLASS_HASH,
|
||||
.ops = &hash_ops_sw,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
|
||||
U_BOOT_DRVINFO(hash_sw) = {
|
||||
.name = "hash_sw",
|
||||
};
|
Loading…
Reference in a new issue