[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen staging] xen/lib: Introduce SHA-1



commit 62bd4c2a8ee809c181d47098583270dc9db9300e
Author:     Krystian Hebel <krystian.hebel@xxxxxxxxx>
AuthorDate: Thu Nov 27 13:21:12 2025 +0000
Commit:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Tue Dec 2 17:11:52 2025 +0000

    xen/lib: Introduce SHA-1
    
    Future work will need to interact with the TPM, which requires calculating
    digests for all active hash banks.  Introduce an implementation in lib/,
    partially derived from Trenchboot which itself is derived from Linux.
    
    Signed-off-by: Krystian Hebel <krystian.hebel@xxxxxxxxx>
    Signed-off-by: Sergii Dmytruk <sergii.dmytruk@xxxxxxxxx>
    Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
    Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
---
 xen/include/xen/sha1.h |  14 ++++
 xen/lib/Makefile       |   1 +
 xen/lib/sha1.c         | 215 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 230 insertions(+)

diff --git a/xen/include/xen/sha1.h b/xen/include/xen/sha1.h
new file mode 100644
index 0000000000..d649da8ebd
--- /dev/null
+++ b/xen/include/xen/sha1.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SHA1: https://csrc.nist.gov/pubs/fips/180-4/upd1/final
+ */
+#ifndef XEN_SHA1_H
+#define XEN_SHA1_H
+
+#include <xen/types.h>
+
+#define SHA1_DIGEST_SIZE  20
+
+void sha1(uint8_t digest[SHA1_DIGEST_SIZE], const void *msg, size_t len);
+
+#endif /* XEN_SHA1_H */
diff --git a/xen/lib/Makefile b/xen/lib/Makefile
index d3e4f981b0..954d9216a3 100644
--- a/xen/lib/Makefile
+++ b/xen/lib/Makefile
@@ -17,6 +17,7 @@ lib-y += memset.o
 lib-y += muldiv64.o
 lib-y += parse-size.o
 lib-y += rbtree.o
+lib-y += sha1.o
 lib-y += sha2-256.o
 lib-y += sort.o
 lib-y += strcasecmp.o
diff --git a/xen/lib/sha1.c b/xen/lib/sha1.c
new file mode 100644
index 0000000000..eac2bdd4df
--- /dev/null
+++ b/xen/lib/sha1.c
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SHA1: https://csrc.nist.gov/pubs/fips/180-4/upd1/final
+ *
+ * Originally derived from Linux.  Modified substantially to optimise for size
+ * and Xen's expected usecases.
+ */
+#include <xen/bitops.h>
+#include <xen/sha1.h>
+#include <xen/string.h>
+#include <xen/unaligned.h>
+
+struct sha1_state {
+    size_t count; /* Byte Count. */
+    uint32_t state[SHA1_DIGEST_SIZE / sizeof(uint32_t)];
+    uint8_t buf[64];
+};
+
+static uint32_t blend(uint32_t w[16], unsigned int i)
+{
+#define W(i) w[(i) & 15]
+
+    return W(i) = rol32(W(i + 13) ^ W(i + 8) ^ W(i + 2) ^ W(i), 1);
+
+#undef W
+}
+
+static void sha1_transform(uint32_t state[5], const void *_input)
+{
+    const uint32_t *input = _input;
+    uint32_t a, b, c, d, e, t;
+    uint32_t w[16];
+    unsigned int i = 0;
+
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+
+    /* Round 1 - iterations 0-16 take their input from 'input' */
+    for ( ; i < 16; ++i )
+    {
+        t = get_unaligned_be32(&input[i]);
+        w[i] = t;
+        e += t + rol32(a, 5) + (((c ^ d) & b) ^ d) + 0x5a827999U;
+        b = ror32(b, 2);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    /* Round 1 tail. Input from 512-bit mixing array */
+    for ( ; i < 20; ++i )
+    {
+        t = blend(w, i);
+        e += t + rol32(a, 5) + (((c ^ d) & b) ^ d) + 0x5a827999U;
+        b = ror32(b, 2);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    /* Round 2 */
+    for ( ; i < 40; ++i )
+    {
+        t = blend(w, i);
+        e += t + rol32(a, 5) + (b ^ c ^ d) + 0x6ed9eba1U;
+        b = ror32(b, 2);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    /* Round 3 */
+    for ( ; i < 60; ++i )
+    {
+        t = blend(w, i);
+        e += t + rol32(a, 5) + ((b & c) + (d & (b ^ c))) + 0x8f1bbcdcU;
+        b = ror32(b, 2);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    /* Round 4 */
+    for ( ; i < 80; ++i )
+    {
+        t = blend(w, i);
+        e += t + rol32(a, 5) + (b ^ c ^ d) + 0xca62c1d6U;
+        b = ror32(b, 2);
+        t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+}
+
+static void sha1_init(struct sha1_state *s)
+{
+    *s = (struct sha1_state){
+        .state = {
+            0x67452301U,
+            0xefcdab89U,
+            0x98badcfeU,
+            0x10325476U,
+            0xc3d2e1f0U,
+        },
+    };
+}
+
+static void sha1_update(struct sha1_state *s, const void *msg, size_t len)
+{
+    unsigned int partial = s->count & 63;
+
+    s->count += len;
+
+    if ( (partial + len) >= 64 )
+    {
+        if ( partial )
+        {
+            unsigned int rem = 64 - partial;
+
+            /* Fill the partial block. */
+            memcpy(s->buf + partial, msg, rem);
+            msg += rem;
+            len -= rem;
+
+            sha1_transform(s->state, s->buf);
+            partial = 0;
+        }
+
+        for ( ; len >= 64; msg += 64, len -= 64 )
+            sha1_transform(s->state, msg);
+    }
+
+    /* Remaining data becomes partial. */
+    memcpy(s->buf + partial, msg, len);
+}
+
+static void sha1_final(struct sha1_state *s, uint8_t digest[SHA1_DIGEST_SIZE])
+{
+    uint32_t *dst = (uint32_t *)digest;
+    unsigned int i, partial = s->count & 63;
+
+    /* Start padding */
+    s->buf[partial++] = 0x80;
+
+    if ( partial > 56 )
+    {
+        /* Need one extra block - pad to 64 */
+        memset(s->buf + partial, 0, 64 - partial);
+        sha1_transform(s->state, s->buf);
+        partial = 0;
+    }
+    /* Pad to 56 */
+    memset(s->buf + partial, 0x0, 56 - partial);
+
+    /* Append the bit count */
+    put_unaligned_be64((uint64_t)s->count << 3, &s->buf[56]);
+    sha1_transform(s->state, s->buf);
+
+    /* Store state in digest */
+    for ( i = 0; i < 5; i++ )
+        put_unaligned_be32(s->state[i], &dst[i]);
+}
+
+void sha1(uint8_t digest[SHA1_DIGEST_SIZE], const void *msg, size_t len)
+{
+    struct sha1_state s;
+
+    sha1_init(&s);
+    sha1_update(&s, msg, len);
+    sha1_final(&s, digest);
+}
+
+#ifdef CONFIG_SELF_TESTS
+
+#include <xen/init.h>
+#include <xen/lib.h>
+
+static const struct test {
+    const char *msg;
+    uint8_t digest[SHA1_DIGEST_SIZE];
+} tests[] __initconst = {
+    {
+        .msg = "abc",
+        .digest = {
+            0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
+            0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d,
+        },
+    },
+    {
+        .msg = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+        .digest = {
+            0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
+            0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1,
+        },
+    },
+};
+
+static void __init __constructor test_sha1(void)
+{
+    for ( unsigned int i = 0; i < ARRAY_SIZE(tests); ++i )
+    {
+        const struct test *t = &tests[i];
+        uint8_t res[SHA1_DIGEST_SIZE] = {};
+
+        sha1(res, t->msg, strlen(t->msg));
+
+        if ( memcmp(res, t->digest, sizeof(t->digest)) == 0 )
+            continue;
+
+        panic("%s() msg '%s' failed\n"
+              "  expected %" STR(SHA1_DIGEST_SIZE) "phN\n"
+              "       got %" STR(SHA1_DIGEST_SIZE) "phN\n",
+              __func__, t->msg, t->digest, res);
+    }
+}
+#endif /* CONFIG_SELF_TESTS */
--
generated by git-patchbot for /home/xen/git/xen.git#staging



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.