kernel/kexec_file.c: move purgatories sha256 to common code
authorPhilipp Rudo <prudo@linux.vnet.ibm.com>
Fri, 13 Apr 2018 22:36:46 +0000 (15:36 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Apr 2018 00:10:28 +0000 (17:10 -0700)
The code to verify the new kernels sha digest is applicable for all
architectures.  Move it to common code.

One problem is the string.c implementation on x86.  Currently sha256
includes x86/boot/string.h which defines memcpy and memset to be gcc
builtins.  By moving the sha256 implementation to common code and
changing the include to linux/string.h both functions are no longer
defined.  Thus definitions have to be provided in x86/purgatory/string.c

Link: http://lkml.kernel.org/r/20180321112751.22196-12-prudo@linux.vnet.ibm.com
Signed-off-by: Philipp Rudo <prudo@linux.vnet.ibm.com>
Acked-by: Dave Young <dyoung@redhat.com>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/x86/purgatory/Makefile
arch/x86/purgatory/purgatory.c
arch/x86/purgatory/sha256.c [deleted file]
arch/x86/purgatory/sha256.h [deleted file]
arch/x86/purgatory/string.c
include/linux/sha256.h [new file with mode: 0644]
lib/sha256.c [new file with mode: 0644]

index d70c15d..2e9ee02 100644 (file)
@@ -6,6 +6,9 @@ purgatory-y := purgatory.o stack.o setup-x86_$(BITS).o sha256.o entry64.o string
 targets += $(purgatory-y)
 PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
 
+$(obj)/sha256.o: $(srctree)/lib/sha256.c
+       $(call if_changed_rule,cc_o_c)
+
 LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib -z nodefaultlib
 targets += purgatory.ro
 
index 470edad..025c34a 100644 (file)
@@ -11,9 +11,9 @@
  */
 
 #include <linux/bug.h>
+#include <linux/sha256.h>
 #include <asm/purgatory.h>
 
-#include "sha256.h"
 #include "../boot/string.h"
 
 unsigned long purgatory_backup_dest __section(.kexec-purgatory);
diff --git a/arch/x86/purgatory/sha256.c b/arch/x86/purgatory/sha256.c
deleted file mode 100644 (file)
index 548ca67..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * SHA-256, as specified in
- * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf
- *
- * SHA-256 code by Jean-Luc Cooke <jlcooke@certainkey.com>.
- *
- * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
- * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- * Copyright (c) 2014 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/bitops.h>
-#include <asm/byteorder.h>
-#include "sha256.h"
-#include "../boot/string.h"
-
-static inline u32 Ch(u32 x, u32 y, u32 z)
-{
-       return z ^ (x & (y ^ z));
-}
-
-static inline u32 Maj(u32 x, u32 y, u32 z)
-{
-       return (x & y) | (z & (x | y));
-}
-
-#define e0(x)       (ror32(x, 2) ^ ror32(x, 13) ^ ror32(x, 22))
-#define e1(x)       (ror32(x, 6) ^ ror32(x, 11) ^ ror32(x, 25))
-#define s0(x)       (ror32(x, 7) ^ ror32(x, 18) ^ (x >> 3))
-#define s1(x)       (ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10))
-
-static inline void LOAD_OP(int I, u32 *W, const u8 *input)
-{
-       W[I] = __be32_to_cpu(((__be32 *)(input))[I]);
-}
-
-static inline void BLEND_OP(int I, u32 *W)
-{
-       W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
-}
-
-static void sha256_transform(u32 *state, const u8 *input)
-{
-       u32 a, b, c, d, e, f, g, h, t1, t2;
-       u32 W[64];
-       int i;
-
-       /* load the input */
-       for (i = 0; i < 16; i++)
-               LOAD_OP(i, W, input);
-
-       /* now blend */
-       for (i = 16; i < 64; i++)
-               BLEND_OP(i, W);
-
-       /* load the state into our registers */
-       a = state[0];  b = state[1];  c = state[2];  d = state[3];
-       e = state[4];  f = state[5];  g = state[6];  h = state[7];
-
-       /* now iterate */
-       t1 = h + e1(e) + Ch(e, f, g) + 0x428a2f98 + W[0];
-       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1 + t2;
-       t1 = g + e1(d) + Ch(d, e, f) + 0x71374491 + W[1];
-       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1 + t2;
-       t1 = f + e1(c) + Ch(c, d, e) + 0xb5c0fbcf + W[2];
-       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1 + t2;
-       t1 = e + e1(b) + Ch(b, c, d) + 0xe9b5dba5 + W[3];
-       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1 + t2;
-       t1 = d + e1(a) + Ch(a, b, c) + 0x3956c25b + W[4];
-       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1 + t2;
-       t1 = c + e1(h) + Ch(h, a, b) + 0x59f111f1 + W[5];
-       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1 + t2;
-       t1 = b + e1(g) + Ch(g, h, a) + 0x923f82a4 + W[6];
-       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1 + t2;
-       t1 = a + e1(f) + Ch(f, g, h) + 0xab1c5ed5 + W[7];
-       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1 + t2;
-
-       t1 = h + e1(e) + Ch(e, f, g) + 0xd807aa98 + W[8];
-       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1 + t2;
-       t1 = g + e1(d) + Ch(d, e, f) + 0x12835b01 + W[9];
-       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1 + t2;
-       t1 = f + e1(c) + Ch(c, d, e) + 0x243185be + W[10];
-       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1 + t2;
-       t1 = e + e1(b) + Ch(b, c, d) + 0x550c7dc3 + W[11];
-       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1 + t2;
-       t1 = d + e1(a) + Ch(a, b, c) + 0x72be5d74 + W[12];
-       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1 + t2;
-       t1 = c + e1(h) + Ch(h, a, b) + 0x80deb1fe + W[13];
-       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1 + t2;
-       t1 = b + e1(g) + Ch(g, h, a) + 0x9bdc06a7 + W[14];
-       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1 + t2;
-       t1 = a + e1(f) + Ch(f, g, h) + 0xc19bf174 + W[15];
-       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
-
-       t1 = h + e1(e) + Ch(e, f, g) + 0xe49b69c1 + W[16];
-       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
-       t1 = g + e1(d) + Ch(d, e, f) + 0xefbe4786 + W[17];
-       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
-       t1 = f + e1(c) + Ch(c, d, e) + 0x0fc19dc6 + W[18];
-       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
-       t1 = e + e1(b) + Ch(b, c, d) + 0x240ca1cc + W[19];
-       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
-       t1 = d + e1(a) + Ch(a, b, c) + 0x2de92c6f + W[20];
-       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
-       t1 = c + e1(h) + Ch(h, a, b) + 0x4a7484aa + W[21];
-       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
-       t1 = b + e1(g) + Ch(g, h, a) + 0x5cb0a9dc + W[22];
-       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
-       t1 = a + e1(f) + Ch(f, g, h) + 0x76f988da + W[23];
-       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
-
-       t1 = h + e1(e) + Ch(e, f, g) + 0x983e5152 + W[24];
-       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
-       t1 = g + e1(d) + Ch(d, e, f) + 0xa831c66d + W[25];
-       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
-       t1 = f + e1(c) + Ch(c, d, e) + 0xb00327c8 + W[26];
-       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
-       t1 = e + e1(b) + Ch(b, c, d) + 0xbf597fc7 + W[27];
-       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
-       t1 = d + e1(a) + Ch(a, b, c) + 0xc6e00bf3 + W[28];
-       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
-       t1 = c + e1(h) + Ch(h, a, b) + 0xd5a79147 + W[29];
-       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
-       t1 = b + e1(g) + Ch(g, h, a) + 0x06ca6351 + W[30];
-       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
-       t1 = a + e1(f) + Ch(f, g, h) + 0x14292967 + W[31];
-       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
-
-       t1 = h + e1(e) + Ch(e, f, g) + 0x27b70a85 + W[32];
-       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
-       t1 = g + e1(d) + Ch(d, e, f) + 0x2e1b2138 + W[33];
-       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
-       t1 = f + e1(c) + Ch(c, d, e) + 0x4d2c6dfc + W[34];
-       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
-       t1 = e + e1(b) + Ch(b, c, d) + 0x53380d13 + W[35];
-       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
-       t1 = d + e1(a) + Ch(a, b, c) + 0x650a7354 + W[36];
-       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
-       t1 = c + e1(h) + Ch(h, a, b) + 0x766a0abb + W[37];
-       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
-       t1 = b + e1(g) + Ch(g, h, a) + 0x81c2c92e + W[38];
-       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
-       t1 = a + e1(f) + Ch(f, g, h) + 0x92722c85 + W[39];
-       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
-
-       t1 = h + e1(e) + Ch(e, f, g) + 0xa2bfe8a1 + W[40];
-       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
-       t1 = g + e1(d) + Ch(d, e, f) + 0xa81a664b + W[41];
-       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
-       t1 = f + e1(c) + Ch(c, d, e) + 0xc24b8b70 + W[42];
-       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
-       t1 = e + e1(b) + Ch(b, c, d) + 0xc76c51a3 + W[43];
-       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
-       t1 = d + e1(a) + Ch(a, b, c) + 0xd192e819 + W[44];
-       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
-       t1 = c + e1(h) + Ch(h, a, b) + 0xd6990624 + W[45];
-       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
-       t1 = b + e1(g) + Ch(g, h, a) + 0xf40e3585 + W[46];
-       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
-       t1 = a + e1(f) + Ch(f, g, h) + 0x106aa070 + W[47];
-       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
-
-       t1 = h + e1(e) + Ch(e, f, g) + 0x19a4c116 + W[48];
-       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
-       t1 = g + e1(d) + Ch(d, e, f) + 0x1e376c08 + W[49];
-       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
-       t1 = f + e1(c) + Ch(c, d, e) + 0x2748774c + W[50];
-       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
-       t1 = e + e1(b) + Ch(b, c, d) + 0x34b0bcb5 + W[51];
-       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
-       t1 = d + e1(a) + Ch(a, b, c) + 0x391c0cb3 + W[52];
-       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
-       t1 = c + e1(h) + Ch(h, a, b) + 0x4ed8aa4a + W[53];
-       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
-       t1 = b + e1(g) + Ch(g, h, a) + 0x5b9cca4f + W[54];
-       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
-       t1 = a + e1(f) + Ch(f, g, h) + 0x682e6ff3 + W[55];
-       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
-
-       t1 = h + e1(e) + Ch(e, f, g) + 0x748f82ee + W[56];
-       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
-       t1 = g + e1(d) + Ch(d, e, f) + 0x78a5636f + W[57];
-       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
-       t1 = f + e1(c) + Ch(c, d, e) + 0x84c87814 + W[58];
-       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
-       t1 = e + e1(b) + Ch(b, c, d) + 0x8cc70208 + W[59];
-       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
-       t1 = d + e1(a) + Ch(a, b, c) + 0x90befffa + W[60];
-       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
-       t1 = c + e1(h) + Ch(h, a, b) + 0xa4506ceb + W[61];
-       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
-       t1 = b + e1(g) + Ch(g, h, a) + 0xbef9a3f7 + W[62];
-       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
-       t1 = a + e1(f) + Ch(f, g, h) + 0xc67178f2 + W[63];
-       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
-
-       state[0] += a; state[1] += b; state[2] += c; state[3] += d;
-       state[4] += e; state[5] += f; state[6] += g; state[7] += h;
-
-       /* clear any sensitive info... */
-       a = b = c = d = e = f = g = h = t1 = t2 = 0;
-       memset(W, 0, 64 * sizeof(u32));
-}
-
-int sha256_init(struct sha256_state *sctx)
-{
-       sctx->state[0] = SHA256_H0;
-       sctx->state[1] = SHA256_H1;
-       sctx->state[2] = SHA256_H2;
-       sctx->state[3] = SHA256_H3;
-       sctx->state[4] = SHA256_H4;
-       sctx->state[5] = SHA256_H5;
-       sctx->state[6] = SHA256_H6;
-       sctx->state[7] = SHA256_H7;
-       sctx->count = 0;
-
-       return 0;
-}
-
-int sha256_update(struct sha256_state *sctx, const u8 *data, unsigned int len)
-{
-       unsigned int partial, done;
-       const u8 *src;
-
-       partial = sctx->count & 0x3f;
-       sctx->count += len;
-       done = 0;
-       src = data;
-
-       if ((partial + len) > 63) {
-               if (partial) {
-                       done = -partial;
-                       memcpy(sctx->buf + partial, data, done + 64);
-                       src = sctx->buf;
-               }
-
-               do {
-                       sha256_transform(sctx->state, src);
-                       done += 64;
-                       src = data + done;
-               } while (done + 63 < len);
-
-               partial = 0;
-       }
-       memcpy(sctx->buf + partial, src, len - done);
-
-       return 0;
-}
-
-int sha256_final(struct sha256_state *sctx, u8 *out)
-{
-       __be32 *dst = (__be32 *)out;
-       __be64 bits;
-       unsigned int index, pad_len;
-       int i;
-       static const u8 padding[64] = { 0x80, };
-
-       /* Save number of bits */
-       bits = cpu_to_be64(sctx->count << 3);
-
-       /* Pad out to 56 mod 64. */
-       index = sctx->count & 0x3f;
-       pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
-       sha256_update(sctx, padding, pad_len);
-
-       /* Append length (before padding) */
-       sha256_update(sctx, (const u8 *)&bits, sizeof(bits));
-
-       /* Store state in digest */
-       for (i = 0; i < 8; i++)
-               dst[i] = cpu_to_be32(sctx->state[i]);
-
-       /* Zeroize sensitive information. */
-       memset(sctx, 0, sizeof(*sctx));
-
-       return 0;
-}
diff --git a/arch/x86/purgatory/sha256.h b/arch/x86/purgatory/sha256.h
deleted file mode 100644 (file)
index 2867d98..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- *  Copyright (C) 2014 Red Hat Inc.
- *
- *  Author: Vivek Goyal <vgoyal@redhat.com>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2.  See the file COPYING for more details.
- */
-
-#ifndef SHA256_H
-#define SHA256_H
-
-#include <linux/types.h>
-#include <crypto/sha.h>
-
-extern int sha256_init(struct sha256_state *sctx);
-extern int sha256_update(struct sha256_state *sctx, const u8 *input,
-                               unsigned int length);
-extern int sha256_final(struct sha256_state *sctx, u8 *hash);
-
-#endif /* SHA256_H */
index d886b1f..795ca4f 100644 (file)
  * Version 2.  See the file COPYING for more details.
  */
 
+#include <linux/types.h>
+
 #include "../boot/string.c"
+
+void *memcpy(void *dst, const void *src, size_t len)
+{
+       return __builtin_memcpy(dst, src, len);
+}
+
+void *memset(void *dst, int c, size_t len)
+{
+       return __builtin_memset(dst, c, len);
+}
diff --git a/include/linux/sha256.h b/include/linux/sha256.h
new file mode 100644 (file)
index 0000000..244fe01
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  Copyright (C) 2014 Red Hat Inc.
+ *
+ *  Author: Vivek Goyal <vgoyal@redhat.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#ifndef SHA256_H
+#define SHA256_H
+
+#include <linux/types.h>
+#include <crypto/sha.h>
+
+/*
+ * Stand-alone implementation of the SHA256 algorithm. It is designed to
+ * have as little dependencies as possible so it can be used in the
+ * kexec_file purgatory. In other cases you should use the implementation in
+ * crypto/.
+ *
+ * For details see lib/sha256.c
+ */
+
+extern int sha256_init(struct sha256_state *sctx);
+extern int sha256_update(struct sha256_state *sctx, const u8 *input,
+                        unsigned int length);
+extern int sha256_final(struct sha256_state *sctx, u8 *hash);
+
+#endif /* SHA256_H */
diff --git a/lib/sha256.c b/lib/sha256.c
new file mode 100644 (file)
index 0000000..4400c83
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * SHA-256, as specified in
+ * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf
+ *
+ * SHA-256 code by Jean-Luc Cooke <jlcooke@certainkey.com>.
+ *
+ * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/sha256.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+static inline u32 Ch(u32 x, u32 y, u32 z)
+{
+       return z ^ (x & (y ^ z));
+}
+
+static inline u32 Maj(u32 x, u32 y, u32 z)
+{
+       return (x & y) | (z & (x | y));
+}
+
+#define e0(x)       (ror32(x, 2) ^ ror32(x, 13) ^ ror32(x, 22))
+#define e1(x)       (ror32(x, 6) ^ ror32(x, 11) ^ ror32(x, 25))
+#define s0(x)       (ror32(x, 7) ^ ror32(x, 18) ^ (x >> 3))
+#define s1(x)       (ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10))
+
+static inline void LOAD_OP(int I, u32 *W, const u8 *input)
+{
+       W[I] = __be32_to_cpu(((__be32 *)(input))[I]);
+}
+
+static inline void BLEND_OP(int I, u32 *W)
+{
+       W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
+}
+
+static void sha256_transform(u32 *state, const u8 *input)
+{
+       u32 a, b, c, d, e, f, g, h, t1, t2;
+       u32 W[64];
+       int i;
+
+       /* load the input */
+       for (i = 0; i < 16; i++)
+               LOAD_OP(i, W, input);
+
+       /* now blend */
+       for (i = 16; i < 64; i++)
+               BLEND_OP(i, W);
+
+       /* load the state into our registers */
+       a = state[0];  b = state[1];  c = state[2];  d = state[3];
+       e = state[4];  f = state[5];  g = state[6];  h = state[7];
+
+       /* now iterate */
+       t1 = h + e1(e) + Ch(e, f, g) + 0x428a2f98 + W[0];
+       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1 + t2;
+       t1 = g + e1(d) + Ch(d, e, f) + 0x71374491 + W[1];
+       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1 + t2;
+       t1 = f + e1(c) + Ch(c, d, e) + 0xb5c0fbcf + W[2];
+       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1 + t2;
+       t1 = e + e1(b) + Ch(b, c, d) + 0xe9b5dba5 + W[3];
+       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1 + t2;
+       t1 = d + e1(a) + Ch(a, b, c) + 0x3956c25b + W[4];
+       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1 + t2;
+       t1 = c + e1(h) + Ch(h, a, b) + 0x59f111f1 + W[5];
+       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1 + t2;
+       t1 = b + e1(g) + Ch(g, h, a) + 0x923f82a4 + W[6];
+       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1 + t2;
+       t1 = a + e1(f) + Ch(f, g, h) + 0xab1c5ed5 + W[7];
+       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1 + t2;
+
+       t1 = h + e1(e) + Ch(e, f, g) + 0xd807aa98 + W[8];
+       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1 + t2;
+       t1 = g + e1(d) + Ch(d, e, f) + 0x12835b01 + W[9];
+       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1 + t2;
+       t1 = f + e1(c) + Ch(c, d, e) + 0x243185be + W[10];
+       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1 + t2;
+       t1 = e + e1(b) + Ch(b, c, d) + 0x550c7dc3 + W[11];
+       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1 + t2;
+       t1 = d + e1(a) + Ch(a, b, c) + 0x72be5d74 + W[12];
+       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1 + t2;
+       t1 = c + e1(h) + Ch(h, a, b) + 0x80deb1fe + W[13];
+       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1 + t2;
+       t1 = b + e1(g) + Ch(g, h, a) + 0x9bdc06a7 + W[14];
+       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1 + t2;
+       t1 = a + e1(f) + Ch(f, g, h) + 0xc19bf174 + W[15];
+       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
+
+       t1 = h + e1(e) + Ch(e, f, g) + 0xe49b69c1 + W[16];
+       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
+       t1 = g + e1(d) + Ch(d, e, f) + 0xefbe4786 + W[17];
+       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
+       t1 = f + e1(c) + Ch(c, d, e) + 0x0fc19dc6 + W[18];
+       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
+       t1 = e + e1(b) + Ch(b, c, d) + 0x240ca1cc + W[19];
+       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
+       t1 = d + e1(a) + Ch(a, b, c) + 0x2de92c6f + W[20];
+       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
+       t1 = c + e1(h) + Ch(h, a, b) + 0x4a7484aa + W[21];
+       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
+       t1 = b + e1(g) + Ch(g, h, a) + 0x5cb0a9dc + W[22];
+       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
+       t1 = a + e1(f) + Ch(f, g, h) + 0x76f988da + W[23];
+       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
+
+       t1 = h + e1(e) + Ch(e, f, g) + 0x983e5152 + W[24];
+       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
+       t1 = g + e1(d) + Ch(d, e, f) + 0xa831c66d + W[25];
+       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
+       t1 = f + e1(c) + Ch(c, d, e) + 0xb00327c8 + W[26];
+       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
+       t1 = e + e1(b) + Ch(b, c, d) + 0xbf597fc7 + W[27];
+       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
+       t1 = d + e1(a) + Ch(a, b, c) + 0xc6e00bf3 + W[28];
+       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
+       t1 = c + e1(h) + Ch(h, a, b) + 0xd5a79147 + W[29];
+       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
+       t1 = b + e1(g) + Ch(g, h, a) + 0x06ca6351 + W[30];
+       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
+       t1 = a + e1(f) + Ch(f, g, h) + 0x14292967 + W[31];
+       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
+
+       t1 = h + e1(e) + Ch(e, f, g) + 0x27b70a85 + W[32];
+       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
+       t1 = g + e1(d) + Ch(d, e, f) + 0x2e1b2138 + W[33];
+       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
+       t1 = f + e1(c) + Ch(c, d, e) + 0x4d2c6dfc + W[34];
+       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
+       t1 = e + e1(b) + Ch(b, c, d) + 0x53380d13 + W[35];
+       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
+       t1 = d + e1(a) + Ch(a, b, c) + 0x650a7354 + W[36];
+       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
+       t1 = c + e1(h) + Ch(h, a, b) + 0x766a0abb + W[37];
+       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
+       t1 = b + e1(g) + Ch(g, h, a) + 0x81c2c92e + W[38];
+       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
+       t1 = a + e1(f) + Ch(f, g, h) + 0x92722c85 + W[39];
+       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
+
+       t1 = h + e1(e) + Ch(e, f, g) + 0xa2bfe8a1 + W[40];
+       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
+       t1 = g + e1(d) + Ch(d, e, f) + 0xa81a664b + W[41];
+       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
+       t1 = f + e1(c) + Ch(c, d, e) + 0xc24b8b70 + W[42];
+       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
+       t1 = e + e1(b) + Ch(b, c, d) + 0xc76c51a3 + W[43];
+       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
+       t1 = d + e1(a) + Ch(a, b, c) + 0xd192e819 + W[44];
+       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
+       t1 = c + e1(h) + Ch(h, a, b) + 0xd6990624 + W[45];
+       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
+       t1 = b + e1(g) + Ch(g, h, a) + 0xf40e3585 + W[46];
+       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
+       t1 = a + e1(f) + Ch(f, g, h) + 0x106aa070 + W[47];
+       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
+
+       t1 = h + e1(e) + Ch(e, f, g) + 0x19a4c116 + W[48];
+       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
+       t1 = g + e1(d) + Ch(d, e, f) + 0x1e376c08 + W[49];
+       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
+       t1 = f + e1(c) + Ch(c, d, e) + 0x2748774c + W[50];
+       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
+       t1 = e + e1(b) + Ch(b, c, d) + 0x34b0bcb5 + W[51];
+       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
+       t1 = d + e1(a) + Ch(a, b, c) + 0x391c0cb3 + W[52];
+       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
+       t1 = c + e1(h) + Ch(h, a, b) + 0x4ed8aa4a + W[53];
+       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
+       t1 = b + e1(g) + Ch(g, h, a) + 0x5b9cca4f + W[54];
+       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
+       t1 = a + e1(f) + Ch(f, g, h) + 0x682e6ff3 + W[55];
+       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
+
+       t1 = h + e1(e) + Ch(e, f, g) + 0x748f82ee + W[56];
+       t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1+t2;
+       t1 = g + e1(d) + Ch(d, e, f) + 0x78a5636f + W[57];
+       t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1+t2;
+       t1 = f + e1(c) + Ch(c, d, e) + 0x84c87814 + W[58];
+       t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1+t2;
+       t1 = e + e1(b) + Ch(b, c, d) + 0x8cc70208 + W[59];
+       t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1+t2;
+       t1 = d + e1(a) + Ch(a, b, c) + 0x90befffa + W[60];
+       t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1+t2;
+       t1 = c + e1(h) + Ch(h, a, b) + 0xa4506ceb + W[61];
+       t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1+t2;
+       t1 = b + e1(g) + Ch(g, h, a) + 0xbef9a3f7 + W[62];
+       t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1+t2;
+       t1 = a + e1(f) + Ch(f, g, h) + 0xc67178f2 + W[63];
+       t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1+t2;
+
+       state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+       state[4] += e; state[5] += f; state[6] += g; state[7] += h;
+
+       /* clear any sensitive info... */
+       a = b = c = d = e = f = g = h = t1 = t2 = 0;
+       memset(W, 0, 64 * sizeof(u32));
+}
+
+int sha256_init(struct sha256_state *sctx)
+{
+       sctx->state[0] = SHA256_H0;
+       sctx->state[1] = SHA256_H1;
+       sctx->state[2] = SHA256_H2;
+       sctx->state[3] = SHA256_H3;
+       sctx->state[4] = SHA256_H4;
+       sctx->state[5] = SHA256_H5;
+       sctx->state[6] = SHA256_H6;
+       sctx->state[7] = SHA256_H7;
+       sctx->count = 0;
+
+       return 0;
+}
+
+int sha256_update(struct sha256_state *sctx, const u8 *data, unsigned int len)
+{
+       unsigned int partial, done;
+       const u8 *src;
+
+       partial = sctx->count & 0x3f;
+       sctx->count += len;
+       done = 0;
+       src = data;
+
+       if ((partial + len) > 63) {
+               if (partial) {
+                       done = -partial;
+                       memcpy(sctx->buf + partial, data, done + 64);
+                       src = sctx->buf;
+               }
+
+               do {
+                       sha256_transform(sctx->state, src);
+                       done += 64;
+                       src = data + done;
+               } while (done + 63 < len);
+
+               partial = 0;
+       }
+       memcpy(sctx->buf + partial, src, len - done);
+
+       return 0;
+}
+
+int sha256_final(struct sha256_state *sctx, u8 *out)
+{
+       __be32 *dst = (__be32 *)out;
+       __be64 bits;
+       unsigned int index, pad_len;
+       int i;
+       static const u8 padding[64] = { 0x80, };
+
+       /* Save number of bits */
+       bits = cpu_to_be64(sctx->count << 3);
+
+       /* Pad out to 56 mod 64. */
+       index = sctx->count & 0x3f;
+       pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
+       sha256_update(sctx, padding, pad_len);
+
+       /* Append length (before padding) */
+       sha256_update(sctx, (const u8 *)&bits, sizeof(bits));
+
+       /* Store state in digest */
+       for (i = 0; i < 8; i++)
+               dst[i] = cpu_to_be32(sctx->state[i]);
+
+       /* Zeroize sensitive information. */
+       memset(sctx, 0, sizeof(*sctx));
+
+       return 0;
+}