u-boot/drivers/crypto/hash/hash_sw.c
Raymond Mao 0fe031dd72 md5: Use typedef for MD5 context
Use of typedef is beneficial for porting with other crypto libs
without changing the API callers.
Secondly, it is for the code consistency with other digest libs.
SHA1, SHA256 and SHA512 are all using typedef for their context.

Signed-off-by: Raymond Mao <raymond.mao@linaro.org>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
2024-05-22 08:55:28 -06:00

301 lines
6.2 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2021 ASPEED Technology Inc.
* Author: ChiaWei Wang <chiawei_wang@aspeedtech.com>
*/
#include <config.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((MD5Context *)ctx);
}
static void hash_update_md5(void *ctx, const void *ibuf, uint32_t ilen)
{
MD5Update((MD5Context *)ctx, ibuf, ilen);
}
static void hash_finish_md5(void *ctx, void *obuf)
{
MD5Final(obuf, (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(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 (IS_ENABLED(CONFIG_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;
schedule();
}
} 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",
};