summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-05-13 09:24:52 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-06-05 23:14:23 +0000
commite166d04e797b605dd2f6784bc863a262c418c0c4 (patch)
tree1ddb71af00e1080d5687fdd72cee5000af79f078
parent786acdabcc15f023330d7c628aca9679e757a238 (diff)
downloadvboot-e166d04e797b605dd2f6784bc863a262c418c0c4.tar.gz
vboot2: Add crypto functions
This is the first of several CLs adding a more memory- and code-efficient firmware verification library. This CL adds the crypto library (modified from firmware/lib/cryptolib) and unit tests for it. BUG=chromium:370082 BRANCH=none TEST=make clean && VBOOT2=1 COV=1 make Change-Id: I4240eab227bb197cacc6c8e7a6397127d74414a2 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/199578 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--Makefile13
-rw-r--r--firmware/2lib/2rsa.c361
-rw-r--r--firmware/2lib/2sha1.c292
-rw-r--r--firmware/2lib/2sha256.c316
-rw-r--r--firmware/2lib/2sha512.c346
-rw-r--r--firmware/2lib/2sha_utility.c130
-rw-r--r--firmware/2lib/include/2rsa.h82
-rw-r--r--firmware/2lib/include/2sha.h159
-rw-r--r--tests/vb2_rsa_padding_tests.c150
-rwxr-xr-xtests/vb2_rsa_tests.sh44
-rw-r--r--tests/vb2_rsa_utility_tests.c106
-rw-r--r--tests/vb2_sha_tests.c148
12 files changed, 2147 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index c9bcec32..33c74179 100644
--- a/Makefile
+++ b/Makefile
@@ -280,6 +280,11 @@ VBSLK_SRCS = \
# Firmware library source needed for smaller library 2
FWLIB2_SRCS = \
firmware/2lib/2common.c \
+ firmware/2lib/2rsa.c \
+ firmware/2lib/2sha1.c \
+ firmware/2lib/2sha256.c \
+ firmware/2lib/2sha512.c \
+ firmware/2lib/2sha_utility.c \
# Support real TPM unless BIOS sets MOCK_TPM
ifeq (${MOCK_TPM},)
@@ -559,6 +564,9 @@ endif
ifneq (${VBOOT2},)
TEST_NAMES += \
tests/vb2_common_tests \
+ tests/vb2_rsa_padding_tests \
+ tests/vb2_rsa_utility_tests \
+ tests/vb2_sha_tests \
endif
@@ -1046,6 +1054,9 @@ runtestscripts: test_setup genfuzztestcases
tests/run_rsa_tests.sh
tests/run_vbutil_kernel_arg_tests.sh
tests/run_vbutil_tests.sh
+ifneq (${VBOOT2},)
+ tests/vb2_rsa_tests.sh
+endif
.PHONY: runmisctests
runmisctests: test_setup
@@ -1077,6 +1088,8 @@ runmisctests: test_setup
.PHONY: run2tests
run2tests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vb2_common_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_tests
.PHONY: runfutiltests
runfutiltests: override DESTDIR = ${TEST_INSTALL_DIR}
diff --git a/firmware/2lib/2rsa.c b/firmware/2lib/2rsa.c
new file mode 100644
index 00000000..e619e78b
--- /dev/null
+++ b/firmware/2lib/2rsa.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Implementation of RSA signature verification which uses a pre-processed key
+ * for computation. The code extends Android's RSA verification code to support
+ * multiple RSA key lengths and hash digest algorithms.
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2rsa.h"
+#include "2sha.h"
+
+/**
+ * a[] -= mod
+ */
+static void subM(const struct vb2_public_key *key, uint32_t *a)
+{
+ int64_t A = 0;
+ uint32_t i;
+ for (i = 0; i < key->arrsize; ++i) {
+ A += (uint64_t)a[i] - key->n[i];
+ a[i] = (uint32_t)A;
+ A >>= 32;
+ }
+}
+
+/**
+ * Return a[] >= mod
+ */
+int vb2_mont_ge(const struct vb2_public_key *key, uint32_t *a)
+{
+ uint32_t i;
+ for (i = key->arrsize; i;) {
+ --i;
+ if (a[i] < key->n[i])
+ return 0;
+ if (a[i] > key->n[i])
+ return 1;
+ }
+ return 1; /* equal */
+}
+
+/**
+ * Montgomery c[] += a * b[] / R % mod
+ */
+static void montMulAdd(const struct vb2_public_key *key,
+ uint32_t *c,
+ const uint32_t a,
+ const uint32_t *b)
+{
+ uint64_t A = (uint64_t)a * b[0] + c[0];
+ uint32_t d0 = (uint32_t)A * key->n0inv;
+ uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+ uint32_t i;
+
+ for (i = 1; i < key->arrsize; ++i) {
+ A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+ B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+ c[i - 1] = (uint32_t)B;
+ }
+
+ A = (A >> 32) + (B >> 32);
+
+ c[i - 1] = (uint32_t)A;
+
+ if (A >> 32) {
+ subM(key, c);
+ }
+}
+
+/**
+ * Montgomery c[] = a[] * b[] / R % mod
+ */
+static void montMul(const struct vb2_public_key *key,
+ uint32_t *c,
+ const uint32_t *a,
+ const uint32_t *b)
+{
+ uint32_t i;
+ for (i = 0; i < key->arrsize; ++i) {
+ c[i] = 0;
+ }
+ for (i = 0; i < key->arrsize; ++i) {
+ montMulAdd(key, c, a[i], b);
+ }
+}
+
+/**
+ * In-place public exponentiation. (65537}
+ *
+ * @param key Key to use in signing
+ * @param inout Input and output big-endian byte array
+ * @param workbuf32 Work buffer; caller must verify this is
+ * (3 * key->arrsize) elements long.
+ */
+static void modpowF4(const struct vb2_public_key *key, uint8_t *inout,
+ uint32_t *workbuf32)
+{
+ uint32_t *a = workbuf32;
+ uint32_t *aR = a + key->arrsize;
+ uint32_t *aaR = aR + key->arrsize;
+ uint32_t *aaa = aaR; /* Re-use location. */
+ int i;
+
+ /* Convert from big endian byte array to little endian word array. */
+ for (i = 0; i < (int)key->arrsize; ++i) {
+ uint32_t tmp =
+ (inout[((key->arrsize - 1 - i) * 4) + 0] << 24) |
+ (inout[((key->arrsize - 1 - i) * 4) + 1] << 16) |
+ (inout[((key->arrsize - 1 - i) * 4) + 2] << 8) |
+ (inout[((key->arrsize - 1 - i) * 4) + 3] << 0);
+ a[i] = tmp;
+ }
+
+ montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
+ for (i = 0; i < 16; i+=2) {
+ montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
+ montMul(key, aR, aaR, aaR); /* aR = aaR * aaR / R mod M */
+ }
+ montMul(key, aaa, aR, a); /* aaa = aR * a / R mod M */
+
+
+ /* Make sure aaa < mod; aaa is at most 1x mod too large. */
+ if (vb2_mont_ge(key, aaa)) {
+ subM(key, aaa);
+ }
+
+ /* Convert to bigendian byte array */
+ for (i = (int)key->arrsize - 1; i >= 0; --i) {
+ uint32_t tmp = aaa[i];
+ *inout++ = (uint8_t)(tmp >> 24);
+ *inout++ = (uint8_t)(tmp >> 16);
+ *inout++ = (uint8_t)(tmp >> 8);
+ *inout++ = (uint8_t)(tmp >> 0);
+ }
+}
+
+/**
+ * Safer memcmp() for use in crypto.
+ *
+ * Compares the buffers to see if they are equal. Time taken to perform
+ * the comparison is dependent only on the size, not the relationship of
+ * the match between the buffers. Note that unlike memcmp(), this only
+ * indicates inequality, not which buffer is lesser.
+ *
+ * @param s1 First buffer
+ * @param s2 Second buffer
+ * @param size Number of bytes to compare
+ * @return 0 if match or size=0, non-zero if at least one byte mismatched.
+ */
+int vb2_safe_memcmp(const void *s1, const void *s2, size_t size)
+{
+ const unsigned char *us1 = s1;
+ const unsigned char *us2 = s2;
+ int result = 0;
+
+ if (0 == size)
+ return 0;
+
+ /*
+ * Code snippet without data-dependent branch due to Nate Lawson
+ * (nate@root.org) of Root Labs.
+ */
+ while (size--)
+ result |= *us1++ ^ *us2++;
+
+ return result != 0;
+}
+
+uint32_t vb2_rsa_sig_size(uint32_t algorithm)
+{
+ switch (algorithm) {
+ case VB2_ALG_RSA1024_SHA1:
+ case VB2_ALG_RSA1024_SHA256:
+ case VB2_ALG_RSA1024_SHA512:
+ return 1024 / 8;
+ case VB2_ALG_RSA2048_SHA1:
+ case VB2_ALG_RSA2048_SHA256:
+ case VB2_ALG_RSA2048_SHA512:
+ return 2048 / 8;
+ case VB2_ALG_RSA4096_SHA1:
+ case VB2_ALG_RSA4096_SHA256:
+ case VB2_ALG_RSA4096_SHA512:
+ return 4096 / 8;
+ case VB2_ALG_RSA8192_SHA1:
+ case VB2_ALG_RSA8192_SHA256:
+ case VB2_ALG_RSA8192_SHA512:
+ return 8192 / 8;
+ default:
+ return 0;
+ }
+}
+
+uint32_t vb2_packed_key_size(uint32_t algorithm)
+{
+ if (algorithm >= VB2_ALG_COUNT)
+ return 0;
+
+ /*
+ * Total size needed by a RSAPublicKey buffer is =
+ * 2 * key_len bytes for the n and rr arrays
+ * + sizeof len + sizeof n0inv.
+ */
+ return 2 * vb2_rsa_sig_size(algorithm) + 2 * sizeof(uint32_t);
+}
+
+/*
+ * PKCS 1.5 padding (from the RSA PKCS#1 v2.1 standard)
+ *
+ * Depending on the RSA key size and hash function, the padding is calculated
+ * as follows:
+ *
+ * 0x00 || 0x01 || PS || 0x00 || T
+ *
+ * T: DER Encoded DigestInfo value which depends on the hash function used.
+ *
+ * SHA-1: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H.
+ * SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H.
+ * SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H.
+ *
+ * Length(T) = 35 octets for SHA-1
+ * Length(T) = 51 octets for SHA-256
+ * Length(T) = 83 octets for SHA-512
+ *
+ * PS: octet string consisting of {Length(RSA Key) - Length(T) - 3} 0xFF
+ */
+static const uint8_t sha1_tail[] = {
+ 0x00,0x30,0x21,0x30,0x09,0x06,0x05,0x2b,
+ 0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14
+};
+
+static const uint8_t sha256_tail[] = {
+ 0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,
+ 0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,
+ 0x05,0x00,0x04,0x20
+};
+
+static const uint8_t sha512_tail[] = {
+ 0x00,0x30,0x51,0x30,0x0d,0x06,0x09,0x60,
+ 0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,
+ 0x05,0x00,0x04,0x40
+};
+
+/**
+ * Check pkcs 1.5 padding bytes
+ *
+ * @param sig Signature to verify
+ * @param algorithm Key algorithm
+ * @return VB2_SUCCESS, or non-zero if error.
+ */
+int vb2_check_padding(uint8_t *sig, int algorithm)
+{
+ /* Determine padding to use depending on the signature type */
+ uint32_t pad_size = vb2_rsa_sig_size(algorithm) -
+ vb2_digest_size(algorithm);
+ const uint8_t *tail;
+ uint32_t tail_size;
+ int result = 0;
+
+ int i;
+
+ switch (algorithm) {
+ case VB2_ALG_RSA1024_SHA1:
+ case VB2_ALG_RSA2048_SHA1:
+ case VB2_ALG_RSA4096_SHA1:
+ case VB2_ALG_RSA8192_SHA1:
+ tail = sha1_tail;
+ tail_size = sizeof(sha1_tail);
+ break;
+ case VB2_ALG_RSA1024_SHA256:
+ case VB2_ALG_RSA2048_SHA256:
+ case VB2_ALG_RSA4096_SHA256:
+ case VB2_ALG_RSA8192_SHA256:
+ tail = sha256_tail;
+ tail_size = sizeof(sha256_tail);
+ break;
+ case VB2_ALG_RSA1024_SHA512:
+ case VB2_ALG_RSA2048_SHA512:
+ case VB2_ALG_RSA4096_SHA512:
+ case VB2_ALG_RSA8192_SHA512:
+ tail = sha512_tail;
+ tail_size = sizeof(sha512_tail);
+ break;
+ default:
+ return VB2_ERROR_BAD_ALGORITHM;
+ }
+
+ /* First 2 bytes are always 0x00 0x01 */
+ result |= *sig++ ^ 0x00;
+ result |= *sig++ ^ 0x01;
+
+ /* Then 0xff bytes until the tail */
+ for (i = 0; i < pad_size - tail_size - 2; i++)
+ result |= *sig++ ^ 0xff;
+
+ /*
+ * Then the tail. Even though there are probably no timing issues
+ * here, we use vb2_safe_memcmp() just to be on the safe side.
+ */
+ result |= vb2_safe_memcmp(sig, tail, tail_size);
+
+ return result ? VB2_ERROR_BAD_SIGNATURE : VB2_SUCCESS;
+}
+
+int vb2_verify_digest(const struct vb2_public_key *key,
+ uint8_t *sig,
+ const uint8_t *digest,
+ struct vb2_workbuf *wb)
+{
+ struct vb2_workbuf wblocal = *wb;
+ uint32_t *workbuf32;
+ uint32_t key_bytes = key->arrsize * sizeof(uint32_t);
+ int pad_size;
+ int rv;
+
+ if (!key || !sig || !digest)
+ return VB2_ERROR_UNKNOWN;
+
+ if (key->algorithm >= VB2_ALG_COUNT) {
+ VB2_DEBUG("Invalid signature type!\n");
+ return VB2_ERROR_BAD_ALGORITHM;
+ }
+
+ /* Signature length should be same as key length */
+ if (key_bytes != vb2_rsa_sig_size(key->algorithm)) {
+ VB2_DEBUG("Signature is of incorrect length!\n");
+ return VB2_ERROR_BAD_SIGNATURE;
+ }
+
+ workbuf32 = vb2_workbuf_alloc(&wblocal, 3 * key_bytes);
+ if (!workbuf32)
+ return VB2_ERROR_UNKNOWN;
+
+ modpowF4(key, sig, workbuf32);
+
+ vb2_workbuf_free(&wblocal, 3 * key_bytes);
+
+ /* Check padding */
+ rv = vb2_check_padding(sig, key->algorithm);
+ if (rv)
+ return rv;
+
+ /*
+ * Check digest. Even though there are probably no timing issues here,
+ * use vb2_safe_memcmp() just to be on the safe side. (That's also why
+ * we don't return before this check if the padding check failed.)
+ */
+ pad_size = vb2_rsa_sig_size(key->algorithm) -
+ vb2_digest_size(key->algorithm);
+
+ if (vb2_safe_memcmp(sig + pad_size, digest, key_bytes - pad_size)) {
+ VB2_DEBUG("Digest check failed!\n");
+ rv = VB2_ERROR_BAD_SIGNATURE;
+ }
+
+ return rv;
+}
diff --git a/firmware/2lib/2sha1.c b/firmware/2lib/2sha1.c
new file mode 100644
index 00000000..41c83174
--- /dev/null
+++ b/firmware/2lib/2sha1.c
@@ -0,0 +1,292 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * SHA-1 implementation largely based on libmincrypt in the the Android
+ * Open Source Project (platorm/system/core.git/libmincrypt/sha.c
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2sha.h"
+
+/*
+ * Some machines lack byteswap.h and endian.h. These have to use the
+ * slower code, even if they're little-endian.
+ */
+
+#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+
+/*
+ * This version is about 28% faster than the generic version below,
+ * but assumes little-endianness.
+ */
+static uint32_t ror27(uint32_t val)
+{
+ return (val >> 27) | (val << 5);
+}
+
+static uint32_t ror2(uint32_t val)
+{
+ return (val >> 2) | (val << 30);
+}
+
+static uint32_t ror31(uint32_t val)
+{
+ return (val >> 31) | (val << 1);
+}
+
+static void sha1_transform(struct vb2_sha1_context *ctx)
+{
+ /* Note that this array uses 80*4=320 bytes of stack */
+ uint32_t W[80];
+ register uint32_t A, B, C, D, E;
+ int t;
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+#define SHA_F1(A,B,C,D,E,t) \
+ E += ror27(A) + \
+ (W[t] = bswap_32(ctx->buf.w[t])) + \
+ (D^(B&(C^D))) + 0x5A827999; \
+ B = ror2(B);
+
+ for (t = 0; t < 15; t += 5) {
+ SHA_F1(A,B,C,D,E,t + 0);
+ SHA_F1(E,A,B,C,D,t + 1);
+ SHA_F1(D,E,A,B,C,t + 2);
+ SHA_F1(C,D,E,A,B,t + 3);
+ SHA_F1(B,C,D,E,A,t + 4);
+ }
+ SHA_F1(A,B,C,D,E,t + 0); /* 16th one, t == 15 */
+
+#undef SHA_F1
+
+#define SHA_F1(A,B,C,D,E,t) \
+ E += ror27(A) + \
+ (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
+ (D^(B&(C^D))) + 0x5A827999; \
+ B = ror2(B);
+
+ SHA_F1(E,A,B,C,D,t + 1);
+ SHA_F1(D,E,A,B,C,t + 2);
+ SHA_F1(C,D,E,A,B,t + 3);
+ SHA_F1(B,C,D,E,A,t + 4);
+
+#undef SHA_F1
+
+#define SHA_F2(A,B,C,D,E,t) \
+ E += ror27(A) + \
+ (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
+ (B^C^D) + 0x6ED9EBA1; \
+ B = ror2(B);
+
+ for (t = 20; t < 40; t += 5) {
+ SHA_F2(A,B,C,D,E,t + 0);
+ SHA_F2(E,A,B,C,D,t + 1);
+ SHA_F2(D,E,A,B,C,t + 2);
+ SHA_F2(C,D,E,A,B,t + 3);
+ SHA_F2(B,C,D,E,A,t + 4);
+ }
+
+#undef SHA_F2
+
+#define SHA_F3(A,B,C,D,E,t) \
+ E += ror27(A) + \
+ (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
+ ((B&C)|(D&(B|C))) + 0x8F1BBCDC; \
+ B = ror2(B);
+
+ for (; t < 60; t += 5) {
+ SHA_F3(A,B,C,D,E,t + 0);
+ SHA_F3(E,A,B,C,D,t + 1);
+ SHA_F3(D,E,A,B,C,t + 2);
+ SHA_F3(C,D,E,A,B,t + 3);
+ SHA_F3(B,C,D,E,A,t + 4);
+ }
+
+#undef SHA_F3
+
+#define SHA_F4(A,B,C,D,E,t) \
+ E += ror27(A) + \
+ (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
+ (B^C^D) + 0xCA62C1D6; \
+ B = ror2(B);
+
+ for (; t < 80; t += 5) {
+ SHA_F4(A,B,C,D,E,t + 0);
+ SHA_F4(E,A,B,C,D,t + 1);
+ SHA_F4(D,E,A,B,C,t + 2);
+ SHA_F4(C,D,E,A,B,t + 3);
+ SHA_F4(B,C,D,E,A,t + 4);
+ }
+
+#undef SHA_F4
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+}
+
+void vb2_sha1_update(struct vb2_sha1_context *ctx,
+ const uint8_t *data,
+ uint32_t size)
+{
+ int i = ctx->count % sizeof(ctx->buf);
+ const uint8_t *p = (const uint8_t*)data;
+
+ ctx->count += size;
+
+ while (size > sizeof(ctx->buf) - i) {
+ memcpy(&ctx->buf.b[i], p, sizeof(ctx->buf) - i);
+ size -= sizeof(ctx->buf) - i;
+ p += sizeof(ctx->buf) - i;
+ sha1_transform(ctx);
+ i = 0;
+ }
+
+ while (size--) {
+ ctx->buf.b[i++] = *p++;
+ if (i == sizeof(ctx->buf)) {
+ sha1_transform(ctx);
+ i = 0;
+ }
+ }
+}
+
+uint8_t *vb2_sha1_finalize(struct vb2_sha1_context *ctx)
+{
+ uint32_t cnt = ctx->count * 8;
+ int i;
+
+ vb2_sha1_update(ctx, (uint8_t*)"\x80", 1);
+ while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
+ vb2_sha1_update(ctx, (uint8_t*)"\0", 1);
+ }
+
+ for (i = 0; i < 8; ++i) {
+ uint8_t tmp = cnt >> ((7 - i) * 8);
+ vb2_sha1_update(ctx, &tmp, 1);
+ }
+
+ for (i = 0; i < 5; i++) {
+ ctx->buf.w[i] = bswap_32(ctx->state[i]);
+ }
+
+ return ctx->buf.b;
+}
+
+#else /* #if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN) */
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void sha1_transform(struct vb2_sha1_context *ctx)
+{
+ /* Note that this array uses 80*4=320 bytes of stack */
+ uint32_t W[80];
+ uint32_t A, B, C, D, E;
+ uint8_t *p = ctx->buf;
+ int t;
+
+ for(t = 0; t < 16; ++t) {
+ uint32_t tmp = *p++ << 24;
+ tmp |= *p++ << 16;
+ tmp |= *p++ << 8;
+ tmp |= *p++;
+ W[t] = tmp;
+ }
+
+ for(; t < 80; t++) {
+ W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+ for(t = 0; t < 80; t++) {
+ uint32_t tmp = rol(5,A) + E + W[t];
+
+ if (t < 20)
+ tmp += (D^(B&(C^D))) + 0x5A827999;
+ else if ( t < 40)
+ tmp += (B^C^D) + 0x6ED9EBA1;
+ else if ( t < 60)
+ tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+ else
+ tmp += (B^C^D) + 0xCA62C1D6;
+
+ E = D;
+ D = C;
+ C = rol(30,B);
+ B = A;
+ A = tmp;
+ }
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+}
+
+void vb2_sha1_update(struct vb2_sha1_context *ctx,
+ const uint8_t *data,
+ uint32_t size)
+{
+ int i = (int)(ctx->count % sizeof(ctx->buf));
+ const uint8_t* p = (const uint8_t*) data;
+
+ ctx->count += size;
+
+ while (size--) {
+ ctx->buf[i++] = *p++;
+ if (i == sizeof(ctx->buf)) {
+ sha1_transform(ctx);
+ i = 0;
+ }
+ }
+}
+
+void vb2_sha1_finalize(struct vb2_sha1_context *ctx, uint8_t *digest)
+{
+ uint32_t cnt = ctx->count << 3;
+ int i;
+
+ vb2_sha1_update(ctx, (uint8_t*)"\x80", 1);
+ while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
+ vb2_sha1_update(ctx, (uint8_t*)"\0", 1);
+ }
+ for (i = 0; i < 8; ++i) {
+ uint8_t tmp = (uint8_t)((uint64_t)cnt >> ((7 - i) * 8));
+ vb2_sha1_update(ctx, &tmp, 1);
+ }
+
+ for (i = 0; i < 5; i++) {
+ uint32_t tmp = ctx->state[i];
+ *digest++ = (uint8_t)(tmp >> 24);
+ *digest++ = (uint8_t)(tmp >> 16);
+ *digest++ = (uint8_t)(tmp >> 8);
+ *digest++ = (uint8_t)(tmp >> 0);
+ }
+}
+
+#endif /* endianness */
+
+void vb2_sha1_init(struct vb2_sha1_context *ctx)
+{
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xc3d2e1f0;
+ ctx->count = 0;
+}
diff --git a/firmware/2lib/2sha256.c b/firmware/2lib/2sha256.c
new file mode 100644
index 00000000..fd41258c
--- /dev/null
+++ b/firmware/2lib/2sha256.c
@@ -0,0 +1,316 @@
+/* SHA-256 and SHA-512 implementation based on code by Oliver Gay
+ * <olivier.gay@a3.epfl.ch> under a BSD-style license. See below.
+ */
+
+/*
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date: 04/30/2005
+ *
+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2sha.h"
+
+#define SHFR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z) ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
+#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
+
+#define UNPACK32(x, str) \
+ { \
+ *((str) + 3) = (uint8_t) ((x) ); \
+ *((str) + 2) = (uint8_t) ((x) >> 8); \
+ *((str) + 1) = (uint8_t) ((x) >> 16); \
+ *((str) + 0) = (uint8_t) ((x) >> 24); \
+ }
+
+#define PACK32(str, x) \
+ { \
+ *(x) = ((uint32_t) *((str) + 3) ) \
+ | ((uint32_t) *((str) + 2) << 8) \
+ | ((uint32_t) *((str) + 1) << 16) \
+ | ((uint32_t) *((str) + 0) << 24); \
+ }
+
+/* Macros used for loops unrolling */
+
+#define SHA256_SCR(i) \
+ { \
+ w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \
+ + SHA256_F3(w[i - 15]) + w[i - 16]; \
+ }
+
+#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \
+ { \
+ t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
+ + sha256_k[j] + w[j]; \
+ t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
+ wv[d] += t1; \
+ wv[h] = t1 + t2; \
+ }
+
+static const uint32_t sha256_h0[8] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+};
+
+static const uint32_t sha256_k[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/* SHA-256 implementation */
+void vb2_sha256_init(struct vb2_sha256_context *ctx)
+{
+#ifndef UNROLL_LOOPS
+ int i;
+ for (i = 0; i < 8; i++) {
+ ctx->h[i] = sha256_h0[i];
+ }
+#else
+ ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1];
+ ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3];
+ ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5];
+ ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7];
+#endif /* !UNROLL_LOOPS */
+
+ ctx->size = 0;
+ ctx->total_size = 0;
+}
+
+static void vb2_sha256_transform(struct vb2_sha256_context *ctx,
+ const uint8_t *message,
+ unsigned int block_nb)
+{
+ /* Note that these arrays use 72*4=288 bytes of stack */
+ uint32_t w[64];
+ uint32_t wv[8];
+ uint32_t t1, t2;
+ const unsigned char *sub_block;
+ int i;
+
+#ifndef UNROLL_LOOPS
+ int j;
+#endif
+
+ for (i = 0; i < (int) block_nb; i++) {
+ sub_block = message + (i << 6);
+
+#ifndef UNROLL_LOOPS
+ for (j = 0; j < 16; j++) {
+ PACK32(&sub_block[j << 2], &w[j]);
+ }
+
+ for (j = 16; j < 64; j++) {
+ SHA256_SCR(j);
+ }
+
+ for (j = 0; j < 8; j++) {
+ wv[j] = ctx->h[j];
+ }
+
+ for (j = 0; j < 64; j++) {
+ t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ + sha256_k[j] + w[j];
+ t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+ wv[7] = wv[6];
+ wv[6] = wv[5];
+ wv[5] = wv[4];
+ wv[4] = wv[3] + t1;
+ wv[3] = wv[2];
+ wv[2] = wv[1];
+ wv[1] = wv[0];
+ wv[0] = t1 + t2;
+ }
+
+ for (j = 0; j < 8; j++) {
+ ctx->h[j] += wv[j];
+ }
+#else
+ PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]);
+ PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]);
+ PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]);
+ PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]);
+ PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]);
+ PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]);
+ PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]);
+ PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]);
+
+ SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19);
+ SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23);
+ SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27);
+ SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31);
+ SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35);
+ SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39);
+ SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43);
+ SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47);
+ SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51);
+ SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55);
+ SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59);
+ SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63);
+
+ wv[0] = ctx->h[0]; wv[1] = ctx->h[1];
+ wv[2] = ctx->h[2]; wv[3] = ctx->h[3];
+ wv[4] = ctx->h[4]; wv[5] = ctx->h[5];
+ wv[6] = ctx->h[6]; wv[7] = ctx->h[7];
+
+ SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1);
+ SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3);
+ SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5);
+ SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7);
+ SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9);
+ SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11);
+ SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13);
+ SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15);
+ SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17);
+ SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19);
+ SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21);
+ SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23);
+ SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25);
+ SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27);
+ SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29);
+ SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31);
+ SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33);
+ SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35);
+ SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37);
+ SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39);
+ SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41);
+ SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43);
+ SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45);
+ SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47);
+ SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49);
+ SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51);
+ SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53);
+ SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55);
+ SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57);
+ SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59);
+ SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61);
+ SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63);
+
+ ctx->h[0] += wv[0]; ctx->h[1] += wv[1];
+ ctx->h[2] += wv[2]; ctx->h[3] += wv[3];
+ ctx->h[4] += wv[4]; ctx->h[5] += wv[5];
+ ctx->h[6] += wv[6]; ctx->h[7] += wv[7];
+#endif /* !UNROLL_LOOPS */
+ }
+}
+
+void vb2_sha256_update(struct vb2_sha256_context *ctx,
+ const uint8_t *data,
+ uint32_t size)
+{
+ unsigned int block_nb;
+ unsigned int new_size, rem_size, tmp_size;
+ const uint8_t *shifted_data;
+
+ tmp_size = VB2_SHA256_BLOCK_SIZE - ctx->size;
+ rem_size = size < tmp_size ? size : tmp_size;
+
+ memcpy(&ctx->block[ctx->size], data, rem_size);
+
+ if (ctx->size + size < VB2_SHA256_BLOCK_SIZE) {
+ ctx->size += size;
+ return;
+ }
+
+ new_size = size - rem_size;
+ block_nb = new_size / VB2_SHA256_BLOCK_SIZE;
+
+ shifted_data = data + rem_size;
+
+ vb2_sha256_transform(ctx, ctx->block, 1);
+ vb2_sha256_transform(ctx, shifted_data, block_nb);
+
+ rem_size = new_size % VB2_SHA256_BLOCK_SIZE;
+
+ memcpy(ctx->block, &shifted_data[block_nb << 6],
+ rem_size);
+
+ ctx->size = rem_size;
+ ctx->total_size += (block_nb + 1) << 6;
+}
+
+void vb2_sha256_finalize(struct vb2_sha256_context *ctx, uint8_t *digest)
+{
+ unsigned int block_nb;
+ unsigned int pm_size;
+ unsigned int size_b;
+#ifndef UNROLL_LOOPS
+ int i;
+#endif
+
+ block_nb = (1 + ((VB2_SHA256_BLOCK_SIZE - 9)
+ < (ctx->size % VB2_SHA256_BLOCK_SIZE)));
+
+ size_b = (ctx->total_size + ctx->size) << 3;
+ pm_size = block_nb << 6;
+
+ memset(ctx->block + ctx->size, 0, pm_size - ctx->size);
+ ctx->block[ctx->size] = 0x80;
+ UNPACK32(size_b, ctx->block + pm_size - 4);
+
+ vb2_sha256_transform(ctx, ctx->block, block_nb);
+
+#ifndef UNROLL_LOOPS
+ for (i = 0 ; i < 8; i++) {
+ UNPACK32(ctx->h[i], &digest[i << 2]);
+ }
+#else
+ UNPACK32(ctx->h[0], &digest[ 0]);
+ UNPACK32(ctx->h[1], &digest[ 4]);
+ UNPACK32(ctx->h[2], &digest[ 8]);
+ UNPACK32(ctx->h[3], &digest[12]);
+ UNPACK32(ctx->h[4], &digest[16]);
+ UNPACK32(ctx->h[5], &digest[20]);
+ UNPACK32(ctx->h[6], &digest[24]);
+ UNPACK32(ctx->h[7], &digest[28]);
+#endif /* !UNROLL_LOOPS */
+}
diff --git a/firmware/2lib/2sha512.c b/firmware/2lib/2sha512.c
new file mode 100644
index 00000000..fedc8b7a
--- /dev/null
+++ b/firmware/2lib/2sha512.c
@@ -0,0 +1,346 @@
+/* SHA-256 and SHA-512 implementation based on code by Oliver Gay
+ * <olivier.gay@a3.epfl.ch> under a BSD-style license. See below.
+ */
+
+/*
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date: 04/30/2005
+ *
+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2sha.h"
+
+#define SHFR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z) ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
+#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
+#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7))
+#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6))
+
+#define UNPACK32(x, str) \
+ { \
+ *((str) + 3) = (uint8_t) ((x) ); \
+ *((str) + 2) = (uint8_t) ((x) >> 8); \
+ *((str) + 1) = (uint8_t) ((x) >> 16); \
+ *((str) + 0) = (uint8_t) ((x) >> 24); \
+ }
+
+#define UNPACK64(x, str) \
+ { \
+ *((str) + 7) = (uint8_t) x; \
+ *((str) + 6) = (uint8_t) ((uint64_t)x >> 8); \
+ *((str) + 5) = (uint8_t) ((uint64_t)x >> 16); \
+ *((str) + 4) = (uint8_t) ((uint64_t)x >> 24); \
+ *((str) + 3) = (uint8_t) ((uint64_t)x >> 32); \
+ *((str) + 2) = (uint8_t) ((uint64_t)x >> 40); \
+ *((str) + 1) = (uint8_t) ((uint64_t)x >> 48); \
+ *((str) + 0) = (uint8_t) ((uint64_t)x >> 56); \
+ }
+
+#define PACK64(str, x) \
+ { \
+ *(x) = ((uint64_t) *((str) + 7) ) \
+ | ((uint64_t) *((str) + 6) << 8) \
+ | ((uint64_t) *((str) + 5) << 16) \
+ | ((uint64_t) *((str) + 4) << 24) \
+ | ((uint64_t) *((str) + 3) << 32) \
+ | ((uint64_t) *((str) + 2) << 40) \
+ | ((uint64_t) *((str) + 1) << 48) \
+ | ((uint64_t) *((str) + 0) << 56); \
+ }
+
+/* Macros used for loops unrolling */
+
+#define SHA512_SCR(i) \
+ { \
+ w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \
+ + SHA512_F3(w[i - 15]) + w[i - 16]; \
+ }
+
+#define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \
+ { \
+ t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
+ + sha512_k[j] + w[j]; \
+ t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
+ wv[d] += t1; \
+ wv[h] = t1 + t2; \
+ }
+
+static const uint64_t sha512_h0[8] = {
+ 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
+ 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
+ 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
+};
+
+static const uint64_t sha512_k[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* SHA-512 implementation */
+
+void vb2_sha512_init(struct vb2_sha512_context *ctx)
+{
+#ifdef UNROLL_LOOPS_SHA512
+ ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1];
+ ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3];
+ ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5];
+ ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7];
+#else
+ int i;
+
+ for (i = 0; i < 8; i++)
+ ctx->h[i] = sha512_h0[i];
+#endif /* UNROLL_LOOPS_SHA512 */
+
+ ctx->size = 0;
+ ctx->total_size = 0;
+}
+
+static void vb2_sha512_transform(struct vb2_sha512_context *ctx,
+ const uint8_t *message,
+ unsigned int block_nb)
+{
+ /* Note that these arrays use 88*8=704 bytes of stack */
+ uint64_t w[80];
+ uint64_t wv[8];
+ uint64_t t1, t2;
+ const uint8_t *sub_block;
+ int i, j;
+
+ for (i = 0; i < (int) block_nb; i++) {
+ sub_block = message + (i << 7);
+
+#ifdef UNROLL_LOOPS_SHA512
+ PACK64(&sub_block[ 0], &w[ 0]);
+ PACK64(&sub_block[ 8], &w[ 1]);
+ PACK64(&sub_block[ 16], &w[ 2]);
+ PACK64(&sub_block[ 24], &w[ 3]);
+ PACK64(&sub_block[ 32], &w[ 4]);
+ PACK64(&sub_block[ 40], &w[ 5]);
+ PACK64(&sub_block[ 48], &w[ 6]);
+ PACK64(&sub_block[ 56], &w[ 7]);
+ PACK64(&sub_block[ 64], &w[ 8]);
+ PACK64(&sub_block[ 72], &w[ 9]);
+ PACK64(&sub_block[ 80], &w[10]);
+ PACK64(&sub_block[ 88], &w[11]);
+ PACK64(&sub_block[ 96], &w[12]);
+ PACK64(&sub_block[104], &w[13]);
+ PACK64(&sub_block[112], &w[14]);
+ PACK64(&sub_block[120], &w[15]);
+
+ SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19);
+ SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23);
+ SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27);
+ SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31);
+ SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35);
+ SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39);
+ SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43);
+ SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47);
+ SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51);
+ SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55);
+ SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59);
+ SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63);
+ SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67);
+ SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71);
+ SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75);
+ SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79);
+
+ wv[0] = ctx->h[0]; wv[1] = ctx->h[1];
+ wv[2] = ctx->h[2]; wv[3] = ctx->h[3];
+ wv[4] = ctx->h[4]; wv[5] = ctx->h[5];
+ wv[6] = ctx->h[6]; wv[7] = ctx->h[7];
+
+ j = 0;
+
+ do {
+ SHA512_EXP(0,1,2,3,4,5,6,7,j); j++;
+ SHA512_EXP(7,0,1,2,3,4,5,6,j); j++;
+ SHA512_EXP(6,7,0,1,2,3,4,5,j); j++;
+ SHA512_EXP(5,6,7,0,1,2,3,4,j); j++;
+ SHA512_EXP(4,5,6,7,0,1,2,3,j); j++;
+ SHA512_EXP(3,4,5,6,7,0,1,2,j); j++;
+ SHA512_EXP(2,3,4,5,6,7,0,1,j); j++;
+ SHA512_EXP(1,2,3,4,5,6,7,0,j); j++;
+ } while (j < 80);
+
+ ctx->h[0] += wv[0]; ctx->h[1] += wv[1];
+ ctx->h[2] += wv[2]; ctx->h[3] += wv[3];
+ ctx->h[4] += wv[4]; ctx->h[5] += wv[5];
+ ctx->h[6] += wv[6]; ctx->h[7] += wv[7];
+#else
+ for (j = 0; j < 16; j++) {
+ PACK64(&sub_block[j << 3], &w[j]);
+ }
+
+ for (j = 16; j < 80; j++) {
+ SHA512_SCR(j);
+ }
+
+ for (j = 0; j < 8; j++) {
+ wv[j] = ctx->h[j];
+ }
+
+ for (j = 0; j < 80; j++) {
+ t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ + sha512_k[j] + w[j];
+ t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+ wv[7] = wv[6];
+ wv[6] = wv[5];
+ wv[5] = wv[4];
+ wv[4] = wv[3] + t1;
+ wv[3] = wv[2];
+ wv[2] = wv[1];
+ wv[1] = wv[0];
+ wv[0] = t1 + t2;
+ }
+
+ for (j = 0; j < 8; j++)
+ ctx->h[j] += wv[j];
+#endif /* UNROLL_LOOPS_SHA512 */
+ }
+}
+
+void vb2_sha512_update(struct vb2_sha512_context *ctx,
+ const uint8_t *data,
+ uint32_t size)
+{
+ unsigned int block_nb;
+ unsigned int new_size, rem_size, tmp_size;
+ const uint8_t *shifted_data;
+
+ tmp_size = VB2_SHA512_BLOCK_SIZE - ctx->size;
+ rem_size = size < tmp_size ? size : tmp_size;
+
+ memcpy(&ctx->block[ctx->size], data, rem_size);
+
+ if (ctx->size + size < VB2_SHA512_BLOCK_SIZE) {
+ ctx->size += size;
+ return;
+ }
+
+ new_size = size - rem_size;
+ block_nb = new_size / VB2_SHA512_BLOCK_SIZE;
+
+ shifted_data = data + rem_size;
+
+ vb2_sha512_transform(ctx, ctx->block, 1);
+ vb2_sha512_transform(ctx, shifted_data, block_nb);
+
+ rem_size = new_size % VB2_SHA512_BLOCK_SIZE;
+
+ memcpy(ctx->block, &shifted_data[block_nb << 7],
+ rem_size);
+
+ ctx->size = rem_size;
+ ctx->total_size += (block_nb + 1) << 7;
+}
+
+void vb2_sha512_finalize(struct vb2_sha512_context *ctx, uint8_t *digest)
+{
+ unsigned int block_nb;
+ unsigned int pm_size;
+ unsigned int size_b;
+
+#ifndef UNROLL_LOOPS_SHA512
+ int i;
+#endif
+
+ block_nb = 1 + ((VB2_SHA512_BLOCK_SIZE - 17)
+ < (ctx->size % VB2_SHA512_BLOCK_SIZE));
+
+ size_b = (ctx->total_size + ctx->size) << 3;
+ pm_size = block_nb << 7;
+
+ memset(ctx->block + ctx->size, 0, pm_size - ctx->size);
+ ctx->block[ctx->size] = 0x80;
+ UNPACK32(size_b, ctx->block + pm_size - 4);
+
+ vb2_sha512_transform(ctx, ctx->block, block_nb);
+
+#ifdef UNROLL_LOOPS_SHA512
+ UNPACK64(ctx->h[0], &digest[ 0]);
+ UNPACK64(ctx->h[1], &digest[ 8]);
+ UNPACK64(ctx->h[2], &digest[16]);
+ UNPACK64(ctx->h[3], &digest[24]);
+ UNPACK64(ctx->h[4], &digest[32]);
+ UNPACK64(ctx->h[5], &digest[40]);
+ UNPACK64(ctx->h[6], &digest[48]);
+ UNPACK64(ctx->h[7], &digest[56]);
+#else
+ for (i = 0 ; i < 8; i++)
+ UNPACK64(ctx->h[i], &digest[i << 3]);
+#endif /* UNROLL_LOOPS_SHA512 */
+}
diff --git a/firmware/2lib/2sha_utility.c b/firmware/2lib/2sha_utility.c
new file mode 100644
index 00000000..66e8b692
--- /dev/null
+++ b/firmware/2lib/2sha_utility.c
@@ -0,0 +1,130 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Utility functions for message digest functions.
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2rsa.h"
+#include "2sha.h"
+
+/* Hash algorithms. Note that they line up with key algorithms. */
+enum vb2_hash_algorithm {
+ VB2_HASH_SHA1 = VB2_ALG_RSA1024_SHA1,
+ VB2_HASH_SHA256 = VB2_ALG_RSA1024_SHA256,
+ VB2_HASH_SHA512 = VB2_ALG_RSA1024_SHA512,
+
+ /* Number of hash algorithms */
+ VB2_HASH_COUNT
+};
+
+/**
+ * Convert key algorithm to hash algorithm.
+ */
+static enum vb2_hash_algorithm vb2_hash_alg(uint32_t algorithm)
+{
+ if (algorithm < VB2_ALG_COUNT)
+ return algorithm % VB2_HASH_COUNT;
+ else
+ return VB2_HASH_COUNT;
+}
+
+int vb2_digest_size(uint32_t algorithm)
+{
+ switch (vb2_hash_alg(algorithm)) {
+#if VB2_SUPPORT_SHA1
+ case VB2_HASH_SHA1:
+ return VB2_SHA1_DIGEST_SIZE;
+#endif
+#if VB2_SUPPORT_SHA256
+ case VB2_HASH_SHA256:
+ return VB2_SHA256_DIGEST_SIZE;
+#endif
+#if VB2_SUPPORT_SHA512
+ case VB2_HASH_SHA512:
+ return VB2_SHA512_DIGEST_SIZE;
+#endif
+ default:
+ return 0;
+ }
+}
+
+int vb2_digest_init(struct vb2_digest_context *dc, uint32_t algorithm)
+{
+ dc->algorithm = algorithm;
+
+ switch (vb2_hash_alg(dc->algorithm)) {
+#if VB2_SUPPORT_SHA1
+ case VB2_HASH_SHA1:
+ vb2_sha1_init(&dc->sha1);
+ return VB2_SUCCESS;
+#endif
+#if VB2_SUPPORT_SHA256
+ case VB2_HASH_SHA256:
+ vb2_sha256_init(&dc->sha256);
+ return VB2_SUCCESS;
+#endif
+#if VB2_SUPPORT_SHA512
+ case VB2_HASH_SHA512:
+ vb2_sha512_init(&dc->sha512);
+ return VB2_SUCCESS;
+#endif
+ default:
+ return VB2_ERROR_BAD_ALGORITHM;
+ }
+}
+
+int vb2_digest_extend(struct vb2_digest_context *dc,
+ const uint8_t *buf,
+ uint32_t size)
+{
+ switch (vb2_hash_alg(dc->algorithm)) {
+#if VB2_SUPPORT_SHA1
+ case VB2_HASH_SHA1:
+ vb2_sha1_update(&dc->sha1, buf, size);
+ return VB2_SUCCESS;
+#endif
+#if VB2_SUPPORT_SHA256
+ case VB2_HASH_SHA256:
+ vb2_sha256_update(&dc->sha256, buf, size);
+ return VB2_SUCCESS;
+#endif
+#if VB2_SUPPORT_SHA512
+ case VB2_HASH_SHA512:
+ vb2_sha512_update(&dc->sha512, buf, size);
+ return VB2_SUCCESS;
+#endif
+ default:
+ return VB2_ERROR_BAD_ALGORITHM;
+ }
+}
+
+int vb2_digest_finalize(struct vb2_digest_context *dc,
+ uint8_t *digest,
+ uint32_t digest_size)
+{
+ if (digest_size < vb2_digest_size(dc->algorithm))
+ return VB2_ERROR_BUFFER_TOO_SMALL;
+
+ switch (vb2_hash_alg(dc->algorithm)) {
+#if VB2_SUPPORT_SHA1
+ case VB2_HASH_SHA1:
+ vb2_sha1_finalize(&dc->sha1, digest);
+ return VB2_SUCCESS;
+#endif
+#if VB2_SUPPORT_SHA256
+ case VB2_HASH_SHA256:
+ vb2_sha256_finalize(&dc->sha256, digest);
+ return VB2_SUCCESS;
+#endif
+#if VB2_SUPPORT_SHA512
+ case VB2_HASH_SHA512:
+ vb2_sha512_finalize(&dc->sha512, digest);
+ return VB2_SUCCESS;
+#endif
+ default:
+ return VB2_ERROR_BAD_ALGORITHM;
+ }
+}
diff --git a/firmware/2lib/include/2rsa.h b/firmware/2lib/include/2rsa.h
new file mode 100644
index 00000000..1fee1922
--- /dev/null
+++ b/firmware/2lib/include/2rsa.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef VBOOT_REFERENCE_2RSA_H_
+#define VBOOT_REFERENCE_2RSA_H_
+
+struct vb2_workbuf;
+
+/* Algorithms for crypto lib */
+enum vb2_crypto_algorithm {
+ VB2_ALG_RSA1024_SHA1 = 0,
+ VB2_ALG_RSA1024_SHA256,
+ VB2_ALG_RSA1024_SHA512,
+ VB2_ALG_RSA2048_SHA1,
+ VB2_ALG_RSA2048_SHA256,
+ VB2_ALG_RSA2048_SHA512,
+ VB2_ALG_RSA4096_SHA1,
+ VB2_ALG_RSA4096_SHA256,
+ VB2_ALG_RSA4096_SHA512,
+ VB2_ALG_RSA8192_SHA1,
+ VB2_ALG_RSA8192_SHA256,
+ VB2_ALG_RSA8192_SHA512,
+ // TODO: add algorithms for bare SHA with no RSA?
+
+ /* Number of algorithms */
+ VB2_ALG_COUNT
+};
+
+/* Public key structure in RAM */
+struct vb2_public_key {
+ uint32_t arrsize; /* Length of n[] and rr[] in number of uint32_t */
+ uint32_t n0inv; /* -1 / n[0] mod 2^32 */
+ const uint32_t *n; /* Modulus as little endian array */
+ const uint32_t *rr; /* R^2 as little endian array */
+ uint32_t algorithm; /* Algorithm to use when verifying with the key */
+};
+
+/**
+ * Return the size of a RSA signature
+ *
+ * @param algorithm Key algorithm
+ * @return The size of the signature, or 0 if error.
+ */
+uint32_t vb2_rsa_sig_size(uint32_t algorithm);
+
+/**
+ * Return the size of a pre-processed RSA public key.
+ *
+ * @param algorithm Key algorithm
+ * @return The size of the preprocessed key, or 0 if error.
+ */
+uint32_t vb2_packed_key_size(uint32_t algorithm);
+
+/**
+ * Check pkcs 1.5 padding bytes
+ *
+ * @param sig Signature to verify
+ * @param algorithm Key algorithm
+ * @return VB2_SUCCESS, or non-zero if error.
+ */
+int vb2_check_padding(uint8_t *sig, int algorithm);
+
+/* Size of work buffer sufficient for vb2_verify_digest() worst case */
+#define VB2_VERIFY_DIGEST_WORKBUF_BYTES (3 * 1024)
+
+/**
+ * Verify a RSA PKCS1.5 signature against an expected hash digest.
+ *
+ * @param key Key to use in signature verification
+ * @param sig Signature to verify (destroyed in process)
+ * @param digest Digest of signed data
+ * @param wb Work buffer
+ * @return VB2_SUCCESS, or non-zero if error.
+ */
+int vb2_verify_digest(const struct vb2_public_key *key,
+ uint8_t *sig,
+ const uint8_t *digest,
+ struct vb2_workbuf *wb);
+
+#endif /* VBOOT_REFERENCE_2RSA_H_ */
diff --git a/firmware/2lib/include/2sha.h b/firmware/2lib/include/2sha.h
new file mode 100644
index 00000000..83a2c624
--- /dev/null
+++ b/firmware/2lib/include/2sha.h
@@ -0,0 +1,159 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef VBOOT_REFERENCE_2SHA_H_
+#define VBOOT_REFERENCE_2SHA_H_
+
+/* Hash algorithms may be disabled individually to save code space */
+
+#ifndef VB2_SUPPORT_SHA1
+#define VB2_SUPPORT_SHA1 1
+#endif
+
+#ifndef VB2_SUPPORT_SHA256
+#define VB2_SUPPORT_SHA256 1
+#endif
+
+#ifndef VB2_SUPPORT_SHA512
+#define VB2_SUPPORT_SHA512 1
+#endif
+
+#define VB2_SHA1_DIGEST_SIZE 20
+#define VB2_SHA1_BLOCK_SIZE 64
+
+/* Context structs for hash algorithms */
+
+struct vb2_sha1_context {
+ uint32_t count;
+ uint32_t state[5];
+#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+ union {
+ uint8_t b[VB2_SHA1_BLOCK_SIZE];
+ uint32_t w[VB2_SHA1_BLOCK_SIZE / sizeof(uint32_t)];
+ } buf;
+#else
+ uint8_t buf[VB2_SHA1_BLOCK_SIZE];
+#endif
+};
+
+#define VB2_SHA256_DIGEST_SIZE 32
+#define VB2_SHA256_BLOCK_SIZE 64
+
+struct vb2_sha256_context {
+ uint32_t h[8];
+ uint32_t total_size;
+ uint32_t size;
+ uint8_t block[2 * VB2_SHA256_BLOCK_SIZE];
+};
+
+#define VB2_SHA512_DIGEST_SIZE 64
+#define VB2_SHA512_BLOCK_SIZE 128
+
+struct vb2_sha512_context {
+ uint64_t h[8];
+ uint32_t total_size;
+ uint32_t size;
+ uint8_t block[2 * VB2_SHA512_BLOCK_SIZE];
+};
+
+/* Hash algorithm independent digest context; includes all of the above. */
+struct vb2_digest_context {
+ /* Context union for all algorithms */
+ union {
+#if VB2_SUPPORT_SHA1
+ struct vb2_sha1_context sha1;
+#endif
+#if VB2_SUPPORT_SHA256
+ struct vb2_sha256_context sha256;
+#endif
+#if VB2_SUPPORT_SHA512
+ struct vb2_sha512_context sha512;
+#endif
+ };
+
+ /* Current hash algorithms */
+ uint32_t algorithm;
+};
+
+/**
+ * Initialize a hash context.
+ *
+ * @param ctx Hash context
+ */
+void vb2_sha1_init(struct vb2_sha1_context *ctx);
+void vb2_sha256_init(struct vb2_sha256_context *ctx);
+void vb2_sha512_init(struct vb2_sha512_context *ctx);
+
+/**
+ * Update (extend) a hash.
+ *
+ * @param ctx Hash context
+ * @param data Data to hash
+ * @param size Length of data in bytes
+ */
+void vb2_sha1_update(struct vb2_sha1_context *ctx,
+ const uint8_t *data,
+ uint32_t size);
+void vb2_sha256_update(struct vb2_sha256_context *ctx,
+ const uint8_t *data,
+ uint32_t size);
+void vb2_sha512_update(struct vb2_sha512_context *ctx,
+ const uint8_t *data,
+ uint32_t size);
+
+/**
+ * Finalize a hash digest.
+ *
+ * @param ctx Hash context
+ * @param digest Destination for hash; must be VB_SHA*_DIGEST_SIZE bytes
+ */
+void vb2_sha1_finalize(struct vb2_sha1_context *ctx, uint8_t *digest);
+void vb2_sha256_finalize(struct vb2_sha256_context *ctx, uint8_t *digest);
+void vb2_sha512_finalize(struct vb2_sha512_context *ctx, uint8_t *digest);
+
+/**
+ * Return the size of the digest for a key algorithm.
+ *
+ * @param algorithm Key algorithm
+ * @return The size of the digest, or 0 if error.
+ */
+int vb2_digest_size(uint32_t algorithm);
+
+/**
+ * Initialize a digest context for doing block-style digesting.
+ *
+ * @param dc Digest context
+ * @param algorithm Key algorithm
+ * @return VB2_SUCCESS, or non-zero on error.
+ */
+int vb2_digest_init(struct vb2_digest_context *dc, uint32_t algorithm);
+
+/**
+ * Extend a digest's hash with another block of data.
+ *
+ * @param dc Digest context
+ * @param buf Data to hash
+ * @param size Length of data in bytes
+ * @return VB2_SUCCESS, or non-zero on error.
+ */
+int vb2_digest_extend(struct vb2_digest_context *dc,
+ const uint8_t *buf,
+ uint32_t size);
+
+/**
+ * Finalize a digest and store the result.
+ *
+ * The destination digest should be at least vb2_digest_size(algorithm).
+ *
+ * @param dc Digest context
+ * @param digest Destination for digest
+ * @param digest_size Length of digest buffer in bytes.
+ * @return VB2_SUCCESS, or non-zero on error.
+ */
+int vb2_digest_finalize(struct vb2_digest_context *dc,
+ uint8_t *digest,
+ uint32_t digest_size);
+
+#endif /* VBOOT_REFERENCE_2SHA_H_ */
diff --git a/tests/vb2_rsa_padding_tests.c b/tests/vb2_rsa_padding_tests.c
new file mode 100644
index 00000000..233f7298
--- /dev/null
+++ b/tests/vb2_rsa_padding_tests.c
@@ -0,0 +1,150 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "cryptolib.h"
+#include "file_keys.h"
+#include "rsa_padding_test.h"
+#include "test_common.h"
+#include "utility.h"
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2rsa.h"
+
+/**
+ * Convert an old-style RSA public key struct to a new one.
+ *
+ * The new one does not allocate memory, so you must keep the old one around
+ * until you're done with the new one.
+ *
+ * @param k2 Destination new key
+ * @param key Source old key
+ */
+void vb2_public_key_to_vb2(struct vb2_public_key *k2,
+ const struct RSAPublicKey *key)
+{
+ k2->arrsize = key->len;
+ k2->n0inv = key->n0inv;
+ k2->n = key->n;
+ k2->rr = key->rr;
+ k2->algorithm = key->algorithm;
+}
+
+/**
+ * Test valid and invalid signatures.
+ */
+static void test_signatures(const struct vb2_public_key *key)
+{
+ uint8_t workbuf[VB2_VERIFY_DIGEST_WORKBUF_BYTES];
+ uint8_t sig[RSA1024NUMBYTES];
+ struct vb2_workbuf wb;
+ int unexpected_success;
+ int i;
+
+ vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
+
+ /* The first test signature is valid. */
+ Memcpy(sig, signatures[0], sizeof(sig));
+ TEST_EQ(vb2_verify_digest(key, sig, test_message_sha1_hash, &wb),
+ 0, "RSA Padding Test valid sig");
+
+ /* All other signatures should fail verification. */
+ unexpected_success = 0;
+ for (i = 1; i < sizeof(signatures) / sizeof(signatures[0]); i++) {
+ Memcpy(sig, signatures[i], sizeof(sig));
+ if (!vb2_verify_digest(key, sig, test_message_sha1_hash, &wb)) {
+ fprintf(stderr,
+ "RSA Padding Test vector %d FAILED!\n", i);
+ unexpected_success++;
+ }
+ }
+ TEST_EQ(unexpected_success, 0, "RSA Padding Test invalid sigs");
+}
+
+
+/**
+ * Test other error conditions in vb2_verify_digest().
+ */
+static void test_verify_digest(struct vb2_public_key *key) {
+ uint8_t workbuf[VB2_VERIFY_DIGEST_WORKBUF_BYTES];
+ uint8_t sig[RSA1024NUMBYTES];
+ struct vb2_workbuf wb;
+
+ vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
+
+ Memcpy(sig, signatures[0], sizeof(sig));
+ TEST_EQ(vb2_verify_digest(key, sig, test_message_sha1_hash, &wb),
+ 0, "vb2_verify_digest() good");
+
+ Memcpy(sig, signatures[0], sizeof(sig));
+ vb2_workbuf_init(&wb, workbuf, sizeof(sig) * 3 - 1);
+ TEST_NEQ(vb2_verify_digest(key, sig, test_message_sha1_hash, &wb),
+ 0, "vb2_verify_digest() small workbuf");
+ vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
+
+ key->algorithm += VB2_ALG_COUNT;
+ Memcpy(sig, signatures[0], sizeof(sig));
+ TEST_NEQ(vb2_verify_digest(key, sig, test_message_sha1_hash, &wb),
+ 0, "vb2_verify_digest() bad key alg");
+ key->algorithm -= VB2_ALG_COUNT;
+
+ key->arrsize *= 2;
+ Memcpy(sig, signatures[0], sizeof(sig));
+ TEST_NEQ(vb2_verify_digest(key, sig, test_message_sha1_hash, &wb),
+ 0, "vb2_verify_digest() bad key len");
+ key->arrsize /= 2;
+
+ /* Corrupt the signature near start and end */
+ Memcpy(sig, signatures[0], sizeof(sig));
+ sig[3] ^= 0x42;
+ TEST_NEQ(vb2_verify_digest(key, sig, test_message_sha1_hash, &wb),
+ 0, "vb2_verify_digest() bad sig");
+
+ Memcpy(sig, signatures[0], sizeof(sig));
+ sig[RSA1024NUMBYTES - 3] ^= 0x56;
+ TEST_NEQ(vb2_verify_digest(key, sig, test_message_sha1_hash, &wb),
+ 0, "vb2_verify_digest() bad sig end");
+}
+
+int main(int argc, char *argv[])
+{
+ int error = 0;
+ RSAPublicKey *key;
+ struct vb2_public_key k2;
+
+ /* Read test key */
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <test public key>\n", argv[0]);
+ return 1;
+ }
+ key = RSAPublicKeyFromFile(argv[1]);
+
+ if (!key) {
+ fprintf(stderr, "Couldn't read RSA public key for the test.\n");
+ return 1;
+ }
+
+ // TODO: why is test key algorithm wrong?
+ key->algorithm = 0;
+
+ /* Convert test key to Vb2 format */
+ vb2_public_key_to_vb2(&k2, key);
+
+ /* Run tests */
+ test_signatures(&k2);
+ test_verify_digest(&k2);
+
+ /* Clean up and exit */
+ RSAPublicKeyFree(key);
+
+ if (!gTestSuccess)
+ error = 255;
+
+ return error;
+}
diff --git a/tests/vb2_rsa_tests.sh b/tests/vb2_rsa_tests.sh
new file mode 100755
index 00000000..331b0669
--- /dev/null
+++ b/tests/vb2_rsa_tests.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Run tests for RSA Signature verification.
+
+# Load common constants and variables.
+. "$(dirname "$0")/common.sh"
+
+set -e
+
+return_code=0
+TEST_FILE=${TESTCASE_DIR}/test_file
+
+function test_signatures {
+ algorithmcounter=0
+ for keylen in ${key_lengths[@]}
+ do
+ for hashalgo in ${hash_algos[@]}
+ do
+ echo -e "For ${COL_YELLOW}RSA-$keylen and $hashalgo${COL_STOP}:"
+ ${UTIL_DIR}/verify_data $algorithmcounter \
+ ${TESTKEY_DIR}/key_rsa${keylen}.keyb \
+ ${TEST_FILE}.rsa${keylen}_${hashalgo}.sig \
+ ${TEST_FILE}
+ if [ $? -ne 0 ]
+ then
+ return_code=255
+ fi
+ let algorithmcounter=algorithmcounter+1
+ done
+ done
+ echo -e "Peforming ${COL_YELLOW}PKCS #1 v1.5 Padding Tests${COL_STOP}..."
+ ${TEST_DIR}/vb2_rsa_padding_tests ${TESTKEY_DIR}/rsa_padding_test_pubkey.keyb
+}
+
+check_test_keys
+echo "Testing signature verification..."
+test_signatures
+
+exit $return_code
+
diff --git a/tests/vb2_rsa_utility_tests.c b/tests/vb2_rsa_utility_tests.c
new file mode 100644
index 00000000..df3eb37a
--- /dev/null
+++ b/tests/vb2_rsa_utility_tests.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include <stdint.h>
+#include <stdio.h>
+
+#define _STUB_IMPLEMENTATION_
+
+#include "cryptolib.h"
+#include "file_keys.h"
+#include "rsa_padding_test.h"
+#include "test_common.h"
+#include "utility.h"
+#include "vboot_api.h"
+
+#include "2common.h"
+#include "2rsa.h"
+
+/*
+ * Internal functions from 2rsa.c that have error conditions we can't trigger
+ * from the public APIs. These include checks for bad algorithms where the
+ * next call level up already checks for bad algorithms, etc.
+ *
+ * These functions aren't in 2rsa.h because they're not part of the public
+ * APIs.
+ */
+int vb2_mont_ge(const struct vb2_public_key *key, uint32_t *a);
+int vb2_check_padding(uint8_t *sig, int algorithm);
+int vb2_safe_memcmp(const void *s1, const void *s2, size_t size);
+
+/**
+ * Test RSA utility funcs
+ */
+static void test_utils(void)
+{
+ /* Verify old and new algorithm count constants match */
+ TEST_EQ(kNumAlgorithms, VB2_ALG_COUNT, "Algorithm counts");
+
+ /* Sig size */
+ TEST_EQ(vb2_rsa_sig_size(VB2_ALG_RSA1024_SHA1), RSA1024NUMBYTES,
+ "Sig size VB2_ALG_RSA1024_SHA1");
+ TEST_EQ(vb2_rsa_sig_size(VB2_ALG_RSA2048_SHA1), RSA2048NUMBYTES,
+ "Sig size VB2_ALG_RSA2048_SHA1");
+ TEST_EQ(vb2_rsa_sig_size(VB2_ALG_RSA4096_SHA256), RSA4096NUMBYTES,
+ "Sig size VB2_ALG_RSA4096_SHA256");
+ TEST_EQ(vb2_rsa_sig_size(VB2_ALG_RSA8192_SHA512), RSA8192NUMBYTES,
+ "Sig size VB2_ALG_RSA8192_SHA512");
+ TEST_EQ(vb2_rsa_sig_size(VB2_ALG_COUNT), 0,
+ "Sig size invalid algorithm");
+
+ /* Packed key size */
+ TEST_EQ(vb2_packed_key_size(VB2_ALG_RSA1024_SHA1),
+ RSA1024NUMBYTES * 2 + sizeof(uint32_t) * 2,
+ "Packed key size VB2_ALG_RSA1024_SHA1");
+ TEST_EQ(vb2_packed_key_size(VB2_ALG_RSA2048_SHA1),
+ RSA2048NUMBYTES * 2 + sizeof(uint32_t) * 2,
+ "Packed key size VB2_ALG_RSA2048_SHA1");
+ TEST_EQ(vb2_packed_key_size(VB2_ALG_RSA4096_SHA256),
+ RSA4096NUMBYTES * 2 + sizeof(uint32_t) * 2,
+ "Packed key size VB2_ALG_RSA4096_SHA256");
+ TEST_EQ(vb2_packed_key_size(VB2_ALG_RSA8192_SHA512),
+ RSA8192NUMBYTES * 2 + sizeof(uint32_t) * 2,
+ "Packed key size VB2_ALG_RSA8192_SHA512");
+ TEST_EQ(vb2_packed_key_size(VB2_ALG_COUNT), 0,
+ "Packed key size invalid algorithm");
+
+ uint8_t sig[RSA1024NUMBYTES];
+
+ /* Test padding check with bad algorithm */
+ Memcpy(sig, signatures[0], sizeof(sig));
+ TEST_EQ(vb2_check_padding(sig, VB2_ALG_COUNT),
+ VB2_ERROR_BAD_ALGORITHM, "vb2_check_padding() bad alg");
+
+ /* Test safe memcmp */
+ TEST_EQ(vb2_safe_memcmp("foo", "foo", 3), 0, "vb2_safe_memcmp() good");
+ TEST_NEQ(vb2_safe_memcmp("foo", "bar", 3), 0, "vb2_safe_memcmp() bad");
+ TEST_EQ(vb2_safe_memcmp("foo", "bar", 0), 0, "vb2_safe_memcmp() zero");
+
+ /* Test Montgomery >= */
+ {
+ uint32_t n[4] = {4, 4, 4, 4};
+ uint32_t a[4] = {4, 4, 4, 4};
+ struct vb2_public_key k = {
+ .arrsize = 4,
+ .n = n,
+ };
+ TEST_EQ(vb2_mont_ge(&k, a), 1, "mont_ge equal");
+
+ a[2] = 3;
+ TEST_EQ(vb2_mont_ge(&k, a), 0, "mont_ge less");
+
+ a[1] = 5;
+ TEST_EQ(vb2_mont_ge(&k, a), 0, "mont_ge greater");
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ /* Run tests */
+ test_utils();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vb2_sha_tests.c b/tests/vb2_sha_tests.c
new file mode 100644
index 00000000..cbcd7282
--- /dev/null
+++ b/tests/vb2_sha_tests.c
@@ -0,0 +1,148 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* FIPS 180-2 Tests for message digest functions. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_common.h"
+
+#include "2rsa.h"
+#include "2sha.h"
+
+#include "cryptolib.h"
+#include "sha_test_vectors.h"
+
+static int vb2_digest(const uint8_t *buf,
+ uint32_t size,
+ uint32_t algorithm,
+ uint8_t *digest,
+ uint32_t digest_size)
+{
+ struct vb2_digest_context dc;
+ int rv;
+
+ rv = vb2_digest_init(&dc, algorithm);
+ if (rv)
+ return rv;
+
+ rv = vb2_digest_extend(&dc, buf, size);
+ if (rv)
+ return rv;
+
+ return vb2_digest_finalize(&dc, digest, digest_size);
+}
+
+void sha1_tests(void)
+{
+ uint8_t digest[VB2_SHA1_DIGEST_SIZE];
+ uint8_t *test_inputs[3];
+ int i;
+
+ test_inputs[0] = (uint8_t *) oneblock_msg;
+ test_inputs[1] = (uint8_t *) multiblock_msg1;
+ test_inputs[2] = (uint8_t *) long_msg;
+
+ for (i = 0; i < 3; i++) {
+ TEST_EQ(vb2_digest(test_inputs[i],
+ strlen((char *)test_inputs[i]),
+ VB2_ALG_RSA1024_SHA1, digest,
+ sizeof(digest)), 0, "vb2_digest() SHA1");
+ TEST_EQ(memcmp(digest, sha1_results[i], sizeof(digest)),
+ 0, "SHA1 digest");
+ }
+
+ TEST_NEQ(vb2_digest(test_inputs[0], strlen((char *)test_inputs[0]),
+ VB2_ALG_RSA1024_SHA1, digest, sizeof(digest) - 1),
+ 0, "vb2_digest() too small");
+}
+
+void sha256_tests(void)
+{
+ uint8_t digest[VB2_SHA256_DIGEST_SIZE];
+ uint8_t *test_inputs[3];
+ int i;
+
+ test_inputs[0] = (uint8_t *) oneblock_msg;
+ test_inputs[1] = (uint8_t *) multiblock_msg1;
+ test_inputs[2] = (uint8_t *) long_msg;
+
+ for (i = 0; i < 3; i++) {
+ TEST_EQ(vb2_digest(test_inputs[i],
+ strlen((char *)test_inputs[i]),
+ VB2_ALG_RSA1024_SHA256, digest,
+ sizeof(digest)), 0, "vb2_digest() SHA256");
+ TEST_EQ(memcmp(digest, sha256_results[i], sizeof(digest)),
+ 0, "SHA-256 digest");
+ }
+
+ TEST_NEQ(vb2_digest(test_inputs[0], strlen((char *)test_inputs[0]),
+ VB2_ALG_RSA1024_SHA256, digest, sizeof(digest) - 1),
+ 0, "vb2_digest() too small");
+}
+
+void sha512_tests(void)
+{
+ uint8_t digest[VB2_SHA512_DIGEST_SIZE];
+ uint8_t *test_inputs[3];
+ int i;
+
+ test_inputs[0] = (uint8_t *) oneblock_msg;
+ test_inputs[1] = (uint8_t *) multiblock_msg2;
+ test_inputs[2] = (uint8_t *) long_msg;
+
+ for (i = 0; i < 3; i++) {
+ TEST_EQ(vb2_digest(test_inputs[i],
+ strlen((char *)test_inputs[i]),
+ VB2_ALG_RSA1024_SHA512, digest,
+ sizeof(digest)), 0, "vb2_digest() SHA512");
+ TEST_EQ(memcmp(digest, sha512_results[i], sizeof(digest)),
+ 0, "SHA-512 digest");
+ }
+
+ TEST_NEQ(vb2_digest(test_inputs[0], strlen((char *)test_inputs[0]),
+ VB2_ALG_RSA1024_SHA512, digest, sizeof(digest) - 1),
+ 0, "vb2_digest() too small");
+}
+
+void misc_tests(void)
+{
+ uint8_t digest[VB2_SHA512_DIGEST_SIZE];
+ struct vb2_digest_context dc;
+
+ TEST_EQ(vb2_digest_size(VB2_ALG_COUNT), 0, "digest size invalid alg");
+
+ TEST_NEQ(vb2_digest((uint8_t *)oneblock_msg, strlen(oneblock_msg),
+ VB2_ALG_COUNT, digest, sizeof(digest)),
+ 0, "vb2_digest() invalid alg");
+
+ /* Test bad algorithm inside extend and finalize */
+ vb2_digest_init(&dc, VB2_ALG_RSA1024_SHA1);
+ dc.algorithm = VB2_ALG_COUNT;
+ TEST_NEQ(vb2_digest_extend(&dc, digest, sizeof(digest)),
+ 0, "vb2_digest_extend() invalid alg");
+ TEST_NEQ(vb2_digest_finalize(&dc, digest, sizeof(digest)),
+ 0, "vb2_digest_finalize() invalid alg");
+}
+
+int main(int argc, char *argv[])
+{
+ /* Initialize long_msg with 'a' x 1,000,000 */
+ long_msg = (char *) malloc(1000001);
+ memset(long_msg, 'a', 1000000);
+ long_msg[1000000]=0;
+
+ sha1_tests();
+ sha256_tests();
+ sha512_tests();
+ misc_tests();
+
+ free(long_msg);
+
+ return gTestSuccess ? 0 : 255;
+}