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>
diff --git a/Makefile b/Makefile
index c9bcec3..33c7417 100644
--- a/Makefile
+++ b/Makefile
@@ -280,6 +280,11 @@
 # 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 @@
 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 @@
 	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 @@
 .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 0000000..e619e78
--- /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 0000000..41c8317
--- /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 0000000..fd41258
--- /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 0000000..fedc8b7
--- /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 0000000..66e8b69
--- /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 0000000..1fee192
--- /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 0000000..83a2c62
--- /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 0000000..233f729
--- /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 0000000..331b066
--- /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 0000000..df3eb37
--- /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 0000000..cbcd728
--- /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;
+}