packages feed

cryptohash-sha256 0.11.100.1 → 0.11.101.0

raw patch · 9 files changed

+654/−362 lines, 9 filesdep ~basedep ~bytestringnew-component:exe:sha256sumPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, bytestring

API changes (from Hackage documentation)

+ Crypto.Hash.SHA256: finalizeAndLength :: Ctx -> (ByteString, Word64)
+ Crypto.Hash.SHA256: hashlazyAndLength :: ByteString -> (ByteString, Word64)
+ Crypto.Hash.SHA256: hkdf :: ByteString -> ByteString -> ByteString -> Int -> ByteString
+ Crypto.Hash.SHA256: hmaclazyAndLength :: ByteString -> ByteString -> (ByteString, Word64)

Files

+ cbits/hs_sha256.h view
@@ -0,0 +1,265 @@+/*+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>+ *               2016      Herbert Valerio Riedel <hvr@gnu.org>+ *+ * 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 ``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 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.+ */++#ifndef HS_CRYPTOHASH_SHA256_H+#define HS_CRYPTOHASH_SHA256_H++#include <stdint.h>+#include <stddef.h>+#include <assert.h>+#include <string.h>+#include <ghcautoconf.h>++struct sha256_ctx+{+  uint64_t sz;+  uint8_t  buf[64];+  uint32_t h[8];+};++/* keep this synchronised with 'digestSize'/'sizeCtx' in SHA256.hs */+#define SHA256_DIGEST_SIZE	32+#define SHA256_CTX_SIZE		104++static inline void hs_cryptohash_sha256_init (struct sha256_ctx *ctx);+static inline void hs_cryptohash_sha256_update (struct sha256_ctx *ctx, const uint8_t *data, size_t len);+static inline uint64_t hs_cryptohash_sha256_finalize (struct sha256_ctx *ctx, uint8_t *out);++#if defined(static_assert)+static_assert(sizeof(struct sha256_ctx) == SHA256_CTX_SIZE, "unexpected sha256_ctx size");+#else+/* poor man's pre-C11 _Static_assert */+typedef char static_assertion__unexpected_sha256_ctx_size[(sizeof(struct sha256_ctx) == SHA256_CTX_SIZE)?1:-1];+#endif++#define ptr_uint32_aligned(ptr) (!((uintptr_t)(ptr) & 0x3))++static inline uint32_t+ror32(const uint32_t word, const unsigned shift)+{+  /* GCC usually transforms this into a 'ror'-insn */+  return (word >> shift) | (word << (32 - shift));+}++static inline uint32_t+cpu_to_be32(const uint32_t hl)+{+#if WORDS_BIGENDIAN+  return hl;+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)+  return __builtin_bswap32(hl);+#else+  /* GCC usually transforms this into a bswap insn */+  return ((hl & 0xff000000) >> 24) |+         ((hl & 0x00ff0000) >> 8)  |+         ((hl & 0x0000ff00) << 8)  |+         ( hl               << 24);+#endif+}++static inline void+cpu_to_be32_array(uint32_t *dest, const uint32_t *src, unsigned wordcnt)+{+  while (wordcnt--)+    *dest++ = cpu_to_be32(*src++);+}++static inline uint64_t+cpu_to_be64(const uint64_t hll)+{+#if WORDS_BIGENDIAN+  return hll;+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)+  return __builtin_bswap64(hll);+#else+  return ((uint64_t)cpu_to_be32(hll & 0xffffffff) << 32LL) | cpu_to_be32(hll >> 32);+#endif+}+++static inline void+hs_cryptohash_sha256_init (struct sha256_ctx *ctx)+{+  memset(ctx, 0, SHA256_CTX_SIZE);++  ctx->h[0] = 0x6a09e667;+  ctx->h[1] = 0xbb67ae85;+  ctx->h[2] = 0x3c6ef372;+  ctx->h[3] = 0xa54ff53a;+  ctx->h[4] = 0x510e527f;+  ctx->h[5] = 0x9b05688c;+  ctx->h[6] = 0x1f83d9ab;+  ctx->h[7] = 0x5be0cd19;+}++/* 232 times the cube root of the first 64 primes 2..311 */+static const uint32_t k[] = {+  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,+  0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,+  0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,+  0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,+  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,+  0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,+  0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,+  0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,+  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,+  0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,+  0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2+};++#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 void+sha256_do_chunk_aligned(struct sha256_ctx *ctx, uint32_t w[])+{+  int i;++  for (i = 16; i < 64; i++)+    w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];++  uint32_t a = ctx->h[0];+  uint32_t b = ctx->h[1];+  uint32_t c = ctx->h[2];+  uint32_t d = ctx->h[3];+  uint32_t e = ctx->h[4];+  uint32_t f = ctx->h[5];+  uint32_t g = ctx->h[6];+  uint32_t h = ctx->h[7];++#define R(a, b, c, d, e, f, g, h, k, w)             \+    t1 = h + e1(e) + (g ^ (e & (f ^ g))) + k + w;   \+    t2 = e0(a) + ((a & b) | (c & (a | b)));         \+    d += t1;                                        \+    h = t1 + t2;++  for (i = 0; i < 64; i += 8) {+    uint32_t t1, t2;++    R(a, b, c, d, e, f, g, h, k[i + 0], w[i + 0]);+    R(h, a, b, c, d, e, f, g, k[i + 1], w[i + 1]);+    R(g, h, a, b, c, d, e, f, k[i + 2], w[i + 2]);+    R(f, g, h, a, b, c, d, e, k[i + 3], w[i + 3]);+    R(e, f, g, h, a, b, c, d, k[i + 4], w[i + 4]);+    R(d, e, f, g, h, a, b, c, k[i + 5], w[i + 5]);+    R(c, d, e, f, g, h, a, b, k[i + 6], w[i + 6]);+    R(b, c, d, e, f, g, h, a, k[i + 7], w[i + 7]);+  }++#undef R++  ctx->h[0] += a;+  ctx->h[1] += b;+  ctx->h[2] += c;+  ctx->h[3] += d;+  ctx->h[4] += e;+  ctx->h[5] += f;+  ctx->h[6] += g;+  ctx->h[7] += h;+}++static void+sha256_do_chunk(struct sha256_ctx *ctx, const uint8_t buf[])+{+  uint32_t w[64]; /* only first 16 words are filled in */+  if (ptr_uint32_aligned(buf)) { /* aligned buf */+    cpu_to_be32_array(w, (const uint32_t *)buf, 16);+  } else { /* unaligned buf */+    memcpy(w, buf, 64);+#if !WORDS_BIGENDIAN+    cpu_to_be32_array(w, w, 16);+#endif+  }+  sha256_do_chunk_aligned(ctx, w);+}++static inline void+hs_cryptohash_sha256_update(struct sha256_ctx *ctx, const uint8_t *data, size_t len)+{+  size_t index = ctx->sz & 0x3f;+  const size_t to_fill = 64 - index;++  ctx->sz += len;++  /* process partial buffer if there's enough data to make a block */+  if (index && len >= to_fill) {+    memcpy(ctx->buf + index, data, to_fill);+    sha256_do_chunk(ctx, ctx->buf);+    /* memset(ctx->buf, 0, 64); */+    len -= to_fill;+    data += to_fill;+    index = 0;+  }++  /* process as many 64-blocks as possible */+  while (len >= 64) {+    sha256_do_chunk(ctx, data);+    len -= 64;+    data += 64;+  }++  /* append data into buf */+  if (len)+    memcpy(ctx->buf + index, data, len);+}++static inline uint64_t+hs_cryptohash_sha256_finalize (struct sha256_ctx *ctx, uint8_t *out)+{+  static const uint8_t padding[64] = { 0x80, };+  const uint64_t sz = ctx->sz;++  /* add padding and update data with it */+  uint64_t bits = cpu_to_be64(ctx->sz << 3);++  /* pad out to 56 */+  const size_t index = ctx->sz & 0x3f;+  const size_t padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);+  hs_cryptohash_sha256_update(ctx, padding, padlen);++  /* append length */+  hs_cryptohash_sha256_update(ctx, (uint8_t *) &bits, sizeof(bits));++  /* output hash */+  cpu_to_be32_array((uint32_t *) out, ctx->h, 8);++  return sz;+}++static inline void+hs_cryptohash_sha256_hash (const uint8_t *data, size_t len, uint8_t *out)+{+  struct sha256_ctx ctx;++  hs_cryptohash_sha256_init(&ctx);++  hs_cryptohash_sha256_update(&ctx, data, len);++  hs_cryptohash_sha256_finalize(&ctx, out);+}++#endif
− cbits/sha256.c
@@ -1,230 +0,0 @@-/*- * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>- *               2016      Herbert Valerio Riedel <hvr@gnu.org>- *- * 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 ``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 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 "sha256.h"--#include <assert.h>-#include <string.h>-#include <ghcautoconf.h>--#if defined(static_assert)-static_assert(sizeof(struct sha256_ctx) == SHA256_CTX_SIZE, "unexpected sha256_ctx size");-#else-/* poor man's pre-C11 _Static_assert */-typedef char static_assertion__unexpected_sha256_ctx_size[(sizeof(struct sha256_ctx) == SHA256_CTX_SIZE)?1:-1];-#endif--#define ptr_uint32_aligned(ptr) (!((uintptr_t)(ptr) & 0x3))--static inline uint32_t-ror32(const uint32_t word, const unsigned shift)-{-  /* GCC usually transforms this into a 'ror'-insn */-  return (word >> shift) | (word << (32 - shift));-}--static inline uint32_t-cpu_to_be32(const uint32_t hl)-{-#if WORDS_BIGENDIAN-  return hl;-#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)-  return __builtin_bswap32(hl);-#else-  /* GCC usually transforms this into a bswap insn */-  return ((hl & 0xff000000) >> 24) |-         ((hl & 0x00ff0000) >> 8)  |-         ((hl & 0x0000ff00) << 8)  |-         ( hl               << 24);-#endif-}--static inline void-cpu_to_be32_array(uint32_t *dest, const uint32_t *src, unsigned wordcnt)-{-  while (wordcnt--)-    *dest++ = cpu_to_be32(*src++);-}--static inline uint64_t-cpu_to_be64(const uint64_t hll)-{-#if WORDS_BIGENDIAN-  return hll;-#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)-  return __builtin_bswap64(hll);-#else-  return ((uint64_t)cpu_to_be32(hll & 0xffffffff) << 32LL) | cpu_to_be32(hll >> 32);-#endif-}---void-hs_cryptohash_sha256_init (struct sha256_ctx *ctx)-{-  memset(ctx, 0, SHA256_CTX_SIZE);--  ctx->h[0] = 0x6a09e667;-  ctx->h[1] = 0xbb67ae85;-  ctx->h[2] = 0x3c6ef372;-  ctx->h[3] = 0xa54ff53a;-  ctx->h[4] = 0x510e527f;-  ctx->h[5] = 0x9b05688c;-  ctx->h[6] = 0x1f83d9ab;-  ctx->h[7] = 0x5be0cd19;-}--/* 232 times the cube root of the first 64 primes 2..311 */-static const uint32_t k[] = {-  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,-  0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,-  0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,-  0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,-  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,-  0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,-  0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,-  0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,-  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,-  0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,-  0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2-};--#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 void-sha256_do_chunk_aligned(struct sha256_ctx *ctx, uint32_t w[])-{-  int i;--  for (i = 16; i < 64; i++)-    w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];--  uint32_t a = ctx->h[0];-  uint32_t b = ctx->h[1];-  uint32_t c = ctx->h[2];-  uint32_t d = ctx->h[3];-  uint32_t e = ctx->h[4];-  uint32_t f = ctx->h[5];-  uint32_t g = ctx->h[6];-  uint32_t h = ctx->h[7];--#define R(a, b, c, d, e, f, g, h, k, w)             \-    t1 = h + e1(e) + (g ^ (e & (f ^ g))) + k + w;   \-    t2 = e0(a) + ((a & b) | (c & (a | b)));         \-    d += t1;                                        \-    h = t1 + t2;--  for (i = 0; i < 64; i += 8) {-    uint32_t t1, t2;--    R(a, b, c, d, e, f, g, h, k[i + 0], w[i + 0]);-    R(h, a, b, c, d, e, f, g, k[i + 1], w[i + 1]);-    R(g, h, a, b, c, d, e, f, k[i + 2], w[i + 2]);-    R(f, g, h, a, b, c, d, e, k[i + 3], w[i + 3]);-    R(e, f, g, h, a, b, c, d, k[i + 4], w[i + 4]);-    R(d, e, f, g, h, a, b, c, k[i + 5], w[i + 5]);-    R(c, d, e, f, g, h, a, b, k[i + 6], w[i + 6]);-    R(b, c, d, e, f, g, h, a, k[i + 7], w[i + 7]);-  }--#undef R--  ctx->h[0] += a;-  ctx->h[1] += b;-  ctx->h[2] += c;-  ctx->h[3] += d;-  ctx->h[4] += e;-  ctx->h[5] += f;-  ctx->h[6] += g;-  ctx->h[7] += h;-}--static void-sha256_do_chunk(struct sha256_ctx *ctx, const uint8_t buf[])-{-  uint32_t w[64]; /* only first 16 words are filled in */-  if (ptr_uint32_aligned(buf)) { /* aligned buf */-    cpu_to_be32_array(w, (const uint32_t *)buf, 16);-  } else { /* unaligned buf */-    memcpy(w, buf, 64);-#if !WORDS_BIGENDIAN-    cpu_to_be32_array(w, w, 16);-#endif-  }-  sha256_do_chunk_aligned(ctx, w);-}--void-hs_cryptohash_sha256_update(struct sha256_ctx *ctx, const uint8_t *data, size_t len)-{-  size_t index = ctx->sz & 0x3f;-  const size_t to_fill = 64 - index;--  ctx->sz += len;--  /* process partial buffer if there's enough data to make a block */-  if (index && len >= to_fill) {-    memcpy(ctx->buf + index, data, to_fill);-    sha256_do_chunk(ctx, ctx->buf);-    /* memset(ctx->buf, 0, 64); */-    len -= to_fill;-    data += to_fill;-    index = 0;-  }--  /* process as many 64-blocks as possible */-  while (len >= 64) {-    sha256_do_chunk(ctx, data);-    len -= 64;-    data += 64;-  }--  /* append data into buf */-  if (len)-    memcpy(ctx->buf + index, data, len);-}--void-hs_cryptohash_sha256_finalize (struct sha256_ctx *ctx, uint8_t *out)-{-  static const uint8_t padding[64] = { 0x80, };--  /* add padding and update data with it */-  uint64_t bits = cpu_to_be64(ctx->sz << 3);--  /* pad out to 56 */-  const size_t index = ctx->sz & 0x3f;-  const size_t padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);-  hs_cryptohash_sha256_update(ctx, padding, padlen);--  /* append length */-  hs_cryptohash_sha256_update(ctx, (uint8_t *) &bits, sizeof(bits));--  /* output hash */-  cpu_to_be32_array((uint32_t *) out, ctx->h, 8);-}
− cbits/sha256.h
@@ -1,47 +0,0 @@-/*- * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>- *               2016      Herbert Valerio Riedel <hvr@gnu.org>- *- * 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 ``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 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.- */--#ifndef CRYPTOHASH_SHA256_H-#define CRYPTOHASH_SHA256_H--#include <stdint.h>-#include <stddef.h>--struct sha256_ctx-{-	uint64_t sz;-	uint8_t  buf[64];-	uint32_t h[8];-};--/* keep this synchronised with 'digestSize'/'sizeCtx' in SHA256.hs */-#define SHA256_DIGEST_SIZE	32-#define SHA256_CTX_SIZE		104--void hs_cryptohash_sha256_init (struct sha256_ctx *ctx);-void hs_cryptohash_sha256_update (struct sha256_ctx *ctx, const uint8_t *data, size_t len);-void hs_cryptohash_sha256_finalize (struct sha256_ctx *ctx, uint8_t *out);--#endif
changelog.md view
@@ -1,3 +1,17 @@+## 0.11.101.0++ - Add `hkdf` function providing HKDF-SHA256 conforming to RFC5869+ - Declare `Crypto.Hash.SHA256` module `-XTrustworthy`+ - Remove ineffective RULES+ - Convert to `CApiFFI`+ - Added `...AndLength` variants of hashing functions:++      - `finalizeAndLength`+      - `hashlazyAndLength`+      - `hmaclazyAndLength`++ - Minor optimizations in `hmac` and `hash`+ ## 0.11.100.1   - Use `__builtin_bswap{32,64}` only with GCC >= 4.3@@ -5,7 +19,7 @@  ## 0.11.100.0 - - new `hmac` and `hmaclazy` functions providing HMAC-SHA1+ - new `hmac` and `hmaclazy` functions providing HMAC-SHA256    computation conforming to RFC2104 and RFC4231  - fix unaligned memory-accesses 
cryptohash-sha256.cabal view
@@ -1,58 +1,107 @@+cabal-version:       1.12 name:                cryptohash-sha256-version:             0.11.100.1-description:-    A practical incremental and one-pass, pure API to the-    <https://en.wikipedia.org/wiki/SHA-2 SHA-256 hash algorithm>-    (including <https://en.wikipedia.org/wiki/HMAC HMAC> support)-    with performance close to the fastest implementations available in other languages.-    .-    The implementation is made in C with a haskell FFI wrapper that hides the C implementation.-    .-    NOTE: This package has been forked off @cryptohash-0.11.7@ because the @cryptohash@ package has been-    deprecated and so this package continues to satisfy the need for a lightweight package-    providing the SHA256 hash algorithm without any dependencies on packages other than-    @base@ and @bytestring@.-    .-    Consequently, this package can be used as a drop-in replacement for @cryptohash@'s-    "Crypto.Hash.SHA256" module, though with a clearly smaller footprint.+version:             0.11.101.0 +synopsis:            Fast, pure and practical SHA-256 implementation+description: {++A practical incremental and one-pass, pure API to+the [SHA-256 cryptographic hash algorithm](https://en.wikipedia.org/wiki/SHA-2) according+to [FIPS 180-4](http://dx.doi.org/10.6028/NIST.FIPS.180-4)+with performance close to the fastest implementations available in other languages.+.+The core SHA-256 algorithm is implemented in C and is thus expected+to be as fast as the standard [sha256sum(1) tool](https://linux.die.net/man/1/sha256sum);+for instance, on an /Intel Core i7-3770/ at 3.40GHz this implementation can+compute a SHA-256 hash over 230 MiB of data in under one second.+(If, instead, you require a pure Haskell implementation and performance is secondary, please refer to the [SHA package](https://hackage.haskell.org/package/SHA).)+.++.+Additionally, this package provides support for+.+- HMAC-SHA-256: SHA-256-based [Hashed Message Authentication Codes](https://en.wikipedia.org/wiki/HMAC) (HMAC)+- HKDF-SHA-256: [HMAC-SHA-256-based Key Derivation Function](https://en.wikipedia.org/wiki/HKDF) (HKDF)+.+conforming to [RFC6234](https://tools.ietf.org/html/rfc6234), [RFC4231](https://tools.ietf.org/html/rfc4231), [RFC5869](https://tools.ietf.org/html/rfc5869), et al..+.+=== Relationship to the @cryptohash@ package and its API+.+This package has been originally a fork of @cryptohash-0.11.7@ because the @cryptohash@+package had been deprecated and so this package continues to satisfy the need for a+lightweight package providing the SHA-256 hash algorithm without any dependencies on packages+other than @base@ and @bytestring@. The API exposed by @cryptohash-sha256-0.11.*@'s+"Crypto.Hash.SHA256" module is guaranteed to remain a compatible superset of the API provided+by the @cryptohash-0.11.7@'s module of the same name.+.+Consequently, this package is designed to be used as a drop-in replacement for @cryptohash-0.11.7@'s+"Crypto.Hash.SHA256" module, though with+a [clearly smaller footprint by almost 3 orders of magnitude](https://www.reddit.com/r/haskell/comments/5lxv75/psa_please_use_unique_module_names_when_uploading/dbzegx3/).++}+ license:             BSD3 license-file:        LICENSE copyright:           Vincent Hanquez, Herbert Valerio Riedel maintainer:          Herbert Valerio Riedel <hvr@gnu.org> homepage:            https://github.com/hvr/cryptohash-sha256 bug-reports:         https://github.com/hvr/cryptohash-sha256/issues-synopsis:            Fast, pure and practical SHA-256 implementation category:            Data, Cryptography build-type:          Simple-cabal-version:       >=1.10 tested-with:         GHC == 7.4.2                    , GHC == 7.6.3                    , GHC == 7.8.4                    , GHC == 7.10.3-                   , GHC == 8.0.1+                   , GHC == 8.0.2+                   , GHC == 8.2.1 -extra-source-files:  cbits/sha256.h+extra-source-files:  cbits/hs_sha256.h                      changelog.md  source-repository head   type:     git   location: https://github.com/hvr/cryptohash-sha256.git +flag exe+  description: Enable building @sha256sum@ executable+  manual:   True+  default:  False+ library   default-language:  Haskell2010-  build-depends:     base             >= 4.5   && < 4.10+  other-extensions:  BangPatterns+                     CApiFFI+                     Trustworthy+                     Unsafe++  build-depends:     base             >= 4.5   && < 4.11                    , bytestring       >= 0.9.2 && < 0.11 +  ghc-options:       -Wall+   hs-source-dirs:    src   exposed-modules:   Crypto.Hash.SHA256-  ghc-options:       -Wall -fno-cse -O2-  cc-options:        -Wall -O3-  c-sources:         cbits/sha256.c+  other-modules:     Crypto.Hash.SHA256.FFI   include-dirs:      cbits +executable sha256sum+  hs-source-dirs:    src-exe+  main-is:           sha256sum.hs+  ghc-options:       -Wall -threaded+  if flag(exe)+    default-language:  Haskell2010+    other-extensions:  RecordWildCards+    build-depends:     cryptohash-sha256+                     , base+                     , bytestring++                     , base16-bytestring >= 0.1.1  && < 0.2+  else+    buildable:       False+ test-suite test-sha256   default-language:  Haskell2010+  other-extensions:  OverloadedStrings   type:              exitcode-stdio-1.0   hs-source-dirs:    src-tests   main-is:           test-sha256.hs@@ -69,6 +118,7 @@  benchmark bench-sha256   default-language:  Haskell2010+  other-extensions:  BangPatterns   type:              exitcode-stdio-1.0   main-is:           bench-sha256.hs   hs-source-dirs:    src-bench
+ src-exe/sha256sum.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE RecordWildCards #-}++module Main where++import           Control.Monad+import qualified Data.ByteString.Base16 as B16+import qualified Data.ByteString.Char8  as B+import qualified Data.ByteString.Lazy   as BL+import           System.Console.GetOpt+import           System.Environment+import           System.Exit+import           System.IO++import qualified Crypto.Hash.SHA256     as H+++data Options = Options+    { optBinary :: Bool+    , optHelp   :: Bool+    , optTag    :: Bool+    } deriving Show++defOptions :: Options+defOptions = Options+    { optBinary = True+    , optHelp = False+    , optTag  = False+    }++options :: [OptDescr (Options -> Options)]+options = [ Option ['b'] ["binary"]+            (NoArg (\o -> o { optBinary = True}))+            "read in binary mode (default)"+          , Option ['t'] ["text"]+            (NoArg (\o -> o { optBinary = False}))+            "read in text mode (ignored)"+          , Option [] ["help"]+            (NoArg (\o -> o { optHelp = True}))+            "display help and exit"+          , Option [] ["tag"]+            (NoArg (\o -> o { optTag = True}))+            "create a BSD-style checksum"+          ]++main :: IO ()+main = do+  argv <- getArgs++  let Options{..} = foldl (flip id) defOptions optset+      (optset,args0,cliErr) = getOpt Permute options argv+      args | null args0 = ["-"]+           | otherwise  = args0++  unless (null cliErr) $ do+    hPutStrLn stderr ("sha256sum: " ++ head cliErr ++ "Try 'sha256sum --help' for more information.")+    exitFailure++  when optHelp $ do+    putStrLn (usageInfo "Usage: sha256sum [OPTION]... [FILE]...\nPrint or check SHA-256 hashes\n" options)+    exitSuccess++  forM_ args $ \fn -> do+    h <- (B16.encode . H.hashlazy) `fmap` bReadFile fn++    case optTag of+      False -> do+        B.hPutStr stdout h+        hPutStrLn stdout (' ':' ':fn)+      True -> do+        hPutStrLn stdout $ concat [ "SHA256 (", fn, ") = ", B.unpack h ]++  return ()++bReadFile :: FilePath -> IO BL.ByteString+bReadFile "-" = do+  clsd <- hIsClosed stdin+  if clsd then return BL.empty else BL.getContents+bReadFile fn  = BL.readFile fn
src-tests/test-sha256.hs view
@@ -4,8 +4,9 @@  import           Data.ByteString        (ByteString) import qualified Data.ByteString        as B-import qualified Data.ByteString.Lazy   as BL import qualified Data.ByteString.Base16 as B16+import qualified Data.ByteString.Lazy   as BL+import           Data.Word  -- reference implementation import qualified Data.Digest.Pure.SHA   as REF@@ -124,6 +125,29 @@      hex = B16.encode +rfc5869Vectors :: [(Int,ByteString,ByteString,ByteString,ByteString)]+rfc5869Vectors = -- (l,ikm,salt,info,okm)+    [ (42, rep 22 0x0b, x"000102030405060708090a0b0c", x"f0f1f2f3f4f5f6f7f8f9", x"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")+    , ( 82+      , x"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"+      , x"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"+      , x"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"+      , x"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"+      )+    , ( 42, rep 22 0x0b, "", "", x"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8")+    ]+  where+    x = fst.B16.decode+    rep n c = B.replicate n c++rfc5869Tests :: [TestTree]+rfc5869Tests = zipWith makeTest [1::Int ..] rfc5869Vectors+  where+    makeTest i (l,ikm,salt,info,okm) = testGroup ("vec"++show i) $+        [ testCase "hkdf" (hex okm @=? hex (IUT.hkdf ikm salt info l)) ]++    hex = B16.encode+ -- define own 'foldl' here to avoid RULE rewriting to 'hashlazy' myfoldl' :: (b -> a -> b) -> b -> [a] -> b myfoldl' f z0 xs0 = lgo z0 xs0@@ -155,8 +179,10 @@ refImplTests =     [ testProperty "hash" prop_hash     , testProperty "hashlazy" prop_hashlazy+    , testProperty "hashlazyAndLength" prop_hashlazyAndLength     , testProperty "hmac" prop_hmac     , testProperty "hmaclazy" prop_hmaclazy+    , testProperty "hmaclazyAndLength" prop_hmaclazyAndLength     ]   where     prop_hash (RandBS bs)@@ -165,24 +191,36 @@     prop_hashlazy (RandLBS bs)         = ref_hashlazy bs == IUT.hashlazy bs +    prop_hashlazyAndLength (RandLBS bs)+        = ref_hashlazyAndLength bs == IUT.hashlazyAndLength bs+     prop_hmac (RandBS k) (RandBS bs)         = ref_hmac k bs == IUT.hmac k bs      prop_hmaclazy (RandBS k) (RandLBS bs)         = ref_hmaclazy k bs == IUT.hmaclazy k bs +    prop_hmaclazyAndLength (RandBS k) (RandLBS bs)+        = ref_hmaclazyAndLength k bs == IUT.hmaclazyAndLength k bs+     ref_hash :: ByteString -> ByteString     ref_hash = ref_hashlazy . fromStrict      ref_hashlazy :: BL.ByteString -> ByteString     ref_hashlazy = toStrict . REF.bytestringDigest . REF.sha256 +    ref_hashlazyAndLength :: BL.ByteString -> (ByteString,Word64)+    ref_hashlazyAndLength x = (ref_hashlazy x, fromIntegral (BL.length x))+     ref_hmac :: ByteString -> ByteString -> ByteString     ref_hmac secret = ref_hmaclazy secret . fromStrict      ref_hmaclazy :: ByteString -> BL.ByteString -> ByteString     ref_hmaclazy secret = toStrict . REF.bytestringDigest . REF.hmacSha256 (fromStrict secret) +    ref_hmaclazyAndLength :: ByteString -> BL.ByteString -> (ByteString,Word64)+    ref_hmaclazyAndLength secret msg = (ref_hmaclazy secret msg, fromIntegral (BL.length msg))+     -- toStrict/fromStrict only available with bytestring-0.10 and later     toStrict = B.concat . BL.toChunks     fromStrict = BL.fromChunks . (:[])@@ -191,5 +229,6 @@ main = defaultMain $ testGroup "cryptohash-sha256"     [ testGroup "KATs" katTests     , testGroup "RFC4231" rfc4231Tests+    , testGroup "RFC5869" rfc5869Tests     , testGroup "REF" refImplTests     ]
src/Crypto/Hash/SHA256.hs view
@@ -1,9 +1,11 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE Trustworthy  #-}+ -- | -- Module      : Crypto.Hash.SHA256--- License     : BSD-style+-- License     : BSD-3 -- Maintainer  : Herbert Valerio Riedel <hvr@gnu.org> -- Stability   : stable--- Portability : unknown -- -- A module containing <https://en.wikipedia.org/wiki/SHA-2 SHA-256> bindings --@@ -40,6 +42,7 @@     , update   -- :: Ctx -> ByteString -> Ctx     , updates  -- :: Ctx -> [ByteString] -> Ctx     , finalize -- :: Ctx -> ByteString+    , finalizeAndLength -- :: Ctx -> (ByteString,Word64)      -- * Single Pass API     --@@ -49,6 +52,7 @@     --     --  - 'hash': create a digest ('init' + 'update' + 'finalize') from a strict 'ByteString'     --  - 'hashlazy': create a digest ('init' + 'update' + 'finalize') from a lazy 'L.ByteString'+    --  - 'hashlazyAndLength': create a digest ('init' + 'update' + 'finalizeAndLength') from a lazy 'L.ByteString'     --     -- Example:     --@@ -64,6 +68,7 @@      , hash     -- :: ByteString -> ByteString     , hashlazy -- :: L.ByteString -> ByteString+    , hashlazyAndLength -- :: L.ByteString -> (ByteString,Int64)      -- ** HMAC-SHA-256     --@@ -72,22 +77,34 @@      , hmac     -- :: ByteString -> ByteString -> ByteString     , hmaclazy -- :: ByteString -> L.ByteString -> ByteString+    , hmaclazyAndLength -- :: ByteString -> L.ByteString -> (ByteString,Word64)++    -- ** HKDF-SHA-256+    --+    -- | <https://tools.ietf.org/html/rfc5869 RFC5869>-compatible+    -- <https://en.wikipedia.org/wiki/HKDF HKDF>-SHA-256 key derivation function++    , hkdf     ) where -import Prelude hiding (init)-import Foreign.C.Types-import Foreign.Ptr-import Foreign.ForeignPtr (withForeignPtr)-import Foreign.Marshal.Alloc-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString as B-import Data.ByteString (ByteString)-import Data.ByteString.Unsafe (unsafeUseAsCStringLen)-import Data.ByteString.Internal (create, toForeignPtr, memcpy)-import Data.Bits (xor)-import Data.Word-import System.IO.Unsafe (unsafeDupablePerformIO)+import           Data.Bits                (xor)+import           Data.ByteString          (ByteString)+import qualified Data.ByteString          as B+import           Data.ByteString.Internal (ByteString (PS), create,+                                           createAndTrim, mallocByteString,+                                           memcpy, toForeignPtr)+import qualified Data.ByteString.Lazy     as L+import           Data.ByteString.Unsafe   (unsafeUseAsCStringLen)+import           Data.Word+import           Foreign.C.Types+import           Foreign.ForeignPtr       (withForeignPtr)+import           Foreign.Marshal.Alloc+import           Foreign.Ptr+import           Prelude                  hiding (init)+import           System.IO.Unsafe         (unsafeDupablePerformIO) +import           Crypto.Hash.SHA256.FFI+ -- | perform IO for hashes that do allocation and ffi. -- unsafeDupablePerformIO is used when possible as the -- computation is pure and the output is directly linked@@ -96,22 +113,6 @@ unsafeDoIO :: IO a -> a unsafeDoIO = unsafeDupablePerformIO --- | SHA-256 Context------ The context data is exactly 104 bytes long, however--- the data in the context is stored in host-endianness.------ The context data is made up of------  * a 'Word64' representing the number of bytes already feed to hash algorithm so far,------  * a 64-element 'Word8' buffer holding partial input-chunks, and finally------  * a 8-element 'Word32' array holding the current work-in-progress digest-value.------ Consequently, a SHA-256 digest as produced by 'hash', 'hashlazy', or 'finalize' is 32 bytes long.-newtype Ctx = Ctx ByteString- -- keep this synchronised with cbits/sha256.h {-# INLINE digestSize #-} digestSize :: Int@@ -121,18 +122,21 @@ sizeCtx :: Int sizeCtx = 104 -{-# RULES "digestSize" B.length (finalize init) = digestSize #-}-{-# RULES "hash" forall b. finalize (update init b) = hash b #-}-{-# RULES "hash.list1" forall b. finalize (updates init [b]) = hash b #-}-{-# RULES "hashmany" forall b. finalize (foldl update init b) = hashlazy (L.fromChunks b) #-}-{-# RULES "hashlazy" forall b. finalize (foldl update init $ L.toChunks b) = hashlazy b #-}- {-# INLINE withByteStringPtr #-} withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a withByteStringPtr b f =     withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)     where (fptr, off, _) = toForeignPtr b +{-# INLINE create' #-}+-- | Variant of 'create' which allows to return an argument+create' :: Int -> (Ptr Word8 -> IO a) -> IO (ByteString,a)+create' l f = do+    fp <- mallocByteString l+    x <- withForeignPtr fp $ \p -> f p+    let bs = PS fp 0 l+    return $! x `seq` bs `seq` (bs,x)+ copyCtx :: Ptr Ctx -> Ptr Ctx -> IO () copyCtx dst src = memcpy (castPtr dst) (castPtr src) (fromIntegral sizeCtx) @@ -157,23 +161,17 @@ withCtxNewThrow :: (Ptr Ctx -> IO a) -> IO a withCtxNewThrow f = allocaBytes sizeCtx (f . castPtr) -foreign import ccall unsafe "sha256.h hs_cryptohash_sha256_init"-    c_sha256_init :: Ptr Ctx -> IO ()--foreign import ccall unsafe "sha256.h hs_cryptohash_sha256_update"-    c_sha256_update_unsafe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()--foreign import ccall safe "sha256.h hs_cryptohash_sha256_update"-    c_sha256_update_safe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()- -- 'safe' call overhead neglible for 4KiB and more c_sha256_update :: Ptr Ctx -> Ptr Word8 -> CSize -> IO () c_sha256_update pctx pbuf sz   | sz < 4096 = c_sha256_update_unsafe pctx pbuf sz   | otherwise = c_sha256_update_safe   pctx pbuf sz -foreign import ccall unsafe "sha256.h hs_cryptohash_sha256_finalize"-    c_sha256_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()+-- 'safe' call overhead neglible for 4KiB and more+c_sha256_hash :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()+c_sha256_hash pbuf sz pout+  | sz < 4096 = c_sha256_hash_unsafe pbuf sz pout+  | otherwise = c_sha256_hash_safe   pbuf sz pout  updateInternalIO :: Ptr Ctx -> ByteString -> IO () updateInternalIO ptr d =@@ -182,10 +180,14 @@ finalizeInternalIO :: Ptr Ctx -> IO ByteString finalizeInternalIO ptr = create digestSize (c_sha256_finalize ptr) +finalizeInternalIO' :: Ptr Ctx -> IO (ByteString,Word64)+finalizeInternalIO' ptr = create' digestSize (c_sha256_finalize_len ptr)++ {-# NOINLINE init #-} -- | create a new hash context init :: Ctx-init = unsafeDoIO $ withCtxNew $ c_sha256_init+init = unsafeDoIO $ withCtxNew c_sha256_init  validCtx :: Ctx -> Bool validCtx (Ctx b) = B.length b == sizeCtx@@ -211,28 +213,44 @@   | validCtx ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO   | otherwise    = error "SHA256.finalize: invalid Ctx" +{-# NOINLINE finalizeAndLength #-}+-- | Variant of 'finalize' also returning length of hashed content+--+-- @since 0.11.101.0+finalizeAndLength :: Ctx -> (ByteString,Word64)+finalizeAndLength ctx+  | validCtx ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO'+  | otherwise    = error "SHA256.finalize: invalid Ctx"+ {-# NOINLINE hash #-} -- | hash a strict bytestring into a digest bytestring (32 bytes) hash :: ByteString -> ByteString-hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do-    c_sha256_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr+-- hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> c_sha256_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr+hash d = unsafeDoIO $ unsafeUseAsCStringLen d $ \(cs, len) -> create digestSize (c_sha256_hash (castPtr cs) (fromIntegral len))  {-# NOINLINE hashlazy #-} -- | hash a lazy bytestring into a digest bytestring (32 bytes) hashlazy :: L.ByteString -> ByteString-hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr ->     c_sha256_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr +{-# NOINLINE hashlazyAndLength #-}+-- | Variant of 'hashlazy' which simultaneously computes the hash and length of a lazy bytestring.+--+-- @since 0.11.101.0+hashlazyAndLength :: L.ByteString -> (ByteString,Word64)+hashlazyAndLength l = unsafeDoIO $ withCtxNewThrow $ \ptr ->+    c_sha256_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO' ptr -{-# NOINLINE hmac #-}+ -- | Compute 32-byte <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible--- HMAC-SHA1 digest for a strict bytestring message+-- HMAC-SHA-256 digest for a strict bytestring message -- -- @since 0.11.100.0 hmac :: ByteString -- ^ secret      -> ByteString -- ^ message-     -> ByteString-hmac secret msg = hash $ B.append opad (hash $ B.append ipad msg)+     -> ByteString -- ^ digest (32 bytes)+hmac secret msg = hash $ B.append opad (hashlazy $ L.fromChunks [ipad,msg])   where     opad = B.map (xor 0x5c) k'     ipad = B.map (xor 0x36) k'@@ -242,14 +260,13 @@     pad = B.replicate (64 - B.length kt) 0  -{-# NOINLINE hmaclazy #-} -- | Compute 32-byte <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible--- HMAC-SHA1 digest for a lazy bytestring message+-- HMAC-SHA-256 digest for a lazy bytestring message -- -- @since 0.11.100.0 hmaclazy :: ByteString   -- ^ secret          -> L.ByteString -- ^ message-         -> ByteString+         -> ByteString   -- ^ digest (32 bytes) hmaclazy secret msg = hash $ B.append opad (hashlazy $ L.append ipad msg)   where     opad = B.map (xor 0x5c) k'@@ -258,3 +275,48 @@     k'  = B.append kt pad     kt  = if B.length secret > 64 then hash secret else secret     pad = B.replicate (64 - B.length kt) 0+++-- | Variant of 'hmaclazy' which also returns length of message+--+-- @since 0.11.101.0+hmaclazyAndLength :: ByteString   -- ^ secret+                  -> L.ByteString -- ^ message+                  -> (ByteString,Word64) -- ^ digest (32 bytes) and length of message+hmaclazyAndLength secret msg =+    (hash (B.append opad htmp), sz' - fromIntegral ipadLen)+  where+    (htmp, sz') = hashlazyAndLength (L.append ipad msg)++    opad = B.map (xor 0x5c) k'+    ipad = L.fromChunks [B.map (xor 0x36) k']+    ipadLen = B.length k'++    k'  = B.append kt pad+    kt  = if B.length secret > 64 then hash secret else secret+    pad = B.replicate (64 - B.length kt) 0++{-# NOINLINE hkdf #-}+-- | <https://tools.ietf.org/html/rfc6234 RFC6234>-compatible+-- HKDF-SHA-256 key derivation function.+--+-- @since 0.11.101.0+hkdf :: ByteString -- ^ /IKM/ Input keying material+     -> ByteString -- ^ /salt/ Optional salt value, a non-secret random value (can be @""@)+     -> ByteString -- ^ /info/ Optional context and application specific information (can be @""@)+     -> Int        -- ^ /L/ length of output keying material in octets (at most 255*32 bytes)+     -> ByteString -- ^ /OKM/ Output keying material (/L/ bytes)+hkdf ikm salt info l+  | l == 0 = B.empty+  | 0 > l || l > 255*32 = error "hkdf: invalid L parameter"+  | otherwise = unsafeDoIO $ createAndTrim (32*fromIntegral cnt) (go 0 B.empty)+  where+    prk = hmac salt ikm+    cnt = fromIntegral ((l+31) `div` 32) :: Word8++    go :: Word8 -> ByteString -> Ptr Word8 -> IO Int+    go !i t !p | i == cnt  = return l+               | otherwise = do+                   let t' = hmaclazy prk (L.fromChunks [t,info,B.singleton (i+1)])+                   withByteStringPtr t' $ \tptr' -> memcpy p tptr' 32+                   go (i+1) t' (p `plusPtr` 32)
+ src/Crypto/Hash/SHA256/FFI.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE Unsafe  #-}++-- Ugly hack to workaround https://ghc.haskell.org/trac/ghc/ticket/14452+{-# OPTIONS_GHC -O0+                -fdo-lambda-eta-expansion+                -fcase-merge+                -fstrictness+                -fno-omit-interface-pragmas+                -fno-ignore-interface-pragmas #-}++{-# OPTIONS_GHC -optc-Wall -optc-O3 #-}++-- |+-- Module      : Crypto.Hash.SHA256.FFI+-- License     : BSD-3+-- Maintainer  : Herbert Valerio Riedel <hvr@gnu.org>+--+module Crypto.Hash.SHA256.FFI where++import           Data.ByteString (ByteString)+import           Data.Word+import           Foreign.C.Types+import           Foreign.Ptr++-- | SHA-256 Context+--+-- The context data is exactly 104 bytes long, however+-- the data in the context is stored in host-endianness.+--+-- The context data is made up of+--+--  * a 'Word64' representing the number of bytes already feed to hash algorithm so far,+--+--  * a 64-element 'Word8' buffer holding partial input-chunks, and finally+--+--  * a 8-element 'Word32' array holding the current work-in-progress digest-value.+--+-- Consequently, a SHA-256 digest as produced by 'hash', 'hashlazy', or 'finalize' is 32 bytes long.+newtype Ctx = Ctx ByteString++foreign import capi unsafe "hs_sha256.h hs_cryptohash_sha256_init"+    c_sha256_init :: Ptr Ctx -> IO ()++foreign import capi unsafe "hs_sha256.h hs_cryptohash_sha256_update"+    c_sha256_update_unsafe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()++foreign import capi safe "hs_sha256.h hs_cryptohash_sha256_update"+    c_sha256_update_safe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()++foreign import capi unsafe "hs_sha256.h hs_cryptohash_sha256_finalize"+    c_sha256_finalize_len :: Ptr Ctx -> Ptr Word8 -> IO Word64++foreign import capi unsafe "hs_sha256.h hs_cryptohash_sha256_finalize"+    c_sha256_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()++foreign import capi unsafe "hs_sha256.h hs_cryptohash_sha256_hash"+    c_sha256_hash_unsafe :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()++foreign import capi safe "hs_sha256.h hs_cryptohash_sha256_hash"+    c_sha256_hash_safe :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()