packages feed

cryptohash-sha256 0.11.7.2 → 0.11.100.0

raw patch · 5 files changed

+230/−102 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Crypto.Hash.SHA256: hmac :: ByteString -> ByteString -> ByteString
+ Crypto.Hash.SHA256: hmaclazy :: ByteString -> ByteString -> ByteString

Files

cbits/sha256.c view
@@ -32,26 +32,28 @@ #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+/* 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(uint32_t word, uint32_t shift)+ror32(const uint32_t word, const unsigned shift) {-  // GCC usually transforms this into a 'ror'-insn+  /* GCC usually transforms this into a 'ror'-insn */   return (word >> shift) | (word << (32 - shift)); }  static inline uint32_t-hs_htonl(uint32_t hl)+cpu_to_be32(const uint32_t hl) { #if WORDS_BIGENDIAN   return hl; #elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)   return __builtin_bswap32(hl); #else-  // GCC usually transforms this into a bswap insn+  /* GCC usually transforms this into a bswap insn */   return ((hl & 0xff000000) >> 24) |          ((hl & 0x00ff0000) >> 8)  |          ((hl & 0x0000ff00) << 8)  |@@ -60,21 +62,21 @@ }  static inline void-hs_htonl_array(uint32_t *dest, const uint32_t *src, unsigned wordcnt)+cpu_to_be32_array(uint32_t *dest, const uint32_t *src, unsigned wordcnt) {   while (wordcnt--)-    *dest++ = hs_htonl(*src++);+    *dest++ = cpu_to_be32(*src++); }  static inline uint64_t-hs_htonll(uint64_t hll)+cpu_to_be64(const uint64_t hll) { #if WORDS_BIGENDIAN   return hll; #elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)   return __builtin_bswap64(hll); #else-  return ((uint64_t)hs_htonl(hll & 0xFFFFFFFF) << 32LL) | hs_htonl(hll >> 32);+  return ((uint64_t)cpu_to_be32(hll & 0xffffffff) << 32LL) | cpu_to_be32(hll >> 32); #endif } @@ -82,31 +84,31 @@ void hs_cryptohash_sha256_init (struct sha256_ctx *ctx) {-	memset(ctx, 0, sizeof(*ctx));-        -	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;+  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+  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))@@ -115,89 +117,114 @@ #define s1(x)       (ror32(x,17) ^ ror32(x,19) ^ (x >> 10))  static void-sha256_do_chunk(struct sha256_ctx *ctx, uint32_t buf[])+sha256_do_chunk_aligned(struct sha256_ctx *ctx, uint32_t w[]) {-	uint32_t a, b, c, d, e, f, g, h, t1, t2;-	int i;-	uint32_t w[64];+  int i; -	hs_htonl_array(w, buf, 16);-	for (i = 16; i < 64; i++)-		w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];+  for (i = 16; i < 64; i++)+    w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16]; -	a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3];-	e = ctx->h[4]; f = ctx->h[5]; g = ctx->h[6]; h = ctx->h[7];+  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;+#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) {-		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]);-	}+  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;+  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; } -void-hs_cryptohash_sha256_update (struct sha256_ctx *ctx, const uint8_t *data, size_t len)+static void+sha256_do_chunk(struct sha256_ctx *ctx, const uint8_t buf[]) {-	size_t index, to_fill;+  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);+} -	/* check for partial buffer */-	index = (size_t) (ctx->sz & 0x3f);-	to_fill = 64 - index;+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;+  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, (uint32_t *) ctx->buf);-		len -= to_fill;-		data += to_fill;-		index = 0;-	}+  /* 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 much 64-block as possible */-	for (; len >= 64; len -= 64, data += 64)-		sha256_do_chunk(ctx, (uint32_t *) data);+  /* 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);+  /* 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 uint8_t padding[64] = { 0x80, };-	uint64_t bits;-	uint32_t index, padlen;+  static const uint8_t padding[64] = { 0x80, }; -	/* cpu -> big endian */-	bits = hs_htonll(ctx->sz << 3);+  /* add padding and update data with it */+  uint64_t bits = cpu_to_be64(ctx->sz << 3); -	/* pad out to 56 */-	index = (uint32_t) (ctx->sz & 0x3f);-	padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);-	hs_cryptohash_sha256_update(ctx, padding, padlen);+  /* 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));+  /* append length */+  hs_cryptohash_sha256_update(ctx, (uint8_t *) &bits, sizeof(bits)); -	/* store to digest */-        hs_htonl_array((uint32_t *) out, ctx->h, 8);+  /* output hash */+  cpu_to_be32_array((uint32_t *) out, ctx->h, 8); }
changelog.md view
@@ -1,3 +1,9 @@+## 0.11.100.0++ - new `hmac` and `hmaclazy` functions providing HMAC-SHA1+   computation conforming to RFC2104 and RFC4231+ - fix unaligned memory-accesses+ ## 0.11.7.2   - switch to 'safe' FFI for calls where overhead becomes neglible
cryptohash-sha256.cabal view
@@ -1,8 +1,9 @@ name:                cryptohash-sha256-version:             0.11.7.2+version:             0.11.100.0 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.@@ -46,7 +47,7 @@   hs-source-dirs:    src   exposed-modules:   Crypto.Hash.SHA256   ghc-options:       -Wall -fno-cse -O2-  cc-options:        -O3+  cc-options:        -Wall -O3   c-sources:         cbits/sha256.c   include-dirs:      cbits 
src-tests/test-sha256.hs view
@@ -8,14 +8,14 @@ import qualified Data.ByteString.Base16 as B16  -- reference implementation-import qualified Data.Digest.Pure.SHA as REF+import qualified Data.Digest.Pure.SHA   as REF  -- implementation under test import qualified Crypto.Hash.SHA256     as IUT  import           Test.Tasty import           Test.Tasty.HUnit-import           Test.Tasty.QuickCheck as QC+import           Test.Tasty.QuickCheck  as QC  vectors :: [ByteString] vectors =@@ -64,7 +64,11 @@         , testCase "lazy-7"   (r @=? runTestLazy 7 v)         , testCase "lazy-8"   (r @=? runTestLazy 8 v)         , testCase "lazy-16"  (r @=? runTestLazy 16 v)-        ]+        ] +++        [ testCase "lazy-63u"  (r @=? runTestLazyU 63 v) | B.length v > 63 ] +++        [ testCase "lazy-65u"  (r @=? runTestLazyU 65 v) | B.length v > 65 ] +++        [ testCase "lazy-97u"  (r @=? runTestLazyU 97 v) | B.length v > 97 ] +++        [ testCase "lazy-131u" (r @=? runTestLazyU 131 v) | B.length v > 131 ]      runTest :: ByteString -> ByteString     runTest = B16.encode . IUT.hash@@ -75,6 +79,10 @@     runTestLazy :: Int -> ByteString -> ByteString     runTestLazy i = B16.encode . IUT.hashlazy . BL.fromChunks . splitB i +    -- force unaligned md5-blocks+    runTestLazyU :: Int -> ByteString -> ByteString+    runTestLazyU i = B16.encode . IUT.hashlazy . BL.fromChunks . map B.copy . splitB i+     ----      xltest = testGroup "XL-vec"@@ -82,13 +90,39 @@       where         vecXL = BL.fromChunks (replicate 16777216 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno") -    splitB :: Int -> ByteString -> [ByteString]-    splitB l b-      | B.length b > l = b1 : splitB l b2-      | otherwise = [b]+splitB :: Int -> ByteString -> [ByteString]+splitB l b+  | B.length b > l = b1 : splitB l b2+  | otherwise = [b]+  where+    (b1, b2) = B.splitAt l b+++rfc4231Vectors :: [(ByteString,ByteString,ByteString)]+rfc4231Vectors = -- (secrect,msg,mac)+    [ (rep 20 0x0b, "Hi There", x"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7")+    , ("Jefe", "what do ya want for nothing?", x"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843")+    , (rep 20 0xaa, rep 50 0xdd, x"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe")+    , (B.pack [1..25], rep 50 0xcd, x"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b")+    , (rep 20 0x0c, "Test With Truncation", x"a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5")+    , (rep 131 0xaa, "Test Using Larger Than Block-Size Key - Hash Key First", x"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54")+    , (rep 131 0xaa, "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", x"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2")+    ]+  where+    x = fst.B16.decode+    rep n c = B.replicate n c++rfc4231Tests :: [TestTree]+rfc4231Tests = zipWith makeTest [1::Int ..] rfc4231Vectors+  where+    makeTest i (key, msg, mac) = testGroup ("vec"++show i) $+        [ testCase "hmac" (hex mac  @=? hex (IUT.hmac key msg))+        , testCase "hmaclazy" (hex mac  @=? hex (IUT.hmaclazy key lazymsg))+        ]       where-        (b1, b2) = B.splitAt l b+        lazymsg = BL.fromChunks . splitB 1 $ msg +    hex = B16.encode  -- define own 'foldl' here to avoid RULE rewriting to 'hashlazy' myfoldl' :: (b -> a -> b) -> b -> [a] -> b@@ -121,6 +155,8 @@ refImplTests =     [ testProperty "hash" prop_hash     , testProperty "hashlazy" prop_hashlazy+    , testProperty "hmac" prop_hmac+    , testProperty "hmaclazy" prop_hmaclazy     ]   where     prop_hash (RandBS bs)@@ -129,12 +165,24 @@     prop_hashlazy (RandLBS bs)         = ref_hashlazy bs == IUT.hashlazy 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+     ref_hash :: ByteString -> ByteString-    ref_hash = toStrict . REF.bytestringDigest . REF.sha256 . fromStrict+    ref_hash = ref_hashlazy . fromStrict      ref_hashlazy :: BL.ByteString -> ByteString     ref_hashlazy = toStrict . REF.bytestringDigest . REF.sha256 +    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)+     -- toStrict/fromStrict only available with bytestring-0.10 and later     toStrict = B.concat . BL.toChunks     fromStrict = BL.fromChunks . (:[])@@ -142,5 +190,6 @@ main :: IO () main = defaultMain $ testGroup "cryptohash-sha256"     [ testGroup "KATs" katTests+    , testGroup "RFC4231" rfc4231Tests     , testGroup "REF" refImplTests     ]
src/Crypto/Hash/SHA256.hs view
@@ -63,7 +63,15 @@     -- package is recommended.      , hash     -- :: ByteString -> ByteString-    , hashlazy -- :: ByteString -> ByteString+    , hashlazy -- :: L.ByteString -> ByteString++    -- ** HMAC-SHA-256+    --+    -- | <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible+    -- <https://en.wikipedia.org/wiki/HMAC HMAC>-SHA-256 digests++    , hmac     -- :: ByteString -> ByteString -> ByteString+    , hmaclazy -- :: ByteString -> L.ByteString -> ByteString     ) where  import Prelude hiding (init)@@ -76,6 +84,7 @@ 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) @@ -213,3 +222,39 @@ hashlazy :: L.ByteString -> ByteString hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do     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+--+-- @since 0.11.100.0+hmac :: ByteString -- ^ secret+     -> ByteString -- ^ message+     -> ByteString+hmac secret msg = hash $ B.append opad (hash $ B.append ipad msg)+  where+    opad = B.map (xor 0x5c) k'+    ipad = B.map (xor 0x36) 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 hmaclazy #-}+-- | Compute 32-byte <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible+-- HMAC-SHA1 digest for a lazy bytestring message+--+-- @since 0.11.100.0+hmaclazy :: ByteString   -- ^ secret+         -> L.ByteString -- ^ message+         -> ByteString+hmaclazy secret msg = hash $ B.append opad (hashlazy $ L.append ipad msg)+  where+    opad = B.map (xor 0x5c) k'+    ipad = L.fromChunks [B.map (xor 0x36) 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