sha256

Pure Haskell SHA-256, HMAC-SHA256 as specified by RFC's 6234 and 2104.
git clone git://git.ppad.tech/sha256.git
Log | Files | Refs | README | LICENSE

commit 3ab45acf8532f35698ecb864c71ca3b2ac1de419
parent 45479003162834f442f2bbcd06d2f37c1d5d3550
Author: Jared Tobin <jared@jtobin.io>
Date:   Wed, 11 Sep 2024 19:16:48 +0400

test: unit tests on good vectors

Diffstat:
MREADME.md | 2+-
Mtest/Main.hs | 249++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
2 files changed, 184 insertions(+), 67 deletions(-)

diff --git a/README.md b/README.md @@ -85,7 +85,7 @@ std dev 634.4 ns (523.1 ns .. 868.8 ns) variance introduced by outliers: 68% (severely inflated) ``` -(Use `cabal bench` to run the benchmark suite.) +Use `cabal bench` to run the benchmark suite. ## Security diff --git a/test/Main.hs b/test/Main.hs @@ -1,52 +1,44 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ViewPatterns #-} module Main where -import Control.Monad (unless) +import qualified Crypto.Hash.SHA256 as SHA256 import qualified Data.ByteString as BS -import qualified Data.ByteString.Base16 as B16 -import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Builder as BSB -import qualified Crypto.Hash.SHA256 as SHA256 -import System.Exit +import qualified Data.ByteString.Lazy as BL +import qualified Data.ByteString.Base16 as B16 +import Test.Tasty +import Test.Tasty.HUnit --- XX add hmac tests, use tasty +main :: IO () +main = defaultMain unit_tests -- vectors from -- https://www.di-mgt.com.au/sha_testvectors.html -v0 :: (BS.ByteString, BS.ByteString) -v0 = ( - "abc" - , "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" - ) - -v1 :: (BS.ByteString, BS.ByteString) -v1 = ( - mempty - , "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - ) - -v2 :: (BS.ByteString, BS.ByteString) -v2 = ( - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - , "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" - ) - -v3 :: (BS.ByteString, BS.ByteString) -v3 = ( - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" - , "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" - ) - -v4 :: (BS.ByteString, BS.ByteString) -v4 = ( - BS.replicate 1000000 0x61 - , "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" - ) - -construct_long :: BL.ByteString -construct_long = go (16777216 :: Int) mempty where +hv0_put, hv0_pec :: BS.ByteString +hv0_put = "abc" +hv0_pec = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + +hv1_put, hv1_pec :: BS.ByteString +hv1_put = mempty +hv1_pec = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + +hv2_put, hv2_pec :: BS.ByteString +hv2_put = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +hv2_pec = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" + +hv3_put, hv3_pec :: BS.ByteString +hv3_put = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +hv3_pec = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" + +hv4_put, hv4_pec :: BS.ByteString +hv4_put = BS.replicate 1000000 0x61 +hv4_pec = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" + +big_input :: BL.ByteString +big_input = go (16777216 :: Int) mempty where go j acc | j == 0 = BSB.toLazyByteString acc | otherwise = @@ -54,34 +46,159 @@ construct_long = go (16777216 :: Int) mempty where "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" in go (pred j) nacc -v5 :: (BL.ByteString, BS.ByteString) -v5 = ( - construct_long - , "50e72a0e26442fe2552dc3938ac58658228c0cbfb1d2ca872ae435266fcd055e" - ) - -main :: IO () -main = do - let (v0_in, v0_out) = v0 - v0_res = B16.encode (SHA256.hash v0_in) == v0_out - - (v1_in, v1_out) = v1 - v1_res = B16.encode (SHA256.hash v1_in) == v1_out +hv5_put :: BL.ByteString +hv5_put = big_input - (v2_in, v2_out) = v2 - v2_res = B16.encode (SHA256.hash v2_in) == v2_out +hv5_pec :: BS.ByteString +hv5_pec = "50e72a0e26442fe2552dc3938ac58658228c0cbfb1d2ca872ae435266fcd055e" - (v3_in, v3_out) = v3 - v3_res = B16.encode (SHA256.hash v3_in) == v3_out - - (v4_in, v4_out) = v4 - v4_res = B16.encode (SHA256.hash v4_in) == v4_out - - -- warning, slow - (v5_in, v5_out) = v5 - v5_res = B16.encode (SHA256.hash_lazy v5_in) == v5_out - - unless (and [v0_res, v1_res, v2_res, v3_res, v4_res, v5_res]) $ - exitFailure +-- vectors from +-- https://datatracker.ietf.org/doc/html/rfc4231#section-4.1 + +hmv1_key :: BS.ByteString +hmv1_key = B16.decodeLenient "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" + +hmv1_put :: BS.ByteString +hmv1_put = "Hi There" + +hmv1_pec :: BS.ByteString +hmv1_pec = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7" + +hmv2_key :: BS.ByteString +hmv2_key = "Jefe" + +hmv2_put :: BS.ByteString +hmv2_put = "what do ya want for nothing?" + +hmv2_pec :: BS.ByteString +hmv2_pec = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" + +hmv3_key :: BS.ByteString +hmv3_key = B16.decodeLenient "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +hmv3_put :: BS.ByteString +hmv3_put = B16.decodeLenient "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + +hmv3_pec :: BS.ByteString +hmv3_pec = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe" + +hmv4_key :: BS.ByteString +hmv4_key = B16.decodeLenient "0102030405060708090a0b0c0d0e0f10111213141516171819" + +hmv4_put :: BS.ByteString +hmv4_put = B16.decodeLenient "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + +hmv4_pec :: BS.ByteString +hmv4_pec = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b" + +hmv5_key :: BS.ByteString +hmv5_key = B16.decodeLenient "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c" + +hmv5_put :: BS.ByteString +hmv5_put = "Test With Truncation" + +hmv5_pec :: BS.ByteString +hmv5_pec = "a3b6167473100ee06e0c796c2955552b" + +hmv6_key :: BS.ByteString +hmv6_key = B16.decodeLenient "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +hmv6_put :: BS.ByteString +hmv6_put = "Test Using Larger Than Block-Size Key - Hash Key First" + +hmv6_pec :: BS.ByteString +hmv6_pec = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54" + +hmv7_key :: BS.ByteString +hmv7_key = hmv6_key + +hmv7_put :: BS.ByteString +hmv7_put = "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." + +hmv7_pec :: BS.ByteString +hmv7_pec = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2" + +unit_tests :: TestTree +unit_tests = testGroup "ppad-sha256" [ + testGroup "hash" [ + cmp_hash "hv0" hv0_put hv0_pec + , cmp_hash "hv1" hv1_put hv1_pec + , cmp_hash "hv2" hv2_put hv2_pec + , cmp_hash "hv3" hv3_put hv3_pec + , cmp_hash "hv4" hv4_put hv4_pec + ] + , testGroup "hash_lazy" [ + cmp_hash_lazy "hv0" hv0_put hv0_pec + , cmp_hash_lazy "hv1" hv1_put hv1_pec + , cmp_hash_lazy "hv2" hv2_put hv2_pec + , cmp_hash_lazy "hv3" hv3_put hv3_pec + , cmp_hash_lazy "hv4" hv4_put hv4_pec + ] + -- uncomment me to run (slow, ~40s) + -- + -- , testGroup "hash_lazy (1GB input)" [ + -- testCase "hv5" $ do + -- let out = B16.encode (SHA256.hash_lazy hv5_put) + -- assertEqual mempty hv5_pec out + -- ] + , testGroup "hmac" [ + cmp_hmac "hmv1" hmv1_key hmv1_put hmv1_pec + , cmp_hmac "hmv2" hmv2_key hmv2_put hmv2_pec + , cmp_hmac "hmv3" hmv3_key hmv3_put hmv3_pec + , cmp_hmac "hmv4" hmv4_key hmv4_put hmv4_pec + , testCase "hmv5" $ do + let out = BS.take 32 $ B16.encode (SHA256.hmac hmv5_key hmv5_put) + assertEqual mempty hmv5_pec out + , testCase "hmv6" $ do + let keh = SHA256.hash hmv6_key + out = B16.encode (SHA256.hmac keh hmv6_put) + assertEqual mempty hmv6_pec out + , testCase "hmv7" $ do + let keh = SHA256.hash hmv7_key + out = B16.encode (SHA256.hmac keh hmv7_put) + assertEqual mempty hmv7_pec out + ] + , testGroup "hmac_lazy" [ + cmp_hmac_lazy "hmv1" hmv1_key hmv1_put hmv1_pec + , cmp_hmac_lazy "hmv2" hmv2_key hmv2_put hmv2_pec + , cmp_hmac_lazy "hmv3" hmv3_key hmv3_put hmv3_pec + , cmp_hmac_lazy "hmv4" hmv4_key hmv4_put hmv4_pec + , testCase "hmv5" $ do + let lut = BL.fromStrict hmv5_put + out = BS.take 32 $ B16.encode (SHA256.hmac_lazy hmv5_key lut) + assertEqual mempty hmv5_pec out + , testCase "hmv6" $ do + let keh = SHA256.hash hmv6_key + lut = BL.fromStrict hmv6_put + out = B16.encode (SHA256.hmac_lazy keh lut) + assertEqual mempty hmv6_pec out + , testCase "hmv7" $ do + let keh = SHA256.hash hmv7_key + lut = BL.fromStrict hmv7_put + out = B16.encode (SHA256.hmac_lazy keh lut) + assertEqual mempty hmv7_pec out + ] + ] + +cmp_hash :: String -> BS.ByteString -> BS.ByteString -> TestTree +cmp_hash msg put pec = testCase msg $ do + let out = B16.encode (SHA256.hash put) + assertEqual mempty pec out + +cmp_hash_lazy :: String -> BS.ByteString -> BS.ByteString -> TestTree +cmp_hash_lazy msg (BL.fromStrict -> put) pec = testCase msg $ do + let out = B16.encode (SHA256.hash_lazy put) + assertEqual mempty pec out + +cmp_hmac + :: String -> BS.ByteString -> BS.ByteString -> BS.ByteString -> TestTree +cmp_hmac msg key put pec = testCase msg $ do + let out = B16.encode (SHA256.hmac key put) + assertEqual mempty pec out + +cmp_hmac_lazy + :: String -> BS.ByteString -> BS.ByteString -> BS.ByteString -> TestTree +cmp_hmac_lazy msg key (BL.fromStrict -> put) pec = testCase msg $ do + let out = B16.encode (SHA256.hmac_lazy key put) + assertEqual mempty pec out - exitSuccess