aboutsummaryrefslogtreecommitdiff
path: root/tests/Data/HMACTests.hs
blob: 162fcea591c4137a2583a15d3cee5a5a52c5e28c (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
-- 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 (md5, sha1, sha224, sha256, sha384, sha512)
import Data.HMAC (HMAC(HMAC), HMACParams(..), hmac)

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

hmacTestCase :: HMACParams -> Lazy.ByteString -> ByteString -> TestTree
hmacTestCase params input output = hmacTestCase' (abbreviate input) params input output

hmacTestCase' :: String -> HMACParams -> Lazy.ByteString -> ByteString -> TestTree
hmacTestCase' description params input output =
  testCase description $ hmac params input `isRightAndHolds` hexHMAC output

-- | Tests from RFC 2202.
testRFC2202 = testGroup "RFC 2202" [testMD5, testSHA1]
  where testMD5 = testGroup "MD5"
          [ hmacTestCase
              HMACParams { algorithm = md5
                         , secretKey = ByteString.replicate 16 0x0b }
              "Hi There"
              "9294727a3638bb1c13f48ef8158bfc9d"
          , hmacTestCase
              HMACParams { algorithm = md5
                         , secretKey = "Jefe" }
              "what do ya want for nothing?"
              "750c783e6ab0b503eaa86e310a5db738"
          , hmacTestCase
              HMACParams { algorithm = md5
                         , secretKey = ByteString.replicate 16 0xaa }
              (ByteString.Lazy.replicate 50 0xdd)
              "56be34521d144c88dbb8c733f0e8b3f6"
          , hmacTestCase
              HMACParams { algorithm = md5
                         , secretKey = ByteString.pack [0x01 .. 0x19] }
              (ByteString.Lazy.replicate 50 0xcd)
              "697eaf0aca3a3aea3a75164746ffaa79"
          , hmacTestCase
              HMACParams { algorithm = md5
                         , secretKey = ByteString.replicate 16 0x0c }
              "Test With Truncation"
              "56461ef2342edc00f9bab995690efd4c"
          , hmacTestCase
              HMACParams { algorithm = md5
                         , secretKey = ByteString.replicate 80 0xaa }
              "Test Using Larger Than Block-Size Key - Hash Key First"
              "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"
          , hmacTestCase
              HMACParams { algorithm = md5
                         , secretKey = ByteString.replicate 80 0xaa }
              "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
              "6f630fad67cda0ee1fb1f562db3aa53e" ]
        testSHA1 = testGroup "SHA-1"
          [ hmacTestCase
              HMACParams { algorithm = sha1
                         , secretKey = ByteString.replicate 20 0x0b }
              "Hi There"
              "b617318655057264e28bc0b6fb378c8ef146be00"
          , hmacTestCase
              HMACParams { algorithm = sha1
                         , secretKey = "Jefe" }
              "what do ya want for nothing?"
              "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"
          , hmacTestCase
              HMACParams { algorithm = sha1
                         , secretKey = ByteString.replicate 20 0xaa }
              (ByteString.Lazy.replicate 50 0xdd)
              "125d7342b9ac11cd91a39af48aa17b4f63f175d3"
          , hmacTestCase
              HMACParams { algorithm = sha1
                         , secretKey = ByteString.pack [0x01 .. 0x19] }
              (ByteString.Lazy.replicate 50 0xcd)
              "4c9007f4026250c6bc8414f9bf50c86c2d7235da"
          , hmacTestCase
              HMACParams { algorithm = sha1
                         , secretKey = ByteString.replicate 20 0x0c }
              "Test With Truncation"
              "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"
          , hmacTestCase
              HMACParams { algorithm = sha1
                         , secretKey = ByteString.replicate 80 0xaa }
              "Test Using Larger Than Block-Size Key - Hash Key First"
              "aa4ae5e15272d00e95705637ce8a3b55ed402112"
          , hmacTestCase
              HMACParams { algorithm = sha1
                         , secretKey = 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)" $
  [ hmacTestCase
      HMACParams { algorithm = sha1
                 , secretKey = ByteString.pack [0 .. 0x3f] }
      "Sample #1"
      "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a"
  , hmacTestCase
      HMACParams { algorithm = sha1
                 , secretKey = ByteString.pack [0x30 .. 0x43] }
      "Sample #2"
      "0922d3405faa3d194f82a45830737d5cc6c75d24"
  , hmacTestCase
      HMACParams { algorithm = sha1
                 , secretKey = ByteString.pack [0x50 .. 0xb3] }
      "Sample #3"
      "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa"
  ] ++ [truncatedFIPS198Test]
  where truncatedFIPS198Test =
          let input = "Sample #4" in
          testCase (abbreviate input) $
            (truncateHMAC 24 <$> hmac HMACParams { algorithm = 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" HMACParams { algorithm = sha224, secretKey = key } input sha224Output
          , hmacTestCase' "SHA-256" HMACParams { algorithm = sha256, secretKey = key } input sha256Output
          , hmacTestCase' "SHA-384" HMACParams { algorithm = sha384, secretKey = key } input sha384Output
          , hmacTestCase' "SHA-512" HMACParams { algorithm = sha512, secretKey = 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 = ByteString.replicate 20 0x0c
              input = "Test With Truncation"
              truncatedTestCase description algo output =
                testCase description $
                  (truncateHMAC 32 <$> hmac HMACParams { algorithm = algo, secretKey = 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)