aboutsummaryrefslogtreecommitdiff
path: root/tests/Data/HMACTests.hs
blob: 10856f50eeaa676a7d95743029fbf9d138779a28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
-- Copyright 2018 Google LLC
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
--     https://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.

{-# LANGUAGE OverloadedStrings #-}

module Data.HMACTests (tests) where

import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as Lazy (ByteString)
import qualified Data.ByteString.Lazy as ByteString.Lazy
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (testCase)

import BTLS.Assertions (isRightAndHolds)
import BTLS.TestUtilities (abbreviate, hex)
import Data.Digest (Algorithm, md5, sha1, sha224, sha256, sha384, sha512)
import Data.HMAC (HMAC(HMAC), SecretKey(SecretKey), hmac)

tests :: TestTree
tests = testGroup "Data.HMAC"
  [ testRFC2202
  , testFIPS198
  , testRFC4231 ]

hmacTestCase :: Algorithm -> ByteString -> Lazy.ByteString -> ByteString -> TestTree
hmacTestCase algo key input output = hmacTestCase' (abbreviate input) algo key input output

hmacTestCase' :: String -> Algorithm -> ByteString -> Lazy.ByteString -> ByteString -> TestTree
hmacTestCase' description algo key input output =
  testCase description $ hmac algo (SecretKey key) input `isRightAndHolds` hexHMAC output

md5TestCase, sha1TestCase :: ByteString -> Lazy.ByteString -> ByteString -> TestTree
md5TestCase = hmacTestCase md5
sha1TestCase = hmacTestCase sha1

-- | Tests from RFC 2202.
testRFC2202 = testGroup "RFC 2202" [testMD5, testSHA1]
  where testMD5 = testGroup "MD5"
          [ md5TestCase (ByteString.replicate 16 0x0b) "Hi There" "9294727a3638bb1c13f48ef8158bfc9d"
          , md5TestCase "Jefe" "what do ya want for nothing?" "750c783e6ab0b503eaa86e310a5db738"
          , md5TestCase (ByteString.replicate 16 0xaa) (ByteString.Lazy.replicate 50 0xdd) "56be34521d144c88dbb8c733f0e8b3f6"
          , md5TestCase (ByteString.pack [0x01 .. 0x19]) (ByteString.Lazy.replicate 50 0xcd) "697eaf0aca3a3aea3a75164746ffaa79"
          , md5TestCase (ByteString.replicate 16 0x0c) ("Test With Truncation") "56461ef2342edc00f9bab995690efd4c"
          , md5TestCase (ByteString.replicate 80 0xaa) ("Test Using Larger Than Block-Size Key - Hash Key First") "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"
          , md5TestCase (ByteString.replicate 80 0xaa) ("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data") "6f630fad67cda0ee1fb1f562db3aa53e" ]
        testSHA1 = testGroup "SHA-1"
          [ sha1TestCase (ByteString.replicate 20 0x0b) ("Hi There") "b617318655057264e28bc0b6fb378c8ef146be00"
          , sha1TestCase "Jefe" "what do ya want for nothing?" "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"
          , sha1TestCase (ByteString.replicate 20 0xaa) (ByteString.Lazy.replicate 50 0xdd) "125d7342b9ac11cd91a39af48aa17b4f63f175d3"
          , sha1TestCase (ByteString.pack [0x01 .. 0x19]) (ByteString.Lazy.replicate 50 0xcd) "4c9007f4026250c6bc8414f9bf50c86c2d7235da"
          , sha1TestCase (ByteString.replicate 20 0x0c) ("Test With Truncation") "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"
          , sha1TestCase (ByteString.replicate 80 0xaa) ("Test Using Larger Than Block-Size Key - Hash Key First") "aa4ae5e15272d00e95705637ce8a3b55ed402112"
          , sha1TestCase (ByteString.replicate 80 0xaa) ("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data") "e8e99d0f45237d786d6bbaa7965c7808bbff1a91" ]

-- | Tests from FIPS 198.
testFIPS198 = testGroup "FIPS 198 (SHA-1)" $
  [ sha1TestCase (ByteString.pack [0 .. 0x3f]) "Sample #1" "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a"
  , sha1TestCase (ByteString.pack [0x30 .. 0x43]) "Sample #2" "0922d3405faa3d194f82a45830737d5cc6c75d24"
  , sha1TestCase (ByteString.pack [0x50 .. 0xb3]) "Sample #3" "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa"
  ] ++ [truncatedFIPS198Test]
  where truncatedFIPS198Test =
          let input = "Sample #4" in
          testCase (abbreviate input) $
            (truncateHMAC 24 <$> hmac sha1 (SecretKey $ ByteString.pack [0x70 .. 0xa0]) input)
            `isRightAndHolds` hexHMAC "9ea886efe268dbecce420c75"

-- | Tests from RFC 4231.
testRFC4231 = testGroup "RFC 4231" $
  let rfc4231TestCase key input sha224Output sha256Output sha384Output sha512Output =
        testGroup (abbreviate input)
          [ hmacTestCase' "SHA-224" sha224 key input sha224Output
          , hmacTestCase' "SHA-256" sha256 key input sha256Output
          , hmacTestCase' "SHA-384" sha384 key input sha384Output
          , hmacTestCase' "SHA-512" sha512 key input sha512Output ] in
  [ rfc4231TestCase (ByteString.replicate 20 0x0b) "Hi There"
      "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"
      "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
      "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6"
      "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"
  , rfc4231TestCase ("Jefe") "what do ya want for nothing?"
      "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44"
      "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
      "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649"
      "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"
  , rfc4231TestCase (ByteString.replicate 20 0xaa) (ByteString.Lazy.replicate 50 0xdd)
      "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea"
      "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"
      "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27"
      "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb"
  , rfc4231TestCase (ByteString.pack [0x01 .. 0x19]) (ByteString.Lazy.replicate 50 0xcd)
      "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a"
      "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"
      "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb"
      "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"
  , rfc4231TestCase (ByteString.replicate 131 0xaa) "Test Using Larger Than Block-Size Key - Hash Key First"
      "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e"
      "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"
      "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952"
      "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598"
  , rfc4231TestCase (ByteString.replicate 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."
      "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1"
      "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"
      "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e"
      "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"
  ] ++ [truncatedRFC4231Test]
  where truncatedRFC4231Test =
          let key = SecretKey $ ByteString.replicate 20 0x0c
              input = "Test With Truncation"
              truncatedTestCase description algo output =
                testCase description $
                  (truncateHMAC 32 <$> hmac algo key input) `isRightAndHolds` hexHMAC output in
          testGroup (abbreviate input)
            [ truncatedTestCase "SHA-224" sha224 "0e2aea68a90c8d37c988bcdb9fca6fa8"
            , truncatedTestCase "SHA-256" sha256 "a3b6167473100ee06e0c796c2955552b"
            , truncatedTestCase "SHA-384" sha384 "3abf34c3503b2a23a46efc619baef897"
            , truncatedTestCase "SHA-512" sha512 "415fad6271580a531d4179bc891d87a6" ]

hexHMAC :: ByteString -> HMAC
hexHMAC = HMAC . hex

truncateHMAC :: Int -> HMAC -> HMAC
truncateHMAC n (HMAC m) = HMAC (ByteString.take n m)