aboutsummaryrefslogtreecommitdiff
path: root/butl
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-02-28 13:15:23 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-02-28 13:15:23 +0200
commitd928de165f8bb896ee77f5668f35611f57429c93 (patch)
tree13161cec5af997984aaeac22c54b8c934cb8e0c6 /butl
parente4a63cd55c6347dd24938ec8a1ef203409be058e (diff)
Add SHA256 calculator
Based on the sha256c.c file from the FreeBSD project and ported to compile on Linux, Mac OS, and Windows. The file is licensed under the simplified/2-clause BSD license so the library is now MIT/BSD-licensed.
Diffstat (limited to 'butl')
-rw-r--r--butl/buildfile1
-rw-r--r--butl/sha25676
-rw-r--r--butl/sha256.cxx76
-rw-r--r--butl/sha256c.c393
4 files changed, 546 insertions, 0 deletions
diff --git a/butl/buildfile b/butl/buildfile
index f075e30..a92f4a9 100644
--- a/butl/buildfile
+++ b/butl/buildfile
@@ -13,6 +13,7 @@ lib{butl}: \
{hxx }{ path-io } \
{hxx }{ path-map } \
{hxx txx }{ prefix-map } \
+{hxx cxx}{ sha256 } \
{hxx ixx cxx}{ process } \
{hxx txx }{ string-table } \
{hxx cxx}{ timestamp } \
diff --git a/butl/sha256 b/butl/sha256
new file mode 100644
index 0000000..3fc9e63
--- /dev/null
+++ b/butl/sha256
@@ -0,0 +1,76 @@
+// file : butl/sha256 -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUTL_SHA256
+#define BUTL_SHA256
+
+#include <string>
+#include <cstring> // strlen()
+#include <cstdint>
+#include <cstddef> // size_t
+
+namespace butl
+{
+ // SHA256 checksum calculator.
+ //
+ // For a single chunk of data a sum can be obtained in one line, for
+ // example:
+ //
+ // cerr << sha256 ("123").string () << endl;
+ //
+ class sha256
+ {
+ public:
+ sha256 ();
+ explicit sha256 (const std::string& s): sha256 () {append (s);}
+ explicit sha256 (const char* s): sha256 () {append (s);}
+ sha256 (const void* b, std::size_t n): sha256 () {append (b, n);}
+
+ // Append string (without the traling '\0').
+ //
+ void
+ append (const std::string& s) {append (s.c_str (), s.size ());}
+
+ // Append C-string (without the traling '\0').
+ //
+ void
+ append (const char* s) {append (s, std::strlen (s));}
+
+ // Append binary data.
+ //
+ void
+ append (const void*, std::size_t);
+
+ // Extract result. It can be obtained as either a 32-byte binary digest or
+ // as a 64- character hex-encoded C-string.
+ //
+ using digest_type = std::uint8_t[32];
+
+ const digest_type&
+ binary () const;
+
+ const char*
+ string () const;
+
+ public:
+ struct context
+ {
+ std::uint32_t state[8];
+ std::uint64_t count;
+ std::uint8_t buf[64];
+ };
+
+ private:
+ union
+ {
+ mutable context ctx_;
+ mutable char str_[65];
+ };
+
+ mutable digest_type bin_;
+ mutable bool done_;
+ };
+};
+
+#endif // BUTL_SHA256
diff --git a/butl/sha256.cxx b/butl/sha256.cxx
new file mode 100644
index 0000000..feca9a7
--- /dev/null
+++ b/butl/sha256.cxx
@@ -0,0 +1,76 @@
+// file : butl/sha256.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <butl/sha256>
+
+// C interface for sha256c.
+//
+#include <stdint.h>
+#include <stddef.h> // size_t
+
+using SHA256_CTX = butl::sha256::context;
+
+extern "C"
+{
+ static void SHA256_Init (SHA256_CTX*);
+ static void SHA256_Update (SHA256_CTX*, const void*, size_t);
+ static void SHA256_Final (uint8_t[32], SHA256_CTX*);
+
+#include "sha256c.c"
+}
+
+using namespace std;
+
+namespace butl
+{
+ sha256::
+ sha256 ()
+ : done_ (false)
+ {
+ SHA256_Init (&ctx_);
+ }
+
+ void sha256::
+ append (const void* b, size_t n)
+ {
+ SHA256_Update (&ctx_, b, n);
+ }
+
+ const sha256::digest_type& sha256::
+ binary () const
+ {
+ if (!done_)
+ {
+ SHA256_Final (bin_, &ctx_);
+ done_ = true;
+ str_[0] = '\0'; // Indicate we haven't computed the string yet.
+ }
+
+ return bin_;
+ }
+
+ static const char hex_map[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ const char* sha256::
+ string () const
+ {
+ if (!done_)
+ binary ();
+
+ if (str_[0] == '\0')
+ {
+ for (size_t i (0); i != 32; ++i)
+ {
+ str_[i * 2] = hex_map[bin_[i] >> 4];
+ str_[i * 2 + 1] = hex_map[bin_[i] & 0x0f];
+ }
+
+ str_[64] = '\0';
+ }
+
+ return str_;
+ }
+}
diff --git a/butl/sha256c.c b/butl/sha256c.c
new file mode 100644
index 0000000..3a6b8eb
--- /dev/null
+++ b/butl/sha256c.c
@@ -0,0 +1,393 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * Copyright 2016 Code Synthesis Ltd
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <stdint.h>
+#include <stddef.h> /* size_t */
+
+#ifdef SHA256_TEST_DRIVER
+
+struct context
+{
+ uint32_t state[8];
+ uint64_t count;
+ uint8_t buf[64];
+};
+
+typedef struct context SHA256_CTX;
+
+static void SHA256_Init (SHA256_CTX*);
+static void SHA256_Update (SHA256_CTX*, const void*, size_t);
+static void SHA256_Final (uint8_t[32], SHA256_CTX*);
+
+#include <string.h>
+#include <assert.h>
+
+int
+main ()
+{
+ SHA256_CTX c;
+ uint8_t r[32];
+
+ /* "" e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 */
+ SHA256_Init (&c);
+ SHA256_Final (r, &c);
+ assert (r[0] == 0xe3 && r[31] == 0x55);
+
+ /* "123" a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3 */
+ SHA256_Init (&c);
+ SHA256_Update (&c, "123", 3);
+ SHA256_Final (r, &c);
+ assert (r[0] == 0xa6 && r[31] == 0xe3);
+
+ return 0;
+}
+
+#endif /* SHA256_TEST_DRIVER */
+
+#ifdef __FreeBSD__
+# include <sys/endian.h> /* BYTE_ORDER, be32dec(), be32enc(), be64enc */
+#else
+# if defined(_WIN32)
+# ifndef BYTE_ORDER
+# define BIG_ENDIAN 4321
+# define LITTLE_ENDIAN 1234
+# define BYTE_ORDER LITTLE_ENDIAN
+# endif
+# else
+# include <sys/param.h> /* BYTE_ORDER/__BYTE_ORDER */
+# ifndef BYTE_ORDER
+# ifdef __BYTE_ORDER
+# define BYTE_ORDER __BYTE_ORDER
+# define BIG_ENDIAN __BIG_ENDIAN
+# define LITTLE_ENDIAN __LITTLE_ENDIAN
+# else
+# error no BYTE_ORDER/__BYTE_ORDER define
+# endif
+# endif
+# endif
+
+static uint32_t
+be32dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static void
+be32enc(void *pp, uint32_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = (u >> 24) & 0xff;
+ p[1] = (u >> 16) & 0xff;
+ p[2] = (u >> 8) & 0xff;
+ p[3] = u & 0xff;
+}
+
+static void
+be64enc(void *pp, uint64_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = (u >> 56) & 0xff;
+ p[1] = (u >> 48) & 0xff;
+ p[2] = (u >> 40) & 0xff;
+ p[3] = (u >> 32) & 0xff;
+ p[4] = (u >> 24) & 0xff;
+ p[5] = (u >> 16) & 0xff;
+ p[6] = (u >> 8) & 0xff;
+ p[7] = u & 0xff;
+}
+#endif
+
+/* The rest is the unmodified (except for a few explicit casts to make it
+ compilable in C++), latest implementation from FreeBSD. */
+
+#include <string.h>
+
+#if BYTE_ORDER == BIG_ENDIAN
+
+/* Copy a vector of big-endian uint32_t into a vector of bytes */
+#define be32enc_vect(dst, src, len) \
+ memcpy((void *)dst, (const void *)src, (size_t)len)
+
+/* Copy a vector of bytes into a vector of big-endian uint32_t */
+#define be32dec_vect(dst, src, len) \
+ memcpy((void *)dst, (const void *)src, (size_t)len)
+
+#else /* BYTE_ORDER != BIG_ENDIAN */
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form. Assumes len is a multiple of 4.
+ */
+static void
+be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ be32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t). Assumes len is a multiple of 4.
+ */
+static void
+be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ dst[i] = be32dec(src + i * 4);
+}
+
+#endif /* BYTE_ORDER != BIG_ENDIAN */
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
+#define Maj(x, y, z) ((x & (y | z)) | (y & z))
+#define SHR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
+#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k) \
+ t0 = h + S1(e) + Ch(e, f, g) + k; \
+ t1 = S0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k) \
+ RND(S[(64 - i) % 8], S[(65 - i) % 8], \
+ S[(66 - i) % 8], S[(67 - i) % 8], \
+ S[(68 - i) % 8], S[(69 - i) % 8], \
+ S[(70 - i) % 8], S[(71 - i) % 8], \
+ W[i] + k)
+
+/*
+ * SHA256 block compression function. The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA256_Transform(uint32_t * state, const unsigned char block[64])
+{
+ uint32_t W[64];
+ uint32_t S[8];
+ uint32_t t0, t1;
+ int i;
+
+ /* 1. Prepare message schedule W. */
+ be32dec_vect(W, block, 64);
+ for (i = 16; i < 64; i++)
+ W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+ /* 2. Initialize working variables. */
+ memcpy(S, state, 32);
+
+ /* 3. Mix. */
+ RNDr(S, W, 0, 0x428a2f98);
+ RNDr(S, W, 1, 0x71374491);
+ RNDr(S, W, 2, 0xb5c0fbcf);
+ RNDr(S, W, 3, 0xe9b5dba5);
+ RNDr(S, W, 4, 0x3956c25b);
+ RNDr(S, W, 5, 0x59f111f1);
+ RNDr(S, W, 6, 0x923f82a4);
+ RNDr(S, W, 7, 0xab1c5ed5);
+ RNDr(S, W, 8, 0xd807aa98);
+ RNDr(S, W, 9, 0x12835b01);
+ RNDr(S, W, 10, 0x243185be);
+ RNDr(S, W, 11, 0x550c7dc3);
+ RNDr(S, W, 12, 0x72be5d74);
+ RNDr(S, W, 13, 0x80deb1fe);
+ RNDr(S, W, 14, 0x9bdc06a7);
+ RNDr(S, W, 15, 0xc19bf174);
+ RNDr(S, W, 16, 0xe49b69c1);
+ RNDr(S, W, 17, 0xefbe4786);
+ RNDr(S, W, 18, 0x0fc19dc6);
+ RNDr(S, W, 19, 0x240ca1cc);
+ RNDr(S, W, 20, 0x2de92c6f);
+ RNDr(S, W, 21, 0x4a7484aa);
+ RNDr(S, W, 22, 0x5cb0a9dc);
+ RNDr(S, W, 23, 0x76f988da);
+ RNDr(S, W, 24, 0x983e5152);
+ RNDr(S, W, 25, 0xa831c66d);
+ RNDr(S, W, 26, 0xb00327c8);
+ RNDr(S, W, 27, 0xbf597fc7);
+ RNDr(S, W, 28, 0xc6e00bf3);
+ RNDr(S, W, 29, 0xd5a79147);
+ RNDr(S, W, 30, 0x06ca6351);
+ RNDr(S, W, 31, 0x14292967);
+ RNDr(S, W, 32, 0x27b70a85);
+ RNDr(S, W, 33, 0x2e1b2138);
+ RNDr(S, W, 34, 0x4d2c6dfc);
+ RNDr(S, W, 35, 0x53380d13);
+ RNDr(S, W, 36, 0x650a7354);
+ RNDr(S, W, 37, 0x766a0abb);
+ RNDr(S, W, 38, 0x81c2c92e);
+ RNDr(S, W, 39, 0x92722c85);
+ RNDr(S, W, 40, 0xa2bfe8a1);
+ RNDr(S, W, 41, 0xa81a664b);
+ RNDr(S, W, 42, 0xc24b8b70);
+ RNDr(S, W, 43, 0xc76c51a3);
+ RNDr(S, W, 44, 0xd192e819);
+ RNDr(S, W, 45, 0xd6990624);
+ RNDr(S, W, 46, 0xf40e3585);
+ RNDr(S, W, 47, 0x106aa070);
+ RNDr(S, W, 48, 0x19a4c116);
+ RNDr(S, W, 49, 0x1e376c08);
+ RNDr(S, W, 50, 0x2748774c);
+ RNDr(S, W, 51, 0x34b0bcb5);
+ RNDr(S, W, 52, 0x391c0cb3);
+ RNDr(S, W, 53, 0x4ed8aa4a);
+ RNDr(S, W, 54, 0x5b9cca4f);
+ RNDr(S, W, 55, 0x682e6ff3);
+ RNDr(S, W, 56, 0x748f82ee);
+ RNDr(S, W, 57, 0x78a5636f);
+ RNDr(S, W, 58, 0x84c87814);
+ RNDr(S, W, 59, 0x8cc70208);
+ RNDr(S, W, 60, 0x90befffa);
+ RNDr(S, W, 61, 0xa4506ceb);
+ RNDr(S, W, 62, 0xbef9a3f7);
+ RNDr(S, W, 63, 0xc67178f2);
+
+ /* 4. Mix local working variables into global state */
+ for (i = 0; i < 8; i++)
+ state[i] += S[i];
+}
+
+static unsigned char PAD[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA256_Pad(SHA256_CTX * ctx)
+{
+ unsigned char len[8];
+ uint32_t r, plen;
+
+ /*
+ * Convert length to a vector of bytes -- we do this now rather
+ * than later because the length will change after we pad.
+ */
+ be64enc(len, ctx->count);
+
+ /* Add 1--64 bytes so that the resulting length is 56 mod 64 */
+ r = (ctx->count >> 3) & 0x3f;
+ plen = (r < 56) ? (56 - r) : (120 - r);
+ SHA256_Update(ctx, PAD, (size_t)plen);
+
+ /* Add the terminating bit-count */
+ SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization. Begins a SHA-256 operation. */
+void
+SHA256_Init(SHA256_CTX * ctx)
+{
+
+ /* Zero bits processed so far */
+ ctx->count = 0;
+
+ /* Magic initialization constants */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash */
+void
+SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
+{
+ uint64_t bitlen;
+ uint32_t r;
+ const unsigned char *src = (const unsigned char *) (in);
+
+ /* Number of bytes left in the buffer from previous updates */
+ r = (ctx->count >> 3) & 0x3f;
+
+ /* Convert the length into a number of bits */
+ bitlen = len << 3;
+
+ /* Update number of bits */
+ ctx->count += bitlen;
+
+ /* Handle the case where we don't need to perform any transforms */
+ if (len < 64 - r) {
+ memcpy(&ctx->buf[r], src, len);
+ return;
+ }
+
+ /* Finish the current block */
+ memcpy(&ctx->buf[r], src, 64 - r);
+ SHA256_Transform(ctx->state, ctx->buf);
+ src += 64 - r;
+ len -= 64 - r;
+
+ /* Perform complete blocks */
+ while (len >= 64) {
+ SHA256_Transform(ctx->state, src);
+ src += 64;
+ len -= 64;
+ }
+
+ /* Copy left over data into buffer */
+ memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-256 finalization. Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx)
+{
+
+ /* Add padding */
+ SHA256_Pad(ctx);
+
+ /* Write the hash */
+ be32enc_vect(digest, ctx->state, 32);
+
+ /* Clear the context state */
+ memset((void *)ctx, 0, sizeof(*ctx));
+}