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 d70c15de417b269983a433713faf6bfcffd717ac..2e9ee023e6bcff25055bf5e05b0fc597d75f49bb 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 470edad96bb9560a218affd4c0922888f9200dba..025c34ac0d848f642a4b4b1c2c9577c52aa72614 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 d886b1fa36f009d173d33dc84a4213ef61d44c14..795ca4f2cb3c912e37f214802cde76fc4fea7985 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;
+}