From 804fae5d16c8c48c6fca8d54f2878a2e382a0bc2 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 11 Mar 2015 17:53:03 +0100 Subject: digest: introduce digest_{init/update/final/length} This will allow to move from a one at a time digest to a multi-instance with too much impact on the code using it Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- include/digest.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'include') diff --git a/include/digest.h b/include/digest.h index 8563c10128..208a463793 100644 --- a/include/digest.h +++ b/include/digest.h @@ -50,4 +50,25 @@ int digest_file(struct digest *d, char *filename, int digest_file_by_name(char *algo, char *filename, unsigned char *hash); +static inline int digest_init(struct digest *d) +{ + return d->init(d); +} + +static inline int digest_update(struct digest *d, const void *data, + unsigned long len) +{ + return d->update(d, data, len); +} + +static inline int digest_final(struct digest *d, unsigned char *md) +{ + return d->final(d, md); +} + +static inline int digest_length(struct digest *d) +{ + return d->length; +} + #endif /* __SH_ST_DEVICES_H__ */ -- cgit v1.2.3 From 27b2336029335ea3f02243ff170986cdab1f98ef Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 11 Mar 2015 17:53:04 +0100 Subject: digest: make it multi-instance Now you need to call digest_alloc and when you finish to use it digest_free. We need this for upcomming aes encryption support and secure boot as we will need multiple instance of the same digest. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- commands/digest.c | 3 ++- common/password.c | 5 +++-- crypto/digest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++--------- crypto/md5.c | 34 ++++++++++-------------------- crypto/sha1.c | 34 ++++++++++-------------------- crypto/sha2.c | 55 ++++++++++++++++++------------------------------ include/digest.h | 28 +++++++++++++++++-------- 7 files changed, 119 insertions(+), 103 deletions(-) (limited to 'include') diff --git a/commands/digest.c b/commands/digest.c index bad7d3f094..c6a2751356 100644 --- a/commands/digest.c +++ b/commands/digest.c @@ -33,7 +33,7 @@ static int do_digest(char *algorithm, int argc, char *argv[]) int i; unsigned char *hash; - d = digest_get_by_name(algorithm); + d = digest_alloc(algorithm); BUG_ON(!d); if (argc < 2) @@ -71,6 +71,7 @@ static int do_digest(char *algorithm, int argc, char *argv[]) } free(hash); + digest_free(d); return ret; } diff --git a/common/password.c b/common/password.c index 16061095a8..4c33152dbe 100644 --- a/common/password.c +++ b/common/password.c @@ -280,7 +280,7 @@ static int __check_passwd(unsigned char* passwd, size_t length, int std) unsigned char *passwd2_sum; int ret = 0; - d = digest_get_by_name(PASSWD_SUM); + d = digest_alloc(PASSWD_SUM); passwd1_sum = calloc(digest_length(d), sizeof(unsigned char)); @@ -315,6 +315,7 @@ err2: free(passwd2_sum); err1: free(passwd1_sum); + digest_free(d); return ret; } @@ -347,7 +348,7 @@ int set_env_passwd(unsigned char* passwd, size_t length) unsigned char *passwd_sum; int ret; - d = digest_get_by_name(PASSWD_SUM); + d = digest_alloc(PASSWD_SUM); passwd_sum = calloc(digest_length(d), sizeof(unsigned char)); diff --git a/crypto/digest.c b/crypto/digest.c index 789c0b2fc9..65224bdbcf 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -28,12 +28,16 @@ static LIST_HEAD(digests); +static struct digest_algo* digest_algo_get_by_name(char* name); + static int dummy_init(struct digest *d) { return 0; } -int digest_register(struct digest *d) +static void dummy_free(struct digest *d) {} + +int digest_algo_register(struct digest_algo *d) { if (!d || !d->name || !d->update || !d->final || d->length < 1) return -EINVAL; @@ -41,27 +45,33 @@ int digest_register(struct digest *d) if (!d->init) d->init = dummy_init; - if (digest_get_by_name(d->name)) + if (!d->alloc) + d->alloc = dummy_init; + + if (!d->free) + d->free = dummy_free; + + if (digest_algo_get_by_name(d->name)) return -EEXIST; list_add_tail(&d->list, &digests); return 0; } -EXPORT_SYMBOL(digest_register); +EXPORT_SYMBOL(digest_algo_register); -void digest_unregister(struct digest *d) +void digest_algo_unregister(struct digest_algo *d) { if (!d) return; list_del(&d->list); } -EXPORT_SYMBOL(digest_unregister); +EXPORT_SYMBOL(digest_algo_unregister); -struct digest* digest_get_by_name(char* name) +static struct digest_algo *digest_algo_get_by_name(char* name) { - struct digest* d; + struct digest_algo* d; if (!name) return NULL; @@ -73,7 +83,37 @@ struct digest* digest_get_by_name(char* name) return NULL; } -EXPORT_SYMBOL_GPL(digest_get_by_name); + +struct digest *digest_alloc(char* name) +{ + struct digest* d; + struct digest_algo* algo; + + algo = digest_algo_get_by_name(name); + if (!algo) + return NULL; + + d = xzalloc(sizeof(*d)); + d->algo = algo; + d->ctx = xzalloc(algo->ctx_length); + if (d->algo->alloc(d)) { + digest_free(d); + return NULL; + } + + return d; +} +EXPORT_SYMBOL_GPL(digest_alloc); + +void digest_free(struct digest *d) +{ + if (!d) + return; + d->algo->free(d); + free(d->ctx); + free(d); +} +EXPORT_SYMBOL_GPL(digest_free); int digest_file_window(struct digest *d, char *filename, unsigned char *hash, @@ -164,11 +204,14 @@ int digest_file_by_name(char *algo, char *filename, unsigned char *hash) { struct digest *d; + int ret; - d = digest_get_by_name(algo); + d = digest_alloc(algo); if (!d) return -EIO; - return digest_file(d, filename, hash); + ret = digest_file(d, filename, hash); + digest_free(d); + return ret; } EXPORT_SYMBOL_GPL(digest_file_by_name); diff --git a/crypto/md5.c b/crypto/md5.c index 6c4ca1dd59..f70dd62131 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -265,16 +265,9 @@ MD5Transform(__u32 buf[4], __u32 const in[16]) buf[3] += d; } -struct md5 { - struct MD5Context context; - struct digest d; -}; - static int digest_md5_init(struct digest *d) { - struct md5 *m = container_of(d, struct md5, d); - - MD5Init(&m->context); + MD5Init(d->ctx); return 0; } @@ -282,35 +275,30 @@ static int digest_md5_init(struct digest *d) static int digest_md5_update(struct digest *d, const void *data, unsigned long len) { - struct md5 *m = container_of(d, struct md5, d); - - MD5Update(&m->context, data, len); + MD5Update(d->ctx, data, len); return 0; } static int digest_md5_final(struct digest *d, unsigned char *md) { - struct md5 *m = container_of(d, struct md5, d); - - MD5Final(md, &m->context); + MD5Final(md, d->ctx); return 0; } -static struct md5 m = { - .d = { - .name = "md5", - .init = digest_md5_init, - .update = digest_md5_update, - .final = digest_md5_final, - .length = 16, - } +static struct digest_algo md5 = { + .name = "md5", + .init = digest_md5_init, + .update = digest_md5_update, + .final = digest_md5_final, + .length = 16, + .ctx_length = sizeof(struct MD5Context), }; static int md5_digest_register(void) { - digest_register(&m.d); + digest_algo_register(&md5); return 0; } diff --git a/crypto/sha1.c b/crypto/sha1.c index 58d14a8b3f..b6f4cbbc5a 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -286,16 +286,9 @@ static void sha1_finish (sha1_context * ctx, uint8_t output[20]) PUT_UINT32_BE (ctx->state[4], output, 16); } -struct sha1 { - sha1_context context; - struct digest d; -}; - static int digest_sha1_init(struct digest *d) { - struct sha1 *m = container_of(d, struct sha1, d); - - sha1_starts(&m->context); + sha1_starts(d->ctx); return 0; } @@ -303,35 +296,30 @@ static int digest_sha1_init(struct digest *d) static int digest_sha1_update(struct digest *d, const void *data, unsigned long len) { - struct sha1 *m = container_of(d, struct sha1, d); - - sha1_update(&m->context, (uint8_t*)data, len); + sha1_update(d->ctx, (uint8_t*)data, len); return 0; } static int digest_sha1_final(struct digest *d, unsigned char *md) { - struct sha1 *m = container_of(d, struct sha1, d); - - sha1_finish(&m->context, md); + sha1_finish(d->ctx, md); return 0; } -static struct sha1 m = { - .d = { - .name = "sha1", - .init = digest_sha1_init, - .update = digest_sha1_update, - .final = digest_sha1_final, - .length = SHA1_SUM_LEN, - } +static struct digest_algo m = { + .name = "sha1", + .init = digest_sha1_init, + .update = digest_sha1_update, + .final = digest_sha1_final, + .length = SHA1_SUM_LEN, + .ctx_length = sizeof(sha1_context), }; static int sha1_digest_register(void) { - digest_register(&m.d); + digest_algo_register(&m); return 0; } diff --git a/crypto/sha2.c b/crypto/sha2.c index 00a1af3419..cc6b167f30 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -275,26 +275,17 @@ static void sha2_finish(sha2_context * ctx, uint8_t digest[32]) PUT_UINT32_BE(ctx->state[7], digest, 28); } -struct sha2 { - sha2_context context; - struct digest d; -}; - static int digest_sha2_update(struct digest *d, const void *data, unsigned long len) { - struct sha2 *m = container_of(d, struct sha2, d); - - sha2_update(&m->context, (uint8_t *)data, len); + sha2_update(d->ctx, (uint8_t *)data, len); return 0; } static int digest_sha2_final(struct digest *d, unsigned char *md) { - struct sha2 *m = container_of(d, struct sha2, d); - - sha2_finish(&m->context, md); + sha2_finish(d->ctx, md); return 0; } @@ -302,52 +293,46 @@ static int digest_sha2_final(struct digest *d, unsigned char *md) #ifdef CONFIG_SHA224 static int digest_sha224_init(struct digest *d) { - struct sha2 *m = container_of(d, struct sha2, d); - - sha2_starts(&m->context, 1); + sha2_starts(d->ctx, 1); return 0; } -static struct sha2 m224 = { - .d = { - .name = "sha224", - .init = digest_sha224_init, - .update = digest_sha2_update, - .final = digest_sha2_final, - .length = SHA224_SUM_LEN, - } +static struct digest_algo m224 = { + .name = "sha224", + .init = digest_sha224_init, + .update = digest_sha2_update, + .final = digest_sha2_final, + .length = SHA224_SUM_LEN, + .ctx_length = sizeof(sha2_context), }; #endif #ifdef CONFIG_SHA256 static int digest_sha256_init(struct digest *d) { - struct sha2 *m = container_of(d, struct sha2, d); - - sha2_starts(&m->context, 0); + sha2_starts(d->ctx, 0); return 0; } -static struct sha2 m256 = { - .d = { - .name = "sha256", - .init = digest_sha256_init, - .update = digest_sha2_update, - .final = digest_sha2_final, - .length = SHA256_SUM_LEN, - } +static struct digest_algo m256 = { + .name = "sha256", + .init = digest_sha256_init, + .update = digest_sha2_update, + .final = digest_sha2_final, + .length = SHA256_SUM_LEN, + .ctx_length = sizeof(sha2_context), }; #endif static int sha2_digest_register(void) { #ifdef CONFIG_SHA224 - digest_register(&m224.d); + digest_algo_register(&m224); #endif #ifdef CONFIG_SHA256 - digest_register(&m256.d); + digest_algo_register(&m256); #endif return 0; diff --git a/include/digest.h b/include/digest.h index 208a463793..2fd1135175 100644 --- a/include/digest.h +++ b/include/digest.h @@ -21,26 +21,36 @@ #include -struct digest -{ +struct digest; + +struct digest_algo { char *name; + int (*alloc)(struct digest *d); + void (*free)(struct digest *d); int (*init)(struct digest *d); int (*update)(struct digest *d, const void *data, unsigned long len); int (*final)(struct digest *d, unsigned char *md); unsigned int length; + unsigned int ctx_length; struct list_head list; }; +struct digest { + struct digest_algo *algo; + void *ctx; +}; + /* * digest functions */ -int digest_register(struct digest *d); -void digest_unregister(struct digest *d); +int digest_algo_register(struct digest_algo *d); +void digest_algo_unregister(struct digest_algo *d); -struct digest* digest_get_by_name(char* name); +struct digest *digest_alloc(char* name); +void digest_free(struct digest *d); int digest_file_window(struct digest *d, char *filename, unsigned char *hash, @@ -52,23 +62,23 @@ int digest_file_by_name(char *algo, char *filename, static inline int digest_init(struct digest *d) { - return d->init(d); + return d->algo->init(d); } static inline int digest_update(struct digest *d, const void *data, unsigned long len) { - return d->update(d, data, len); + return d->algo->update(d, data, len); } static inline int digest_final(struct digest *d, unsigned char *md) { - return d->final(d, md); + return d->algo->final(d, md); } static inline int digest_length(struct digest *d) { - return d->length; + return d->algo->length; } #endif /* __SH_ST_DEVICES_H__ */ -- cgit v1.2.3 From 2f3c3f512b2ff5023a4177e167eb6b55055fe883 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 11 Mar 2015 17:53:08 +0100 Subject: digest: add HMAC support for md5, sha1, sha224, sha256, sha384, sha512 the hmac algo will be registered as hmac(%s) such as hmac(sha256) Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- crypto/Kconfig | 3 ++ crypto/Makefile | 1 + crypto/hmac.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ crypto/internal.h | 15 ++++++ crypto/md5.c | 10 +++- crypto/sha1.c | 10 +++- crypto/sha2.c | 41 +++++++++----- crypto/sha4.c | 35 +++++++++--- include/digest.h | 8 +++ 9 files changed, 258 insertions(+), 24 deletions(-) create mode 100644 crypto/hmac.c create mode 100644 crypto/internal.h (limited to 'include') diff --git a/crypto/Kconfig b/crypto/Kconfig index 3b78a147e3..e72b91ef79 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -30,4 +30,7 @@ config SHA384 config SHA512 bool "SHA512" +config DIGEST_HMAC + bool "HMAC" + endif diff --git a/crypto/Makefile b/crypto/Makefile index aef8733c91..ff5c289ce1 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_CRC32) += crc32.o obj-$(CONFIG_CRC16) += crc16.o obj-$(CONFIG_CRC7) += crc7.o obj-$(CONFIG_DIGEST) += digest.o +obj-$(CONFIG_DIGEST_HMAC) += hmac.o obj-$(CONFIG_MD5) += md5.o obj-$(CONFIG_SHA1) += sha1.o obj-$(CONFIG_SHA224) += sha2.o diff --git a/crypto/hmac.c b/crypto/hmac.c new file mode 100644 index 0000000000..4e6bfa3f09 --- /dev/null +++ b/crypto/hmac.c @@ -0,0 +1,159 @@ +/* + * (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD + * + * GPL v2 only + */ + +#include +#include +#include + +#include "internal.h" + +struct digest_hmac { + char *name; + unsigned int pad_length; + struct digest_algo algo; +}; + +struct digest_hmac_ctx { + struct digest *d; + + unsigned char *ipad; + unsigned char *opad; + + unsigned char *key; + unsigned int keylen; +}; + +static inline struct digest_hmac * to_digest_hmac(struct digest_algo *algo) +{ + return container_of(algo, struct digest_hmac, algo); +} + +static int digest_hmac_alloc(struct digest *d) +{ + struct digest_hmac_ctx *dh = d->ctx; + struct digest_hmac *hmac = to_digest_hmac(d->algo); + + dh->d = digest_alloc(hmac->name); + if (!dh->d) + return -EINVAL; + + dh->ipad = xmalloc(hmac->pad_length); + dh->opad = xmalloc(hmac->pad_length); + + return 0; +} + +static void digest_hmac_free(struct digest *d) +{ + struct digest_hmac_ctx *dh = d->ctx; + + free(dh->ipad); + free(dh->opad); + free(dh->key); + + digest_free(dh->d); +} + +static int digest_hmac_set_key(struct digest *d, const unsigned char *key, + unsigned int len) +{ + struct digest_hmac_ctx *dh = d->ctx; + struct digest_hmac *hmac = to_digest_hmac(d->algo); + + free(dh->key); + if (len > hmac->pad_length) { + unsigned char *sum; + + sum = xmalloc(digest_length(dh->d)); + digest_init(dh->d); + digest_update(dh->d, dh->key, dh->keylen); + digest_final(dh->d, sum); + dh->keylen = digest_length(dh->d); + dh->key = sum; + } else { + dh->key = xmalloc(len); + memcpy(dh->key, key, len); + dh->keylen = len; + } + + return 0; +} + +static int digest_hmac_init(struct digest *d) +{ + struct digest_hmac_ctx *dh = d->ctx; + struct digest_hmac *hmac = to_digest_hmac(d->algo); + int i; + unsigned char *key = dh->key; + unsigned int keylen = dh->keylen; + + memset(dh->ipad, 0x36, hmac->pad_length); + memset(dh->opad, 0x5C, hmac->pad_length); + + for (i = 0; i < keylen; i++) { + dh->ipad[i] = (unsigned char)(dh->ipad[i] ^ key[i]); + dh->opad[i] = (unsigned char)(dh->opad[i] ^ key[i]); + } + + digest_init(dh->d); + digest_update(dh->d, dh->ipad, hmac->pad_length); + + return 0; +} + +static int digest_hmac_update(struct digest *d, const void *data, + unsigned long len) +{ + struct digest_hmac_ctx *dh = d->ctx; + + return digest_update(dh->d, data, len); +} + +static int digest_hmac_final(struct digest *d, unsigned char *md) +{ + struct digest_hmac_ctx *dh = d->ctx; + struct digest_hmac *hmac = to_digest_hmac(d->algo); + unsigned char *tmp = NULL; + + tmp = xmalloc(digest_length(d)); + + digest_final(dh->d, tmp); + digest_init(dh->d); + digest_update(dh->d, dh->opad, hmac->pad_length); + digest_update(dh->d, tmp, digest_length(d)); + digest_final(dh->d, md); + + free(tmp); + + return 0; +} + +struct digest_algo hmac_algo = { + .alloc = digest_hmac_alloc, + .init = digest_hmac_init, + .update = digest_hmac_update, + .final = digest_hmac_final, + .set_key = digest_hmac_set_key, + .free = digest_hmac_free, + .ctx_length = sizeof(struct digest_hmac), +}; + +int digest_hmac_register(struct digest_algo *algo, unsigned int pad_length) +{ + struct digest_hmac *dh; + + if (!algo || !pad_length) + return -EINVAL; + + dh = xzalloc(sizeof(*dh)); + dh->name = xstrdup(algo->name); + dh->pad_length = pad_length; + dh->algo = hmac_algo; + dh->algo.length = algo->length; + dh->algo.name = asprintf("hmac(%s)", algo->name); + + return digest_algo_register(&dh->algo); +} diff --git a/crypto/internal.h b/crypto/internal.h new file mode 100644 index 0000000000..cc409d8d21 --- /dev/null +++ b/crypto/internal.h @@ -0,0 +1,15 @@ +/* + * (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD + * + * GPL v2 only + */ + +#ifdef CONFIG_DIGEST_HMAC +int digest_hmac_register(struct digest_algo *algo, unsigned int pad_length); +#else +static inline int digest_hmac_register(struct digest_algo *algo, + unsigned int pad_length) +{ + return 0; +} +#endif diff --git a/crypto/md5.c b/crypto/md5.c index f70dd62131..fe17ff5863 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -29,6 +29,8 @@ #include #include +#include "internal.h" + struct MD5Context { __u32 buf[4]; __u32 bits[2]; @@ -298,8 +300,12 @@ static struct digest_algo md5 = { static int md5_digest_register(void) { - digest_algo_register(&md5); + int ret; - return 0; + ret = digest_algo_register(&md5); + if (ret) + return ret; + + return digest_hmac_register(&md5, 64); } device_initcall(md5_digest_register); diff --git a/crypto/sha1.c b/crypto/sha1.c index b6f4cbbc5a..766e4eace2 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -26,6 +26,8 @@ #include #include +#include "internal.h" + #define SHA1_SUM_POS -0x20 #define SHA1_SUM_LEN 20 @@ -319,8 +321,12 @@ static struct digest_algo m = { static int sha1_digest_register(void) { - digest_algo_register(&m); + int ret; - return 0; + ret = digest_algo_register(&m); + if (ret) + return ret; + + return digest_hmac_register(&m, 64); } device_initcall(sha1_digest_register); diff --git a/crypto/sha2.c b/crypto/sha2.c index cc6b167f30..8558030547 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -21,6 +21,8 @@ #include #include +#include "internal.h" + #define SHA224_SUM_LEN 28 #define SHA256_SUM_LEN 32 @@ -290,7 +292,6 @@ static int digest_sha2_final(struct digest *d, unsigned char *md) return 0; } -#ifdef CONFIG_SHA224 static int digest_sha224_init(struct digest *d) { sha2_starts(d->ctx, 1); @@ -306,9 +307,22 @@ static struct digest_algo m224 = { .length = SHA224_SUM_LEN, .ctx_length = sizeof(sha2_context), }; -#endif -#ifdef CONFIG_SHA256 +static int sha224_digest_register(void) +{ + int ret; + + if (!IS_ENABLED(CONFIG_SHA224)) + return 0; + + ret = digest_algo_register(&m224); + if (ret) + return ret; + + return digest_hmac_register(&m224, 64); +} +device_initcall(sha224_digest_register); + static int digest_sha256_init(struct digest *d) { sha2_starts(d->ctx, 0); @@ -324,17 +338,18 @@ static struct digest_algo m256 = { .length = SHA256_SUM_LEN, .ctx_length = sizeof(sha2_context), }; -#endif -static int sha2_digest_register(void) +static int sha256_digest_register(void) { -#ifdef CONFIG_SHA224 - digest_algo_register(&m224); -#endif -#ifdef CONFIG_SHA256 - digest_algo_register(&m256); -#endif + int ret; - return 0; + if (!IS_ENABLED(CONFIG_SHA256)) + return 0; + + ret = digest_algo_register(&m256); + if (ret) + return ret; + + return digest_hmac_register(&m256, 64); } -device_initcall(sha2_digest_register); +device_initcall(sha256_digest_register); diff --git a/crypto/sha4.c b/crypto/sha4.c index c3dcf17dd2..8a56081c33 100644 --- a/crypto/sha4.c +++ b/crypto/sha4.c @@ -29,6 +29,8 @@ #include #include +#include "internal.h" + #define SHA384_SUM_LEN 48 #define SHA512_SUM_LEN 64 @@ -311,6 +313,22 @@ static struct digest_algo m384 = { .ctx_length = sizeof(sha4_context), }; + +static int sha384_digest_register(void) +{ + int ret; + + if (!IS_ENABLED(CONFIG_SHA384)) + return 0; + + ret = digest_algo_register(&m384); + if (ret) + return ret; + + return digest_hmac_register(&m384, 128); +} +device_initcall(sha384_digest_register); + static int digest_sha512_init(struct digest *d) { sha4_starts(d->ctx, 0); @@ -327,14 +345,17 @@ static struct digest_algo m512 = { .ctx_length = sizeof(sha4_context), }; -static int sha4_digest_register(void) +static int sha512_digest_register(void) { - if IS_ENABLED(CONFIG_SHA384) - digest_algo_register(&m384); + int ret; - if IS_ENABLED(CONFIG_SHA512) - digest_algo_register(&m512); + if (!IS_ENABLED(CONFIG_SHA512)) + return 0; - return 0; + ret = digest_algo_register(&m512); + if (ret) + return ret; + + return digest_hmac_register(&m512, 128); } -device_initcall(sha4_digest_register); +device_initcall(sha512_digest_register); diff --git a/include/digest.h b/include/digest.h index 2fd1135175..a26848c291 100644 --- a/include/digest.h +++ b/include/digest.h @@ -31,6 +31,7 @@ struct digest_algo { int (*init)(struct digest *d); int (*update)(struct digest *d, const void *data, unsigned long len); int (*final)(struct digest *d, unsigned char *md); + int (*set_key)(struct digest *d, unsigned char *key, unsigned int len); unsigned int length; unsigned int ctx_length; @@ -81,4 +82,11 @@ static inline int digest_length(struct digest *d) return d->algo->length; } +static inline int digest_set_key(struct digest *d, unsigned char *key, unsigned int len) +{ + if (!d->algo->set_key) + return -ENOTSUPP; + return d->algo->set_key(d, key, len); +} + #endif /* __SH_ST_DEVICES_H__ */ -- cgit v1.2.3 From 102d59f91fdd327c68c1b7a8c43f3f4685422f52 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 11 Mar 2015 17:53:09 +0100 Subject: command: add hmac sum supportfor md5, sha1, sha224, sha256, sha384, sha512 pass the key via -h param barebox@barebox sandbox:/ sha256sum -h test /dev/fd0 c297473e9bb221c5dc51d47ad75c76095f1bdc4ca9dff1d5931c2e22bf11a0de /dev/fd0 0x00000000 ... 0xffffffffffffffff use the same idea as openssl command $ openssl dgst -sha256 -hmac "test" TODO HMAC-SHA256(TODO)= c297473e9bb221c5dc51d47ad75c76095f1bdc4ca9dff1d5931c2e22bf11a0de Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- commands/digest.c | 34 +++++++++++++++++++++++++++++----- crypto/digest.c | 10 ++++++++-- include/digest.h | 3 +++ 3 files changed, 40 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/commands/digest.c b/commands/digest.c index 20fa13f303..701e6a16fa 100644 --- a/commands/digest.c +++ b/commands/digest.c @@ -25,6 +25,7 @@ #include #include #include +#include static int do_digest(char *algorithm, int argc, char *argv[]) { @@ -32,11 +33,32 @@ static int do_digest(char *algorithm, int argc, char *argv[]) int ret = 0; int i; unsigned char *hash; + unsigned char *key = NULL; + size_t keylen = 0; + int opt; + + while((opt = getopt(argc, argv, "h:")) > 0) { + switch(opt) { + case 'h': + key = optarg; + keylen = strlen(key); + break; + } + } - d = digest_alloc(algorithm); + argc -= optind; + argv += optind; + + if (key) { + char *tmp = asprintf("hmac(%s)", algorithm); + d = digest_alloc(tmp); + free(tmp); + } else { + d = digest_alloc(algorithm); + } BUG_ON(!d); - if (argc < 2) + if (argc < 1) return COMMAND_ERROR_USAGE; hash = calloc(digest_length(d), sizeof(unsigned char)); @@ -45,7 +67,6 @@ static int do_digest(char *algorithm, int argc, char *argv[]) return COMMAND_ERROR_USAGE; } - argv++; while (*argv) { char *filename = "/dev/mem"; loff_t start = 0, size = ~0; @@ -53,11 +74,14 @@ static int do_digest(char *algorithm, int argc, char *argv[]) /* arguments are either file, file+area or area */ if (parse_area_spec(*argv, &start, &size)) { filename = *argv; - if (argv[1] && !parse_area_spec(argv[1], &start, &size)) + if (argv[0] && !parse_area_spec(argv[0], &start, &size)) argv++; } - if (digest_file_window(d, filename, hash, start, size) < 0) { + ret = digest_file_window(d, filename, + key, keylen, + hash, start, size); + if (ret < 0) { ret = 1; } else { for (i = 0; i < digest_length(d); i++) diff --git a/crypto/digest.c b/crypto/digest.c index 65224bdbcf..2f2039c0ce 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -116,6 +116,7 @@ void digest_free(struct digest *d) EXPORT_SYMBOL_GPL(digest_free); int digest_file_window(struct digest *d, char *filename, + unsigned char *key, size_t keylen, unsigned char *hash, ulong start, ulong size) { @@ -124,6 +125,9 @@ int digest_file_window(struct digest *d, char *filename, unsigned char *buf; int flags = 0; + if (key) + digest_set_key(d, key, keylen); + digest_init(d); fd = open(filename, O_RDONLY); @@ -186,6 +190,7 @@ out: EXPORT_SYMBOL_GPL(digest_file_window); int digest_file(struct digest *d, char *filename, + unsigned char *key, size_t keylen, unsigned char *hash) { struct stat st; @@ -196,11 +201,12 @@ int digest_file(struct digest *d, char *filename, if (ret < 0) return ret; - return digest_file_window(d, filename, hash, 0, st.st_size); + return digest_file_window(d, filename, key, keylen, hash, 0, st.st_size); } EXPORT_SYMBOL_GPL(digest_file); int digest_file_by_name(char *algo, char *filename, + unsigned char *key, size_t keylen, unsigned char *hash) { struct digest *d; @@ -210,7 +216,7 @@ int digest_file_by_name(char *algo, char *filename, if (!d) return -EIO; - ret = digest_file(d, filename, hash); + ret = digest_file(d, filename, key, keylen, hash); digest_free(d); return ret; } diff --git a/include/digest.h b/include/digest.h index a26848c291..fd47a7e248 100644 --- a/include/digest.h +++ b/include/digest.h @@ -54,11 +54,14 @@ struct digest *digest_alloc(char* name); void digest_free(struct digest *d); int digest_file_window(struct digest *d, char *filename, + unsigned char *key, size_t keylen, unsigned char *hash, ulong start, ulong size); int digest_file(struct digest *d, char *filename, + unsigned char *key, size_t keylen, unsigned char *hash); int digest_file_by_name(char *algo, char *filename, + unsigned char *key, size_t keylen, unsigned char *hash); static inline int digest_init(struct digest *d) -- cgit v1.2.3 From ac2407db7a25ba81852919c34de56db792e77fca Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 12 Mar 2015 08:06:08 +0100 Subject: crypto: digest: Make string arguments const Most string arguments for keys and filenames can be const. Change that. Signed-off-by: Sascha Hauer --- crypto/digest.c | 18 +++++++++--------- include/digest.h | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/crypto/digest.c b/crypto/digest.c index 2f2039c0ce..922d9d05f8 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -28,7 +28,7 @@ static LIST_HEAD(digests); -static struct digest_algo* digest_algo_get_by_name(char* name); +static struct digest_algo* digest_algo_get_by_name(const char *name); static int dummy_init(struct digest *d) { @@ -69,7 +69,7 @@ void digest_algo_unregister(struct digest_algo *d) } EXPORT_SYMBOL(digest_algo_unregister); -static struct digest_algo *digest_algo_get_by_name(char* name) +static struct digest_algo *digest_algo_get_by_name(const char *name) { struct digest_algo* d; @@ -84,7 +84,7 @@ static struct digest_algo *digest_algo_get_by_name(char* name) return NULL; } -struct digest *digest_alloc(char* name) +struct digest *digest_alloc(const char *name) { struct digest* d; struct digest_algo* algo; @@ -115,8 +115,8 @@ void digest_free(struct digest *d) } EXPORT_SYMBOL_GPL(digest_free); -int digest_file_window(struct digest *d, char *filename, - unsigned char *key, size_t keylen, +int digest_file_window(struct digest *d, const char *filename, + const unsigned char *key, size_t keylen, unsigned char *hash, ulong start, ulong size) { @@ -189,8 +189,8 @@ out: } EXPORT_SYMBOL_GPL(digest_file_window); -int digest_file(struct digest *d, char *filename, - unsigned char *key, size_t keylen, +int digest_file(struct digest *d, const char *filename, + const unsigned char *key, size_t keylen, unsigned char *hash) { struct stat st; @@ -205,8 +205,8 @@ int digest_file(struct digest *d, char *filename, } EXPORT_SYMBOL_GPL(digest_file); -int digest_file_by_name(char *algo, char *filename, - unsigned char *key, size_t keylen, +int digest_file_by_name(const char *algo, const char *filename, + const unsigned char *key, size_t keylen, unsigned char *hash) { struct digest *d; diff --git a/include/digest.h b/include/digest.h index fd47a7e248..b890a7a10b 100644 --- a/include/digest.h +++ b/include/digest.h @@ -31,7 +31,7 @@ struct digest_algo { int (*init)(struct digest *d); int (*update)(struct digest *d, const void *data, unsigned long len); int (*final)(struct digest *d, unsigned char *md); - int (*set_key)(struct digest *d, unsigned char *key, unsigned int len); + int (*set_key)(struct digest *d, const unsigned char *key, unsigned int len); unsigned int length; unsigned int ctx_length; @@ -50,18 +50,18 @@ struct digest { int digest_algo_register(struct digest_algo *d); void digest_algo_unregister(struct digest_algo *d); -struct digest *digest_alloc(char* name); +struct digest *digest_alloc(const char *name); void digest_free(struct digest *d); -int digest_file_window(struct digest *d, char *filename, - unsigned char *key, size_t keylen, +int digest_file_window(struct digest *d, const char *filename, + const unsigned char *key, size_t keylen, unsigned char *hash, ulong start, ulong size); -int digest_file(struct digest *d, char *filename, - unsigned char *key, size_t keylen, +int digest_file(struct digest *d, const char *filename, + const unsigned char *key, size_t keylen, unsigned char *hash); -int digest_file_by_name(char *algo, char *filename, - unsigned char *key, size_t keylen, +int digest_file_by_name(const char *algo, const char *filename, + const unsigned char *key, size_t keylen, unsigned char *hash); static inline int digest_init(struct digest *d) @@ -85,7 +85,8 @@ static inline int digest_length(struct digest *d) return d->algo->length; } -static inline int digest_set_key(struct digest *d, unsigned char *key, unsigned int len) +static inline int digest_set_key(struct digest *d, const unsigned char *key, + unsigned int len) { if (!d->algo->set_key) return -ENOTSUPP; -- cgit v1.2.3 From 92138a77544da7ad7d880082e905c1ca8cd0c527 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 17 Mar 2015 12:53:09 +0100 Subject: crypto: digest: digest_file_window/digest_file/digest_file_by_name drop key params expect the key to be set before calling Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- commands/digest.c | 10 ++++++++-- crypto/digest.c | 10 ++-------- include/digest.h | 3 --- 3 files changed, 10 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/commands/digest.c b/commands/digest.c index 701e6a16fa..59c94ea2bf 100644 --- a/commands/digest.c +++ b/commands/digest.c @@ -52,11 +52,17 @@ static int do_digest(char *algorithm, int argc, char *argv[]) if (key) { char *tmp = asprintf("hmac(%s)", algorithm); d = digest_alloc(tmp); + BUG_ON(!d); + ret = digest_set_key(d, key, keylen); free(tmp); + if (ret) { + perror("set_key"); + goto err; + } } else { d = digest_alloc(algorithm); + BUG_ON(!d); } - BUG_ON(!d); if (argc < 1) return COMMAND_ERROR_USAGE; @@ -79,7 +85,6 @@ static int do_digest(char *algorithm, int argc, char *argv[]) } ret = digest_file_window(d, filename, - key, keylen, hash, start, size); if (ret < 0) { ret = 1; @@ -94,6 +99,7 @@ static int do_digest(char *algorithm, int argc, char *argv[]) argv++; } +err: free(hash); digest_free(d); diff --git a/crypto/digest.c b/crypto/digest.c index 2228ec7eb5..208a2041b1 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -116,7 +116,6 @@ void digest_free(struct digest *d) EXPORT_SYMBOL_GPL(digest_free); int digest_file_window(struct digest *d, const char *filename, - const unsigned char *key, size_t keylen, unsigned char *hash, ulong start, ulong size) { @@ -125,9 +124,6 @@ int digest_file_window(struct digest *d, const char *filename, unsigned char *buf; int flags = 0; - if (key) - digest_set_key(d, key, keylen); - ret = digest_init(d); if (ret) return ret; @@ -194,7 +190,6 @@ out: EXPORT_SYMBOL_GPL(digest_file_window); int digest_file(struct digest *d, const char *filename, - const unsigned char *key, size_t keylen, unsigned char *hash) { struct stat st; @@ -205,12 +200,11 @@ int digest_file(struct digest *d, const char *filename, if (ret < 0) return ret; - return digest_file_window(d, filename, key, keylen, hash, 0, st.st_size); + return digest_file_window(d, filename, hash, 0, st.st_size); } EXPORT_SYMBOL_GPL(digest_file); int digest_file_by_name(const char *algo, const char *filename, - const unsigned char *key, size_t keylen, unsigned char *hash) { struct digest *d; @@ -220,7 +214,7 @@ int digest_file_by_name(const char *algo, const char *filename, if (!d) return -EIO; - ret = digest_file(d, filename, key, keylen, hash); + ret = digest_file(d, filename, hash); digest_free(d); return ret; } diff --git a/include/digest.h b/include/digest.h index b890a7a10b..1c742f615e 100644 --- a/include/digest.h +++ b/include/digest.h @@ -54,14 +54,11 @@ struct digest *digest_alloc(const char *name); void digest_free(struct digest *d); int digest_file_window(struct digest *d, const char *filename, - const unsigned char *key, size_t keylen, unsigned char *hash, ulong start, ulong size); int digest_file(struct digest *d, const char *filename, - const unsigned char *key, size_t keylen, unsigned char *hash); int digest_file_by_name(const char *algo, const char *filename, - const unsigned char *key, size_t keylen, unsigned char *hash); static inline int digest_init(struct digest *d) -- cgit v1.2.3 From ec4f9699718054f2b4e49ed441f3420c257f5f26 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 17 Mar 2015 12:53:10 +0100 Subject: digest: add verify callback this will allow to compare a md with the original one When calling this do not call final For RSA_SIGN verification final does not exist only verify as final will be for signing Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- crypto/digest.c | 24 +++++++++++++++++++++++- crypto/hmac.c | 1 + crypto/internal.h | 2 ++ crypto/md5.c | 1 + crypto/sha1.c | 1 + crypto/sha2.c | 2 ++ crypto/sha4.c | 2 ++ include/digest.h | 6 ++++++ 8 files changed, 38 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/crypto/digest.c b/crypto/digest.c index 208a2041b1..7869c049e9 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -26,6 +26,8 @@ #include #include +#include "internal.h" + static LIST_HEAD(digests); static struct digest_algo *digest_algo_get_by_name(const char *name); @@ -37,9 +39,29 @@ static int dummy_init(struct digest *d) static void dummy_free(struct digest *d) {} +int digest_generic_verify(struct digest *d, const unsigned char *md) +{ + int ret; + int len = digest_length(d); + unsigned char *tmp; + + tmp = xmalloc(len); + + ret = digest_final(d, tmp); + if (ret) + goto end; + + ret = memcmp(md, tmp, len); + ret = ret ? -EINVAL : 0; +end: + free(tmp); + return ret; +} + int digest_algo_register(struct digest_algo *d) { - if (!d || !d->name || !d->update || !d->final || d->length < 1) + if (!d || !d->name || !d->update || !d->final || !d->verify || + d->length < 1) return -EINVAL; if (!d->init) diff --git a/crypto/hmac.c b/crypto/hmac.c index 1462730a0d..f39e4c8e8c 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -136,6 +136,7 @@ struct digest_algo hmac_algo = { .init = digest_hmac_init, .update = digest_hmac_update, .final = digest_hmac_final, + .verify = digest_generic_verify, .set_key = digest_hmac_set_key, .free = digest_hmac_free, .ctx_length = sizeof(struct digest_hmac), diff --git a/crypto/internal.h b/crypto/internal.h index cc409d8d21..f482654f63 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -13,3 +13,5 @@ static inline int digest_hmac_register(struct digest_algo *algo, return 0; } #endif + +int digest_generic_verify(struct digest *d, const unsigned char *md); diff --git a/crypto/md5.c b/crypto/md5.c index fe17ff5863..4847b38631 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -294,6 +294,7 @@ static struct digest_algo md5 = { .init = digest_md5_init, .update = digest_md5_update, .final = digest_md5_final, + .verify = digest_generic_verify, .length = 16, .ctx_length = sizeof(struct MD5Context), }; diff --git a/crypto/sha1.c b/crypto/sha1.c index a244b5d627..09dee87321 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -315,6 +315,7 @@ static struct digest_algo m = { .init = digest_sha1_init, .update = digest_sha1_update, .final = digest_sha1_final, + .verify = digest_generic_verify, .length = SHA1_SUM_LEN, .ctx_length = sizeof(sha1_context), }; diff --git a/crypto/sha2.c b/crypto/sha2.c index cb89c82312..9bf6541498 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -304,6 +304,7 @@ static struct digest_algo m224 = { .init = digest_sha224_init, .update = digest_sha2_update, .final = digest_sha2_final, + .verify = digest_generic_verify, .length = SHA224_SUM_LEN, .ctx_length = sizeof(sha2_context), }; @@ -335,6 +336,7 @@ static struct digest_algo m256 = { .init = digest_sha256_init, .update = digest_sha2_update, .final = digest_sha2_final, + .verify = digest_generic_verify, .length = SHA256_SUM_LEN, .ctx_length = sizeof(sha2_context), }; diff --git a/crypto/sha4.c b/crypto/sha4.c index 1c768e720e..5c3097db4a 100644 --- a/crypto/sha4.c +++ b/crypto/sha4.c @@ -309,6 +309,7 @@ static struct digest_algo m384 = { .init = digest_sha384_init, .update = digest_sha4_update, .final = digest_sha4_final, + .verify = digest_generic_verify, .length = SHA384_SUM_LEN, .ctx_length = sizeof(sha4_context), }; @@ -341,6 +342,7 @@ static struct digest_algo m512 = { .init = digest_sha512_init, .update = digest_sha4_update, .final = digest_sha4_final, + .verify = digest_generic_verify, .length = SHA512_SUM_LEN, .ctx_length = sizeof(sha4_context), }; diff --git a/include/digest.h b/include/digest.h index 1c742f615e..5d1d80c31d 100644 --- a/include/digest.h +++ b/include/digest.h @@ -32,6 +32,7 @@ struct digest_algo { int (*update)(struct digest *d, const void *data, unsigned long len); int (*final)(struct digest *d, unsigned char *md); int (*set_key)(struct digest *d, const unsigned char *key, unsigned int len); + int (*verify)(struct digest *d, const unsigned char *md); unsigned int length; unsigned int ctx_length; @@ -77,6 +78,11 @@ static inline int digest_final(struct digest *d, unsigned char *md) return d->algo->final(d, md); } +static inline int digest_verify(struct digest *d, const unsigned char *md) +{ + return d->algo->verify(d, md); +} + static inline int digest_length(struct digest *d) { return d->algo->length; -- cgit v1.2.3 From 7aeb9650b6c57a81c0cf903a3977e6d6fbb2808c Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 17 Mar 2015 12:53:11 +0100 Subject: digest: add digest callback Combination of @init and @update and @final. This function effectively behaves as the entire chain of operations, @init, @update and @final issued in sequence. This is added for hardware which cannot do even the @finup, but can only do the whole transformation in one run. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- crypto/digest.c | 18 ++++++++++++++++++ crypto/hmac.c | 1 + crypto/internal.h | 2 ++ crypto/md5.c | 1 + crypto/sha1.c | 1 + crypto/sha2.c | 1 + crypto/sha4.c | 1 + include/digest.h | 8 ++++++++ 8 files changed, 33 insertions(+) (limited to 'include') diff --git a/crypto/digest.c b/crypto/digest.c index 7869c049e9..7670ed06b7 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -58,6 +58,24 @@ end: return ret; } +int digest_generic_digest(struct digest *d, const void *data, + unsigned int len, u8 *md) + +{ + int ret; + + if (!data || len == 0 || !md) + return -EINVAL; + + ret = digest_init(d); + if (ret) + return ret; + ret = digest_update(d, data, len); + if (ret) + return ret; + return digest_final(d, md); +} + int digest_algo_register(struct digest_algo *d) { if (!d || !d->name || !d->update || !d->final || !d->verify || diff --git a/crypto/hmac.c b/crypto/hmac.c index f39e4c8e8c..b1c17afdf6 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -136,6 +136,7 @@ struct digest_algo hmac_algo = { .init = digest_hmac_init, .update = digest_hmac_update, .final = digest_hmac_final, + .digest = digest_generic_digest, .verify = digest_generic_verify, .set_key = digest_hmac_set_key, .free = digest_hmac_free, diff --git a/crypto/internal.h b/crypto/internal.h index f482654f63..c6f5908ea0 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -15,3 +15,5 @@ static inline int digest_hmac_register(struct digest_algo *algo, #endif int digest_generic_verify(struct digest *d, const unsigned char *md); +int digest_generic_digest(struct digest *d, const void *data, + unsigned int len, u8 *out); diff --git a/crypto/md5.c b/crypto/md5.c index 4847b38631..b7ad6f27e9 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -294,6 +294,7 @@ static struct digest_algo md5 = { .init = digest_md5_init, .update = digest_md5_update, .final = digest_md5_final, + .digest = digest_generic_digest, .verify = digest_generic_verify, .length = 16, .ctx_length = sizeof(struct MD5Context), diff --git a/crypto/sha1.c b/crypto/sha1.c index 09dee87321..b108f8ae31 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -315,6 +315,7 @@ static struct digest_algo m = { .init = digest_sha1_init, .update = digest_sha1_update, .final = digest_sha1_final, + .digest = digest_generic_digest, .verify = digest_generic_verify, .length = SHA1_SUM_LEN, .ctx_length = sizeof(sha1_context), diff --git a/crypto/sha2.c b/crypto/sha2.c index 9bf6541498..375a40e1f6 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -336,6 +336,7 @@ static struct digest_algo m256 = { .init = digest_sha256_init, .update = digest_sha2_update, .final = digest_sha2_final, + .digest = digest_generic_digest, .verify = digest_generic_verify, .length = SHA256_SUM_LEN, .ctx_length = sizeof(sha2_context), diff --git a/crypto/sha4.c b/crypto/sha4.c index 5c3097db4a..1b91e7fcc3 100644 --- a/crypto/sha4.c +++ b/crypto/sha4.c @@ -342,6 +342,7 @@ static struct digest_algo m512 = { .init = digest_sha512_init, .update = digest_sha4_update, .final = digest_sha4_final, + .digest = digest_generic_digest, .verify = digest_generic_verify, .length = SHA512_SUM_LEN, .ctx_length = sizeof(sha4_context), diff --git a/include/digest.h b/include/digest.h index 5d1d80c31d..718793a1a7 100644 --- a/include/digest.h +++ b/include/digest.h @@ -31,6 +31,8 @@ struct digest_algo { int (*init)(struct digest *d); int (*update)(struct digest *d, const void *data, unsigned long len); int (*final)(struct digest *d, unsigned char *md); + int (*digest)(struct digest *d, const void *data, + unsigned int len, u8 *out); int (*set_key)(struct digest *d, const unsigned char *key, unsigned int len); int (*verify)(struct digest *d, const unsigned char *md); @@ -78,6 +80,12 @@ static inline int digest_final(struct digest *d, unsigned char *md) return d->algo->final(d, md); } +static inline int digest_digest(struct digest *d, const void *data, + unsigned int len, u8 *md) +{ + return d->algo->digest(d, data, len, md); +} + static inline int digest_verify(struct digest *d, const unsigned char *md) { return d->algo->verify(d, md); -- cgit v1.2.3 From 5f5d5331bb5e029264b9bc0cfbb3c32ec3158638 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 17 Mar 2015 12:53:13 +0100 Subject: crypto: add pbkdf2 hmac key generator this will allow to generate a KEY + IV based on a password and salt for AES encryption/decryption as example or simply the key for hmac or rsa from text password Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- crypto/Kconfig | 5 +++ crypto/Makefile | 2 ++ crypto/pbkdf2.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ include/crypto/pbkdf2.h | 23 ++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 crypto/pbkdf2.c create mode 100644 include/crypto/pbkdf2.h (limited to 'include') diff --git a/crypto/Kconfig b/crypto/Kconfig index e72b91ef79..b721e3049e 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -34,3 +34,8 @@ config DIGEST_HMAC bool "HMAC" endif + +config CRYPTO_PBKDF2 + select DIGEST + select SHA1 + bool diff --git a/crypto/Makefile b/crypto/Makefile index ff5c289ce1..0bb67d5e23 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -9,3 +9,5 @@ obj-$(CONFIG_SHA224) += sha2.o obj-$(CONFIG_SHA256) += sha2.o obj-$(CONFIG_SHA384) += sha4.o obj-$(CONFIG_SHA512) += sha4.o + +obj-$(CONFIG_CRYPTO_PBKDF2) += pbkdf2.o diff --git a/crypto/pbkdf2.c b/crypto/pbkdf2.c new file mode 100644 index 0000000000..c4ba7be5ef --- /dev/null +++ b/crypto/pbkdf2.c @@ -0,0 +1,94 @@ +/* + * (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD + * + * Under GPLv2 Only + */ + +#include +#include +#include +#include + +int pkcs5_pbkdf2_hmac(struct digest* d, + const unsigned char *pwd, size_t pwd_len, + const unsigned char *salt, size_t salt_len, + uint32_t iteration, + uint32_t key_len, unsigned char *key) +{ + int i, j, k; + unsigned char cnt[4]; + uint32_t pass_len; + unsigned char *tmpdgt; + uint32_t d_len; + int ret; + + if (!d) + return -EINVAL; + + d_len = digest_length(d); + tmpdgt = malloc(d_len); + if (!tmpdgt) + return -ENOMEM; + + i = 1; + + ret = digest_set_key(d, pwd, pwd_len); + if (ret) + goto err; + + while (key_len) { + pass_len = min(key_len, d_len); + cnt[0] = (i >> 24) & 0xff; + cnt[1] = (i >> 16) & 0xff; + cnt[2] = (i >> 8) & 0xff; + cnt[3] = i & 0xff; + ret = digest_init(d); + if (ret) + goto err; + ret = digest_update(d, salt, salt_len); + if (ret) + goto err; + ret = digest_update(d, cnt, 4); + if (ret) + goto err; + ret = digest_final(d, tmpdgt); + if (ret) + goto err; + + memcpy(key, tmpdgt, pass_len); + + for (j = 1; j < iteration; j++) { + ret = digest_digest(d, tmpdgt, d_len, tmpdgt); + if (ret) + goto err; + + for(k = 0; k < pass_len; k++) + key[k] ^= tmpdgt[k]; + } + + key_len -= pass_len; + key += pass_len; + i++; + } + + ret = 0; +err: + free(tmpdgt); + + return ret;; +} + +int pkcs5_pbkdf2_hmac_sha1(const unsigned char *pwd, size_t pwd_len, + const unsigned char *salt, size_t salt_len, + uint32_t iter, + uint32_t key_len, unsigned char *key) +{ + int ret; + struct digest* d = digest_alloc("hmac(sha1)"); + + ret = pkcs5_pbkdf2_hmac(d, pwd, pwd_len, salt, salt_len, iter, + key_len, key); + + digest_free(d); + return ret; +} diff --git a/include/crypto/pbkdf2.h b/include/crypto/pbkdf2.h new file mode 100644 index 0000000000..fa66675261 --- /dev/null +++ b/include/crypto/pbkdf2.h @@ -0,0 +1,23 @@ +/* + * (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD + * + * Under GPLv2 Only + */ + +#ifndef __PBKDF2_H__ +#define __PBKDF2_H__ + +#include + +int pkcs5_pbkdf2_hmac_sha1(const unsigned char *pwd, size_t pwd_len, + const unsigned char *salt, size_t salt_len, + uint32_t iteration, + uint32_t key_len, unsigned char *buf); + +int pkcs5_pbkdf2_hmac(struct digest* d, + const unsigned char *pwd, size_t pwd_len, + const unsigned char *salt, size_t salt_len, + uint32_t iteration, + uint32_t key_len, unsigned char *key); + +#endif /* __PBKDF2_H__ */ -- cgit v1.2.3 From 9f15b421057304c17556a75b439eef42a9d38436 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 17 Mar 2015 12:53:14 +0100 Subject: command: allow runtime usage This will allow as example to list the currently supported digest. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- common/command.c | 2 ++ include/command.h | 3 +++ 2 files changed, 5 insertions(+) (limited to 'include') diff --git a/common/command.c b/common/command.c index 61191c2d62..dc2cb88eaf 100644 --- a/common/command.c +++ b/common/command.c @@ -47,6 +47,8 @@ void barebox_cmd_usage(struct command *cmdtp) puts(cmdtp->help); putchar('\n'); } + if (cmdtp->usage) + cmdtp->usage(); #endif } EXPORT_SYMBOL(barebox_cmd_usage); diff --git a/include/command.h b/include/command.h index 5d5bf53544..3aca1a9f1b 100644 --- a/include/command.h +++ b/include/command.h @@ -54,6 +54,7 @@ struct command { uint32_t group; #ifdef CONFIG_LONGHELP const char *help; /* Help message (long) */ + void (*usage)(void); #endif } #ifdef __x86_64__ @@ -115,8 +116,10 @@ static const __maybe_unused char cmd_##_name##_help[] = #ifdef CONFIG_LONGHELP #define BAREBOX_CMD_HELP(text) .help = text, +#define BAREBOX_CMD_USAGE(fn) .usage = fn, #else #define BAREBOX_CMD_HELP(text) +#define BAREBOX_CMD_USAGE(fn) #endif #define BAREBOX_CMD_GROUP(grp) .group = grp, -- cgit v1.2.3 From df4b6f133b5e63d33e1029b21cd6998ff51b5be3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 13 Mar 2015 08:23:30 +0100 Subject: lib: Add hex2bin and bin2hex implementations Taken from the Kernel, put into the same place as in the kernel, although the hexdump.c does not actually contain hexdum functions. Signed-off-by: Sascha Hauer --- include/linux/kernel.h | 4 +++ lib/Makefile | 1 + lib/hexdump.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/misc.c | 2 -- 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 lib/hexdump.c (limited to 'include') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 5b6b448395..945e063f02 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -246,6 +246,10 @@ static inline char *hex_byte_pack_upper(char *buf, u8 byte) return buf; } +extern int hex_to_bin(char ch); +extern int __must_check hex2bin(u8 *dst, const char *src, size_t count); +extern char *bin2hex(char *dst, const void *src, size_t count); + /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. diff --git a/lib/Makefile b/lib/Makefile index f08ac5937d..6a3e9fdc8e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -53,3 +53,4 @@ obj-y += wchar.o obj-y += libfile.o obj-y += bitmap.o obj-y += gcd.o +obj-y += hexdump.o diff --git a/lib/hexdump.c b/lib/hexdump.c new file mode 100644 index 0000000000..3b1d5e6736 --- /dev/null +++ b/lib/hexdump.c @@ -0,0 +1,74 @@ +/* + * lib/hexdump.c + * + * 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. See README and COPYING for + * more details. + */ + +#include +#include +#include + +const char hex_asc[] = "0123456789abcdef"; +EXPORT_SYMBOL(hex_asc); +const char hex_asc_upper[] = "0123456789ABCDEF"; +EXPORT_SYMBOL(hex_asc_upper); + +/** + * hex_to_bin - convert a hex digit to its real value + * @ch: ascii character represents hex digit + * + * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad + * input. + */ +int hex_to_bin(char ch) +{ + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + ch = tolower(ch); + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + return -1; +} +EXPORT_SYMBOL(hex_to_bin); + +/** + * hex2bin - convert an ascii hexadecimal string to its binary representation + * @dst: binary result + * @src: ascii hexadecimal string + * @count: result length + * + * Return 0 on success, -1 in case of bad input. + */ +int hex2bin(u8 *dst, const char *src, size_t count) +{ + while (count--) { + int hi = hex_to_bin(*src++); + int lo = hex_to_bin(*src++); + + if ((hi < 0) || (lo < 0)) + return -1; + + *dst++ = (hi << 4) | lo; + } + return 0; +} +EXPORT_SYMBOL(hex2bin); + +/** + * bin2hex - convert binary data to an ascii hexadecimal string + * @dst: ascii hexadecimal result + * @src: binary data + * @count: binary data length + */ +char *bin2hex(char *dst, const void *src, size_t count) +{ + const unsigned char *_src = src; + + while (count--) + dst = hex_byte_pack(dst, *_src++); + return dst; +} +EXPORT_SYMBOL(bin2hex); diff --git a/lib/misc.c b/lib/misc.c index 87626c1e8b..62ddd66779 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -114,5 +114,3 @@ int parse_area_spec(const char *str, loff_t *start, loff_t *size) return -1; } EXPORT_SYMBOL(parse_area_spec); - -const char hex_asc[] = "0123456789abcdef"; -- cgit v1.2.3 From b0be99fc10e50c41b75647a2486c05f9bd47f1c3 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 17 Mar 2015 12:53:16 +0100 Subject: command: add generic digest command That can be used for digest calculation and verify Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- commands/Kconfig | 12 +++- commands/Makefile | 1 + commands/digest.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++ commands/hashsum.c | 76 ++++---------------- commands/internal.h | 3 + crypto/digest.c | 25 +++++-- include/digest.h | 8 ++- 7 files changed, 260 insertions(+), 69 deletions(-) create mode 100644 commands/digest.c create mode 100644 commands/internal.h (limited to 'include') diff --git a/commands/Kconfig b/commands/Kconfig index 49709ded67..2618eda2f6 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -14,7 +14,7 @@ if COMMAND_SUPPORT config COMPILE_HASH tristate - select DIGEST + select CMD_DIGEST help Turns on compilation of digest.c @@ -842,6 +842,16 @@ config CMD_CMP Returns successfully if the two files are the same, return with an error if not +config CMD_DIGEST + tristate + select DIGEST + prompt "digest" + help + Usage: digest -a [-k | -K ] [-s | -S ] FILE|AREA + + Calculate a digest over a FILE or a memory area with the possibility + to checkit. + config CMD_DIRNAME tristate prompt "dirname" diff --git a/commands/Makefile b/commands/Makefile index 095e4b624e..d69e3f0b06 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_STDDEV) += stddev.o +obj-$(CONFIG_CMD_DIGEST) += digest.o obj-$(CONFIG_COMPILE_HASH) += hashsum.o obj-$(CONFIG_COMPILE_MEMORY) += mem.o obj-$(CONFIG_CMD_BOOTM) += bootm.o diff --git a/commands/digest.c b/commands/digest.c new file mode 100644 index 0000000000..ef95e94816 --- /dev/null +++ b/commands/digest.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 ONLY + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +int __do_digest(struct digest *d, unsigned char *key, int keylen, + unsigned char *sig, + int argc, char *argv[]) +{ + int ret = COMMAND_ERROR_USAGE; + int i; + unsigned char *hash; + + if (argc < 1) + goto err; + + if (key) { + ret = digest_set_key(d, key, keylen); + if (ret) { + perror("set_key"); + goto err; + } + } + + hash = calloc(digest_length(d), sizeof(unsigned char)); + if (!hash) { + perror("calloc"); + goto err; + } + + while (*argv) { + char *filename = "/dev/mem"; + loff_t start = 0, size = ~0; + + /* arguments are either file, file+area or area */ + if (parse_area_spec(*argv, &start, &size)) { + filename = *argv; + if (argv[1] && !parse_area_spec(argv[1], &start, &size)) + argv++; + } + + ret = digest_file_window(d, filename, + hash, sig, start, size); + if (ret < 0) { + ret = 1; + } else { + if (!sig) { + for (i = 0; i < digest_length(d); i++) + printf("%02x", hash[i]); + + printf(" %s\t0x%08llx ... 0x%08llx\n", + filename, start, start + size); + } + } + + argv++; + } + + free(hash); +err: + digest_free(d); + + return ret; +} + +static void prints_algo_help(void) +{ + puts("\navailable algo:\n"); + digest_algo_prints("\t"); +} + +static int do_digest(int argc, char *argv[]) +{ + struct digest *d; + unsigned char *tmp_key = NULL; + unsigned char *tmp_sig = NULL; + char *sig = NULL; + char *sigfile = NULL; + size_t siglen = 0; + char *key = NULL; + char *keyfile = NULL; + size_t keylen = 0; + size_t digestlen = 0; + char *algo = NULL; + int opt; + int ret = COMMAND_ERROR; + + if (argc < 2) + return COMMAND_ERROR_USAGE; + + while((opt = getopt(argc, argv, "a:k:K:s:S:")) > 0) { + switch(opt) { + case 'k': + key = optarg; + keylen = strlen(key); + break; + case 'K': + keyfile = optarg; + break; + case 'a': + algo = optarg; + break; + case 's': + sig = optarg; + siglen = strlen(sig); + break; + case 'S': + sigfile = optarg; + break; + } + } + + if (!algo) + return COMMAND_ERROR_USAGE; + + d = digest_alloc(algo); + if (!d) { + eprintf("algo '%s' not found\n", algo); + return COMMAND_ERROR_USAGE; + } + + argc -= optind; + argv += optind; + + if (keyfile) { + tmp_key = key = read_file(keyfile, &keylen); + if (!key) { + eprintf("file '%s' not found\n", keyfile); + goto err; + } + } + + ret = digest_set_key(d, key, keylen); + free(tmp_key); + if (ret) + goto err; + + if (sigfile) { + sig = tmp_sig = read_file(sigfile, &siglen); + if (!tmp_sig) { + eprintf("file '%s' not found\n", sigfile); + goto err; + } + } + + if (sig) { + digestlen = digest_length(d); + if (siglen == 2 * digestlen) { + if (!tmp_sig) + tmp_sig = xmalloc(digestlen); + + ret = hex2bin(tmp_sig, sig, digestlen); + if (ret) + goto err; + + sig = tmp_sig; + } else if (siglen != digestlen) { + eprintf("%s wrong size %zu, expected %zu\n", + sigfile, siglen, digestlen); + goto err; + } + } + + ret = __do_digest(d, NULL, 0, sig, argc, argv); + free(tmp_sig); + return ret; + +err: + digest_free(d); + return ret; +} + +BAREBOX_CMD_HELP_START(digest) +BAREBOX_CMD_HELP_TEXT("Calculate a digest over a FILE or a memory area.") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-a \t", "hash or signature algorithm to use") +BAREBOX_CMD_HELP_OPT ("-k \t", "use supplied (ASCII or hex) for MAC") +BAREBOX_CMD_HELP_OPT ("-K \t", "use key from (binary) for MAC") +BAREBOX_CMD_HELP_OPT ("-v \t", "verify data against supplied (hash, MAC or signature)") +BAREBOX_CMD_HELP_OPT ("-V \t", "verify data against (hash, MAC or signature)") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(digest) + .cmd = do_digest, + BAREBOX_CMD_DESC("calculate digest") + BAREBOX_CMD_OPTS("-a [-k | -K ] [-s | -S ] FILE|AREA") + BAREBOX_CMD_GROUP(CMD_GRP_FILE) + BAREBOX_CMD_HELP(cmd_digest_help) + BAREBOX_CMD_USAGE(prints_algo_help) +BAREBOX_CMD_END diff --git a/commands/hashsum.c b/commands/hashsum.c index 59c94ea2bf..dc48af53d8 100644 --- a/commands/hashsum.c +++ b/commands/hashsum.c @@ -27,12 +27,11 @@ #include #include -static int do_digest(char *algorithm, int argc, char *argv[]) +#include "internal.h" + +static int do_hash(char *algo, int argc, char *argv[]) { struct digest *d; - int ret = 0; - int i; - unsigned char *hash; unsigned char *key = NULL; size_t keylen = 0; int opt; @@ -46,71 +45,26 @@ static int do_digest(char *algorithm, int argc, char *argv[]) } } - argc -= optind; - argv += optind; - if (key) { - char *tmp = asprintf("hmac(%s)", algorithm); + char *tmp = asprintf("hmac(%s)", algo); d = digest_alloc(tmp); - BUG_ON(!d); - ret = digest_set_key(d, key, keylen); free(tmp); - if (ret) { - perror("set_key"); - goto err; - } } else { - d = digest_alloc(algorithm); - BUG_ON(!d); - } - - if (argc < 1) - return COMMAND_ERROR_USAGE; - - hash = calloc(digest_length(d), sizeof(unsigned char)); - if (!hash) { - perror("calloc"); - return COMMAND_ERROR_USAGE; - } - - while (*argv) { - char *filename = "/dev/mem"; - loff_t start = 0, size = ~0; - - /* arguments are either file, file+area or area */ - if (parse_area_spec(*argv, &start, &size)) { - filename = *argv; - if (argv[0] && !parse_area_spec(argv[0], &start, &size)) - argv++; - } - - ret = digest_file_window(d, filename, - hash, start, size); - if (ret < 0) { - ret = 1; - } else { - for (i = 0; i < digest_length(d); i++) - printf("%02x", hash[i]); - - printf(" %s\t0x%08llx ... 0x%08llx\n", - filename, start, start + size); - } - - argv++; + d = digest_alloc(algo); } + BUG_ON(!d); -err: - free(hash); - digest_free(d); + argc -= optind; + argv += optind; - return ret; + return __do_digest(d, key, keylen, NULL, argc, argv); } #ifdef CONFIG_CMD_MD5SUM static int do_md5(int argc, char *argv[]) { - return do_digest("md5", argc, argv); + return do_hash("md5", argc, argv); } BAREBOX_CMD_HELP_START(md5sum) @@ -131,7 +85,7 @@ BAREBOX_CMD_END static int do_sha1(int argc, char *argv[]) { - return do_digest("sha1", argc, argv); + return do_hash("sha1", argc, argv); } BAREBOX_CMD_HELP_START(sha1sum) @@ -152,7 +106,7 @@ BAREBOX_CMD_END static int do_sha224(int argc, char *argv[]) { - return do_digest("sha224", argc, argv); + return do_hash("sha224", argc, argv); } BAREBOX_CMD_HELP_START(sha224sum) @@ -173,7 +127,7 @@ BAREBOX_CMD_END static int do_sha256(int argc, char *argv[]) { - return do_digest("sha256", argc, argv); + return do_hash("sha256", argc, argv); } BAREBOX_CMD_HELP_START(sha256sum) @@ -194,7 +148,7 @@ BAREBOX_CMD_END static int do_sha384(int argc, char *argv[]) { - return do_digest("sha384", argc, argv); + return do_hash("sha384", argc, argv); } BAREBOX_CMD_HELP_START(sha384sum) @@ -215,7 +169,7 @@ BAREBOX_CMD_END static int do_sha512(int argc, char *argv[]) { - return do_digest("sha512", argc, argv); + return do_hash("sha512", argc, argv); } BAREBOX_CMD_HELP_START(sha512sum) diff --git a/commands/internal.h b/commands/internal.h new file mode 100644 index 0000000000..29cc656e9b --- /dev/null +++ b/commands/internal.h @@ -0,0 +1,3 @@ +int __do_digest(struct digest *d, unsigned char *key, int keylen, + unsigned char *sig, + int argc, char *argv[]); diff --git a/crypto/digest.c b/crypto/digest.c index 7670ed06b7..047131b537 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -124,6 +124,15 @@ static struct digest_algo *digest_algo_get_by_name(const char *name) return NULL; } +void digest_algo_prints(const char *prefix) +{ + struct digest_algo* d; + + list_for_each_entry(d, &digests, list) { + printf("%s%s\n", prefix, d->name); + } +} + struct digest *digest_alloc(const char *name) { struct digest *d; @@ -157,6 +166,7 @@ EXPORT_SYMBOL_GPL(digest_free); int digest_file_window(struct digest *d, const char *filename, unsigned char *hash, + unsigned char *sig, ulong start, ulong size) { ulong len = 0; @@ -217,7 +227,10 @@ int digest_file_window(struct digest *d, const char *filename, len += now; } - ret = digest_final(d, hash); + if (sig) + ret = digest_verify(d, sig); + else + ret = digest_final(d, hash); out_free: if (flags) @@ -230,7 +243,8 @@ out: EXPORT_SYMBOL_GPL(digest_file_window); int digest_file(struct digest *d, const char *filename, - unsigned char *hash) + unsigned char *hash, + unsigned char *sig) { struct stat st; int ret; @@ -240,12 +254,13 @@ int digest_file(struct digest *d, const char *filename, if (ret < 0) return ret; - return digest_file_window(d, filename, hash, 0, st.st_size); + return digest_file_window(d, filename, hash, sig, 0, st.st_size); } EXPORT_SYMBOL_GPL(digest_file); int digest_file_by_name(const char *algo, const char *filename, - unsigned char *hash) + unsigned char *hash, + unsigned char *sig) { struct digest *d; int ret; @@ -254,7 +269,7 @@ int digest_file_by_name(const char *algo, const char *filename, if (!d) return -EIO; - ret = digest_file(d, filename, hash); + ret = digest_file(d, filename, hash, sig); digest_free(d); return ret; } diff --git a/include/digest.h b/include/digest.h index 718793a1a7..cb579ee03d 100644 --- a/include/digest.h +++ b/include/digest.h @@ -52,17 +52,21 @@ struct digest { */ int digest_algo_register(struct digest_algo *d); void digest_algo_unregister(struct digest_algo *d); +void digest_algo_prints(const char *prefix); struct digest *digest_alloc(const char *name); void digest_free(struct digest *d); int digest_file_window(struct digest *d, const char *filename, unsigned char *hash, + unsigned char *sig, ulong start, ulong size); int digest_file(struct digest *d, const char *filename, - unsigned char *hash); + unsigned char *hash, + unsigned char *sig); int digest_file_by_name(const char *algo, const char *filename, - unsigned char *hash); + unsigned char *hash, + unsigned char *sig); static inline int digest_init(struct digest *d) { -- cgit v1.2.3 From ca95c2531f7ff68c95cfa205623e157e720615f0 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 18 Mar 2015 10:37:53 +0100 Subject: crypto: digest: speficied when a digest need a key to be used such as for hmac(xxx) you must provide a key This will allow to enforce the correct parameter at digest command sum is not impacted Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- commands/digest.c | 3 +++ crypto/hmac.c | 1 + include/digest.h | 12 ++++++++++++ 3 files changed, 16 insertions(+) (limited to 'include') diff --git a/commands/digest.c b/commands/digest.c index ef95e94816..b6bce88297 100644 --- a/commands/digest.c +++ b/commands/digest.c @@ -34,6 +34,9 @@ int __do_digest(struct digest *d, unsigned char *key, int keylen, perror("set_key"); goto err; } + } else if (digest_is_flags(d, DIGEST_ALGO_NEED_KEY)) { + eprintf("%s need a key to be used\n", digest_name(d)); + goto err; } hash = calloc(digest_length(d), sizeof(unsigned char)); diff --git a/crypto/hmac.c b/crypto/hmac.c index c2195d972e..4c6a703e5e 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -145,6 +145,7 @@ err: } struct digest_algo hmac_algo = { + .flags = DIGEST_ALGO_NEED_KEY, .alloc = digest_hmac_alloc, .init = digest_hmac_init, .update = digest_hmac_update, diff --git a/include/digest.h b/include/digest.h index cb579ee03d..85c4da36f5 100644 --- a/include/digest.h +++ b/include/digest.h @@ -25,6 +25,8 @@ struct digest; struct digest_algo { char *name; +#define DIGEST_ALGO_NEED_KEY (1 << 0) + unsigned int flags; int (*alloc)(struct digest *d); void (*free)(struct digest *d); @@ -108,4 +110,14 @@ static inline int digest_set_key(struct digest *d, const unsigned char *key, return d->algo->set_key(d, key, len); } +static inline int digest_is_flags(struct digest *d, unsigned int flags) +{ + return d->algo->flags & flags; +} + +static inline const char *digest_name(struct digest *d) +{ + return d->algo->name; +} + #endif /* __SH_ST_DEVICES_H__ */ -- cgit v1.2.3 From e10cc0b3330d4dd72fef076a7f1b2b67cb271a12 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 25 Mar 2015 12:56:13 +0100 Subject: digest: allow algo to specify their length at runtime such as RSA as we load a DER key we will detect the key size at runtime and so the algo length. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- crypto/digest.c | 3 +-- include/digest.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/crypto/digest.c b/crypto/digest.c index 047131b537..f902dc1fb1 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -78,8 +78,7 @@ int digest_generic_digest(struct digest *d, const void *data, int digest_algo_register(struct digest_algo *d) { - if (!d || !d->name || !d->update || !d->final || !d->verify || - d->length < 1) + if (!d || !d->name || !d->update || !d->final || !d->verify) return -EINVAL; if (!d->init) diff --git a/include/digest.h b/include/digest.h index 85c4da36f5..c574b4d568 100644 --- a/include/digest.h +++ b/include/digest.h @@ -47,6 +47,7 @@ struct digest_algo { struct digest { struct digest_algo *algo; void *ctx; + unsigned int length; }; /* @@ -99,7 +100,7 @@ static inline int digest_verify(struct digest *d, const unsigned char *md) static inline int digest_length(struct digest *d) { - return d->algo->length; + return d->length ? d->length : d->algo->length; } static inline int digest_set_key(struct digest *d, const unsigned char *key, -- cgit v1.2.3 From ab5b2c35e143a87483700ca92d7fd50292a891d0 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 25 Mar 2015 12:56:14 +0100 Subject: crypto: prepare to allow multiple digest driver This will allow to have hw driver or asm optimised driver. Use a priority level to determine which one to use at runtime. The generic one will be 0. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- arch/arm/configs/at91rm9200ek_defconfig | 4 +-- arch/arm/configs/highbank_defconfig | 4 +-- arch/arm/configs/mioa701_defconfig | 2 +- arch/arm/configs/module-mb7707_defconfig | 4 +-- arch/arm/configs/nhk8815_defconfig | 2 +- arch/arm/configs/phytec-phycard-omap3_defconfig | 6 ++-- arch/arm/configs/rpi_defconfig | 4 +-- arch/arm/configs/versatilepb_arm1176_defconfig | 4 +-- arch/arm/configs/versatilepb_defconfig | 4 +-- arch/arm/configs/vexpress_ca9_defconfig | 4 +-- arch/arm/configs/vexpress_defconfig | 4 +-- arch/arm/configs/virt2real_defconfig | 4 +-- arch/arm/configs/zylonite310_defconfig | 2 +- arch/mips/configs/img-ci20_defconfig | 6 ++-- arch/mips/configs/ritmix-rzx50_defconfig | 6 ++-- arch/mips/configs/tplink-mr3020_defconfig | 4 +-- crypto/Kconfig | 40 +++++++++++++++++++++---- crypto/Makefile | 14 ++++----- crypto/digest.c | 31 +++++++++++-------- crypto/hmac.c | 16 ++++++---- crypto/internal.h | 19 ------------ crypto/md5.c | 9 ++++-- crypto/sha1.c | 9 ++++-- crypto/sha2.c | 17 ++++++++--- crypto/sha4.c | 17 ++++++++--- include/crypto/internal.h | 19 ++++++++++++ include/digest.h | 12 ++++++-- 27 files changed, 170 insertions(+), 97 deletions(-) delete mode 100644 crypto/internal.h create mode 100644 include/crypto/internal.h (limited to 'include') diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig index 54e3b1d8b8..03fca04cb7 100644 --- a/arch/arm/configs/at91rm9200ek_defconfig +++ b/arch/arm/configs/at91rm9200ek_defconfig @@ -76,5 +76,5 @@ CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_LED_TRIGGERS=y CONFIG_FS_CRAMFS=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/highbank_defconfig b/arch/arm/configs/highbank_defconfig index cf42d29622..8c965c83a5 100644 --- a/arch/arm/configs/highbank_defconfig +++ b/arch/arm/configs/highbank_defconfig @@ -59,5 +59,5 @@ CONFIG_DISK=y CONFIG_DISK_AHCI=y CONFIG_GPIO_PL061=y CONFIG_FS_TFTP=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/mioa701_defconfig b/arch/arm/configs/mioa701_defconfig index d405edf01b..cc4587ccbd 100644 --- a/arch/arm/configs/mioa701_defconfig +++ b/arch/arm/configs/mioa701_defconfig @@ -104,4 +104,4 @@ CONFIG_FS_UBIFS_COMPRESSION_ZLIB=y CONFIG_BZLIB=y CONFIG_BMP=y CONFIG_PNG=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/module-mb7707_defconfig b/arch/arm/configs/module-mb7707_defconfig index 843dd59889..83a798bac1 100644 --- a/arch/arm/configs/module-mb7707_defconfig +++ b/arch/arm/configs/module-mb7707_defconfig @@ -45,5 +45,5 @@ CONFIG_USB_HOST=y CONFIG_USB_EHCI=y CONFIG_USB_STORAGE=y CONFIG_CLOCKSOURCE_DUMMY=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig index dcb00c0755..46c3a68e53 100644 --- a/arch/arm/configs/nhk8815_defconfig +++ b/arch/arm/configs/nhk8815_defconfig @@ -55,4 +55,4 @@ CONFIG_MTD_NAND_NOMADIK=y CONFIG_UBI=y CONFIG_FS_CRAMFS=y CONFIG_MD5=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/phytec-phycard-omap3_defconfig b/arch/arm/configs/phytec-phycard-omap3_defconfig index aefc78d5ca..a2564d4459 100644 --- a/arch/arm/configs/phytec-phycard-omap3_defconfig +++ b/arch/arm/configs/phytec-phycard-omap3_defconfig @@ -173,6 +173,6 @@ CONFIG_CRC32=y CONFIG_CRC16=y CONFIG_DIGEST=y CONFIG_MD5=y -CONFIG_SHA1=y -CONFIG_SHA224=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA224_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/rpi_defconfig b/arch/arm/configs/rpi_defconfig index c6b2c50c7b..25770a007f 100644 --- a/arch/arm/configs/rpi_defconfig +++ b/arch/arm/configs/rpi_defconfig @@ -64,5 +64,5 @@ CONFIG_FS_EXT4=y CONFIG_FS_FAT=y CONFIG_FS_FAT_WRITE=y CONFIG_FS_FAT_LFN=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/versatilepb_arm1176_defconfig b/arch/arm/configs/versatilepb_arm1176_defconfig index ca0ab3603f..cefdb296a1 100644 --- a/arch/arm/configs/versatilepb_arm1176_defconfig +++ b/arch/arm/configs/versatilepb_arm1176_defconfig @@ -95,5 +95,5 @@ CONFIG_FS_EXT4=y CONFIG_FS_TFTP=y CONFIG_FS_NFS=y CONFIG_PNG=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/versatilepb_defconfig b/arch/arm/configs/versatilepb_defconfig index 54a6fec919..0876824f66 100644 --- a/arch/arm/configs/versatilepb_defconfig +++ b/arch/arm/configs/versatilepb_defconfig @@ -81,5 +81,5 @@ CONFIG_FS_CRAMFS=y CONFIG_FS_EXT4=y CONFIG_FS_TFTP=y CONFIG_FS_NFS=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/vexpress_ca9_defconfig b/arch/arm/configs/vexpress_ca9_defconfig index 84171c473d..c5ad315a8c 100644 --- a/arch/arm/configs/vexpress_ca9_defconfig +++ b/arch/arm/configs/vexpress_ca9_defconfig @@ -58,5 +58,5 @@ CONFIG_DRIVER_CFI=y # CONFIG_DRIVER_CFI_BANK_WIDTH_1 is not set # CONFIG_DRIVER_CFI_BANK_WIDTH_2 is not set CONFIG_FS_TFTP=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/vexpress_defconfig b/arch/arm/configs/vexpress_defconfig index c7928c45a5..beea11aece 100644 --- a/arch/arm/configs/vexpress_defconfig +++ b/arch/arm/configs/vexpress_defconfig @@ -57,5 +57,5 @@ CONFIG_DRIVER_CFI=y # CONFIG_DRIVER_CFI_BANK_WIDTH_1 is not set # CONFIG_DRIVER_CFI_BANK_WIDTH_2 is not set CONFIG_FS_TFTP=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/virt2real_defconfig b/arch/arm/configs/virt2real_defconfig index a81d18b25b..0c686caadf 100644 --- a/arch/arm/configs/virt2real_defconfig +++ b/arch/arm/configs/virt2real_defconfig @@ -45,5 +45,5 @@ CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_LED_GPIO_OF=y -CONFIG_SHA1=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/arm/configs/zylonite310_defconfig b/arch/arm/configs/zylonite310_defconfig index 77e4f84ff1..fa6587c0ee 100644 --- a/arch/arm/configs/zylonite310_defconfig +++ b/arch/arm/configs/zylonite310_defconfig @@ -114,4 +114,4 @@ CONFIG_FS_UBIFS_COMPRESSION_ZLIB=y CONFIG_BZLIB=y CONFIG_BMP=y CONFIG_PNG=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/mips/configs/img-ci20_defconfig b/arch/mips/configs/img-ci20_defconfig index 56235c4cf3..6702c88b65 100644 --- a/arch/mips/configs/img-ci20_defconfig +++ b/arch/mips/configs/img-ci20_defconfig @@ -37,6 +37,6 @@ CONFIG_OFDEVICE=y # CONFIG_SPI is not set CONFIG_CLOCKSOURCE_DUMMY=y CONFIG_CLOCKSOURCE_DUMMY_RATE=3500 -CONFIG_SHA1=y -CONFIG_SHA224=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA224_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/mips/configs/ritmix-rzx50_defconfig b/arch/mips/configs/ritmix-rzx50_defconfig index 0814883e89..eedb329ee5 100644 --- a/arch/mips/configs/ritmix-rzx50_defconfig +++ b/arch/mips/configs/ritmix-rzx50_defconfig @@ -46,6 +46,6 @@ CONFIG_LED_TRIGGERS=y CONFIG_GPIO_JZ4740=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_JZ4740=y -CONFIG_SHA1=y -CONFIG_SHA224=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA1_GENERIC=y +CONFIG_DIGEST_SHA224_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/arch/mips/configs/tplink-mr3020_defconfig b/arch/mips/configs/tplink-mr3020_defconfig index d249919bed..9f81ce39dc 100644 --- a/arch/mips/configs/tplink-mr3020_defconfig +++ b/arch/mips/configs/tplink-mr3020_defconfig @@ -30,5 +30,5 @@ CONFIG_MTD=y # CONFIG_MTD_OOB_DEVICE is not set CONFIG_MTD_M25P80=y CONFIG_MD5=y -CONFIG_SHA224=y -CONFIG_SHA256=y +CONFIG_DIGEST_SHA224_GENERIC=y +CONFIG_DIGEST_SHA256_GENERIC=y diff --git a/crypto/Kconfig b/crypto/Kconfig index b721e3049e..5a69236e5f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -13,25 +13,53 @@ menuconfig DIGEST if DIGEST config MD5 - bool "MD5" + bool config SHA1 - bool "SHA1" + bool config SHA224 - bool "SHA224" + bool config SHA256 - bool "SHA256" + bool config SHA384 - bool "SHA384" + bool config SHA512 - bool "SHA512" + bool config DIGEST_HMAC + bool + +config DIGEST_MD5_GENERIC + bool "MD5" + select MD5 + +config DIGEST_SHA1_GENERIC + bool "SHA1" + select SHA1 + +config DIGEST_SHA224_GENERIC + bool "SHA224" + select SHA224 + +config DIGEST_SHA256_GENERIC + bool "SHA256" + select SHA256 + +config DIGEST_SHA384_GENERIC + bool "SHA384" + select SHA384 + +config DIGEST_SHA512_GENERIC + bool "SHA512" + select SHA512 + +config DIGEST_HMAC_GENERIC bool "HMAC" + select DIGEST_HMAC endif diff --git a/crypto/Makefile b/crypto/Makefile index 0bb67d5e23..f39de718e5 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -2,12 +2,12 @@ obj-$(CONFIG_CRC32) += crc32.o obj-$(CONFIG_CRC16) += crc16.o obj-$(CONFIG_CRC7) += crc7.o obj-$(CONFIG_DIGEST) += digest.o -obj-$(CONFIG_DIGEST_HMAC) += hmac.o -obj-$(CONFIG_MD5) += md5.o -obj-$(CONFIG_SHA1) += sha1.o -obj-$(CONFIG_SHA224) += sha2.o -obj-$(CONFIG_SHA256) += sha2.o -obj-$(CONFIG_SHA384) += sha4.o -obj-$(CONFIG_SHA512) += sha4.o +obj-$(CONFIG_DIGEST_HMAC_GENERIC) += hmac.o +obj-$(CONFIG_DIGEST_MD5_GENERIC) += md5.o +obj-$(CONFIG_DIGEST_SHA1_GENERIC) += sha1.o +obj-$(CONFIG_DIGEST_SHA224_GENERIC) += sha2.o +obj-$(CONFIG_DIGEST_SHA256_GENERIC) += sha2.o +obj-$(CONFIG_DIGEST_SHA384_GENERIC) += sha4.o +obj-$(CONFIG_DIGEST_SHA512_GENERIC) += sha4.o obj-$(CONFIG_CRYPTO_PBKDF2) += pbkdf2.o diff --git a/crypto/digest.c b/crypto/digest.c index f902dc1fb1..b3f514c8ad 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -25,8 +25,7 @@ #include #include #include - -#include "internal.h" +#include static LIST_HEAD(digests); @@ -78,7 +77,7 @@ int digest_generic_digest(struct digest *d, const void *data, int digest_algo_register(struct digest_algo *d) { - if (!d || !d->name || !d->update || !d->final || !d->verify) + if (!d || !d->base.name || !d->update || !d->final || !d->verify) return -EINVAL; if (!d->init) @@ -90,9 +89,6 @@ int digest_algo_register(struct digest_algo *d) if (!d->free) d->free = dummy_free; - if (digest_algo_get_by_name(d->name)) - return -EEXIST; - list_add_tail(&d->list, &digests); return 0; @@ -110,25 +106,36 @@ EXPORT_SYMBOL(digest_algo_unregister); static struct digest_algo *digest_algo_get_by_name(const char *name) { - struct digest_algo *d; + struct digest_algo *d = NULL; + struct digest_algo *tmp; + int priority = -1; if (!name) return NULL; - list_for_each_entry(d, &digests, list) { - if(strcmp(d->name, name) == 0) - return d; + list_for_each_entry(tmp, &digests, list) { + if (strcmp(tmp->base.name, name) != 0) + continue; + + if (tmp->base.priority <= priority) + continue; + + d = tmp; + priority = tmp->base.priority; } - return NULL; + return d; } void digest_algo_prints(const char *prefix) { struct digest_algo* d; + printf("%s%-15s\t%-20s\t%-15s\n", prefix, "name", "driver", "priority"); + printf("%s--------------------------------------------------\n", prefix); list_for_each_entry(d, &digests, list) { - printf("%s%s\n", prefix, d->name); + printf("%s%-15s\t%-20s\t%d\n", prefix, d->base.name, + d->base.driver_name, d->base.priority); } } diff --git a/crypto/hmac.c b/crypto/hmac.c index 4c6a703e5e..77814a1643 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -7,8 +7,7 @@ #include #include #include - -#include "internal.h" +#include struct digest_hmac { char *name; @@ -145,7 +144,10 @@ err: } struct digest_algo hmac_algo = { - .flags = DIGEST_ALGO_NEED_KEY, + .base = { + .priority = 0, + .flags = DIGEST_ALGO_NEED_KEY, + }, .alloc = digest_hmac_alloc, .init = digest_hmac_init, .update = digest_hmac_update, @@ -160,16 +162,20 @@ struct digest_algo hmac_algo = { int digest_hmac_register(struct digest_algo *algo, unsigned int pad_length) { struct digest_hmac *dh; + char *name; if (!algo || !pad_length) return -EINVAL; + name = algo->base.name; dh = xzalloc(sizeof(*dh)); - dh->name = xstrdup(algo->name); + dh->name = xstrdup(name); dh->pad_length = pad_length; dh->algo = hmac_algo; dh->algo.length = algo->length; - dh->algo.name = asprintf("hmac(%s)", algo->name); + dh->algo.base.name = asprintf("hmac(%s)", name); + dh->algo.base.driver_name = asprintf("hmac(%s)-generic", name); + dh->algo.base.priority = algo->base.priority; return digest_algo_register(&dh->algo); } diff --git a/crypto/internal.h b/crypto/internal.h deleted file mode 100644 index c6f5908ea0..0000000000 --- a/crypto/internal.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD - * - * GPL v2 only - */ - -#ifdef CONFIG_DIGEST_HMAC -int digest_hmac_register(struct digest_algo *algo, unsigned int pad_length); -#else -static inline int digest_hmac_register(struct digest_algo *algo, - unsigned int pad_length) -{ - return 0; -} -#endif - -int digest_generic_verify(struct digest *d, const unsigned char *md); -int digest_generic_digest(struct digest *d, const void *data, - unsigned int len, u8 *out); diff --git a/crypto/md5.c b/crypto/md5.c index b7ad6f27e9..74c9b706f0 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -28,8 +28,7 @@ #include #include #include - -#include "internal.h" +#include struct MD5Context { __u32 buf[4]; @@ -290,7 +289,11 @@ static int digest_md5_final(struct digest *d, unsigned char *md) } static struct digest_algo md5 = { - .name = "md5", + .base = { + .name = "md5", + .driver_name = "md5-generic", + .priority = 0, + }, .init = digest_md5_init, .update = digest_md5_update, .final = digest_md5_final, diff --git a/crypto/sha1.c b/crypto/sha1.c index b108f8ae31..a2ca191899 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -26,7 +26,7 @@ #include #include -#include "internal.h" +#include #define SHA1_SUM_POS -0x20 #define SHA1_SUM_LEN 20 @@ -311,7 +311,12 @@ static int digest_sha1_final(struct digest *d, unsigned char *md) } static struct digest_algo m = { - .name = "sha1", + .base = { + .name = "sha1", + .driver_name = "sha1-generic", + .priority = 0, + }, + .init = digest_sha1_init, .update = digest_sha1_update, .final = digest_sha1_final, diff --git a/crypto/sha2.c b/crypto/sha2.c index 375a40e1f6..42c40da757 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -20,8 +20,7 @@ #include #include #include - -#include "internal.h" +#include #define SHA224_SUM_LEN 28 #define SHA256_SUM_LEN 32 @@ -300,7 +299,12 @@ static int digest_sha224_init(struct digest *d) } static struct digest_algo m224 = { - .name = "sha224", + .base = { + .name = "sha224", + .driver_name = "sha224-generic", + .priority = 0, + }, + .init = digest_sha224_init, .update = digest_sha2_update, .final = digest_sha2_final, @@ -332,7 +336,12 @@ static int digest_sha256_init(struct digest *d) } static struct digest_algo m256 = { - .name = "sha256", + .base = { + .name = "sha256", + .driver_name = "sha256-generic", + .priority = 0, + }, + .init = digest_sha256_init, .update = digest_sha2_update, .final = digest_sha2_final, diff --git a/crypto/sha4.c b/crypto/sha4.c index 1b91e7fcc3..cb62d1d2f2 100644 --- a/crypto/sha4.c +++ b/crypto/sha4.c @@ -28,8 +28,7 @@ #include #include #include - -#include "internal.h" +#include #define SHA384_SUM_LEN 48 #define SHA512_SUM_LEN 64 @@ -305,7 +304,12 @@ static int digest_sha384_init(struct digest *d) } static struct digest_algo m384 = { - .name = "sha384", + .base = { + .name = "sha384", + .driver_name = "sha384-generic", + .priority = 0, + }, + .init = digest_sha384_init, .update = digest_sha4_update, .final = digest_sha4_final, @@ -338,7 +342,12 @@ static int digest_sha512_init(struct digest *d) } static struct digest_algo m512 = { - .name = "sha512", + .base = { + .name = "sha512", + .driver_name = "sha512-generic", + .priority = 0, + }, + .init = digest_sha512_init, .update = digest_sha4_update, .final = digest_sha4_final, diff --git a/include/crypto/internal.h b/include/crypto/internal.h new file mode 100644 index 0000000000..c6f5908ea0 --- /dev/null +++ b/include/crypto/internal.h @@ -0,0 +1,19 @@ +/* + * (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD + * + * GPL v2 only + */ + +#ifdef CONFIG_DIGEST_HMAC +int digest_hmac_register(struct digest_algo *algo, unsigned int pad_length); +#else +static inline int digest_hmac_register(struct digest_algo *algo, + unsigned int pad_length) +{ + return 0; +} +#endif + +int digest_generic_verify(struct digest *d, const unsigned char *md); +int digest_generic_digest(struct digest *d, const void *data, + unsigned int len, u8 *out); diff --git a/include/digest.h b/include/digest.h index c574b4d568..00aeee5237 100644 --- a/include/digest.h +++ b/include/digest.h @@ -23,10 +23,16 @@ struct digest; -struct digest_algo { +struct crypto_alg { char *name; + char *driver_name; + int priority; #define DIGEST_ALGO_NEED_KEY (1 << 0) unsigned int flags; +}; + +struct digest_algo { + struct crypto_alg base; int (*alloc)(struct digest *d); void (*free)(struct digest *d); @@ -113,12 +119,12 @@ static inline int digest_set_key(struct digest *d, const unsigned char *key, static inline int digest_is_flags(struct digest *d, unsigned int flags) { - return d->algo->flags & flags; + return d->algo->base.flags & flags; } static inline const char *digest_name(struct digest *d) { - return d->algo->name; + return d->algo->base.name; } #endif /* __SH_ST_DEVICES_H__ */ -- cgit v1.2.3 From c3fe3d705949c83029560c8eebb280dff6fc50d6 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 25 Mar 2015 12:56:15 +0100 Subject: crypto: hmac: move register to hmac As we will use the best sha algo at runtime Add a new init level crypto_initcall to ensure that all the sha present before hmac Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- crypto/hmac.c | 48 +++++++++++++++++++++++++++------------ crypto/md5.c | 8 +------ crypto/sha1.c | 8 +------ crypto/sha2.c | 16 ++----------- crypto/sha4.c | 16 ++----------- include/asm-generic/barebox.lds.h | 3 ++- include/crypto/internal.h | 10 -------- include/init.h | 3 ++- 8 files changed, 43 insertions(+), 69 deletions(-) (limited to 'include') diff --git a/crypto/hmac.c b/crypto/hmac.c index 77814a1643..20af2a56de 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -7,6 +7,7 @@ #include #include #include +#include #include struct digest_hmac { @@ -39,6 +40,8 @@ static int digest_hmac_alloc(struct digest *d) if (!dh->d) return -EINVAL; + d->length = dh->d->algo->length; + dh->ipad = xmalloc(hmac->pad_length); dh->opad = xmalloc(hmac->pad_length); @@ -148,34 +151,49 @@ struct digest_algo hmac_algo = { .priority = 0, .flags = DIGEST_ALGO_NEED_KEY, }, - .alloc = digest_hmac_alloc, - .init = digest_hmac_init, - .update = digest_hmac_update, - .final = digest_hmac_final, - .digest = digest_generic_digest, - .verify = digest_generic_verify, - .set_key = digest_hmac_set_key, - .free = digest_hmac_free, - .ctx_length = sizeof(struct digest_hmac), + .alloc = digest_hmac_alloc, + .init = digest_hmac_init, + .update = digest_hmac_update, + .final = digest_hmac_final, + .digest = digest_generic_digest, + .verify = digest_generic_verify, + .set_key = digest_hmac_set_key, + .free = digest_hmac_free, + .ctx_length = sizeof(struct digest_hmac), }; -int digest_hmac_register(struct digest_algo *algo, unsigned int pad_length) +static int digest_hmac_register(char *name, unsigned int pad_length) { struct digest_hmac *dh; - char *name; - if (!algo || !pad_length) + if (!name || !pad_length) return -EINVAL; - name = algo->base.name; dh = xzalloc(sizeof(*dh)); dh->name = xstrdup(name); dh->pad_length = pad_length; dh->algo = hmac_algo; - dh->algo.length = algo->length; dh->algo.base.name = asprintf("hmac(%s)", name); dh->algo.base.driver_name = asprintf("hmac(%s)-generic", name); - dh->algo.base.priority = algo->base.priority; return digest_algo_register(&dh->algo); } + +static int digest_hmac_initcall(void) +{ + if (IS_ENABLED(CONFIG_MD5)) + digest_hmac_register("md5", 64); + if (IS_ENABLED(CONFIG_SHA1)) + digest_hmac_register("sha1", 64); + if (IS_ENABLED(CONFIG_SHA224)) + digest_hmac_register("sha224", 64); + if (IS_ENABLED(CONFIG_SHA256)) + digest_hmac_register("sha256", 64); + if (IS_ENABLED(CONFIG_SHA384)) + digest_hmac_register("sha384", 128); + if (IS_ENABLED(CONFIG_SHA512)) + digest_hmac_register("sha512", 128); + + return 0; +} +crypto_initcall(digest_hmac_initcall); diff --git a/crypto/md5.c b/crypto/md5.c index 74c9b706f0..23892babce 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -305,12 +305,6 @@ static struct digest_algo md5 = { static int md5_digest_register(void) { - int ret; - - ret = digest_algo_register(&md5); - if (ret) - return ret; - - return digest_hmac_register(&md5, 64); + return digest_algo_register(&md5); } device_initcall(md5_digest_register); diff --git a/crypto/sha1.c b/crypto/sha1.c index a2ca191899..94d56c3e46 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -328,12 +328,6 @@ static struct digest_algo m = { static int sha1_digest_register(void) { - int ret; - - ret = digest_algo_register(&m); - if (ret) - return ret; - - return digest_hmac_register(&m, 64); + return digest_algo_register(&m); } device_initcall(sha1_digest_register); diff --git a/crypto/sha2.c b/crypto/sha2.c index 42c40da757..f7b8bebde2 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -315,16 +315,10 @@ static struct digest_algo m224 = { static int sha224_digest_register(void) { - int ret; - if (!IS_ENABLED(CONFIG_SHA224)) return 0; - ret = digest_algo_register(&m224); - if (ret) - return ret; - - return digest_hmac_register(&m224, 64); + return digest_algo_register(&m224); } device_initcall(sha224_digest_register); @@ -353,15 +347,9 @@ static struct digest_algo m256 = { static int sha256_digest_register(void) { - int ret; - if (!IS_ENABLED(CONFIG_SHA256)) return 0; - ret = digest_algo_register(&m256); - if (ret) - return ret; - - return digest_hmac_register(&m256, 64); + return digest_algo_register(&m256); } device_initcall(sha256_digest_register); diff --git a/crypto/sha4.c b/crypto/sha4.c index cb62d1d2f2..3f8fa0d293 100644 --- a/crypto/sha4.c +++ b/crypto/sha4.c @@ -321,16 +321,10 @@ static struct digest_algo m384 = { static int sha384_digest_register(void) { - int ret; - if (!IS_ENABLED(CONFIG_SHA384)) return 0; - ret = digest_algo_register(&m384); - if (ret) - return ret; - - return digest_hmac_register(&m384, 128); + return digest_algo_register(&m384); } device_initcall(sha384_digest_register); @@ -359,15 +353,9 @@ static struct digest_algo m512 = { static int sha512_digest_register(void) { - int ret; - if (!IS_ENABLED(CONFIG_SHA512)) return 0; - ret = digest_algo_register(&m512); - if (ret) - return ret; - - return digest_hmac_register(&m512, 128); + return digest_algo_register(&m512); } device_initcall(sha512_digest_register); diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h index 66abff30fa..e359187d7f 100644 --- a/include/asm-generic/barebox.lds.h +++ b/include/asm-generic/barebox.lds.h @@ -33,7 +33,8 @@ KEEP(*(.initcall.8)) \ KEEP(*(.initcall.9)) \ KEEP(*(.initcall.10)) \ - KEEP(*(.initcall.11)) + KEEP(*(.initcall.11)) \ + KEEP(*(.initcall.12)) #define BAREBOX_CMDS KEEP(*(SORT_BY_NAME(.barebox_cmd*))) diff --git a/include/crypto/internal.h b/include/crypto/internal.h index c6f5908ea0..0987ccc160 100644 --- a/include/crypto/internal.h +++ b/include/crypto/internal.h @@ -4,16 +4,6 @@ * GPL v2 only */ -#ifdef CONFIG_DIGEST_HMAC -int digest_hmac_register(struct digest_algo *algo, unsigned int pad_length); -#else -static inline int digest_hmac_register(struct digest_algo *algo, - unsigned int pad_length) -{ - return 0; -} -#endif - int digest_generic_verify(struct digest *d, const unsigned char *md); int digest_generic_digest(struct digest *d, const void *data, unsigned int len, u8 *out); diff --git a/include/init.h b/include/init.h index 40cea55fb1..37c7eedf67 100644 --- a/include/init.h +++ b/include/init.h @@ -37,7 +37,8 @@ typedef int (*initcall_t)(void); #define coredevice_initcall(fn) __define_initcall("8",fn,8) #define fs_initcall(fn) __define_initcall("9",fn,9) #define device_initcall(fn) __define_initcall("10",fn,10) -#define late_initcall(fn) __define_initcall("11",fn,11) +#define crypto_initcall(fn) __define_initcall("11",fn,11) +#define late_initcall(fn) __define_initcall("12",fn,12) /* section for code used very early when * - we're not running from where we linked at -- cgit v1.2.3 From 144e104a1ea48102bb784f04e73064a0f76a0c0a Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 25 Mar 2015 12:56:16 +0100 Subject: crypto: sha1: switch to linux implementation current implementation $ ls -al build/versatilpb/arch/arm/pbl/zbarebox.bin -rw-r--r-- 1 root root 211095 Mar 24 13:21 build/versatilpb/arch/arm/pbl/zbarebox.bin linux generic implementation $ ls -al build/versatilpb/arch/arm/pbl/zbarebox.bin -rw-r--r-- 1 root root 210829 Mar 24 13:21 build/versatilpb/arch/arm/pbl/zbarebox.bin on a compressed lzo barebox we will 266 bytes Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- crypto/sha1.c | 522 ++++++++++++++++++++++++--------------------------- include/crypto/sha.h | 95 ++++++++++ include/digest.h | 5 + 3 files changed, 347 insertions(+), 275 deletions(-) create mode 100644 include/crypto/sha.h (limited to 'include') diff --git a/crypto/sha1.c b/crypto/sha1.c index 94d56c3e46..a3de2719d8 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -1,311 +1,283 @@ /* - * Heiko Schocher, DENX Software Engineering, hs@denx.de. - * based on: - * FIPS-180-1 compliant SHA-1 implementation + * Cryptographic API. * - * Copyright (C) 2003-2006 Christophe Devine + * SHA1 Secure Hash Algorithm. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License, version 2.1 as published by the Free Software Foundation. + * Derived from cryptoapi implementation, adapted for in-place + * scatterlist interface. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - */ -/* - * The SHA-1 standard was published by NIST in 1993. + * Copyright (c) Alan Smithee. + * Copyright (c) Andrew McDonald + * Copyright (c) Jean-Francois Dive + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. * - * http://www.itl.nist.gov/fipspubs/fip180-1.htm */ #include #include #include #include +#include #include +#include #include -#define SHA1_SUM_POS -0x20 -#define SHA1_SUM_LEN 20 +#define SHA_WORKSPACE_WORDS 16 -typedef struct +static int sha1_init(struct digest *desc) { - uint32_t total[2]; /*!< number of bytes processed */ - uint32_t state[5]; /*!< intermediate digest state */ - uint8_t buffer[64]; /*!< data block being processed */ -} -sha1_context; - -/* - * 32-bit integer manipulation macros (big endian) - */ -#define GET_UINT32_BE(n,b,i) (n) = be32_to_cpu(((uint32_t*)(b))[i / 4]) -#define PUT_UINT32_BE(n,b,i) ((uint32_t*)(b))[i / 4] = cpu_to_be32(n) + struct sha1_state *ctx = digest_ctx(desc); -/* - * SHA-1 context setup - */ -static void sha1_starts (sha1_context *ctx) -{ - ctx->total[0] = 0; - ctx->total[1] = 0; - - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; - ctx->state[4] = 0xC3D2E1F0; -} + ctx->count = 0; -static void sha1_process (sha1_context *ctx, uint8_t data[64]) -{ - uint32_t temp, W[16], A, B, C, D, E; - - GET_UINT32_BE (W[0], data, 0); - GET_UINT32_BE (W[1], data, 4); - GET_UINT32_BE (W[2], data, 8); - GET_UINT32_BE (W[3], data, 12); - GET_UINT32_BE (W[4], data, 16); - GET_UINT32_BE (W[5], data, 20); - GET_UINT32_BE (W[6], data, 24); - GET_UINT32_BE (W[7], data, 28); - GET_UINT32_BE (W[8], data, 32); - GET_UINT32_BE (W[9], data, 36); - GET_UINT32_BE (W[10], data, 40); - GET_UINT32_BE (W[11], data, 44); - GET_UINT32_BE (W[12], data, 48); - GET_UINT32_BE (W[13], data, 52); - GET_UINT32_BE (W[14], data, 56); - GET_UINT32_BE (W[15], data, 60); - -#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) - -#define R(t) ( \ - temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ - W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ - ( W[t & 0x0F] = S(temp,1) ) \ -) - -#define P(a,b,c,d,e,x) { \ - e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ -} + ctx->state[0] = SHA1_H0; + ctx->state[1] = SHA1_H1; + ctx->state[2] = SHA1_H2; + ctx->state[3] = SHA1_H3; + ctx->state[4] = SHA1_H4; - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - -#define F(x,y,z) (z ^ (x & (y ^ z))) -#define K 0x5A827999 - - P (A, B, C, D, E, W[0]); - P (E, A, B, C, D, W[1]); - P (D, E, A, B, C, W[2]); - P (C, D, E, A, B, W[3]); - P (B, C, D, E, A, W[4]); - P (A, B, C, D, E, W[5]); - P (E, A, B, C, D, W[6]); - P (D, E, A, B, C, W[7]); - P (C, D, E, A, B, W[8]); - P (B, C, D, E, A, W[9]); - P (A, B, C, D, E, W[10]); - P (E, A, B, C, D, W[11]); - P (D, E, A, B, C, W[12]); - P (C, D, E, A, B, W[13]); - P (B, C, D, E, A, W[14]); - P (A, B, C, D, E, W[15]); - P (E, A, B, C, D, R (16)); - P (D, E, A, B, C, R (17)); - P (C, D, E, A, B, R (18)); - P (B, C, D, E, A, R (19)); - -#undef K -#undef F - -#define F(x,y,z) (x ^ y ^ z) -#define K 0x6ED9EBA1 - - P (A, B, C, D, E, R (20)); - P (E, A, B, C, D, R (21)); - P (D, E, A, B, C, R (22)); - P (C, D, E, A, B, R (23)); - P (B, C, D, E, A, R (24)); - P (A, B, C, D, E, R (25)); - P (E, A, B, C, D, R (26)); - P (D, E, A, B, C, R (27)); - P (C, D, E, A, B, R (28)); - P (B, C, D, E, A, R (29)); - P (A, B, C, D, E, R (30)); - P (E, A, B, C, D, R (31)); - P (D, E, A, B, C, R (32)); - P (C, D, E, A, B, R (33)); - P (B, C, D, E, A, R (34)); - P (A, B, C, D, E, R (35)); - P (E, A, B, C, D, R (36)); - P (D, E, A, B, C, R (37)); - P (C, D, E, A, B, R (38)); - P (B, C, D, E, A, R (39)); - -#undef K -#undef F - -#define F(x,y,z) ((x & y) | (z & (x | y))) -#define K 0x8F1BBCDC - - P (A, B, C, D, E, R (40)); - P (E, A, B, C, D, R (41)); - P (D, E, A, B, C, R (42)); - P (C, D, E, A, B, R (43)); - P (B, C, D, E, A, R (44)); - P (A, B, C, D, E, R (45)); - P (E, A, B, C, D, R (46)); - P (D, E, A, B, C, R (47)); - P (C, D, E, A, B, R (48)); - P (B, C, D, E, A, R (49)); - P (A, B, C, D, E, R (50)); - P (E, A, B, C, D, R (51)); - P (D, E, A, B, C, R (52)); - P (C, D, E, A, B, R (53)); - P (B, C, D, E, A, R (54)); - P (A, B, C, D, E, R (55)); - P (E, A, B, C, D, R (56)); - P (D, E, A, B, C, R (57)); - P (C, D, E, A, B, R (58)); - P (B, C, D, E, A, R (59)); - -#undef K -#undef F - -#define F(x,y,z) (x ^ y ^ z) -#define K 0xCA62C1D6 - - P (A, B, C, D, E, R (60)); - P (E, A, B, C, D, R (61)); - P (D, E, A, B, C, R (62)); - P (C, D, E, A, B, R (63)); - P (B, C, D, E, A, R (64)); - P (A, B, C, D, E, R (65)); - P (E, A, B, C, D, R (66)); - P (D, E, A, B, C, R (67)); - P (C, D, E, A, B, R (68)); - P (B, C, D, E, A, R (69)); - P (A, B, C, D, E, R (70)); - P (E, A, B, C, D, R (71)); - P (D, E, A, B, C, R (72)); - P (C, D, E, A, B, R (73)); - P (B, C, D, E, A, R (74)); - P (A, B, C, D, E, R (75)); - P (E, A, B, C, D, R (76)); - P (D, E, A, B, C, R (77)); - P (C, D, E, A, B, R (78)); - P (B, C, D, E, A, R (79)); - -#undef K -#undef F - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; - ctx->state[4] += E; + return 0; } /* - * SHA-1 process buffer + * If you have 32 registers or more, the compiler can (and should) + * try to change the array[] accesses into registers. However, on + * machines with less than ~25 registers, that won't really work, + * and at least gcc will make an unholy mess of it. + * + * So to avoid that mess which just slows things down, we force + * the stores to memory to actually happen (we might be better off + * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as + * suggested by Artur Skawina - that will also make gcc unable to + * try to do the silly "optimize away loads" part because it won't + * see what the value will be). + * + * Ben Herrenschmidt reports that on PPC, the C version comes close + * to the optimized asm with this (ie on PPC you don't want that + * 'volatile', since there are lots of registers). + * + * On ARM we get the best code generation by forcing a full memory barrier + * between each SHA_ROUND, otherwise gcc happily get wild with spilling and + * the stack frame size simply explode and performance goes down the drain. */ -static void sha1_update (sha1_context *ctx, uint8_t *input, uint32_t ilen) -{ - uint32_t fill, left; - if (ilen <= 0) - return; +#ifdef CONFIG_X86 + #define setW(x, val) (*(volatile __u32 *)&W(x) = (val)) +#elif defined(CONFIG_ARM) + #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0) +#else + #define setW(x, val) (W(x) = (val)) +#endif - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if (ctx->total[0] < ilen) - ctx->total[1]++; - - if (left && ilen >= fill) { - memcpy ((void *) (ctx->buffer + left), (void *) input, fill); - sha1_process (ctx, ctx->buffer); - input += fill; - ilen -= fill; - left = 0; - } - - while (ilen >= 64) { - sha1_process (ctx, input); - input += 64; - ilen -= 64; - } - - if (ilen > 0) { - memcpy ((void *) (ctx->buffer + left), (void *) input, ilen); - } -} - -static uint8_t sha1_padding[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; +/* This "rolls" over the 512-bit array */ +#define W(x) (array[(x)&15]) /* - * SHA-1 final digest + * Where do we get the source from? The first 16 iterations get it from + * the input data, the next mix it from the 512-bit array. + */ +#define SHA_SRC(t) get_unaligned_be32((__u32 *)data + t) +#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) + +#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ + __u32 TEMP = input(t); setW(t, TEMP); \ + E += TEMP + rol32(A,5) + (fn) + (constant); \ + B = ror32(B, 2); } while (0) + +#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) +#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) +#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) +#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) +#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) + +/** + * sha_transform - single block SHA1 transform + * + * @digest: 160 bit digest to update + * @data: 512 bits of data to hash + * @array: 16 words of workspace (see note) + * + * This function generates a SHA1 digest for a single 512-bit block. + * Be warned, it does not handle padding and message digest, do not + * confuse it with the full FIPS 180-1 digest algorithm for variable + * length messages. + * + * Note: If the hash is security sensitive, the caller should be sure + * to clear the workspace. This is left to the caller to avoid + * unnecessary clears between chained hashing operations. */ -static void sha1_finish (sha1_context *ctx, uint8_t output[20]) +static void sha_transform(__u32 *digest, const char *data, __u32 *array) { - uint32_t last, padn; - uint32_t high, low; - uint8_t msglen[8]; - - high = (ctx->total[0] >> 29) - | (ctx->total[1] << 3); - low = (ctx->total[0] << 3); - - PUT_UINT32_BE (high, msglen, 0); - PUT_UINT32_BE (low, msglen, 4); - - last = ctx->total[0] & 0x3F; - padn = (last < 56) ? (56 - last) : (120 - last); - - sha1_update (ctx, sha1_padding, padn); - sha1_update (ctx, msglen, 8); - - PUT_UINT32_BE (ctx->state[0], output, 0); - PUT_UINT32_BE (ctx->state[1], output, 4); - PUT_UINT32_BE (ctx->state[2], output, 8); - PUT_UINT32_BE (ctx->state[3], output, 12); - PUT_UINT32_BE (ctx->state[4], output, 16); + __u32 A, B, C, D, E; + + A = digest[0]; + B = digest[1]; + C = digest[2]; + D = digest[3]; + E = digest[4]; + + /* Round 1 - iterations 0-16 take their input from 'data' */ + T_0_15( 0, A, B, C, D, E); + T_0_15( 1, E, A, B, C, D); + T_0_15( 2, D, E, A, B, C); + T_0_15( 3, C, D, E, A, B); + T_0_15( 4, B, C, D, E, A); + T_0_15( 5, A, B, C, D, E); + T_0_15( 6, E, A, B, C, D); + T_0_15( 7, D, E, A, B, C); + T_0_15( 8, C, D, E, A, B); + T_0_15( 9, B, C, D, E, A); + T_0_15(10, A, B, C, D, E); + T_0_15(11, E, A, B, C, D); + T_0_15(12, D, E, A, B, C); + T_0_15(13, C, D, E, A, B); + T_0_15(14, B, C, D, E, A); + T_0_15(15, A, B, C, D, E); + + /* Round 1 - tail. Input from 512-bit mixing array */ + T_16_19(16, E, A, B, C, D); + T_16_19(17, D, E, A, B, C); + T_16_19(18, C, D, E, A, B); + T_16_19(19, B, C, D, E, A); + + /* Round 2 */ + T_20_39(20, A, B, C, D, E); + T_20_39(21, E, A, B, C, D); + T_20_39(22, D, E, A, B, C); + T_20_39(23, C, D, E, A, B); + T_20_39(24, B, C, D, E, A); + T_20_39(25, A, B, C, D, E); + T_20_39(26, E, A, B, C, D); + T_20_39(27, D, E, A, B, C); + T_20_39(28, C, D, E, A, B); + T_20_39(29, B, C, D, E, A); + T_20_39(30, A, B, C, D, E); + T_20_39(31, E, A, B, C, D); + T_20_39(32, D, E, A, B, C); + T_20_39(33, C, D, E, A, B); + T_20_39(34, B, C, D, E, A); + T_20_39(35, A, B, C, D, E); + T_20_39(36, E, A, B, C, D); + T_20_39(37, D, E, A, B, C); + T_20_39(38, C, D, E, A, B); + T_20_39(39, B, C, D, E, A); + + /* Round 3 */ + T_40_59(40, A, B, C, D, E); + T_40_59(41, E, A, B, C, D); + T_40_59(42, D, E, A, B, C); + T_40_59(43, C, D, E, A, B); + T_40_59(44, B, C, D, E, A); + T_40_59(45, A, B, C, D, E); + T_40_59(46, E, A, B, C, D); + T_40_59(47, D, E, A, B, C); + T_40_59(48, C, D, E, A, B); + T_40_59(49, B, C, D, E, A); + T_40_59(50, A, B, C, D, E); + T_40_59(51, E, A, B, C, D); + T_40_59(52, D, E, A, B, C); + T_40_59(53, C, D, E, A, B); + T_40_59(54, B, C, D, E, A); + T_40_59(55, A, B, C, D, E); + T_40_59(56, E, A, B, C, D); + T_40_59(57, D, E, A, B, C); + T_40_59(58, C, D, E, A, B); + T_40_59(59, B, C, D, E, A); + + /* Round 4 */ + T_60_79(60, A, B, C, D, E); + T_60_79(61, E, A, B, C, D); + T_60_79(62, D, E, A, B, C); + T_60_79(63, C, D, E, A, B); + T_60_79(64, B, C, D, E, A); + T_60_79(65, A, B, C, D, E); + T_60_79(66, E, A, B, C, D); + T_60_79(67, D, E, A, B, C); + T_60_79(68, C, D, E, A, B); + T_60_79(69, B, C, D, E, A); + T_60_79(70, A, B, C, D, E); + T_60_79(71, E, A, B, C, D); + T_60_79(72, D, E, A, B, C); + T_60_79(73, C, D, E, A, B); + T_60_79(74, B, C, D, E, A); + T_60_79(75, A, B, C, D, E); + T_60_79(76, E, A, B, C, D); + T_60_79(77, D, E, A, B, C); + T_60_79(78, C, D, E, A, B); + T_60_79(79, B, C, D, E, A); + + digest[0] += A; + digest[1] += B; + digest[2] += C; + digest[3] += D; + digest[4] += E; } -static int digest_sha1_init(struct digest *d) +static int sha1_update(struct digest *desc, const void *data, + unsigned long len) { - sha1_starts(d->ctx); + struct sha1_state *sctx = digest_ctx(desc); + unsigned int partial, done; + const u8 *src; + + partial = sctx->count % SHA1_BLOCK_SIZE; + sctx->count += len; + done = 0; + src = data; + + if ((partial + len) >= SHA1_BLOCK_SIZE) { + u32 temp[SHA_WORKSPACE_WORDS]; + + if (partial) { + done = -partial; + memcpy(sctx->buffer + partial, data, + done + SHA1_BLOCK_SIZE); + src = sctx->buffer; + } + + do { + sha_transform(sctx->state, src, temp); + done += SHA1_BLOCK_SIZE; + src = data + done; + } while (done + SHA1_BLOCK_SIZE <= len); + + memset(temp, 0, sizeof(temp)); + partial = 0; + } + memcpy(sctx->buffer + partial, src, len - done); return 0; } -static int digest_sha1_update(struct digest *d, const void *data, - unsigned long len) +static int sha1_final(struct digest *desc, unsigned char *md) { - sha1_update(d->ctx, (uint8_t*)data, len); + struct sha1_state *sctx = digest_ctx(desc); + __be32 *dst = (__be32 *)md; + u32 i, index, padlen; + __be64 bits; + static const u8 padding[64] = { 0x80, }; - return 0; -} + bits = cpu_to_be64(sctx->count << 3); -static int digest_sha1_final(struct digest *d, unsigned char *md) -{ - sha1_finish(d->ctx, md); + /* Pad out to 56 mod 64 */ + index = sctx->count & 0x3f; + padlen = (index < 56) ? (56 - index) : ((64+56) - index); + sha1_update(desc, padding, padlen); + + /* Append length */ + sha1_update(desc, (const u8 *)&bits, sizeof(bits)); + + /* Store state in digest */ + for (i = 0; i < 5; i++) + dst[i] = cpu_to_be32(sctx->state[i]); + + /* Wipe context */ + memset(sctx, 0, sizeof *sctx); return 0; } @@ -317,13 +289,13 @@ static struct digest_algo m = { .priority = 0, }, - .init = digest_sha1_init, - .update = digest_sha1_update, - .final = digest_sha1_final, - .digest = digest_generic_digest, - .verify = digest_generic_verify, - .length = SHA1_SUM_LEN, - .ctx_length = sizeof(sha1_context), + .init = sha1_init, + .update = sha1_update, + .final = sha1_final, + .digest = digest_generic_digest, + .verify = digest_generic_verify, + .length = SHA1_DIGEST_SIZE, + .ctx_length = sizeof(struct sha1_state), }; static int sha1_digest_register(void) diff --git a/include/crypto/sha.h b/include/crypto/sha.h new file mode 100644 index 0000000000..190f8a0e02 --- /dev/null +++ b/include/crypto/sha.h @@ -0,0 +1,95 @@ +/* + * Common values for SHA algorithms + */ + +#ifndef _CRYPTO_SHA_H +#define _CRYPTO_SHA_H + +#include + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 + +#define SHA224_DIGEST_SIZE 28 +#define SHA224_BLOCK_SIZE 64 + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +#define SHA384_DIGEST_SIZE 48 +#define SHA384_BLOCK_SIZE 128 + +#define SHA512_DIGEST_SIZE 64 +#define SHA512_BLOCK_SIZE 128 + +#define SHA1_H0 0x67452301UL +#define SHA1_H1 0xefcdab89UL +#define SHA1_H2 0x98badcfeUL +#define SHA1_H3 0x10325476UL +#define SHA1_H4 0xc3d2e1f0UL + +#define SHA224_H0 0xc1059ed8UL +#define SHA224_H1 0x367cd507UL +#define SHA224_H2 0x3070dd17UL +#define SHA224_H3 0xf70e5939UL +#define SHA224_H4 0xffc00b31UL +#define SHA224_H5 0x68581511UL +#define SHA224_H6 0x64f98fa7UL +#define SHA224_H7 0xbefa4fa4UL + +#define SHA256_H0 0x6a09e667UL +#define SHA256_H1 0xbb67ae85UL +#define SHA256_H2 0x3c6ef372UL +#define SHA256_H3 0xa54ff53aUL +#define SHA256_H4 0x510e527fUL +#define SHA256_H5 0x9b05688cUL +#define SHA256_H6 0x1f83d9abUL +#define SHA256_H7 0x5be0cd19UL + +#define SHA384_H0 0xcbbb9d5dc1059ed8ULL +#define SHA384_H1 0x629a292a367cd507ULL +#define SHA384_H2 0x9159015a3070dd17ULL +#define SHA384_H3 0x152fecd8f70e5939ULL +#define SHA384_H4 0x67332667ffc00b31ULL +#define SHA384_H5 0x8eb44a8768581511ULL +#define SHA384_H6 0xdb0c2e0d64f98fa7ULL +#define SHA384_H7 0x47b5481dbefa4fa4ULL + +#define SHA512_H0 0x6a09e667f3bcc908ULL +#define SHA512_H1 0xbb67ae8584caa73bULL +#define SHA512_H2 0x3c6ef372fe94f82bULL +#define SHA512_H3 0xa54ff53a5f1d36f1ULL +#define SHA512_H4 0x510e527fade682d1ULL +#define SHA512_H5 0x9b05688c2b3e6c1fULL +#define SHA512_H6 0x1f83d9abfb41bd6bULL +#define SHA512_H7 0x5be0cd19137e2179ULL + +struct sha1_state { + u64 count; + u32 state[SHA1_DIGEST_SIZE / 4]; + u8 buffer[SHA1_BLOCK_SIZE]; +}; + +struct sha256_state { + u64 count; + u32 state[SHA256_DIGEST_SIZE / 4]; + u8 buf[SHA256_BLOCK_SIZE]; +}; + +struct sha512_state { + u64 count[2]; + u64 state[SHA512_DIGEST_SIZE / 8]; + u8 buf[SHA512_BLOCK_SIZE]; +}; + +struct shash_desc; + +extern int crypto_sha1_update(struct shash_desc *desc, const u8 *data, + unsigned int len); + +extern int crypto_sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len); + +extern int crypto_sha512_update(struct shash_desc *desc, const u8 *data, + unsigned int len); +#endif diff --git a/include/digest.h b/include/digest.h index 00aeee5237..7f8d696eb6 100644 --- a/include/digest.h +++ b/include/digest.h @@ -127,4 +127,9 @@ static inline const char *digest_name(struct digest *d) return d->algo->base.name; } +static inline void* digest_ctx(struct digest *d) +{ + return d->ctx; +} + #endif /* __SH_ST_DEVICES_H__ */ -- cgit v1.2.3