1// Copyright 2020 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package subtle_test 18 19import ( 20 "bytes" 21 "encoding/hex" 22 "fmt" 23 "strings" 24 "testing" 25 26 "github.com/google/tink/go/prf/subtle" 27 "github.com/google/tink/go/testutil" 28) 29 30type rfc4868test struct { 31 key string 32 data string 33 prf map[string]string 34} 35 36func TestVectorsRFC4868(t *testing.T) { 37 // Test vectors from RFC 4868. 38 testvectors := []*rfc4868test{ 39 { 40 key: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", 41 data: "4869205468657265", 42 prf: map[string]string{ 43 "SHA256": "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", 44 "SHA512": "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854", 45 }, 46 }, 47 { 48 key: "4a656665", 49 data: "7768617420646f2079612077616e7420666f72206e6f7468696e673f", 50 prf: map[string]string{ 51 "SHA256": "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", 52 "SHA512": "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737", 53 }, 54 }, 55 { 56 key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 57 data: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", 58 prf: map[string]string{ 59 "SHA256": "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", 60 "SHA512": "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb", 61 }, 62 }, 63 { 64 key: "0102030405060708090a0b0c0d0e0f10111213141516171819", 65 data: "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", 66 prf: map[string]string{ 67 "SHA256": "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", 68 "SHA512": "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd", 69 }, 70 }, 71 { 72 key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 73 data: "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374", 74 prf: map[string]string{ 75 "SHA256": "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", 76 "SHA512": "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598", 77 }, 78 }, 79 { 80 key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 81 data: "5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e", 82 prf: map[string]string{ 83 "SHA256": "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", 84 "SHA512": "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58", 85 }, 86 }, 87 } 88 for _, v := range testvectors { 89 key, err := hex.DecodeString(v.key) 90 if err != nil { 91 t.Errorf("Could not decode key: %v", err) 92 } 93 data, err := hex.DecodeString(v.data) 94 if err != nil { 95 t.Errorf("Could not decode data: %v", err) 96 } 97 for hash, e := range v.prf { 98 h, err := subtle.NewHMACPRF(hash, key) 99 if err != nil { 100 t.Errorf("Could not create HMAC PRF object: %v", err) 101 } 102 output, err := h.ComputePRF(data, uint32(len(e)/2)) 103 if err != nil { 104 t.Errorf("Error computing HMAC: %v", err) 105 } 106 if hex.EncodeToString(output) != e { 107 t.Errorf("Computation and test vector differ. Computation: %q, Test Vector %q", hex.EncodeToString(output), e) 108 } 109 } 110 } 111} 112 113func TestHMACPRFWycheproofCases(t *testing.T) { 114 testutil.SkipTestIfTestSrcDirIsNotSet(t) 115 for _, hash := range []string{"SHA1", "SHA256", "SHA512"} { 116 filename := fmt.Sprintf("hmac_%s_test.json", strings.ToLower(hash)) 117 suite := new(macSuite) 118 if err := testutil.PopulateSuite(suite, filename); err != nil { 119 t.Fatalf("Failed populating suite: %s", err) 120 } 121 for _, group := range suite.TestGroups { 122 groupName := fmt.Sprintf("%s-%s-%s(%d)", suite.Algorithm, group.Type, hash, group.KeySize) 123 if group.TagSize%8 != 0 { 124 t.Errorf("For %s, requested tag size is not a multiple of 8, but %d", groupName, group.TagSize) 125 } 126 127 for _, test := range group.Tests { 128 caseName := fmt.Sprintf("%s:Case-%d", groupName, test.CaseID) 129 t.Run(caseName, func(t *testing.T) { 130 131 h, err := subtle.NewHMACPRF(hash, test.Key) 132 switch test.Result { 133 case "valid": 134 if err != nil { 135 t.Fatalf("NewHMACPRF() failed: %v", err) 136 } 137 res, err := h.ComputePRF(test.Message, group.TagSize/8) 138 if err != nil { 139 t.Fatalf("ComputePRF() failed: %v", err) 140 } 141 if !bytes.Equal(res, test.Tag) { 142 t.Errorf("ComputePRF() result and expected result do not match:\nComputed: %q\nExpected: %q", hex.EncodeToString(res), hex.EncodeToString(test.Tag)) 143 } 144 145 case "invalid": 146 if err != nil { 147 return 148 } 149 res, err := h.ComputePRF(test.Message, group.TagSize/8) 150 if err != nil { 151 return 152 } 153 if bytes.Equal(res, test.Tag) { 154 t.Errorf("ComputePRF() result and invalid expected result match:\nComputed: %q\nExpected: %q", hex.EncodeToString(res), hex.EncodeToString(test.Tag)) 155 } 156 157 default: 158 t.Fatalf("Unsupported test result: %q", test.Result) 159 } 160 }) 161 } 162 } 163 } 164} 165 166func TestHMACPRFHash(t *testing.T) { 167 if _, err := subtle.NewHMACPRF("SHA256", []byte{ 168 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 169 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}); err != nil { 170 t.Errorf("Expected NewHMACPRF to work with SHA256: %v", err) 171 } 172 if _, err := subtle.NewHMACPRF("SHA512", []byte{ 173 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 174 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}); err != nil { 175 t.Errorf("Expected NewHMACPRF to work with SHA512: %v", err) 176 } 177 if _, err := subtle.NewHMACPRF("SHA1", []byte{ 178 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 179 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}); err != nil { 180 t.Errorf("Expected NewHMACPRF to work with SHA1: %v", err) 181 } 182 if _, err := subtle.NewHMACPRF("md5", []byte{ 183 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 184 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}); err == nil { 185 t.Errorf("Expected NewHMACPRF to fail with md5") 186 } 187} 188 189func TestHMACPRFOutputLength(t *testing.T) { 190 for hash, length := range map[string]int{"SHA1": 20, "SHA256": 32, "SHA512": 64} { 191 prf, err := subtle.NewHMACPRF(hash, []byte{ 192 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 193 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 194 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 195 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}) 196 if err != nil { 197 t.Errorf("Expected NewHMACPRF to work on 32 byte key with hash %s", hash) 198 } 199 for i := 0; i <= length; i++ { 200 output, err := prf.ComputePRF([]byte{0x01, 0x02}, uint32(i)) 201 if err != nil { 202 t.Errorf("Expected to be able to compute HMAC %s PRF with %d output length", hash, i) 203 } 204 if len(output) != i { 205 t.Errorf("Expected HMAC %s PRF to compute %d bytes, got %d", hash, i, len(output)) 206 } 207 } 208 for i := length + 1; i < 100; i++ { 209 _, err := prf.ComputePRF([]byte{0x01, 0x02}, uint32(i)) 210 if err == nil { 211 t.Errorf("Expected to not be able to compute HMAC %s PRF with %d output length", hash, i) 212 } 213 } 214 } 215} 216 217func TestValidateHMACPRFParams(t *testing.T) { 218 if err := subtle.ValidateHMACPRFParams("SHA256", 32); err != nil { 219 t.Errorf("Unexpected error for valid HMAC PRF params: %v", err) 220 } 221 if err := subtle.ValidateHMACPRFParams("SHA256", 4); err == nil { 222 t.Errorf("Short key size not detected for HMAC PRF params") 223 } 224 if err := subtle.ValidateHMACPRFParams("md5", 32); err == nil { 225 t.Errorf("Weak hash function not detected for HMAC PRF params") 226 } 227} 228