Browse Source

Fix big endianess support in InternalMessageDigest and PBKDF2

- Replace sha1/md5 implementation by ones from https://github.com/nmaier/crypto
- Add endianess functionality fro https://github.com/nmaier/crypto

Closes GH-239
Nils Maier 11 năm trước cách đây
mục cha
commit
8587669995
11 tập tin đã thay đổi với 1402 bổ sung611 xóa
  1. 37 47
      src/InternalMessageDigestImpl.cc
  2. 2 2
      src/Makefile.am
  3. 116 0
      src/crypto_endian.h
  4. 1140 0
      src/crypto_hash.cc
  5. 103 0
      src/crypto_hash.h
  6. 0 311
      src/md5.c
  7. 0 47
      src/md5.h
  8. 0 160
      src/sha1.c
  9. 0 28
      src/sha1.h
  10. 4 10
      src/util_security.cc
  11. 0 6
      test/HttpResponseTest.cc

+ 37 - 47
src/InternalMessageDigestImpl.cc

@@ -35,81 +35,71 @@
 
 #include "MessageDigestImpl.h"
 
-#include "md5.h"
-#include "sha1.h"
+#include "crypto_hash.h"
 
-namespace aria2 {
 namespace {
+using namespace aria2;
+using namespace crypto;
 
-template<size_t dlen,
-         typename ctx_t,
-         int (*init_fn)(ctx_t**),
-         void (*update_fn)(ctx_t*, const void*, size_t),
-         void (*final_fn)(ctx_t*, uint8_t*),
-         void (*free_fn)(ctx_t**)>
-class MessageDigestBase : public MessageDigestImpl {
+template<hash::Algorithms algo>
+class MessageDigestBase : public MessageDigestImpl
+{
 public:
-  MessageDigestBase() : ctx_(nullptr) { reset(); }
-  virtual ~MessageDigestBase()
-  {
-    free_fn(&ctx_);
-  }
+  MessageDigestBase() : ctx_{hash::create(algo)} {}
+  virtual ~MessageDigestBase() {}
 
-  static  size_t length()
+  static size_t length()
   {
-    return dlen;
+    auto ctx = hash::create(algo);
+    return ctx->length();
   }
+
   virtual size_t getDigestLength() const CXX11_OVERRIDE
   {
-    return dlen;
+    return ctx_->length();
   }
+
   virtual void reset() CXX11_OVERRIDE
   {
-    free_fn(&ctx_);
-    init_fn(&ctx_);
+    ctx_->reset();
   }
-  virtual void update(const void* data, size_t length) CXX11_OVERRIDE
+
+  virtual void update(const void *data, size_t length) CXX11_OVERRIDE
   {
-    auto bytes = reinterpret_cast<const char*>(data);
-    while (length) {
-      size_t l = std::min(length, (size_t)std::numeric_limits<uint32_t>::max());
-      update_fn(ctx_, bytes, l);
-      length -= l;
-      bytes += l;
-    }
+    ctx_->update(data, length);
   }
-  virtual void digest(unsigned char* md) CXX11_OVERRIDE
+
+  virtual void digest(unsigned char *md) CXX11_OVERRIDE
   {
-    final_fn(ctx_, md);
+    auto rv = ctx_->finalize();
+    memcpy(md, rv.data(), rv.length());
   }
+
 private:
-  ctx_t* ctx_;
+  std::unique_ptr<hash::Algorithm> ctx_;
 };
 
-typedef MessageDigestBase<MD5_LENGTH,
-                          struct MD5_CTX,
-                          MD5_Init,
-                          MD5_Update,
-                          MD5_Final,
-                          MD5_Free>
-MessageDigestMD5;
-typedef MessageDigestBase<SHA1_LENGTH,
-                          SHA1_CTX,
-                          SHA1_Init,
-                          SHA1_Update,
-                          SHA1_Final,
-                          SHA1_Free>
-MessageDigestSHA1;
+typedef MessageDigestBase<hash::algoMD5> MessageDigestMD5;
+typedef MessageDigestBase<hash::algoSHA1> MessageDigestSHA1;
+typedef MessageDigestBase<hash::algoSHA224> MessageDigestSHA224;
+typedef MessageDigestBase<hash::algoSHA256> MessageDigestSHA256;
+typedef MessageDigestBase<hash::algoSHA384> MessageDigestSHA384;
+typedef MessageDigestBase<hash::algoSHA512> MessageDigestSHA512;
 
 } // namespace
 
-std::unique_ptr<MessageDigestImpl> MessageDigestImpl::sha1()
-{
+namespace aria2 {
+
+std::unique_ptr<MessageDigestImpl> MessageDigestImpl::sha1() {
   return make_unique<MessageDigestSHA1>();
 }
 
 MessageDigestImpl::hashes_t MessageDigestImpl::hashes = {
   { "sha-1", make_hi<MessageDigestSHA1>() },
+  { "sha-224", make_hi<MessageDigestSHA224>() },
+  { "sha-256", make_hi<MessageDigestSHA256>() },
+  { "sha-384", make_hi<MessageDigestSHA384>() },
+  { "sha-512", make_hi<MessageDigestSHA512>() },
   { "md5", make_hi<MessageDigestMD5>() },
 };
 

+ 2 - 2
src/Makefile.am

@@ -58,6 +58,7 @@ SRCS =  \
 	CookieStorage.cc CookieStorage.h\
 	cookie_helper.cc cookie_helper.h\
 	CreateRequestCommand.cc CreateRequestCommand.h\
+	crypto_endian.h\
 	CUIDCounter.cc CUIDCounter.h\
 	DefaultAuthResolver.cc DefaultAuthResolver.h\
 	DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\
@@ -370,8 +371,7 @@ endif
 if USE_INTERNAL_MD
 SRCS += \
 	InternalMessageDigestImpl.cc\
-	md5.c md5.h\
-	sha1.c sha1.h
+	crypto_hash.cc crypto_hash.h
 endif # USE_WINDOWS_MD
 
 if HAVE_LIBGNUTLS

+ 116 - 0
src/crypto_endian.h

@@ -0,0 +1,116 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+// Written in 2014 by Nils Maier
+
+#ifndef CRYPTO_ENDIAN_H
+#define CRYPTO_ENDIAN_H
+
+#include <cstdint>
+
+#include "config.h"
+
+namespace crypto {
+
+#if defined(__GNUG__)
+#define forceinline __attribute__((always_inline)) inline
+#elif defined(_MSC_VER)
+#define forceinline __forceinline
+#else // ! _MSC_VER
+#define forceinline inline
+#endif // ! _MSC_VER
+
+/* In order for this implementation to work your system (or you yourself) must
+ * define after including <sys/param.h>
+ *   - LITTLE_ENDIAN
+ *   - BIG_ENDIAN
+ *   - BYTE_ORDER
+ *   - where BYTE_ORDER == LITTLE_ENDIAN or BYTE_ORDER == BIG_ENDIAN
+ * Failing to conform will render this implementation utterly incorrect.
+ */
+#if defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
+// Itanium is dead!
+#define LITTLE_ENDIAN 1234
+#define BIG_ENDIAN 4321
+#define BYTE_ORDER LITTLE_ENDIAN
+#else // !  defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif // HAVE_SYS_PARAM_H
+#endif // !  defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
+
+#if !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) || !defined(BYTE_ORDER) || (LITTLE_ENDIAN != BYTE_ORDER && BIG_ENDIAN != BYTE_ORDER)
+#error Unsupported byte order/endianess
+#endif
+
+// Lets spend some quality time mucking around with byte swap and endian-ness.
+// First bswap32:
+#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUG__)
+#define __crypto_bswap32(p)                                                    \
+  ({                                                                           \
+    uint32_t t = p;                                                            \
+    __asm__ __volatile__("bswap %0" : "=r"(t) : "0"(t));                       \
+    t;                                                                         \
+  })
+#elif defined(__GNUG__)
+#define __crypto_bswap32 __builtin_bswap32
+#else // defined(__GNUG__)
+forceinline uint32_t __crypto_bswap32(uint32_t n)
+{
+  n = ((n << 8) & 0xff00ff00) | ((n >> 8) & 0xff00ff);
+  return (n << 16) | (n >> 16);
+}
+#endif // defined(__GNUG__)
+
+// Next up: bswap64
+#if defined(__x86_64__) && defined(__GNUG__)
+#define __crypto_bswap64(p)                                                    \
+  ({                                                                           \
+    uint64_t t = p;                                                            \
+    __asm__ __volatile__("bswapq %q0" : "=r"(t) : "0"(t));                     \
+    t;                                                                         \
+  })
+
+#elif defined(__GNUG__)
+#define __crypto_bswap64 __builtin_bswap64
+#else // defined(__GNUG__)
+forceinline uint64_t __crypto_bswap64(uint64_t n)
+{
+  n = ((n << 8) & 0xff00ff00ff00ff00) | ((n >> 8) & 0x00ff00ff00ff00ff);
+  n = ((n << 16) & 0xffff0000ffff0000) | ((n >> 16) & 0x0000ffff0000ffff);
+  return (n << 32) | (n >> 32);
+}
+#endif // defined(__GNUG__)
+
+// Time for an implementation that makes reuse easier.
+namespace {
+template<typename T>
+inline T __crypto_bswap(T n)
+{
+  static_assert(sizeof(T) != sizeof(T), "Not implemented");
+}
+
+template<>
+inline uint32_t __crypto_bswap(uint32_t n)
+{
+  return __crypto_bswap32(n);
+}
+
+template<>
+inline uint64_t __crypto_bswap(uint64_t n)
+{
+  return __crypto_bswap64(n);
+}
+} // namespace
+
+// __crypto_le and __crypto_be depending on byte order
+#if LITTLE_ENDIAN == BYTE_ORDER
+#define __crypto_be(n) __crypto_bswap(n)
+#define __crypto_le(n) (n)
+#else // LITTLE_ENDIAN == WORD_ORDER
+#define __crypto_be(n) (n)
+#define __crypto_le(n) __crypto_bswap(n)
+#endif
+
+} // namespace crypto
+
+#endif // CRYPTO_ENDIAN_H

+ 1140 - 0
src/crypto_hash.cc

@@ -0,0 +1,1140 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+// Written in 2014 by Nils Maier
+
+#include "crypto_hash.h"
+#include "crypto_endian.h"
+
+#include <cstring>
+#include <stdexcept>
+#include <unordered_map>
+
+// Compiler hints
+#if defined(__GNUG__)
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else // ! __GNUG_
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif // ! __GNUG__
+
+// Basic operations
+static forceinline uint32_t rol(uint32_t x, uint32_t n)
+{
+  return x << n | x >> (32 - n);
+}
+
+static forceinline uint32_t ror(uint32_t x, uint32_t n)
+{
+  return x >> n | x << (32 - n);
+}
+
+static forceinline uint64_t ror(uint64_t x, uint64_t n)
+{
+  return x >> n | x << (64 - n);
+}
+
+// SHA functions
+template<typename T>
+static forceinline T ch(T b, T c, T d)
+{
+  return d ^ (b & (c ^ d));
+}
+
+template<typename T>
+static forceinline T maj(T b, T c, T d)
+{
+  return (b & c) | (d & (b | c));
+}
+
+template<typename T>
+static forceinline T par(T b, T c, T d)
+{
+  return b ^ c ^ d;
+}
+
+#ifdef __GNUG__
+#define __hash_maybe_memfence __asm__("" ::: "memory")
+#else // __GNUG__
+#define __hash_maybe_memfence
+#endif // __GNUG__
+
+// Template for the |::transform|s
+#define __hash_assign_words(endian)                                            \
+  word_t w00, w01, w02, w03, w04, w05, w06, w07, w08, w09, w10, w11, w12, w13, \
+      w14, w15;                                                                \
+  w15 = endian(buffer[15]), w14 = endian(buffer[14]);                          \
+  w13 = endian(buffer[13]), w12 = endian(buffer[12]);                          \
+  w11 = endian(buffer[11]), w10 = endian(buffer[10]);                          \
+  w09 = endian(buffer[9]), w08 = endian(buffer[8]);                            \
+  w07 = endian(buffer[7]), w06 = endian(buffer[6]);                            \
+  w05 = endian(buffer[5]), w04 = endian(buffer[4]);                            \
+  w03 = endian(buffer[3]), w02 = endian(buffer[2]);                            \
+  w01 = endian(buffer[1]), w00 = endian(buffer[0])
+
+using namespace crypto;
+using namespace crypto::hash;
+
+// Our base implementation, doing most of the work, short of |tranform|,
+// |digest| and initialization.
+template <typename word_, uint_fast8_t bsize, uint_fast8_t ssize>
+class AlgorithmImpl : public Algorithm
+{
+public:
+  typedef word_ word_t;
+
+protected:
+  template <uint_fast8_t size>
+  union buffer_t
+  {
+    uint8_t bytes[size * sizeof(word_t)];
+    word_t words[size];
+  };
+
+  uint_fast64_t count_;
+  buffer_t<bsize> buffer_;
+  buffer_t<ssize> state_;
+  uint_fast8_t offset_;
+
+  virtual void transform(const word_t* buffer) = 0;
+
+  virtual std::string digest()
+  {
+    return std::string((const char*)state_.bytes, sizeof(state_.bytes));
+  }
+
+public:
+  AlgorithmImpl() {}
+
+  virtual void update(const void* data, uint64_t len)
+  {
+    if (unlikely(!len)) {
+      return;
+    }
+
+    auto bytes = reinterpret_cast<const uint8_t*>(data);
+    count_ += len;
+
+    // We have data buffered...
+    if (unlikely(offset_)) {
+      const uint32_t rem = sizeof(buffer_) - offset_;
+      const uint32_t turn = (uint32_t)(len + ((rem - len) & (rem - len) >> 31));
+      memcpy(buffer_.bytes + offset_, bytes, turn);
+      len -= turn;
+      bytes += turn;
+      offset_ += turn;
+      if (likely(offset_ == sizeof(buffer_))) {
+        transform(buffer_.words);
+        offset_ = 0;
+      }
+    }
+
+    // |transform| as many blocks as possible.
+    while (len >= sizeof(buffer_)) {
+      // |offset_| has to be 0 at this point!
+      // Which is guaranteed by the block above.
+
+      transform(reinterpret_cast<const word_t*>(bytes));
+      bytes += sizeof(buffer_);
+      len -= sizeof(buffer_);
+    }
+
+    // Buffer remaining bytes, if any.
+    if (unlikely(len)) {
+      const uint32_t rem = sizeof(buffer_) - offset_;
+      const uint32_t turn = (uint32_t)(len + ((rem - len) & (rem - len) >> 31));
+      memcpy(buffer_.bytes + offset_, bytes, turn);
+      offset_ += turn;
+    }
+  }
+
+  virtual std::string finalize()
+  {
+    // Pad the message according to spec.
+    const uint_fast16_t cutoff = sizeof(buffer_) - sizeof(word_t) * 2;
+    buffer_.bytes[offset_] = 0x80;
+    if (unlikely(++offset_ == sizeof(buffer_))) {
+      transform(buffer_.words);
+      memset(buffer_.bytes, 0x00, cutoff);
+    }
+    else if (offset_ > cutoff) {
+      memset(buffer_.bytes + offset_, 0x00, sizeof(buffer_) - offset_);
+      transform(buffer_.words);
+      memset(buffer_.bytes, 0x00, cutoff);
+    }
+    else if (likely(offset_ != cutoff)) {
+      memset(buffer_.bytes + offset_, 0x00, cutoff - offset_);
+    }
+
+    // Append length, multiplied by 8 (because bits!)
+    const uint_fast64_t bits = count_ << 3;
+    if (sizeof(word_t) == 4) {
+      *reinterpret_cast<uint64_t*>(buffer_.words + bsize - 2) =
+        __crypto_be(bits);
+    }
+    else {
+      buffer_.words[bsize - 2] = 0;
+      buffer_.words[bsize - 1] = (word_t)__crypto_be(bits);
+    }
+
+    // Last transform:
+    transform(buffer_.words);
+
+#if LITTLE_ENDIAN == BYTE_ORDER
+    // On little endian, we still need to swap the bytes.
+    for (auto i = 0; i < ssize; ++i) {
+      state_.words[i] = __crypto_bswap(state_.words[i]);
+    }
+#endif // LITTLE_ENDIAN == BYTE_ORDER
+
+    auto rv = digest();
+    reset();
+    return rv;
+  }
+
+  virtual uint_fast16_t blocksize() const {
+    return sizeof(buffer_);
+  }
+};
+
+// Important! Other than the SHA family, MD5 is actually LE.
+class MD5 : public AlgorithmImpl<uint32_t, 16, 4>
+{
+private:
+  static const word_t initvec[];
+
+protected:
+  virtual void transform(const word_t* buffer)
+  {
+    __hash_assign_words(__crypto_le);
+    __hash_maybe_memfence;
+
+    word_t a, b, c, d;
+    a = state_.words[0];
+    b = state_.words[1];
+    c = state_.words[2];
+    d = state_.words[3];
+    __hash_maybe_memfence;
+
+#define f1(x, y, z) (z ^ (x & (y ^ z)))
+#define f2(x, y, z) (y ^ (z & (x ^ y)))
+#define f3(x, y, z) (x ^ y ^ z)
+#define f4(x, y, z) (y ^ (x | ~z))
+
+#define r(f, a1, a2, a3, a4, w, k, n)                                          \
+  a1 += f(a2, a3, a4) + w + k;                                                 \
+  a1 = rol(a1, n);                                                             \
+  a1 += a2;
+
+    // Yeah, unrolled loops.
+    // This stuff is generated, but accidentially deleted the generator script.
+
+    r(f1, a, b, c, d, w00, 0xd76aa478, 7);
+    r(f1, d, a, b, c, w01, 0xe8c7b756, 12);
+    r(f1, c, d, a, b, w02, 0x242070db, 17);
+    r(f1, b, c, d, a, w03, 0xc1bdceee, 22);
+    r(f1, a, b, c, d, w04, 0xf57c0faf, 7);
+    r(f1, d, a, b, c, w05, 0x4787c62a, 12);
+    r(f1, c, d, a, b, w06, 0xa8304613, 17);
+    r(f1, b, c, d, a, w07, 0xfd469501, 22);
+    r(f1, a, b, c, d, w08, 0x698098d8, 7);
+    r(f1, d, a, b, c, w09, 0x8b44f7af, 12);
+    r(f1, c, d, a, b, w10, 0xffff5bb1, 17);
+    r(f1, b, c, d, a, w11, 0x895cd7be, 22);
+    r(f1, a, b, c, d, w12, 0x6b901122, 7);
+    r(f1, d, a, b, c, w13, 0xfd987193, 12);
+    r(f1, c, d, a, b, w14, 0xa679438e, 17);
+    r(f1, b, c, d, a, w15, 0x49b40821, 22);
+
+    r(f2, a, b, c, d, w01, 0xf61e2562, 5);
+    r(f2, d, a, b, c, w06, 0xc040b340, 9);
+    r(f2, c, d, a, b, w11, 0x265e5a51, 14);
+    r(f2, b, c, d, a, w00, 0xe9b6c7aa, 20);
+    r(f2, a, b, c, d, w05, 0xd62f105d, 5);
+    r(f2, d, a, b, c, w10, 0x02441453, 9);
+    r(f2, c, d, a, b, w15, 0xd8a1e681, 14);
+    r(f2, b, c, d, a, w04, 0xe7d3fbc8, 20);
+    r(f2, a, b, c, d, w09, 0x21e1cde6, 5);
+    r(f2, d, a, b, c, w14, 0xc33707d6, 9);
+    r(f2, c, d, a, b, w03, 0xf4d50d87, 14);
+    r(f2, b, c, d, a, w08, 0x455a14ed, 20);
+    r(f2, a, b, c, d, w13, 0xa9e3e905, 5);
+    r(f2, d, a, b, c, w02, 0xfcefa3f8, 9);
+    r(f2, c, d, a, b, w07, 0x676f02d9, 14);
+    r(f2, b, c, d, a, w12, 0x8d2a4c8a, 20);
+
+    r(f3, a, b, c, d, w05, 0xfffa3942, 4);
+    r(f3, d, a, b, c, w08, 0x8771f681, 11);
+    r(f3, c, d, a, b, w11, 0x6d9d6122, 16);
+    r(f3, b, c, d, a, w14, 0xfde5380c, 23);
+    r(f3, a, b, c, d, w01, 0xa4beea44, 4);
+    r(f3, d, a, b, c, w04, 0x4bdecfa9, 11);
+    r(f3, c, d, a, b, w07, 0xf6bb4b60, 16);
+    r(f3, b, c, d, a, w10, 0xbebfbc70, 23);
+    r(f3, a, b, c, d, w13, 0x289b7ec6, 4);
+    r(f3, d, a, b, c, w00, 0xeaa127fa, 11);
+    r(f3, c, d, a, b, w03, 0xd4ef3085, 16);
+    r(f3, b, c, d, a, w06, 0x04881d05, 23);
+    r(f3, a, b, c, d, w09, 0xd9d4d039, 4);
+    r(f3, d, a, b, c, w12, 0xe6db99e5, 11);
+    r(f3, c, d, a, b, w15, 0x1fa27cf8, 16);
+    r(f3, b, c, d, a, w02, 0xc4ac5665, 23);
+
+    r(f4, a, b, c, d, w00, 0xf4292244, 6);
+    r(f4, d, a, b, c, w07, 0x432aff97, 10);
+    r(f4, c, d, a, b, w14, 0xab9423a7, 15);
+    r(f4, b, c, d, a, w05, 0xfc93a039, 21);
+    r(f4, a, b, c, d, w12, 0x655b59c3, 6);
+    r(f4, d, a, b, c, w03, 0x8f0ccc92, 10);
+    r(f4, c, d, a, b, w10, 0xffeff47d, 15);
+    r(f4, b, c, d, a, w01, 0x85845dd1, 21);
+    r(f4, a, b, c, d, w08, 0x6fa87e4f, 6);
+    r(f4, d, a, b, c, w15, 0xfe2ce6e0, 10);
+    r(f4, c, d, a, b, w06, 0xa3014314, 15);
+    r(f4, b, c, d, a, w13, 0x4e0811a1, 21);
+    r(f4, a, b, c, d, w04, 0xf7537e82, 6);
+    r(f4, d, a, b, c, w11, 0xbd3af235, 10);
+    r(f4, c, d, a, b, w02, 0x2ad7d2bb, 15);
+    r(f4, b, c, d, a, w09, 0xeb86d391, 21);
+
+#undef r
+#undef f4
+#undef f3
+#undef f2
+#undef f1
+
+    __hash_maybe_memfence;
+    state_.words[0] += a;
+    state_.words[1] += b;
+    state_.words[2] += c;
+    state_.words[3] += d;
+  }
+
+public:
+  MD5()
+  {
+    reset();
+  }
+
+  virtual ~MD5()
+  {
+    reset();
+  }
+
+  // Since this is LE, and I am lazy, copy-paste overwriting with BE -> LE.
+  virtual std::string finalize()
+  {
+    // Pad
+    buffer_.bytes[offset_] = 0x80;
+    if (unlikely(++offset_ == 64)) {
+      transform(buffer_.words);
+      memset(buffer_.bytes, 0x00, 56);
+    }
+    else if (offset_ > 56) {
+      memset(buffer_.bytes + offset_, 0x00, 64 - offset_);
+      transform(buffer_.words);
+      memset(buffer_.bytes, 0x00, 56);
+    }
+    else if (likely(offset_ != 56)) {
+      memset(buffer_.bytes + offset_, 0x00, 56 - offset_);
+    }
+
+    // Append length, multiplied by 8 (because bits!)
+    const uint_fast64_t bits = count_ << 3;
+    *reinterpret_cast<uint64_t*>(buffer_.words + 14) =
+      __crypto_le(bits);
+    transform(buffer_.words);
+#if BIG_ENDIAN == BYTE_ORDER
+    state_.words[0] = __crypto_bswap(state_.words[0]);
+    state_.words[1] = __crypto_bswap(state_.words[1]);
+    state_.words[2] = __crypto_bswap(state_.words[2]);
+    state_.words[3] = __crypto_bswap(state_.words[3]);
+#endif // LITTLE_ENDIAN == BYTE_ORDER
+
+    auto rv = std::string((const char*)state_.bytes, sizeof(state_.bytes));
+    reset();
+    return rv;
+  }
+
+  virtual void reset()
+  {
+    memset(buffer_.bytes, 0, sizeof(buffer_));
+    memcpy(state_.bytes, initvec, sizeof(state_));
+    count_ = offset_ = 0;
+  }
+
+  virtual inline uint_fast16_t length() const
+  {
+    return 16;
+  }
+};
+
+const MD5::word_t MD5::initvec[] = {
+  0x67452301,
+  0xefcdab89,
+  0x98badcfe,
+  0x10325476
+};
+
+class SHA1 : public AlgorithmImpl<uint32_t, 16, 5>
+{
+private:
+  static const word_t initvec[];
+
+protected:
+  virtual void transform(const word_t* buffer)
+  {
+    __hash_assign_words(__crypto_be);
+    __hash_maybe_memfence;
+
+    word_t a, b, c, d, e;
+    a = state_.words[0];
+    b = state_.words[1];
+    c = state_.words[2];
+    d = state_.words[3];
+    e = state_.words[4];
+    __hash_maybe_memfence;
+
+#define c1 0x5a827999UL
+#define c2 0x6ed9eba1UL
+#define c3 0x8f1bbcdcUL
+#define c4 0xca62c1d6UL
+
+#define r(f, k, a1, a2, a3, a4, a5, w)                                         \
+  a1 = rol(a2, 5) + f(a3, a4, a5) + a1 + w + k;                                \
+  a3 = rol(a3, 30);
+
+#define r1(a1, a2, a3, a4, a5, w) r(ch, c1, a1, a2, a3, a4, a5, w)
+#define r2(a1, a2, a3, a4, a5, w) r(par, c2, a1, a2, a3, a4, a5, w)
+#define r3(a1, a2, a3, a4, a5, w) r(maj, c3, a1, a2, a3, a4, a5, w)
+#define r4(a1, a2, a3, a4, a5, w) r(par, c4, a1, a2, a3, a4, a5, w)
+
+    // Generated code. See sha1-transgen.py
+    // Round 0
+    r1(e, a, b, c, d, w00);
+    r1(d, e, a, b, c, w01);
+    r1(c, d, e, a, b, w02);
+    r1(b, c, d, e, a, w03);
+    r1(a, b, c, d, e, w04);
+    r1(e, a, b, c, d, w05);
+    r1(d, e, a, b, c, w06);
+    r1(c, d, e, a, b, w07);
+    r1(b, c, d, e, a, w08);
+    r1(a, b, c, d, e, w09);
+
+    // Round 10
+    r1(e, a, b, c, d, w10);
+    r1(d, e, a, b, c, w11);
+    r1(c, d, e, a, b, w12);
+    r1(b, c, d, e, a, w13);
+    r1(a, b, c, d, e, w14);
+    r1(e, a, b, c, d, w15);
+    w00 = rol((w13 ^ w08 ^ w02 ^ w00), 1),   r1(d, e, a, b, c, w00);
+    w01 = rol((w14 ^ w09 ^ w03 ^ w01), 1),   r1(c, d, e, a, b, w01);
+    w02 = rol((w15 ^ w10 ^ w04 ^ w02), 1),   r1(b, c, d, e, a, w02);
+    w03 = rol((w00 ^ w11 ^ w05 ^ w03), 1),   r1(a, b, c, d, e, w03);
+
+    // Round 20
+    w04 = rol((w01 ^ w12 ^ w06 ^ w04), 1),   r2(e, a, b, c, d, w04);
+    w05 = rol((w02 ^ w13 ^ w07 ^ w05), 1),   r2(d, e, a, b, c, w05);
+    w06 = rol((w03 ^ w14 ^ w08 ^ w06), 1),   r2(c, d, e, a, b, w06);
+    w07 = rol((w04 ^ w15 ^ w09 ^ w07), 1),   r2(b, c, d, e, a, w07);
+    w08 = rol((w05 ^ w00 ^ w10 ^ w08), 1),   r2(a, b, c, d, e, w08);
+    w09 = rol((w06 ^ w01 ^ w11 ^ w09), 1),   r2(e, a, b, c, d, w09);
+    w10 = rol((w07 ^ w02 ^ w12 ^ w10), 1),   r2(d, e, a, b, c, w10);
+    w11 = rol((w08 ^ w03 ^ w13 ^ w11), 1),   r2(c, d, e, a, b, w11);
+    w12 = rol((w09 ^ w04 ^ w14 ^ w12), 1),   r2(b, c, d, e, a, w12);
+    w13 = rol((w10 ^ w05 ^ w15 ^ w13), 1),   r2(a, b, c, d, e, w13);
+
+    // Round 30
+    w14 = rol((w11 ^ w06 ^ w00 ^ w14), 1),   r2(e, a, b, c, d, w14);
+    w15 = rol((w12 ^ w07 ^ w01 ^ w15), 1),   r2(d, e, a, b, c, w15);
+    w00 = rol((w13 ^ w08 ^ w02 ^ w00), 1),   r2(c, d, e, a, b, w00);
+    w01 = rol((w14 ^ w09 ^ w03 ^ w01), 1),   r2(b, c, d, e, a, w01);
+    w02 = rol((w15 ^ w10 ^ w04 ^ w02), 1),   r2(a, b, c, d, e, w02);
+    w03 = rol((w00 ^ w11 ^ w05 ^ w03), 1),   r2(e, a, b, c, d, w03);
+    w04 = rol((w01 ^ w12 ^ w06 ^ w04), 1),   r2(d, e, a, b, c, w04);
+    w05 = rol((w02 ^ w13 ^ w07 ^ w05), 1),   r2(c, d, e, a, b, w05);
+    w06 = rol((w03 ^ w14 ^ w08 ^ w06), 1),   r2(b, c, d, e, a, w06);
+    w07 = rol((w04 ^ w15 ^ w09 ^ w07), 1),   r2(a, b, c, d, e, w07);
+
+    // Round 40
+    w08 = rol((w05 ^ w00 ^ w10 ^ w08), 1),   r3(e, a, b, c, d, w08);
+    w09 = rol((w06 ^ w01 ^ w11 ^ w09), 1),   r3(d, e, a, b, c, w09);
+    w10 = rol((w07 ^ w02 ^ w12 ^ w10), 1),   r3(c, d, e, a, b, w10);
+    w11 = rol((w08 ^ w03 ^ w13 ^ w11), 1),   r3(b, c, d, e, a, w11);
+    w12 = rol((w09 ^ w04 ^ w14 ^ w12), 1),   r3(a, b, c, d, e, w12);
+    w13 = rol((w10 ^ w05 ^ w15 ^ w13), 1),   r3(e, a, b, c, d, w13);
+    w14 = rol((w11 ^ w06 ^ w00 ^ w14), 1),   r3(d, e, a, b, c, w14);
+    w15 = rol((w12 ^ w07 ^ w01 ^ w15), 1),   r3(c, d, e, a, b, w15);
+    w00 = rol((w13 ^ w08 ^ w02 ^ w00), 1),   r3(b, c, d, e, a, w00);
+    w01 = rol((w14 ^ w09 ^ w03 ^ w01), 1),   r3(a, b, c, d, e, w01);
+
+    // Round 50
+    w02 = rol((w15 ^ w10 ^ w04 ^ w02), 1),   r3(e, a, b, c, d, w02);
+    w03 = rol((w00 ^ w11 ^ w05 ^ w03), 1),   r3(d, e, a, b, c, w03);
+    w04 = rol((w01 ^ w12 ^ w06 ^ w04), 1),   r3(c, d, e, a, b, w04);
+    w05 = rol((w02 ^ w13 ^ w07 ^ w05), 1),   r3(b, c, d, e, a, w05);
+    w06 = rol((w03 ^ w14 ^ w08 ^ w06), 1),   r3(a, b, c, d, e, w06);
+    w07 = rol((w04 ^ w15 ^ w09 ^ w07), 1),   r3(e, a, b, c, d, w07);
+    w08 = rol((w05 ^ w00 ^ w10 ^ w08), 1),   r3(d, e, a, b, c, w08);
+    w09 = rol((w06 ^ w01 ^ w11 ^ w09), 1),   r3(c, d, e, a, b, w09);
+    w10 = rol((w07 ^ w02 ^ w12 ^ w10), 1),   r3(b, c, d, e, a, w10);
+    w11 = rol((w08 ^ w03 ^ w13 ^ w11), 1),   r3(a, b, c, d, e, w11);
+
+    // Round 60
+    w12 = rol((w09 ^ w04 ^ w14 ^ w12), 1),   r4(e, a, b, c, d, w12);
+    w13 = rol((w10 ^ w05 ^ w15 ^ w13), 1),   r4(d, e, a, b, c, w13);
+    w14 = rol((w11 ^ w06 ^ w00 ^ w14), 1),   r4(c, d, e, a, b, w14);
+    w15 = rol((w12 ^ w07 ^ w01 ^ w15), 1),   r4(b, c, d, e, a, w15);
+    w00 = rol((w13 ^ w08 ^ w02 ^ w00), 1),   r4(a, b, c, d, e, w00);
+    w01 = rol((w14 ^ w09 ^ w03 ^ w01), 1),   r4(e, a, b, c, d, w01);
+    w02 = rol((w15 ^ w10 ^ w04 ^ w02), 1),   r4(d, e, a, b, c, w02);
+    w03 = rol((w00 ^ w11 ^ w05 ^ w03), 1),   r4(c, d, e, a, b, w03);
+    w04 = rol((w01 ^ w12 ^ w06 ^ w04), 1),   r4(b, c, d, e, a, w04);
+    w05 = rol((w02 ^ w13 ^ w07 ^ w05), 1),   r4(a, b, c, d, e, w05);
+
+    // Round 70
+    w06 = rol((w03 ^ w14 ^ w08 ^ w06), 1),   r4(e, a, b, c, d, w06);
+    w07 = rol((w04 ^ w15 ^ w09 ^ w07), 1),   r4(d, e, a, b, c, w07);
+    w08 = rol((w05 ^ w00 ^ w10 ^ w08), 1),   r4(c, d, e, a, b, w08);
+    w09 = rol((w06 ^ w01 ^ w11 ^ w09), 1),   r4(b, c, d, e, a, w09);
+    w10 = rol((w07 ^ w02 ^ w12 ^ w10), 1),   r4(a, b, c, d, e, w10);
+    w11 = rol((w08 ^ w03 ^ w13 ^ w11), 1),   r4(e, a, b, c, d, w11);
+    w12 = rol((w09 ^ w04 ^ w14 ^ w12), 1),   r4(d, e, a, b, c, w12);
+    w13 = rol((w10 ^ w05 ^ w15 ^ w13), 1),   r4(c, d, e, a, b, w13);
+    w14 = rol((w11 ^ w06 ^ w00 ^ w14), 1),   r4(b, c, d, e, a, w14);
+    w15 = rol((w12 ^ w07 ^ w01 ^ w15), 1),   r4(a, b, c, d, e, w15);
+
+#undef r4
+#undef r3
+#undef r2
+#undef r1
+#undef r
+#undef c4
+#undef c3
+#undef c2
+#undef c1
+
+    __hash_maybe_memfence;
+    state_.words[0] += a;
+    state_.words[1] += b;
+    state_.words[2] += c;
+    state_.words[3] += d;
+    state_.words[4] += e;
+  }
+
+public:
+  SHA1()
+  {
+    reset();
+  }
+
+  virtual ~SHA1()
+  {
+    reset();
+  }
+
+  virtual void reset()
+  {
+    memset(buffer_.bytes, 0, sizeof(buffer_));
+    memcpy(state_.bytes, initvec, sizeof(state_));
+    count_ = offset_ = 0;
+  }
+
+  virtual inline uint_fast16_t length() const
+  {
+    return 20;
+  }
+};
+
+const SHA1::word_t SHA1::initvec[] = {
+  0x67452301,
+  0xefcdab89,
+  0x98badcfe,
+  0x10325476,
+  0xc3d2e1f0
+};
+
+class SHA256 : public AlgorithmImpl<uint32_t, 16, 8>
+{
+private:
+  static const word_t initvec[];
+
+protected:
+  virtual void transform(const word_t* buffer)
+  {
+    __hash_assign_words(__crypto_be);
+    __hash_maybe_memfence;
+
+    word_t a, b, c, d, e, f, g, h;
+    word_t t;
+    a = state_.words[0];
+    b = state_.words[1];
+    c = state_.words[2];
+    d = state_.words[3];
+    e = state_.words[4];
+    f = state_.words[5];
+    g = state_.words[6];
+    h = state_.words[7];
+    __hash_maybe_memfence;
+
+#define b0(w) \
+  (ror(w, 2) ^ ror(w, 13) ^ ror(w, 22))
+#define b1(w) \
+  (ror(w, 6) ^ ror(w, 11) ^ ror(w, 25))
+
+#define s0(w) \
+  (ror(w, 7) ^ ror(w, 18) ^ (w >> 3))
+#define s1(w) \
+  (ror(w, 17) ^ ror(w, 19) ^ (w >> 10))
+
+#define r(a1, a2, a3, a4, a5, a6, a7, a8, k, w)                                \
+  a4 += t = a8 + b1(a5) + ch(a5, a6, a7) + k + w;                              \
+  a8 = t + b0(a1) + maj(a1, a2, a3);                                           \
+
+    // Generated code. See sha256-transgen.py
+  // Round 0
+  r(a, b, c, d, e, f, g, h, 0x428a2f98, w00);
+  r(h, a, b, c, d, e, f, g, 0x71374491, w01);
+  r(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w02);
+  r(f, g, h, a, b, c, d, e, 0xe9b5dba5, w03);
+  r(e, f, g, h, a, b, c, d, 0x3956c25b, w04);
+  r(d, e, f, g, h, a, b, c, 0x59f111f1, w05);
+  r(c, d, e, f, g, h, a, b, 0x923f82a4, w06);
+  r(b, c, d, e, f, g, h, a, 0xab1c5ed5, w07);
+
+  // Round 8
+  r(a, b, c, d, e, f, g, h, 0xd807aa98, w08);
+  r(h, a, b, c, d, e, f, g, 0x12835b01, w09);
+  r(g, h, a, b, c, d, e, f, 0x243185be, w10);
+  r(f, g, h, a, b, c, d, e, 0x550c7dc3, w11);
+  r(e, f, g, h, a, b, c, d, 0x72be5d74, w12);
+  r(d, e, f, g, h, a, b, c, 0x80deb1fe, w13);
+  r(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14);
+  r(b, c, d, e, f, g, h, a, 0xc19bf174, w15);
+
+  // Round 16
+  w00 = s1(w14) + w09 + s0(w01) + w00,   r(a, b, c, d, e, f, g, h, 0xe49b69c1, w00);
+  w01 = s1(w15) + w10 + s0(w02) + w01,   r(h, a, b, c, d, e, f, g, 0xefbe4786, w01);
+  w02 = s1(w00) + w11 + s0(w03) + w02,   r(g, h, a, b, c, d, e, f, 0x0fc19dc6, w02);
+  w03 = s1(w01) + w12 + s0(w04) + w03,   r(f, g, h, a, b, c, d, e, 0x240ca1cc, w03);
+  w04 = s1(w02) + w13 + s0(w05) + w04,   r(e, f, g, h, a, b, c, d, 0x2de92c6f, w04);
+  w05 = s1(w03) + w14 + s0(w06) + w05,   r(d, e, f, g, h, a, b, c, 0x4a7484aa, w05);
+  w06 = s1(w04) + w15 + s0(w07) + w06,   r(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w06);
+  w07 = s1(w05) + w00 + s0(w08) + w07,   r(b, c, d, e, f, g, h, a, 0x76f988da, w07);
+
+  // Round 24
+  w08 = s1(w06) + w01 + s0(w09) + w08,   r(a, b, c, d, e, f, g, h, 0x983e5152, w08);
+  w09 = s1(w07) + w02 + s0(w10) + w09,   r(h, a, b, c, d, e, f, g, 0xa831c66d, w09);
+  w10 = s1(w08) + w03 + s0(w11) + w10,   r(g, h, a, b, c, d, e, f, 0xb00327c8, w10);
+  w11 = s1(w09) + w04 + s0(w12) + w11,   r(f, g, h, a, b, c, d, e, 0xbf597fc7, w11);
+  w12 = s1(w10) + w05 + s0(w13) + w12,   r(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12);
+  w13 = s1(w11) + w06 + s0(w14) + w13,   r(d, e, f, g, h, a, b, c, 0xd5a79147, w13);
+  w14 = s1(w12) + w07 + s0(w15) + w14,   r(c, d, e, f, g, h, a, b, 0x06ca6351, w14);
+  w15 = s1(w13) + w08 + s0(w00) + w15,   r(b, c, d, e, f, g, h, a, 0x14292967, w15);
+
+  // Round 32
+  w00 = s1(w14) + w09 + s0(w01) + w00,   r(a, b, c, d, e, f, g, h, 0x27b70a85, w00);
+  w01 = s1(w15) + w10 + s0(w02) + w01,   r(h, a, b, c, d, e, f, g, 0x2e1b2138, w01);
+  w02 = s1(w00) + w11 + s0(w03) + w02,   r(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w02);
+  w03 = s1(w01) + w12 + s0(w04) + w03,   r(f, g, h, a, b, c, d, e, 0x53380d13, w03);
+  w04 = s1(w02) + w13 + s0(w05) + w04,   r(e, f, g, h, a, b, c, d, 0x650a7354, w04);
+  w05 = s1(w03) + w14 + s0(w06) + w05,   r(d, e, f, g, h, a, b, c, 0x766a0abb, w05);
+  w06 = s1(w04) + w15 + s0(w07) + w06,   r(c, d, e, f, g, h, a, b, 0x81c2c92e, w06);
+  w07 = s1(w05) + w00 + s0(w08) + w07,   r(b, c, d, e, f, g, h, a, 0x92722c85, w07);
+
+  // Round 40
+  w08 = s1(w06) + w01 + s0(w09) + w08,   r(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w08);
+  w09 = s1(w07) + w02 + s0(w10) + w09,   r(h, a, b, c, d, e, f, g, 0xa81a664b, w09);
+  w10 = s1(w08) + w03 + s0(w11) + w10,   r(g, h, a, b, c, d, e, f, 0xc24b8b70, w10);
+  w11 = s1(w09) + w04 + s0(w12) + w11,   r(f, g, h, a, b, c, d, e, 0xc76c51a3, w11);
+  w12 = s1(w10) + w05 + s0(w13) + w12,   r(e, f, g, h, a, b, c, d, 0xd192e819, w12);
+  w13 = s1(w11) + w06 + s0(w14) + w13,   r(d, e, f, g, h, a, b, c, 0xd6990624, w13);
+  w14 = s1(w12) + w07 + s0(w15) + w14,   r(c, d, e, f, g, h, a, b, 0xf40e3585, w14);
+  w15 = s1(w13) + w08 + s0(w00) + w15,   r(b, c, d, e, f, g, h, a, 0x106aa070, w15);
+
+  // Round 48
+  w00 = s1(w14) + w09 + s0(w01) + w00,   r(a, b, c, d, e, f, g, h, 0x19a4c116, w00);
+  w01 = s1(w15) + w10 + s0(w02) + w01,   r(h, a, b, c, d, e, f, g, 0x1e376c08, w01);
+  w02 = s1(w00) + w11 + s0(w03) + w02,   r(g, h, a, b, c, d, e, f, 0x2748774c, w02);
+  w03 = s1(w01) + w12 + s0(w04) + w03,   r(f, g, h, a, b, c, d, e, 0x34b0bcb5, w03);
+  w04 = s1(w02) + w13 + s0(w05) + w04,   r(e, f, g, h, a, b, c, d, 0x391c0cb3, w04);
+  w05 = s1(w03) + w14 + s0(w06) + w05,   r(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w05);
+  w06 = s1(w04) + w15 + s0(w07) + w06,   r(c, d, e, f, g, h, a, b, 0x5b9cca4f, w06);
+  w07 = s1(w05) + w00 + s0(w08) + w07,   r(b, c, d, e, f, g, h, a, 0x682e6ff3, w07);
+
+  // Round 56
+  w08 = s1(w06) + w01 + s0(w09) + w08,   r(a, b, c, d, e, f, g, h, 0x748f82ee, w08);
+  w09 = s1(w07) + w02 + s0(w10) + w09,   r(h, a, b, c, d, e, f, g, 0x78a5636f, w09);
+  w10 = s1(w08) + w03 + s0(w11) + w10,   r(g, h, a, b, c, d, e, f, 0x84c87814, w10);
+  w11 = s1(w09) + w04 + s0(w12) + w11,   r(f, g, h, a, b, c, d, e, 0x8cc70208, w11);
+  w12 = s1(w10) + w05 + s0(w13) + w12,   r(e, f, g, h, a, b, c, d, 0x90befffa, w12);
+  w13 = s1(w11) + w06 + s0(w14) + w13,   r(d, e, f, g, h, a, b, c, 0xa4506ceb, w13);
+  w14 = s1(w12) + w07 + s0(w15) + w14,   r(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14);
+  w15 = s1(w13) + w08 + s0(w00) + w15,   r(b, c, d, e, f, g, h, a, 0xc67178f2, w15);
+
+#undef b0
+#undef b1
+#undef s0
+#undef s1
+#undef r
+
+    __hash_maybe_memfence;
+    state_.words[0] += a;
+    state_.words[1] += b;
+    state_.words[2] += c;
+    state_.words[3] += d;
+    state_.words[4] += e;
+    state_.words[5] += f;
+    state_.words[6] += g;
+    state_.words[7] += h;
+  }
+
+public:
+  SHA256()
+  {
+    reset();
+  }
+
+  virtual ~SHA256()
+  {
+    reset();
+  }
+
+  virtual void reset()
+  {
+    memset(buffer_.bytes, 0, sizeof(buffer_));
+    memcpy(state_.bytes, initvec, sizeof(state_));
+    count_ = offset_ = 0;
+  }
+
+  virtual inline uint_fast16_t length() const
+  {
+    return 32;
+  }
+};
+
+const SHA256::word_t SHA256::initvec[] = {
+  0x6a09e667,
+  0xbb67ae85,
+  0x3c6ef372,
+  0xa54ff53a,
+  0x510e527f,
+  0x9b05688c,
+  0x1f83d9ab,
+  0x5be0cd19
+};
+
+class SHA224 : public SHA256
+{
+private:
+  static const word_t initvec[];
+
+protected:
+  virtual std::string digest()
+  {
+    return std::string((const char*)state_.bytes,
+                       sizeof(state_.bytes) - sizeof(word_t));
+  }
+
+public:
+  SHA224()
+  {
+    reset();
+  }
+
+  virtual ~SHA224()
+  {
+    reset();
+  }
+
+  virtual void reset()
+  {
+    memset(buffer_.bytes, 0, sizeof(buffer_));
+    memcpy(state_.bytes, initvec, sizeof(state_));
+    count_ = offset_ = 0;
+  }
+
+  virtual inline uint_fast16_t length() const
+  {
+    return 28;
+  }
+};
+
+const SHA224::word_t SHA224::initvec[] = {
+  0xc1059ed8,
+  0x367cd507,
+  0x3070dd17,
+  0xf70e5939,
+  0xffc00b31,
+  0x68581511,
+  0x64f98fa7,
+  0xbefa4fa4
+};
+
+class SHA512 : public AlgorithmImpl<uint64_t, 16, 8>
+{
+private:
+  static const word_t initvec[];
+
+protected:
+  virtual void transform(const word_t* buffer)
+  {
+    __hash_assign_words(__crypto_be);
+    __hash_maybe_memfence;
+
+    word_t a, b, c, d, e, f, g, h;
+    word_t t;
+    a = state_.words[0];
+    b = state_.words[1];
+    c = state_.words[2];
+    d = state_.words[3];
+    e = state_.words[4];
+    f = state_.words[5];
+    g = state_.words[6];
+    h = state_.words[7];
+    __hash_maybe_memfence;
+
+#define b0(w) \
+  (ror(w, 28) ^ ror(w, 34) ^ ror(w, 39))
+#define b1(w) \
+  (ror(w, 14) ^ ror(w, 18) ^ ror(w, 41))
+
+#define s0(w) \
+  (ror(w, 1) ^ ror(w, 8) ^ (w >> 7))
+#define s1(w) \
+  (ror(w, 19) ^ ror(w, 61) ^ (w >> 6))
+
+#define r(a1, a2, a3, a4, a5, a6, a7, a8, k, w)                                \
+  a4 += t = a8 + b1(a5) + ch(a5, a6, a7) + k + w;                              \
+  a8 = t + b0(a1) + maj(a1, a2, a3);
+
+    // Generated code. See sha512-transgen.py
+    // Round 0
+    r(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22, w00);
+    r(h, a, b, c, d, e, f, g, 0x7137449123ef65cd, w01);
+    r(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2f, w02);
+    r(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbc, w03);
+    r(e, f, g, h, a, b, c, d, 0x3956c25bf348b538, w04);
+    r(d, e, f, g, h, a, b, c, 0x59f111f1b605d019, w05);
+    r(c, d, e, f, g, h, a, b, 0x923f82a4af194f9b, w06);
+    r(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118, w07);
+
+    // Round 8
+    r(a, b, c, d, e, f, g, h, 0xd807aa98a3030242, w08);
+    r(h, a, b, c, d, e, f, g, 0x12835b0145706fbe, w09);
+    r(g, h, a, b, c, d, e, f, 0x243185be4ee4b28c, w10);
+    r(f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2, w11);
+    r(e, f, g, h, a, b, c, d, 0x72be5d74f27b896f, w12);
+    r(d, e, f, g, h, a, b, c, 0x80deb1fe3b1696b1, w13);
+    r(c, d, e, f, g, h, a, b, 0x9bdc06a725c71235, w14);
+    r(b, c, d, e, f, g, h, a, 0xc19bf174cf692694, w15);
+
+    // Round 16
+    w00 = s1(w14) + w09 + s0(w01) + w00;
+    r(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2, w00);
+    w01 = s1(w15) + w10 + s0(w02) + w01;
+    r(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3, w01);
+    w02 = s1(w00) + w11 + s0(w03) + w02;
+    r(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5, w02);
+    w03 = s1(w01) + w12 + s0(w04) + w03;
+    r(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65, w03);
+    w04 = s1(w02) + w13 + s0(w05) + w04;
+    r(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275, w04);
+    w05 = s1(w03) + w14 + s0(w06) + w05;
+    r(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483, w05);
+    w06 = s1(w04) + w15 + s0(w07) + w06;
+    r(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4, w06);
+    w07 = s1(w05) + w00 + s0(w08) + w07;
+    r(b, c, d, e, f, g, h, a, 0x76f988da831153b5, w07);
+
+    // Round 24
+    w08 = s1(w06) + w01 + s0(w09) + w08;
+    r(a, b, c, d, e, f, g, h, 0x983e5152ee66dfab, w08);
+    w09 = s1(w07) + w02 + s0(w10) + w09;
+    r(h, a, b, c, d, e, f, g, 0xa831c66d2db43210, w09);
+    w10 = s1(w08) + w03 + s0(w11) + w10;
+    r(g, h, a, b, c, d, e, f, 0xb00327c898fb213f, w10);
+    w11 = s1(w09) + w04 + s0(w12) + w11;
+    r(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4, w11);
+    w12 = s1(w10) + w05 + s0(w13) + w12;
+    r(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2, w12);
+    w13 = s1(w11) + w06 + s0(w14) + w13;
+    r(d, e, f, g, h, a, b, c, 0xd5a79147930aa725, w13);
+    w14 = s1(w12) + w07 + s0(w15) + w14;
+    r(c, d, e, f, g, h, a, b, 0x06ca6351e003826f, w14);
+    w15 = s1(w13) + w08 + s0(w00) + w15;
+    r(b, c, d, e, f, g, h, a, 0x142929670a0e6e70, w15);
+
+    // Round 32
+    w00 = s1(w14) + w09 + s0(w01) + w00;
+    r(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffc, w00);
+    w01 = s1(w15) + w10 + s0(w02) + w01;
+    r(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926, w01);
+    w02 = s1(w00) + w11 + s0(w03) + w02;
+    r(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aed, w02);
+    w03 = s1(w01) + w12 + s0(w04) + w03;
+    r(f, g, h, a, b, c, d, e, 0x53380d139d95b3df, w03);
+    w04 = s1(w02) + w13 + s0(w05) + w04;
+    r(e, f, g, h, a, b, c, d, 0x650a73548baf63de, w04);
+    w05 = s1(w03) + w14 + s0(w06) + w05;
+    r(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8, w05);
+    w06 = s1(w04) + w15 + s0(w07) + w06;
+    r(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6, w06);
+    w07 = s1(w05) + w00 + s0(w08) + w07;
+    r(b, c, d, e, f, g, h, a, 0x92722c851482353b, w07);
+
+    // Round 40
+    w08 = s1(w06) + w01 + s0(w09) + w08;
+    r(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364, w08);
+    w09 = s1(w07) + w02 + s0(w10) + w09;
+    r(h, a, b, c, d, e, f, g, 0xa81a664bbc423001, w09);
+    w10 = s1(w08) + w03 + s0(w11) + w10;
+    r(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791, w10);
+    w11 = s1(w09) + w04 + s0(w12) + w11;
+    r(f, g, h, a, b, c, d, e, 0xc76c51a30654be30, w11);
+    w12 = s1(w10) + w05 + s0(w13) + w12;
+    r(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218, w12);
+    w13 = s1(w11) + w06 + s0(w14) + w13;
+    r(d, e, f, g, h, a, b, c, 0xd69906245565a910, w13);
+    w14 = s1(w12) + w07 + s0(w15) + w14;
+    r(c, d, e, f, g, h, a, b, 0xf40e35855771202a, w14);
+    w15 = s1(w13) + w08 + s0(w00) + w15;
+    r(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8, w15);
+
+    // Round 48
+    w00 = s1(w14) + w09 + s0(w01) + w00;
+    r(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8, w00);
+    w01 = s1(w15) + w10 + s0(w02) + w01;
+    r(h, a, b, c, d, e, f, g, 0x1e376c085141ab53, w01);
+    w02 = s1(w00) + w11 + s0(w03) + w02;
+    r(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99, w02);
+    w03 = s1(w01) + w12 + s0(w04) + w03;
+    r(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8, w03);
+    w04 = s1(w02) + w13 + s0(w05) + w04;
+    r(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63, w04);
+    w05 = s1(w03) + w14 + s0(w06) + w05;
+    r(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acb, w05);
+    w06 = s1(w04) + w15 + s0(w07) + w06;
+    r(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373, w06);
+    w07 = s1(w05) + w00 + s0(w08) + w07;
+    r(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3, w07);
+
+    // Round 56
+    w08 = s1(w06) + w01 + s0(w09) + w08;
+    r(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fc, w08);
+    w09 = s1(w07) + w02 + s0(w10) + w09;
+    r(h, a, b, c, d, e, f, g, 0x78a5636f43172f60, w09);
+    w10 = s1(w08) + w03 + s0(w11) + w10;
+    r(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72, w10);
+    w11 = s1(w09) + w04 + s0(w12) + w11;
+    r(f, g, h, a, b, c, d, e, 0x8cc702081a6439ec, w11);
+    w12 = s1(w10) + w05 + s0(w13) + w12;
+    r(e, f, g, h, a, b, c, d, 0x90befffa23631e28, w12);
+    w13 = s1(w11) + w06 + s0(w14) + w13;
+    r(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9, w13);
+    w14 = s1(w12) + w07 + s0(w15) + w14;
+    r(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915, w14);
+    w15 = s1(w13) + w08 + s0(w00) + w15;
+    r(b, c, d, e, f, g, h, a, 0xc67178f2e372532b, w15);
+
+    // Round 64
+    w00 = s1(w14) + w09 + s0(w01) + w00;
+    r(a, b, c, d, e, f, g, h, 0xca273eceea26619c, w00);
+    w01 = s1(w15) + w10 + s0(w02) + w01;
+    r(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207, w01);
+    w02 = s1(w00) + w11 + s0(w03) + w02;
+    r(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1e, w02);
+    w03 = s1(w01) + w12 + s0(w04) + w03;
+    r(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178, w03);
+    w04 = s1(w02) + w13 + s0(w05) + w04;
+    r(e, f, g, h, a, b, c, d, 0x06f067aa72176fba, w04);
+    w05 = s1(w03) + w14 + s0(w06) + w05;
+    r(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6, w05);
+    w06 = s1(w04) + w15 + s0(w07) + w06;
+    r(c, d, e, f, g, h, a, b, 0x113f9804bef90dae, w06);
+    w07 = s1(w05) + w00 + s0(w08) + w07;
+    r(b, c, d, e, f, g, h, a, 0x1b710b35131c471b, w07);
+
+    // Round 72
+    w08 = s1(w06) + w01 + s0(w09) + w08;
+    r(a, b, c, d, e, f, g, h, 0x28db77f523047d84, w08);
+    w09 = s1(w07) + w02 + s0(w10) + w09;
+    r(h, a, b, c, d, e, f, g, 0x32caab7b40c72493, w09);
+    w10 = s1(w08) + w03 + s0(w11) + w10;
+    r(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebc, w10);
+    w11 = s1(w09) + w04 + s0(w12) + w11;
+    r(f, g, h, a, b, c, d, e, 0x431d67c49c100d4c, w11);
+    w12 = s1(w10) + w05 + s0(w13) + w12;
+    r(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6, w12);
+    w13 = s1(w11) + w06 + s0(w14) + w13;
+    r(d, e, f, g, h, a, b, c, 0x597f299cfc657e2a, w13);
+    w14 = s1(w12) + w07 + s0(w15) + w14;
+    r(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faec, w14);
+    w15 = s1(w13) + w08 + s0(w00) + w15;
+    r(b, c, d, e, f, g, h, a, 0x6c44198c4a475817, w15);
+
+#undef b0
+#undef b1
+#undef s0
+#undef s1
+#undef r
+
+    __hash_maybe_memfence;
+    state_.words[0] += a;
+    state_.words[1] += b;
+    state_.words[2] += c;
+    state_.words[3] += d;
+    state_.words[4] += e;
+    state_.words[5] += f;
+    state_.words[6] += g;
+    state_.words[7] += h;
+  }
+
+public:
+  SHA512()
+  {
+    reset();
+  }
+
+  virtual ~SHA512()
+  {
+    reset();
+  }
+
+  virtual void reset()
+  {
+    memset(buffer_.bytes, 0, sizeof(buffer_));
+    memcpy(state_.bytes, initvec, sizeof(state_));
+    count_ = offset_ = 0;
+  }
+
+  virtual inline uint_fast16_t length() const
+  {
+    return 64;
+  }
+};
+
+const SHA512::word_t SHA512::initvec[] = {
+  0x6a09e667f3bcc908,
+  0xbb67ae8584caa73b,
+  0x3c6ef372fe94f82b,
+  0xa54ff53a5f1d36f1,
+  0x510e527fade682d1,
+  0x9b05688c2b3e6c1f,
+  0x1f83d9abfb41bd6b,
+  0x5be0cd19137e2179,
+};
+
+class SHA384 : public SHA512
+{
+private:
+  static const word_t initvec[];
+
+protected:
+  virtual std::string digest()
+  {
+    return std::string((const char*)state_.bytes,
+                       sizeof(state_.bytes) - sizeof(word_t) * 2);
+  }
+
+public:
+  SHA384()
+  {
+    reset();
+  }
+
+  virtual ~SHA384()
+  {
+    reset();
+  }
+
+  virtual void reset()
+  {
+    memset(buffer_.bytes, 0, sizeof(buffer_));
+    memcpy(state_.bytes, initvec, sizeof(state_));
+    count_ = offset_ = 0;
+  }
+
+  virtual inline uint_fast16_t length() const
+  {
+    return 48;
+  }
+};
+
+const SHA384::word_t SHA384::initvec[] = {
+  0xcbbb9d5dc1059ed8,
+  0x629a292a367cd507,
+  0x9159015a3070dd17,
+  0x152fecd8f70e5939,
+  0x67332667ffc00b31,
+  0x8eb44a8768581511,
+  0xdb0c2e0d64f98fa7,
+  0x47b5481dbefa4fa4
+};
+
+namespace {
+// For |all|
+static const std::set<std::string> names{
+    "md5",    "sha",     "sha1",   "sha-1",   "sha224", "sha-224",
+    "sha256", "sha-256", "sha384", "sha-384", "sha512", "sha-512",
+};
+
+// For fast name |lookup|
+static const std::unordered_map<std::string, Algorithms> mapped {
+  { "md5", algoMD5 },
+  { "sha", algoSHA1 },
+  { "sha1", algoSHA1 },
+  { "sha-1", algoSHA1 },
+  { "sha224", algoSHA224 },
+  { "sha-224", algoSHA224 },
+  { "sha256", algoSHA256 },
+  { "sha-256", algoSHA256 },
+  { "sha384", algoSHA384 },
+  { "sha-384", algoSHA384 },
+  { "sha512", algoSHA512 },
+  { "sha-512", algoSHA512 },
+};
+static const auto mapped_end = mapped.end();
+} // namespace
+
+const std::set<std::string>& crypto::hash::all()
+{
+  return names;
+}
+
+Algorithms crypto::hash::lookup(const std::string& name)
+{
+  auto i = mapped.find(name);
+  if (unlikely(i == mapped_end)) {
+    return algoNone;
+  }
+  return i->second;
+}
+
+std::unique_ptr<Algorithm> crypto::hash::create(Algorithms algo)
+{
+  switch (algo) {
+  case algoMD5:
+    return std::unique_ptr<MD5>(new MD5());
+
+  case algoSHA1:
+    return std::unique_ptr<SHA1>(new SHA1());
+
+  case algoSHA224:
+    return std::unique_ptr<SHA224>(new SHA224());
+
+  case algoSHA256:
+    return std::unique_ptr<SHA256>(new SHA256());
+
+  case algoSHA384:
+    return std::unique_ptr<SHA384>(new SHA384());
+
+  case algoSHA512:
+    return std::unique_ptr<SHA512>(new SHA512());
+
+  default:
+    throw std::domain_error("Invalid hash algorithm");
+  }
+}

+ 103 - 0
src/crypto_hash.h

@@ -0,0 +1,103 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+// Written in 2014 by Nils Maier
+
+#ifndef CRYPTO_HASH_H
+#define CRYPTO_HASH_H
+
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <set>
+#include <string>
+#include <limits>
+
+namespace crypto {
+namespace hash {
+
+enum Algorithms {
+  algoNone = 0x0,
+  algoMD5 = 0x1,
+  algoSHA1 = 0x2,
+  algoSHA224 = 0x3,
+  algoSHA256 = 0x4,
+  algoSHA384 = 0x5,
+  algoSHA512 = 0x6,
+};
+
+class Algorithm
+{
+public:
+  Algorithm() {}
+
+  virtual ~Algorithm() {}
+
+  virtual void update(const void* data, uint64_t len) = 0;
+
+  inline void update(const std::string& data)
+  {
+    return update(data.data(), data.length());
+  }
+
+  virtual std::string finalize() = 0;
+
+  virtual void reset() = 0;
+
+  virtual uint_fast16_t length() const = 0;
+
+  virtual uint_fast16_t blocksize() const = 0;
+
+private:
+  Algorithm(const Algorithm&) = delete;
+
+  Algorithm& operator=(const Algorithm&) = delete;
+};
+
+const std::set<std::string>& all();
+
+Algorithms lookup(const std::string& name);
+
+std::unique_ptr<Algorithm> create(Algorithms algo);
+
+inline std::unique_ptr<Algorithm> create(const std::string& name)
+{
+  return create(lookup(name));
+}
+
+inline uint_fast16_t length(Algorithms algo)
+{
+  return create(algo)->length();
+}
+
+inline uint_fast16_t length(const std::string& name)
+{
+  return create(name)->length();
+}
+
+inline std::string compute(Algorithms algo, const void* data, uint_fast64_t len)
+{
+  auto ctx = create(algo);
+  ctx->update(data, len);
+  return ctx->finalize();
+}
+
+inline std::string compute(Algorithms algo, const std::string& data)
+{
+  return compute(algo, data.data(), data.length());
+}
+
+inline std::string
+compute(const std::string& name, const void* data, uint_fast64_t len)
+{
+  return compute(lookup(name), data, len);
+}
+
+inline std::string compute(const std::string& name, const std::string& data)
+{
+  return compute(lookup(name), data.data(), data.length());
+}
+
+} // namespace hash
+} // namespace crypto
+
+#endif // CRYPTO_HASH_H

+ 0 - 311
src/md5.c

@@ -1,311 +0,0 @@
-/*
- * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
- * MD5 Message-Digest Algorithm (RFC 1321).
- *
- * Homepage:
- * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
- *
- * Author:
- * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
- *
- * This software was written by Alexander Peslyak in 2001.  No copyright is
- * claimed, and the software is hereby placed in the public domain.
- * In case this attempt to disclaim copyright and place the software in the
- * public domain is deemed null and void, then the software is
- * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
- * general public under the following terms:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted.
- *
- * There's ABSOLUTELY NO WARRANTY, express or implied.
- *
- * (This is a heavily cut-down "BSD license".)
- *
- * This differs from Colin Plumb's older public domain implementation in that
- * no exactly 32-bit integer data type is required (any 32-bit or wider
- * unsigned integer data type will do), there's no compile-time endianness
- * configuration, and the function prototypes match OpenSSL's.  No code from
- * Colin Plumb's implementation has been reused; this comment merely compares
- * the properties of the two independent implementations.
- *
- * The primary goals of this implementation are portability and ease of use.
- * It is meant to be fast, but not as fast as possible.  Some known
- * optimizations are not included to reduce source code size and avoid
- * compile-time configuration.
- */
-
-#include "md5.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-struct MD5_CTX {
-  size_t lo, hi;
-  size_t a, b, c, d;
-  uint8_t buffer[64];
-  size_t block[16];
-};
-
-
-/*
- * The basic MD5 functions.
- *
- * F and G are optimized compared to their RFC 1321 definitions for
- * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
- * implementation.
- */
-#define F(x, y, z)      ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z)      ((y) ^ ((z) & ((x) ^ (y))))
-#define H(x, y, z)      ((x) ^ (y) ^ (z))
-#define I(x, y, z)      ((y) ^ ((x) | ~(z)))
-
-/*
- * The MD5 transformation for all four rounds.
- */
-#define STEP(f, a, b, c, d, x, t, s) \
-  (a) += f((b), (c), (d)) + (x) + (t); \
-  (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
-  (a) += (b);
-
-/*
- * SET reads 4 input bytes in little-endian byte order and stores them
- * in a properly aligned word in host byte order.
- *
- * The check for little-endian architectures that tolerate unaligned
- * memory accesses is just an optimization.  Nothing will break if it
- * doesn't work.
- */
-#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
-#define SET(n) \
-  (*(size_t *)&ptr[(n) * 4])
-#define GET(n) \
-  SET(n)
-#else
-#define SET(n) \
-  (ctx->block[(n)] = \
-  (size_t)ptr[(n) * 4] | \
-  ((size_t)ptr[(n) * 4 + 1] << 8) | \
-  ((size_t)ptr[(n) * 4 + 2] << 16) | \
-  ((size_t)ptr[(n) * 4 + 3] << 24))
-#define GET(n) \
-  (ctx->block[(n)])
-#endif
-
-/*
- * This processes one or more 64-byte data blocks, but does NOT update
- * the bit counters.  There are no alignment requirements.
- */
-static const void *body(struct MD5_CTX *ctx, const void *data, size_t size)
-{
-  const uint8_t *ptr;
-  size_t a, b, c, d;
-  size_t saved_a, saved_b, saved_c, saved_d;
-
-  ptr = data;
-
-  a = ctx->a;
-  b = ctx->b;
-  c = ctx->c;
-  d = ctx->d;
-
-  do {
-    saved_a = a;
-    saved_b = b;
-    saved_c = c;
-    saved_d = d;
-
-/* Round 1 */
-    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
-    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
-    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
-    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
-    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
-    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
-    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
-    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
-    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
-    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
-    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
-    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
-    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
-    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
-    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
-    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
-
-/* Round 2 */
-    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
-    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
-    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
-    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
-    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
-    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
-    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
-    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
-    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
-    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
-    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
-    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
-    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
-    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
-    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
-    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
-
-/* Round 3 */
-    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
-    STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
-    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
-    STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
-    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
-    STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
-    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
-    STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
-    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
-    STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
-    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
-    STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
-    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
-    STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
-    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
-    STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
-
-/* Round 4 */
-    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
-    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
-    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
-    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
-    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
-    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
-    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
-    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
-    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
-    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
-    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
-    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
-    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
-    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
-    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
-    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
-
-    a += saved_a;
-    b += saved_b;
-    c += saved_c;
-    d += saved_d;
-
-    ptr += 64;
-  } while (size -= 64);
-
-  ctx->a = a;
-  ctx->b = b;
-  ctx->c = c;
-  ctx->d = d;
-
-  return ptr;
-}
-
-int MD5_Init(struct MD5_CTX **ctx)
-{
-  *ctx = malloc(sizeof(struct MD5_CTX));
-  if (!*ctx) {
-    return 0;
-  }
-  (*ctx)->a = 0x67452301;
-  (*ctx)->b = 0xefcdab89;
-  (*ctx)->c = 0x98badcfe;
-  (*ctx)->d = 0x10325476;
-
-  (*ctx)->lo = 0;
-  (*ctx)->hi = 0;
-  return 1;
-}
-
-void MD5_Update(struct MD5_CTX *ctx, const void *data, size_t size)
-{
-  size_t saved_lo;
-  size_t used, free;
-
-  saved_lo = ctx->lo;
-  if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
-    ctx->hi++;
-  ctx->hi += size >> 29;
-
-  used = saved_lo & 0x3f;
-
-  if (used) {
-    free = 64 - used;
-
-    if (size < free) {
-      memcpy(&ctx->buffer[used], data, size);
-      return;
-    }
-
-    memcpy(&ctx->buffer[used], data, free);
-    data = (unsigned char *)data + free;
-    size -= free;
-    body(ctx, ctx->buffer, 64);
-  }
-
-  if (size >= 64) {
-    data = body(ctx, data, size & ~(size_t)0x3f);
-    size &= 0x3f;
-  }
-
-  memcpy(ctx->buffer, data, size);
-}
-
-void MD5_Final(struct MD5_CTX *ctx, unsigned char* result)
-{
-  size_t used, free;
-
-  used = ctx->lo & 0x3f;
-
-  ctx->buffer[used++] = 0x80;
-
-  free = 64 - used;
-
-  if (free < 8) {
-    memset(&ctx->buffer[used], 0, free);
-    body(ctx, ctx->buffer, 64);
-    used = 0;
-    free = 64;
-  }
-
-  memset(&ctx->buffer[used], 0, free - 8);
-
-  ctx->lo <<= 3;
-  ctx->buffer[56] = ctx->lo;
-  ctx->buffer[57] = ctx->lo >> 8;
-  ctx->buffer[58] = ctx->lo >> 16;
-  ctx->buffer[59] = ctx->lo >> 24;
-  ctx->buffer[60] = ctx->hi;
-  ctx->buffer[61] = ctx->hi >> 8;
-  ctx->buffer[62] = ctx->hi >> 16;
-  ctx->buffer[63] = ctx->hi >> 24;
-
-  body(ctx, ctx->buffer, 64);
-
-  result[0] = ctx->a;
-  result[1] = ctx->a >> 8;
-  result[2] = ctx->a >> 16;
-  result[3] = ctx->a >> 24;
-  result[4] = ctx->b;
-  result[5] = ctx->b >> 8;
-  result[6] = ctx->b >> 16;
-  result[7] = ctx->b >> 24;
-  result[8] = ctx->c;
-  result[9] = ctx->c >> 8;
-  result[10] = ctx->c >> 16;
-  result[11] = ctx->c >> 24;
-  result[12] = ctx->d;
-  result[13] = ctx->d >> 8;
-  result[14] = ctx->d >> 16;
-  result[15] = ctx->d >> 24;
-}
-
-void MD5_Free(struct MD5_CTX** ctx) {
-  if (!ctx || !*ctx) {
-    return;
-  }
-  free(*ctx);
-  *ctx = NULL;
-}

+ 0 - 47
src/md5.h

@@ -1,47 +0,0 @@
-/*
- * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
- * MD5 Message-Digest Algorithm (RFC 1321).
- *
- * Homepage:
- * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
- *
- * Author:
- * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
- *
- * This software was written by Alexander Peslyak in 2001.  No copyright is
- * claimed, and the software is hereby placed in the public domain.
- * In case this attempt to disclaim copyright and place the software in the
- * public domain is deemed null and void, then the software is
- * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
- * general public under the following terms:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted.
- *
- * There's ABSOLUTELY NO WARRANTY, express or implied.
- *
- * See md5.c for more information.
- */
-
-#ifndef INTERNAL_MD5_H
-#define INTERNAL_MD5_H
-
-#include <sys/types.h>
-#include <stdint.h>
-
-struct MD5_CTX;
-
-#define MD5_LENGTH 16
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-int MD5_Init(struct MD5_CTX **ctx);
-void MD5_Update(struct MD5_CTX *ctx, const void *data, size_t size);
-void MD5_Final(struct MD5_CTX *ctx, uint8_t *result);
-void MD5_Free(struct MD5_CTX **ctx);
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* INTERNAL_MD5_H */

+ 0 - 160
src/sha1.c

@@ -1,160 +0,0 @@
-/* This code is public-domain - it is based on libcrypt 
- * placed in the public domain by Wei Dai and other contributors.
- */
-
-#include "sha1.h"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#define BLOCK_LENGTH 64
-
-union _buffer {
-  uint8_t b[BLOCK_LENGTH];
-  uint32_t w[BLOCK_LENGTH/4];
-};
-
-union _state {
-  uint8_t b[SHA1_LENGTH];
-  uint32_t w[SHA1_LENGTH/4];
-};
-
-struct SHA1_CTX {
-  union _buffer buffer;
-  uint8_t bufferOffset;
-  union _state state;
-  uint32_t byteCount;
-  uint8_t keyBuffer[BLOCK_LENGTH];
-  uint8_t innerHash[SHA1_LENGTH];
-};
-
-#define SHA1_K0 0x5a827999
-#define SHA1_K20 0x6ed9eba1
-#define SHA1_K40 0x8f1bbcdc
-#define SHA1_K60 0xca62c1d6
-
-const uint8_t sha1InitState[] = {
-  0x01,0x23,0x45,0x67, // H0
-  0x89,0xab,0xcd,0xef, // H1
-  0xfe,0xdc,0xba,0x98, // H2
-  0x76,0x54,0x32,0x10, // H3
-  0xf0,0xe1,0xd2,0xc3  // H4
-};
-
-static uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
-  return ((number << bits) | (number >> (32-bits)));
-}
-
-static void sha1_hashBlock(struct SHA1_CTX *s) {
-  uint8_t i;
-  uint32_t a,b,c,d,e,t;
-
-  a=s->state.w[0];
-  b=s->state.w[1];
-  c=s->state.w[2];
-  d=s->state.w[3];
-  e=s->state.w[4];
-  for (i=0; i<80; i++) {
-    if (i>=16) {
-      t = s->buffer.w[(i+13)&15] ^ s->buffer.w[(i+8)&15] ^ s->buffer.w[(i+2)&15] ^ s->buffer.w[i&15];
-      s->buffer.w[i&15] = sha1_rol32(t,1);
-    }
-    if (i<20) {
-      t = (d ^ (b & (c ^ d))) + SHA1_K0;
-    } else if (i<40) {
-      t = (b ^ c ^ d) + SHA1_K20;
-    } else if (i<60) {
-      t = ((b & c) | (d & (b | c))) + SHA1_K40;
-    } else {
-      t = (b ^ c ^ d) + SHA1_K60;
-    }
-    t+=sha1_rol32(a,5) + e + s->buffer.w[i&15];
-    e=d;
-    d=c;
-    c=sha1_rol32(b,30);
-    b=a;
-    a=t;
-  }
-  s->state.w[0] += a;
-  s->state.w[1] += b;
-  s->state.w[2] += c;
-  s->state.w[3] += d;
-  s->state.w[4] += e;
-}
-
-static void sha1_addUncounted(struct SHA1_CTX *s, uint8_t data) {
-  s->buffer.b[s->bufferOffset ^ 3] = data;
-  s->bufferOffset++;
-  if (s->bufferOffset == BLOCK_LENGTH) {
-    sha1_hashBlock(s);
-    s->bufferOffset = 0;
-  }
-}
-
-static void sha1_writebyte(struct SHA1_CTX *s, uint8_t data) {
-  ++s->byteCount;
-  sha1_addUncounted(s, data);
-}
-
-static void sha1_pad(struct SHA1_CTX *s) {
-  // Implement SHA-1 padding (fips180-2 §5.1.1)
-
-  // Pad with 0x80 followed by 0x00 until the end of the block
-  sha1_addUncounted(s, 0x80);
-  while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
-
-  // Append length in the last 8 bytes
-  sha1_addUncounted(s, 0); // We're only using 32 bit lengths
-  sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
-  sha1_addUncounted(s, 0); // So zero pad the top bits
-  sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
-  sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
-  sha1_addUncounted(s, s->byteCount >> 13); // byte.
-  sha1_addUncounted(s, s->byteCount >> 5);
-  sha1_addUncounted(s, s->byteCount << 3);
-}
-
-int SHA1_Init(struct SHA1_CTX **s) {
-  *s = malloc(sizeof(struct SHA1_CTX));
-  if (!*s) {
-    return 0;
-  }
-  memcpy((*s)->state.b, sha1InitState, SHA1_LENGTH);
-  (*s)->byteCount = 0;
-  (*s)->bufferOffset = 0;
-  return 1;
-}
-
-void SHA1_Update(struct SHA1_CTX *s, const void *data, size_t len) {
-  const uint8_t *bytes = data;
-  for (;len--;) sha1_writebyte(s, *bytes++);
-}
-
-void SHA1_Final(struct SHA1_CTX *s, unsigned char* result) {
-  int i;
-  // Pad to complete the last block
-  sha1_pad(s);
-
-  // Swap byte order back
-  for (i=0; i<5; i++) {
-    uint32_t a,b;
-    a=s->state.w[i];
-    b=a<<24;
-    b|=(a<<8) & 0x00ff0000;
-    b|=(a>>8) & 0x0000ff00;
-    b|=a>>24;
-    s->state.w[i]=b;
-  }
-
-  // Return pointer to hash (20 characters)
-  memcpy(result, s->state.b, sizeof(s->state.b));
-}
-
-void SHA1_Free(struct SHA1_CTX** s) {
-  if (!s || !*s) {
-    return;
-  }
-  free(*s);
-  *s = NULL;
-}

+ 0 - 28
src/sha1.h

@@ -1,28 +0,0 @@
-/* This code is public-domain - it is based on libcrypt 
- * placed in the public domain by Wei Dai and other contributors.
- */
-
-#ifndef INTERNAL_SHA1_H
-#define INTERNAL_SHA1_H
-
-#include <sys/types.h>
-#include <stdint.h>
-
-#define SHA1_LENGTH 20
-
-struct SHA1_CTX;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int SHA1_Init(struct SHA1_CTX **s);
-void SHA1_Update(struct SHA1_CTX *s, const void *data, size_t len);
-void SHA1_Final(struct SHA1_CTX *s, uint8_t *result);
-void SHA1_Free(struct SHA1_CTX **s);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* INTERNAL_SHA1_H */

+ 4 - 10
src/util_security.cc

@@ -37,6 +37,7 @@
 
 #include "FatalException.h"
 #include "util.h"
+#include "crypto_endian.h"
 
 namespace {
 using namespace aria2;
@@ -156,13 +157,6 @@ HMACResult PBKDF2(HMAC* hmac,
   if (key_length == 0) {
     key_length = hmac_length;
   }
-  typedef union
-  {
-    uint8_t bytes[4];
-    uint32_t count;
-  } counter_t;
-  counter_t counter, swapped;
-  counter.count = 1;
 
   auto work = make_unique<char[]>(hmac_length);
   char* p = work.get();
@@ -170,10 +164,10 @@ HMACResult PBKDF2(HMAC* hmac,
 
   hmac->reset();
 
-  while (key_length) {
+  for (uint32_t counter = 1; key_length; ++counter) {
     hmac->update(salt, salt_length);
-    swapped.count = htonl(counter.count++);
-    hmac->update((char*)swapped.bytes, sizeof(swapped.bytes));
+    const uint32_t c = crypto::__crypto_be(counter);
+    hmac->update((char*)&c, sizeof(c));
 
     auto bytes = hmac->getResult().getBytes();
     memcpy(p, bytes.data(), bytes.length());

+ 0 - 6
test/HttpResponseTest.cc

@@ -685,20 +685,14 @@ void HttpResponseTest::testGetDigest()
      "MD5=LJDK2+9ClF8Nz/K5WZd/+A==");
   std::vector<Checksum> result;
   httpResponse.getDigest(result);
-#ifdef USE_INTERNAL_MD
-  CPPUNIT_ASSERT_EQUAL((size_t)2, result.size());
-#else // USE_INTERNAL_MD
   CPPUNIT_ASSERT_EQUAL((size_t)3, result.size());
-#endif // USE_INTERNAL_MD
 
   Checksum c = result[0];
-#ifndef USE_INTERNAL_MD
   CPPUNIT_ASSERT_EQUAL(std::string("sha-256"), c.getHashType());
   CPPUNIT_ASSERT_EQUAL(std::string("f83f271ae773dc6fe4a6454a41e0eb237c43e7bbf451e426cc60993a4d379ec5"),
                        util::toHex(c.getDigest()));
 
   c = result[1];
-#endif
   CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), c.getHashType());
   CPPUNIT_ASSERT_EQUAL(std::string("f36003f22b462ffa184390533c500d8989e9f681"),
                        util::toHex(c.getDigest()));