summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Kleine-Budde <mkl@pengutronix.de>2015-05-25 14:50:12 +0200
committerMarc Kleine-Budde <mkl@pengutronix.de>2015-05-25 23:52:18 +0200
commitcd3e06e67af4f52eb5fd98e26ecebb995beb4690 (patch)
treebde4b27e6fe45d1ebbe3ef0f6c4f7b89032183da
parentaba4493455b4dc88c48e2e3fffa52bb7d9ec3ae8 (diff)
downloaddt-utils-cd3e06e67af4f52eb5fd98e26ecebb995beb4690.tar.gz
dt-utils-cd3e06e67af4f52eb5fd98e26ecebb995beb4690.tar.xz
crypto: import crypto layer from barebox
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--Makefile.am7
-rw-r--r--src/asm/unaligned.h1
-rw-r--r--src/barebox-state.c15
-rw-r--r--src/crypto/digest.c323
-rw-r--r--src/crypto/hmac.c201
-rw-r--r--src/crypto/internal.h13
-rw-r--r--src/crypto/sha.h95
-rw-r--r--src/crypto/sha1.c306
-rw-r--r--src/crypto/sha2.c375
-rw-r--r--src/digest.h158
-rw-r--r--src/dt/common.h195
-rw-r--r--src/fs.h1
-rw-r--r--src/init.h1
-rw-r--r--src/linux/err.h1
-rw-r--r--src/linux/list.h1
-rw-r--r--src/module.h1
16 files changed, 1679 insertions, 15 deletions
diff --git a/Makefile.am b/Makefile.am
index 9cee974..22995db 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -43,7 +43,12 @@ pkginclude_HEADERS = \
lib_LTLIBRARIES = src/libdt-utils.la
bin_PROGRAMS = barebox-state fdtdump
-barebox_state_SOURCES = src/barebox-state.c
+barebox_state_SOURCES = \
+ src/crypto/digest.c \
+ src/crypto/hmac.c \
+ src/crypto/sha1.c \
+ src/crypto/sha2.c \
+ src/barebox-state.c
barebox_state_CFLAGS = $(LIBDT_CFLAGS)
barebox_state_LDADD = src/libdt-utils.la
diff --git a/src/asm/unaligned.h b/src/asm/unaligned.h
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/src/asm/unaligned.h
@@ -0,0 +1 @@
+/* empty */
diff --git a/src/barebox-state.c b/src/barebox-state.c
index 01b396e..840c700 100644
--- a/src/barebox-state.c
+++ b/src/barebox-state.c
@@ -33,6 +33,7 @@
#include <mtd/mtd-abi.h>
#include <common.h>
+#include <digest.h>
#include <dt.h>
#include <fdt.h>
@@ -50,20 +51,6 @@ static char *state_mac_get(struct state_variable *var);
#define asprintf(fmt, arg...) barebox_asprintf(fmt, ##arg)
-char *barebox_asprintf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
-char *barebox_asprintf(const char *fmt, ...)
-{
- va_list ap;
- char *p;
- int ret;
-
- va_start(ap, fmt);
- ret = vasprintf(&p, fmt, ap);
- va_end(ap);
-
- return ret == -1 ? NULL : p;
-}
-
/* ------------------------------------------------------------ */
#define RAW_BACKEND_COPIES 2
diff --git a/src/crypto/digest.c b/src/crypto/digest.c
new file mode 100644
index 0000000..7a8c3c0
--- /dev/null
+++ b/src/crypto/digest.c
@@ -0,0 +1,323 @@
+/*
+ * (C) Copyright 2008-2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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; version 2 of
+ * the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <digest.h>
+#include <malloc.h>
+#include <fs.h>
+#include <fcntl.h>
+#include <linux/stat.h>
+#include <errno.h>
+#include <module.h>
+#include <linux/err.h>
+#include <crypto/internal.h>
+
+static LIST_HEAD(digests);
+
+static struct digest_algo *digest_algo_get_by_name(const char *name);
+
+static int dummy_init(struct digest *d)
+{
+ return 0;
+}
+
+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_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->base.name || !d->update || !d->final || !d->verify)
+ return -EINVAL;
+
+ if (!d->init)
+ d->init = dummy_init;
+
+ if (!d->alloc)
+ d->alloc = dummy_init;
+
+ if (!d->free)
+ d->free = dummy_free;
+
+ list_add_tail(&d->list, &digests);
+
+ return 0;
+}
+EXPORT_SYMBOL(digest_algo_register);
+
+void digest_algo_unregister(struct digest_algo *d)
+{
+ if (!d)
+ return;
+
+ list_del(&d->list);
+}
+EXPORT_SYMBOL(digest_algo_unregister);
+
+static struct digest_algo *digest_algo_get_by_name(const char *name)
+{
+ struct digest_algo *d = NULL;
+ struct digest_algo *tmp;
+ int priority = -1;
+
+ if (!name)
+ return NULL;
+
+ 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 d;
+}
+
+static struct digest_algo *digest_algo_get_by_algo(enum hash_algo algo)
+{
+ struct digest_algo *d = NULL;
+ struct digest_algo *tmp;
+ int priority = -1;
+
+ list_for_each_entry(tmp, &digests, list) {
+ if (tmp->base.algo != algo)
+ continue;
+
+ if (tmp->base.priority <= priority)
+ continue;
+
+ d = tmp;
+ priority = tmp->base.priority;
+ }
+
+ 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%-15s\t%-20s\t%d\n", prefix, d->base.name,
+ d->base.driver_name, d->base.priority);
+ }
+}
+
+struct digest *digest_alloc(const 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);
+
+struct digest *digest_alloc_by_algo(enum hash_algo hash_algo)
+{
+ struct digest *d;
+ struct digest_algo *algo;
+
+ algo = digest_algo_get_by_algo(hash_algo);
+ 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_by_algo);
+
+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, const char *filename,
+ unsigned char *hash,
+ const unsigned char *sig,
+ ulong start, ulong size)
+{
+ ulong len = 0;
+ int fd, now, ret = 0;
+ unsigned char *buf;
+ int flags = 0;
+
+ ret = digest_init(d);
+ if (ret)
+ return ret;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror(filename);
+ return fd;
+ }
+
+ buf = memmap(fd, PROT_READ);
+ if (buf == (void *)-1) {
+ buf = xmalloc(4096);
+ flags = 1;
+ }
+
+ if (start > 0) {
+ if (flags) {
+ ret = lseek(fd, start, SEEK_SET);
+ if (ret == -1) {
+ perror("lseek");
+ goto out;
+ }
+ } else {
+ buf += start;
+ }
+ }
+
+ while (size) {
+ now = min((ulong)4096, size);
+ if (flags) {
+ now = read(fd, buf, now);
+ if (now < 0) {
+ ret = now;
+ perror("read");
+ goto out_free;
+ }
+ if (!now)
+ break;
+ }
+
+ if (ctrlc()) {
+ ret = -EINTR;
+ goto out_free;
+ }
+
+ ret = digest_update(d, buf, now);
+ if (ret)
+ goto out_free;
+ size -= now;
+ len += now;
+ }
+
+ if (sig)
+ ret = digest_verify(d, sig);
+ else
+ ret = digest_final(d, hash);
+
+out_free:
+ if (flags)
+ free(buf);
+out:
+ close(fd);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(digest_file_window);
+
+int digest_file(struct digest *d, const char *filename,
+ unsigned char *hash,
+ const unsigned char *sig)
+{
+ struct stat st;
+ int ret;
+
+ ret = stat(filename, &st);
+
+ if (ret < 0)
+ return ret;
+
+ 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,
+ const unsigned char *sig)
+{
+ struct digest *d;
+ int ret;
+
+ d = digest_alloc(algo);
+ if (!d)
+ return -EIO;
+
+ ret = digest_file(d, filename, hash, sig);
+ digest_free(d);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(digest_file_by_name);
diff --git a/src/crypto/hmac.c b/src/crypto/hmac.c
new file mode 100644
index 0000000..ab1b24d
--- /dev/null
+++ b/src/crypto/hmac.c
@@ -0,0 +1,201 @@
+/*
+ * (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPL v2 only
+ */
+
+#include <common.h>
+#include <digest.h>
+#include <malloc.h>
+#include <init.h>
+#include <crypto/internal.h>
+
+#define asprintf(fmt, arg...) barebox_asprintf(fmt, ##arg)
+
+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;
+
+ d->length = dh->d->algo->length;
+
+ 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);
+ unsigned char *sum = NULL;
+ int ret;
+
+ free(dh->key);
+ if (len > hmac->pad_length) {
+ sum = xmalloc(digest_length(dh->d));
+ ret = digest_digest(dh->d, dh->key, dh->keylen, sum);
+ if (ret)
+ goto err;
+ dh->keylen = digest_length(dh->d);
+ dh->key = sum;
+ } else {
+ dh->key = xmalloc(len);
+ memcpy(dh->key, key, len);
+ dh->keylen = len;
+ }
+
+ ret = 0;
+err:
+ free(sum);
+ return ret;
+}
+
+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, ret;
+ 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]);
+ }
+
+ ret = digest_init(dh->d);
+ if (ret)
+ return ret;
+ return digest_update(dh->d, dh->ipad, hmac->pad_length);
+}
+
+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;
+ int ret;
+
+ tmp = xmalloc(digest_length(d));
+
+ ret = digest_final(dh->d, tmp);
+ if (ret)
+ goto err;
+ ret = digest_init(dh->d);
+ if (ret)
+ goto err;
+ ret = digest_update(dh->d, dh->opad, hmac->pad_length);
+ if (ret)
+ goto err;
+ ret = digest_update(dh->d, tmp, digest_length(d));
+ if (ret)
+ goto err;
+ ret = digest_final(dh->d, md);
+
+err:
+ free(tmp);
+
+ return ret;
+}
+
+struct digest_algo hmac_algo = {
+ .base = {
+ .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),
+};
+
+static int digest_hmac_register(char *name, unsigned int pad_length)
+{
+ struct digest_hmac *dh;
+
+ if (!name || !pad_length)
+ return -EINVAL;
+
+ dh = xzalloc(sizeof(*dh));
+ dh->name = xstrdup(name);
+ dh->pad_length = pad_length;
+ dh->algo = hmac_algo;
+ dh->algo.base.name = asprintf("hmac(%s)", name);
+ dh->algo.base.driver_name = asprintf("hmac(%s)-generic", name);
+
+ 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/src/crypto/internal.h b/src/crypto/internal.h
new file mode 100644
index 0000000..06254ea
--- /dev/null
+++ b/src/crypto/internal.h
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2015 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPL v2 only
+ */
+
+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);
+
+#define CONFIG_SHA1 1
+#define CONFIG_SHA224 1
+#define CONFIG_SHA256 1
diff --git a/src/crypto/sha.h b/src/crypto/sha.h
new file mode 100644
index 0000000..190f8a0
--- /dev/null
+++ b/src/crypto/sha.h
@@ -0,0 +1,95 @@
+/*
+ * Common values for SHA algorithms
+ */
+
+#ifndef _CRYPTO_SHA_H
+#define _CRYPTO_SHA_H
+
+#include <linux/types.h>
+
+#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/src/crypto/sha1.c b/src/crypto/sha1.c
new file mode 100644
index 0000000..cbde4d2
--- /dev/null
+++ b/src/crypto/sha1.c
@@ -0,0 +1,306 @@
+/*
+ * Cryptographic API.
+ *
+ * SHA1 Secure Hash Algorithm.
+ *
+ * Derived from cryptoapi implementation, adapted for in-place
+ * scatterlist interface.
+ *
+ * Copyright (c) Alan Smithee.
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <digest.h>
+#include <init.h>
+#include <linux/string.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#include <crypto/sha.h>
+#include <crypto/internal.h>
+
+#define SHA_WORKSPACE_WORDS 16
+
+static int sha1_init(struct digest *desc)
+{
+ struct sha1_state *ctx = digest_ctx(desc);
+
+ ctx->count = 0;
+
+ 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;
+
+ return 0;
+}
+
+/*
+ * 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.
+ */
+
+#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
+
+/* This "rolls" over the 512-bit array */
+#define W(x) (array[(x)&15])
+
+/*
+ * 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 sha_transform(__u32 *digest, const char *data, __u32 *array)
+{
+ __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 sha1_update(struct digest *desc, const void *data,
+ unsigned long len)
+{
+ 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 sha1_final(struct digest *desc, unsigned char *md)
+{
+ struct sha1_state *sctx = digest_ctx(desc);
+ __be32 *dst = (__be32 *)md;
+ u32 i, index, padlen;
+ __be64 bits;
+ static const u8 padding[64] = { 0x80, };
+
+ bits = cpu_to_be64(sctx->count << 3);
+
+ /* 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;
+}
+
+static struct digest_algo m = {
+ .base = {
+ .name = "sha1",
+ .driver_name = "sha1-generic",
+ .priority = 0,
+ .algo = HASH_ALGO_SHA1,
+ },
+
+ .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)
+{
+ return digest_algo_register(&m);
+}
+device_initcall(sha1_digest_register);
diff --git a/src/crypto/sha2.c b/src/crypto/sha2.c
new file mode 100644
index 0000000..cb0f11c
--- /dev/null
+++ b/src/crypto/sha2.c
@@ -0,0 +1,375 @@
+/*
+ * Cryptographic API.
+ *
+ * SHA-256, as specified in
+ * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf
+ *
+ * SHA-256 code by Jean-Luc Cooke <jlcooke@certainkey.com>.
+ *
+ * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * SHA224 Support Copyright 2007 Intel Corporation <jonathan.lynch@intel.com>
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <digest.h>
+#include <init.h>
+#include <linux/string.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#include <crypto/sha.h>
+#include <crypto/internal.h>
+
+static inline u32 Ch(u32 x, u32 y, u32 z)
+{
+ return z ^ (x & (y ^ z));
+}
+
+static inline u32 Maj(u32 x, u32 y, u32 z)
+{
+ return (x & y) | (z & (x | y));
+}
+
+#define e0(x) (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22))
+#define e1(x) (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25))
+#define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3))
+#define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10))
+
+static inline void LOAD_OP(int I, u32 *W, const u8 *input)
+{
+ W[I] = get_unaligned_be32((__u32 *)input + I);
+}
+
+static inline void BLEND_OP(int I, u32 *W)
+{
+ W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
+}
+
+static void sha256_transform(u32 *state, const u8 *input)
+{
+ u32 a, b, c, d, e, f, g, h, t1, t2;
+ u32 W[64];
+ int i;
+
+ /* load the input */
+ for (i = 0; i < 16; i++)
+ LOAD_OP(i, W, input);
+
+ /* now blend */
+ for (i = 16; i < 64; i++)
+ BLEND_OP(i, W);
+
+ /* load the state into our registers */
+ a=state[0]; b=state[1]; c=state[2]; d=state[3];
+ e=state[4]; f=state[5]; g=state[6]; h=state[7];
+
+ /* now iterate */
+ t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0];
+ t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2;
+ t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1];
+ t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2;
+ t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2];
+ t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2;
+ t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3];
+ t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2;
+ t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4];
+ t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2;
+ t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5];
+ t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2;
+ t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6];
+ t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2;
+ t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7];
+ t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2;
+
+ t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8];
+ t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2;
+ t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9];
+ t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2;
+ t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10];
+ t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2;
+ t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11];
+ t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2;
+ t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12];
+ t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2;
+ t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13];
+ t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2;
+ t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14];
+ t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2;
+ t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15];
+ t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2;
+
+ t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16];
+ t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2;
+ t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17];
+ t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2;
+ t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18];
+ t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2;
+ t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19];
+ t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2;
+ t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20];
+ t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2;
+ t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21];
+ t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2;
+ t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22];
+ t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2;
+ t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23];
+ t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2;
+
+ t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24];
+ t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2;
+ t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25];
+ t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2;
+ t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26];
+ t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2;
+ t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27];
+ t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2;
+ t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28];
+ t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2;
+ t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29];
+ t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2;
+ t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30];
+ t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2;
+ t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31];
+ t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2;
+
+ t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32];
+ t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2;
+ t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33];
+ t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2;
+ t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34];
+ t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2;
+ t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35];
+ t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2;
+ t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36];
+ t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2;
+ t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37];
+ t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2;
+ t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38];
+ t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2;
+ t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39];
+ t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2;
+
+ t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40];
+ t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2;
+ t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41];
+ t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2;
+ t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42];
+ t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2;
+ t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43];
+ t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2;
+ t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44];
+ t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2;
+ t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45];
+ t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2;
+ t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46];
+ t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2;
+ t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47];
+ t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2;
+
+ t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48];
+ t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2;
+ t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49];
+ t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2;
+ t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50];
+ t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2;
+ t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51];
+ t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2;
+ t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52];
+ t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2;
+ t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53];
+ t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2;
+ t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54];
+ t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2;
+ t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55];
+ t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2;
+
+ t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56];
+ t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2;
+ t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57];
+ t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2;
+ t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58];
+ t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2;
+ t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59];
+ t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2;
+ t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60];
+ t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2;
+ t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61];
+ t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2;
+ t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62];
+ t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2;
+ t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63];
+ t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2;
+
+ state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+ state[4] += e; state[5] += f; state[6] += g; state[7] += h;
+
+ /* clear any sensitive info... */
+ a = b = c = d = e = f = g = h = t1 = t2 = 0;
+ memset(W, 0, 64 * sizeof(u32));
+}
+
+static int sha224_init(struct digest *desc)
+{
+ struct sha256_state *sctx = digest_ctx(desc);
+ sctx->state[0] = SHA224_H0;
+ sctx->state[1] = SHA224_H1;
+ sctx->state[2] = SHA224_H2;
+ sctx->state[3] = SHA224_H3;
+ sctx->state[4] = SHA224_H4;
+ sctx->state[5] = SHA224_H5;
+ sctx->state[6] = SHA224_H6;
+ sctx->state[7] = SHA224_H7;
+ sctx->count = 0;
+
+ return 0;
+}
+
+static int sha256_init(struct digest *desc)
+{
+ struct sha256_state *sctx = digest_ctx(desc);
+ sctx->state[0] = SHA256_H0;
+ sctx->state[1] = SHA256_H1;
+ sctx->state[2] = SHA256_H2;
+ sctx->state[3] = SHA256_H3;
+ sctx->state[4] = SHA256_H4;
+ sctx->state[5] = SHA256_H5;
+ sctx->state[6] = SHA256_H6;
+ sctx->state[7] = SHA256_H7;
+ sctx->count = 0;
+
+ return 0;
+}
+
+static int sha256_update(struct digest *desc, const void *data,
+ unsigned long len)
+{
+ struct sha256_state *sctx = digest_ctx(desc);
+ unsigned int partial, done;
+ const u8 *src;
+
+ partial = sctx->count & 0x3f;
+ sctx->count += len;
+ done = 0;
+ src = data;
+
+ if ((partial + len) > 63) {
+ if (partial) {
+ done = -partial;
+ memcpy(sctx->buf + partial, data, done + 64);
+ src = sctx->buf;
+ }
+
+ do {
+ sha256_transform(sctx->state, src);
+ done += 64;
+ src = data + done;
+ } while (done + 63 < len);
+
+ partial = 0;
+ }
+ memcpy(sctx->buf + partial, src, len - done);
+
+ return 0;
+}
+
+static int sha256_final(struct digest *desc, u8 *out)
+{
+ struct sha256_state *sctx = digest_ctx(desc);
+ __be32 *dst = (__be32 *)out;
+ __be64 bits;
+ unsigned int index, pad_len;
+ int i;
+ static const u8 padding[64] = { 0x80, };
+
+ /* Save number of bits */
+ bits = cpu_to_be64(sctx->count << 3);
+
+ /* Pad out to 56 mod 64. */
+ index = sctx->count & 0x3f;
+ pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
+ sha256_update(desc, padding, pad_len);
+
+ /* Append length (before padding) */
+ sha256_update(desc, (const u8 *)&bits, sizeof(bits));
+
+ /* Store state in digest */
+ for (i = 0; i < 8; i++)
+ dst[i] = cpu_to_be32(sctx->state[i]);
+
+ /* Zeroize sensitive information. */
+ memset(sctx, 0, sizeof(*sctx));
+
+ return 0;
+}
+
+static int sha224_final(struct digest *desc, u8 *hash)
+{
+ u8 D[SHA256_DIGEST_SIZE];
+
+ sha256_final(desc, D);
+
+ memcpy(hash, D, SHA224_DIGEST_SIZE);
+ memset(D, 0, SHA256_DIGEST_SIZE);
+
+ return 0;
+}
+
+static struct digest_algo m224 = {
+ .base = {
+ .name = "sha224",
+ .driver_name = "sha224-generic",
+ .priority = 0,
+ .algo = HASH_ALGO_SHA224,
+ },
+
+ .init = sha224_init,
+ .update = sha256_update,
+ .final = sha224_final,
+ .digest = digest_generic_digest,
+ .verify = digest_generic_verify,
+ .length = SHA224_DIGEST_SIZE,
+ .ctx_length = sizeof(struct sha256_state),
+};
+
+static int sha224_digest_register(void)
+{
+ if (!IS_ENABLED(CONFIG_SHA224))
+ return 0;
+
+ return digest_algo_register(&m224);
+}
+device_initcall(sha224_digest_register);
+
+static struct digest_algo m256 = {
+ .base = {
+ .name = "sha256",
+ .driver_name = "sha256-generic",
+ .priority = 0,
+ .algo = HASH_ALGO_SHA256,
+ },
+
+ .init = sha256_init,
+ .update = sha256_update,
+ .final = sha256_final,
+ .digest = digest_generic_digest,
+ .verify = digest_generic_verify,
+ .length = SHA256_DIGEST_SIZE,
+ .ctx_length = sizeof(struct sha256_state),
+};
+
+static int sha256_digest_register(void)
+{
+ if (!IS_ENABLED(CONFIG_SHA256))
+ return 0;
+
+ return digest_algo_register(&m256);
+}
+device_initcall(sha256_digest_register);
diff --git a/src/digest.h b/src/digest.h
new file mode 100644
index 0000000..efe330d
--- /dev/null
+++ b/src/digest.h
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2008-2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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; version 2 of
+ * the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#ifndef __DIGEST_H__
+#define __DIGEST_H__
+
+#include <linux/list.h>
+
+struct digest;
+
+enum hash_algo {
+ HASH_ALGO_MD4,
+ HASH_ALGO_MD5,
+ HASH_ALGO_SHA1,
+ HASH_ALGO_RIPE_MD_160,
+ HASH_ALGO_SHA224,
+ HASH_ALGO_SHA256,
+ HASH_ALGO_SHA384,
+ HASH_ALGO_SHA512,
+ HASH_ALGO_RIPE_MD_128,
+ HASH_ALGO_RIPE_MD_256,
+ HASH_ALGO_RIPE_MD_320,
+ HASH_ALGO_WP_256,
+ HASH_ALGO_WP_384,
+ HASH_ALGO_WP_512,
+ HASH_ALGO_TGR_128,
+ HASH_ALGO_TGR_160,
+ HASH_ALGO_TGR_192,
+ HASH_ALGO__LAST
+};
+
+struct crypto_alg {
+ char *name;
+ char *driver_name;
+ int priority;
+#define DIGEST_ALGO_NEED_KEY (1 << 0)
+ unsigned int flags;
+ enum hash_algo algo;
+};
+
+struct digest_algo {
+ struct crypto_alg base;
+
+ 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);
+ 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);
+
+ unsigned int length;
+ unsigned int ctx_length;
+
+ struct list_head list;
+};
+
+struct digest {
+ struct digest_algo *algo;
+ void *ctx;
+ unsigned int length;
+};
+
+/*
+ * digest functions
+ */
+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);
+struct digest *digest_alloc_by_algo(enum hash_algo);
+void digest_free(struct digest *d);
+
+int digest_file_window(struct digest *d, const char *filename,
+ unsigned char *hash,
+ const unsigned char *sig,
+ ulong start, ulong size);
+int digest_file(struct digest *d, const char *filename,
+ unsigned char *hash,
+ const unsigned char *sig);
+int digest_file_by_name(const char *algo, const char *filename,
+ unsigned char *hash,
+ const unsigned char *sig);
+
+static inline int digest_init(struct digest *d)
+{
+ return d->algo->init(d);
+}
+
+static inline int digest_update(struct digest *d, const void *data,
+ unsigned long len)
+{
+ return d->algo->update(d, data, len);
+}
+
+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);
+}
+
+static inline int digest_length(struct digest *d)
+{
+ return d->length ? d->length : d->algo->length;
+}
+
+static inline int digest_set_key(struct digest *d, const unsigned char *key,
+ unsigned int len)
+{
+ if (!d->algo->set_key)
+ return -ENOTSUPP;
+ return d->algo->set_key(d, key, len);
+}
+
+static inline int digest_is_flags(struct digest *d, unsigned int flags)
+{
+ return d->algo->base.flags & flags;
+}
+
+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__ */
diff --git a/src/dt/common.h b/src/dt/common.h
index 5645bad..d049ee7 100644
--- a/src/dt/common.h
+++ b/src/dt/common.h
@@ -3,8 +3,10 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -40,11 +42,23 @@
#define dev_info(dev, fmt, arg...) pr_err(fmt, ##arg)
#define dev_dbg(dev, fmt, arg...) pr_debug(fmt, ##arg)
+#ifndef ENOTSUPP
+#define ENOTSUPP 524
+#endif
+
static inline void *xzalloc(size_t size)
{
return calloc(1, size);
}
+static inline void *xmalloc(size_t size)
+{
+ return xzalloc(size);
+}
+
+#define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_GPL(sym)
+
/*
* Kernel pointers have redundant information, so we can use a
* scheme where we can return either an error code or a dentry
@@ -92,6 +106,20 @@ static inline void *ERR_CAST(const void *ptr)
return (void *) ptr;
}
+static inline char *barebox_asprintf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
+static inline char *barebox_asprintf(const char *fmt, ...)
+{
+ va_list ap;
+ char *p;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(&p, fmt, ap);
+ va_end(ap);
+
+ return ret == -1 ? NULL : p;
+}
+
/**
* strlcpy - Copy a %NUL terminated string into a sized buffer
* @dest: Where to copy the string to
@@ -226,6 +254,15 @@ static inline int write_full(int fd, void *buf, size_t size)
return insize;
}
+static inline void *memmap(int fd, int flags)
+{
+ return (void *)-1;
+}
+
+static inline int ctrlc (void)
+{
+ return 0;
+}
#define MAX_DRIVER_NAME 32
#define DEVICE_ID_SINGLE -1
@@ -295,9 +332,37 @@ static inline int of_unregister_fixup(int (*fixup)(struct device_node *, void *)
return 0;
}
+#define __define_initcall(level,fn,id) \
+static void __attribute__ ((constructor)) __initcall_##id##_##fn() { \
+ fn(); \
+}
+
+#define core_initcall(fn) __define_initcall("1",fn,1)
+#define postcore_initcall(fn) __define_initcall("2",fn,2)
+#define console_initcall(fn) __define_initcall("3",fn,3)
+#define postconsole_initcall(fn) __define_initcall("4",fn,4)
+#define mem_initcall(fn) __define_initcall("5",fn,5)
+#define mmu_initcall(fn) __define_initcall("6",fn,6)
+#define postmmu_initcall(fn) __define_initcall("7",fn,7)
+#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 crypto_initcall(fn) __define_initcall("11",fn,11)
+#define late_initcall(fn) __define_initcall("12",fn,12)
+#define environment_initcall(fn) __define_initcall("13",fn,13)
+#define postenvironment_initcall(fn) __define_initcall("14",fn,14)
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
#define cpu_to_be32 __cpu_to_be32
#define be32_to_cpu __be32_to_cpu
+#define cpu_to_be64 __cpu_to_be64
+#define be64_to_cpu __be64_to_cpu
+
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
@@ -305,6 +370,136 @@ static inline int of_unregister_fixup(int (*fixup)(struct device_node *, void *)
#define __maybe_unused __attribute__((unused))
+static inline u16 __get_unaligned_be16(const u8 *p)
+{
+ return p[0] << 8 | p[1];
+}
+
+static inline u32 __get_unaligned_be32(const u8 *p)
+{
+ return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+}
+
+static inline u64 __get_unaligned_be64(const u8 *p)
+{
+ return (u64)__get_unaligned_be32(p) << 32 |
+ __get_unaligned_be32(p + 4);
+}
+
+static inline void __put_unaligned_be16(u16 val, u8 *p)
+{
+ *p++ = val >> 8;
+ *p++ = val;
+}
+
+static inline void __put_unaligned_be32(u32 val, u8 *p)
+{
+ __put_unaligned_be16(val >> 16, p);
+ __put_unaligned_be16(val, p + 2);
+}
+
+static inline void __put_unaligned_be64(u64 val, u8 *p)
+{
+ __put_unaligned_be32(val >> 32, p);
+ __put_unaligned_be32(val, p + 4);
+}
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+ return __get_unaligned_be16((const u8 *)p);
+}
+
+static inline u32 get_unaligned_be32(const void *p)
+{
+ return __get_unaligned_be32((const u8 *)p);
+}
+
+static inline u64 get_unaligned_be64(const void *p)
+{
+ return __get_unaligned_be64((const u8 *)p);
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+ __put_unaligned_be16(val, p);
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+ __put_unaligned_be32(val, p);
+}
+
+static inline void put_unaligned_be64(u64 val, void *p)
+{
+ __put_unaligned_be64(val, p);
+}
+
+/**
+ * rol32 - rotate a 32-bit value left
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline __u32 rol32(__u32 word, unsigned int shift)
+{
+ return (word << shift) | (word >> (32 - shift));
+}
+
+/**
+ * ror32 - rotate a 32-bit value right
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline __u32 ror32(__u32 word, unsigned int shift)
+{
+ return (word >> shift) | (word << (32 - shift));
+}
+
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+/*
+ * Helper macros to use CONFIG_ options in C expressions. Note that
+ * these only work with boolean and tristate options.
+ */
+
+/*
+ * Getting something that works in C and CPP for an arg that may or may
+ * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1"
+ * we match on the placeholder define, insert the "0," for arg1 and generate
+ * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one).
+ * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
+ * the last step cherry picks the 2nd arg, we get a zero.
+ */
+#define __ARG_PLACEHOLDER_1 0,
+#define config_enabled(cfg) _config_enabled(cfg)
+#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
+#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
+#define ___config_enabled(__ignored, val, ...) val
+
+/*
+ * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
+ * 0 otherwise.
+ *
+ */
+#define IS_ENABLED(option) \
+ (config_enabled(option) || config_enabled(option##_MODULE))
+
+/*
+ * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
+ * otherwise. For boolean options, this is equivalent to
+ * IS_ENABLED(CONFIG_FOO).
+ */
+#define IS_BUILTIN(option) config_enabled(option)
+
+/*
+ * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
+ * otherwise.
+ */
+#define IS_MODULE(option) config_enabled(option##_MODULE)
+
#endif
uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len);
diff --git a/src/fs.h b/src/fs.h
new file mode 100644
index 0000000..8b05b1a
--- /dev/null
+++ b/src/fs.h
@@ -0,0 +1 @@
+#include <sys/mman.h>
diff --git a/src/init.h b/src/init.h
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/src/init.h
@@ -0,0 +1 @@
+/* empty */
diff --git a/src/linux/err.h b/src/linux/err.h
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/src/linux/err.h
@@ -0,0 +1 @@
+/* empty */
diff --git a/src/linux/list.h b/src/linux/list.h
new file mode 100644
index 0000000..83c6d75
--- /dev/null
+++ b/src/linux/list.h
@@ -0,0 +1 @@
+#include <dt/list.h>
diff --git a/src/module.h b/src/module.h
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/src/module.h
@@ -0,0 +1 @@
+/* empty */