9
0
Fork 0

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 <plagnioj@jcrosoft.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Jean-Christophe PLAGNIOL-VILLARD 2015-03-11 17:53:08 +01:00 committed by Sascha Hauer
parent 3a43692412
commit 2f3c3f512b
9 changed files with 258 additions and 24 deletions

View File

@ -30,4 +30,7 @@ config SHA384
config SHA512
bool "SHA512"
config DIGEST_HMAC
bool "HMAC"
endif

View File

@ -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

159
crypto/hmac.c Normal file
View File

@ -0,0 +1,159 @@
/*
* (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
* GPL v2 only
*/
#include <common.h>
#include <digest.h>
#include <malloc.h>
#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);
}

15
crypto/internal.h Normal file
View File

@ -0,0 +1,15 @@
/*
* (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
* 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

View File

@ -29,6 +29,8 @@
#include <digest.h>
#include <init.h>
#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);

View File

@ -26,6 +26,8 @@
#include <linux/string.h>
#include <asm/byteorder.h>
#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);

View File

@ -21,6 +21,8 @@
#include <linux/string.h>
#include <asm/byteorder.h>
#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);

View File

@ -29,6 +29,8 @@
#include <linux/string.h>
#include <asm/byteorder.h>
#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);

View File

@ -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__ */