diff options
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/Kconfig | 2 | ||||
-rw-r--r-- | drivers/crypto/Makefile | 1 | ||||
-rw-r--r-- | drivers/crypto/hash/Kconfig | 16 | ||||
-rw-r--r-- | drivers/crypto/hash/Makefile | 6 | ||||
-rw-r--r-- | drivers/crypto/hash/hash-uclass.c | 121 | ||||
-rw-r--r-- | drivers/crypto/hash/hash_sw.c | 301 |
6 files changed, 447 insertions, 0 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 1ea116be75..0082177c21 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -1,5 +1,7 @@ menu "Hardware crypto devices" +source drivers/crypto/hash/Kconfig + source drivers/crypto/fsl/Kconfig endmenu diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index efbd1d3fca..4a12b56be6 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o obj-y += rsa_mod_exp/ obj-y += fsl/ +obj-y += hash/ diff --git a/drivers/crypto/hash/Kconfig b/drivers/crypto/hash/Kconfig new file mode 100644 index 0000000000..cd29a5c6a4 --- /dev/null +++ b/drivers/crypto/hash/Kconfig @@ -0,0 +1,16 @@ +config DM_HASH + bool "Enable Driver Model for 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. diff --git a/drivers/crypto/hash/Makefile b/drivers/crypto/hash/Makefile new file mode 100644 index 0000000000..33d88161ed --- /dev/null +++ b/drivers/crypto/hash/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2021 ASPEED Technology Inc. + +obj-$(CONFIG_DM_HASH) += hash-uclass.o +obj-$(CONFIG_HASH_SOFTWARE) += hash_sw.o diff --git a/drivers/crypto/hash/hash-uclass.c b/drivers/crypto/hash/hash-uclass.c new file mode 100644 index 0000000000..446eb9e56a --- /dev/null +++ b/drivers/crypto/hash/hash-uclass.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 ASPEED Technology Inc. + * Author: ChiaWei Wang <chiawei_wang@aspeedtech.com> + */ + +#define LOG_CATEGORY UCLASS_HASH + +#include <common.h> +#include <dm.h> +#include <asm/global_data.h> +#include <u-boot/hash.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/io.h> +#include <linux/list.h> + +struct hash_info { + char *name; + uint32_t digest_size; +}; + +static const struct hash_info hash_info[HASH_ALGO_NUM] = { + [HASH_ALGO_CRC16_CCITT] = { "crc16-ccitt", 2 }, + [HASH_ALGO_CRC32] = { "crc32", 4 }, + [HASH_ALGO_MD5] = { "md5", 16 }, + [HASH_ALGO_SHA1] = { "sha1", 20 }, + [HASH_ALGO_SHA256] = { "sha256", 32 }, + [HASH_ALGO_SHA384] = { "sha384", 48 }, + [HASH_ALGO_SHA512] = { "sha512", 64}, +}; + +enum HASH_ALGO hash_algo_lookup_by_name(const char *name) +{ + int i; + + if (!name) + return HASH_ALGO_INVALID; + + for (i = 0; i < HASH_ALGO_NUM; ++i) + if (!strcmp(name, hash_info[i].name)) + return i; + + return HASH_ALGO_INVALID; +} + +ssize_t hash_algo_digest_size(enum HASH_ALGO algo) +{ + if (algo >= HASH_ALGO_NUM) + return -EINVAL; + + return hash_info[algo].digest_size; +} + +const char *hash_algo_name(enum HASH_ALGO algo) +{ + if (algo >= HASH_ALGO_NUM) + return NULL; + + return hash_info[algo].name; +} + +int hash_digest(struct udevice *dev, enum HASH_ALGO algo, + const void *ibuf, const uint32_t ilen, + void *obuf) +{ + struct hash_ops *ops = (struct hash_ops *)device_get_ops(dev); + + if (!ops->hash_digest) + return -ENOSYS; + + return ops->hash_digest(dev, algo, ibuf, ilen, obuf); +} + +int hash_digest_wd(struct udevice *dev, enum HASH_ALGO algo, + const void *ibuf, const uint32_t ilen, + void *obuf, uint32_t chunk_sz) +{ + struct hash_ops *ops = (struct hash_ops *)device_get_ops(dev); + + if (!ops->hash_digest_wd) + return -ENOSYS; + + return ops->hash_digest_wd(dev, algo, ibuf, ilen, obuf, chunk_sz); +} + +int hash_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp) +{ + struct hash_ops *ops = (struct hash_ops *)device_get_ops(dev); + + if (!ops->hash_init) + return -ENOSYS; + + return ops->hash_init(dev, algo, ctxp); +} + +int hash_update(struct udevice *dev, void *ctx, const void *ibuf, const uint32_t ilen) +{ + struct hash_ops *ops = (struct hash_ops *)device_get_ops(dev); + + if (!ops->hash_update) + return -ENOSYS; + + return ops->hash_update(dev, ctx, ibuf, ilen); +} + +int hash_finish(struct udevice *dev, void *ctx, void *obuf) +{ + struct hash_ops *ops = (struct hash_ops *)device_get_ops(dev); + + if (!ops->hash_finish) + return -ENOSYS; + + return ops->hash_finish(dev, ctx, obuf); +} + +UCLASS_DRIVER(hash) = { + .id = UCLASS_HASH, + .name = "hash", +}; diff --git a/drivers/crypto/hash/hash_sw.c b/drivers/crypto/hash/hash_sw.c new file mode 100644 index 0000000000..fea9d12609 --- /dev/null +++ b/drivers/crypto/hash/hash_sw.c @@ -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", +}; |