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 rfc5869test struct { 31 hash string 32 key string 33 salt string 34 info string 35 outputLength uint32 36 okm string 37} 38 39func TestVectorsRFC5869(t *testing.T) { 40 // Test vectors from RFC 5869. 41 testvectors := []*rfc5869test{ 42 { 43 hash: "SHA256", 44 key: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", 45 salt: "000102030405060708090a0b0c", 46 info: "f0f1f2f3f4f5f6f7f8f9", 47 outputLength: 42, 48 okm: "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", 49 }, 50 { 51 hash: "SHA256", 52 key: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", 53 salt: "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", 54 info: "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", 55 outputLength: 82, 56 okm: "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87", 57 }, 58 { 59 hash: "SHA256", 60 key: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", 61 salt: "", 62 info: "", 63 outputLength: 42, 64 okm: "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8", 65 }, 66 { 67 hash: "SHA1", 68 key: "0b0b0b0b0b0b0b0b0b0b0b", 69 salt: "000102030405060708090a0b0c", 70 info: "f0f1f2f3f4f5f6f7f8f9", 71 outputLength: 42, 72 okm: "085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896", 73 }, 74 { 75 hash: "SHA1", 76 key: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", 77 salt: "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", 78 info: "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", 79 outputLength: 82, 80 okm: "0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4", 81 }, 82 { 83 hash: "SHA1", 84 key: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", 85 salt: "", 86 info: "", 87 outputLength: 42, 88 okm: "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918", 89 }, 90 { 91 hash: "SHA1", 92 key: "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", 93 salt: "", 94 info: "", 95 outputLength: 42, 96 okm: "2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48", 97 }, 98 } 99 for _, v := range testvectors { 100 key, err := hex.DecodeString(v.key) 101 if err != nil { 102 t.Errorf("Could not decode key: %v", err) 103 } 104 salt, err := hex.DecodeString(v.salt) 105 if err != nil { 106 t.Errorf("Could not decode salt: %v", err) 107 } 108 info, err := hex.DecodeString(v.info) 109 if err != nil { 110 t.Errorf("Could not decode info: %v", err) 111 } 112 p, err := subtle.NewHKDFPRF(v.hash, key, salt) 113 if err != nil { 114 t.Errorf("Could not create HKDF object: %v", err) 115 } 116 output, err := p.ComputePRF(info, v.outputLength) 117 if err != nil { 118 t.Errorf("Error computing HKDF: %v", err) 119 } 120 if hex.EncodeToString(output) != v.okm { 121 t.Errorf("Computation and test vector differ. Computation: %q, Test Vector %q", hex.EncodeToString(output), v.okm) 122 } 123 } 124} 125 126func TestHKDFPRFWycheproofCases(t *testing.T) { 127 testutil.SkipTestIfTestSrcDirIsNotSet(t) 128 for _, hash := range []string{"SHA1", "SHA256", "SHA512"} { 129 filename := fmt.Sprintf("hkdf_%s_test.json", strings.ToLower(hash)) 130 suite := new(hkdfSuite) 131 if err := testutil.PopulateSuite(suite, filename); err != nil { 132 t.Fatalf("Failed populating suite: %s", err) 133 } 134 for _, group := range suite.TestGroups { 135 for _, test := range group.Tests { 136 caseName := fmt.Sprintf("%s-%s-%s(%d):Case-%d", suite.Algorithm, group.Type, hash, group.KeySize, test.CaseID) 137 t.Run(caseName, func(t *testing.T) { 138 if uint32(len(test.IKM))*8 != group.KeySize { 139 t.Fatal("Invalid key length") 140 } 141 142 hkdfPRF, err := subtle.NewHKDFPRF(hash, test.IKM, test.Salt) 143 switch test.Result { 144 case "valid": 145 if err != nil { 146 t.Fatalf("NewHKDFPRF failed: %v", err) 147 } 148 res, err := hkdfPRF.ComputePRF(test.Info, test.Size) 149 if err != nil { 150 t.Fatalf("ComputePRF() failed: %v", err) 151 } 152 if !bytes.Equal(res, test.OKM) { 153 t.Errorf("ComputePRF() result and expected result do not match:\nComputed: %q\nExpected: %q", hex.EncodeToString(res), test.OKM) 154 } 155 156 case "invalid": 157 if err != nil { 158 return 159 } 160 res, err := hkdfPRF.ComputePRF(test.Info, test.Size) 161 if err != nil { 162 return 163 } 164 if bytes.Equal(res, test.OKM) { 165 t.Errorf("ComputePRF() result and invalid expected result match:\nComputed: %q\nExpected: %q", hex.EncodeToString(res), test.OKM) 166 } 167 168 default: 169 t.Fatalf("Unsupported test result: %q", test.Result) 170 } 171 }) 172 } 173 } 174 } 175} 176 177func TestHKDFPRFHash(t *testing.T) { 178 if _, err := subtle.NewHKDFPRF("SHA256", []byte{ 179 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 180 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err != nil { 181 t.Errorf("Expected NewHKDFPRF to work with SHA256: %v", err) 182 } 183 if _, err := subtle.NewHKDFPRF("SHA512", []byte{ 184 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 185 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err != nil { 186 t.Errorf("Expected NewHKDFPRF to work with SHA512: %v", err) 187 } 188 if _, err := subtle.NewHKDFPRF("SHA1", []byte{ 189 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 190 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err != nil { 191 t.Errorf("Expected NewHKDFPRF to work with SHA1: %v", err) 192 } 193 if _, err := subtle.NewHKDFPRF("md5", []byte{ 194 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 195 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err == nil { 196 t.Errorf("Expected NewHKDFPRF to fail with md5") 197 } 198} 199 200func TestHKDFPRFSalt(t *testing.T) { 201 if _, err := subtle.NewHKDFPRF("SHA256", []byte{ 202 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 203 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, nil); err != nil { 204 t.Errorf("Expected NewHKDFPRF to work nil salt: %v", err) 205 } 206 if _, err := subtle.NewHKDFPRF("SHA256", []byte{ 207 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 208 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}); err != nil { 209 t.Errorf("Expected NewHKDFPRF to work empty salt: %v", err) 210 } 211 if _, err := subtle.NewHKDFPRF("SHA256", []byte{ 212 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 213 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{0xaf, 0xfe, 0xc0, 0xff, 0xee}); err != nil { 214 t.Errorf("Expected NewHKDFPRF to work with salt: %v", err) 215 } 216} 217 218func TestHKDFPRFOutputLength(t *testing.T) { 219 for hash, length := range map[string]int{"SHA1": 20, "SHA256": 32, "SHA512": 64} { 220 prf, err := subtle.NewHKDFPRF(hash, []byte{ 221 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 222 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 223 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 224 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, []byte{}) 225 if err != nil { 226 t.Errorf("Expected NewHKDFPRF to work on 32 byte key with hash %s", hash) 227 } 228 for i := 0; i <= length*255; i++ { 229 output, err := prf.ComputePRF([]byte{0x01, 0x02}, uint32(i)) 230 if err != nil { 231 t.Errorf("Expected to be able to compute HKDF %s PRF with %d output length", hash, i) 232 } 233 if len(output) != i { 234 t.Errorf("Expected HKDF %s PRF to compute %d bytes, got %d", hash, i, len(output)) 235 } 236 } 237 for i := length*255 + 1; i < length*255+100; i++ { 238 _, err := prf.ComputePRF([]byte{0x01, 0x02}, uint32(i)) 239 if err == nil { 240 t.Errorf("Expected to not be able to compute HKDF %s PRF with %d output length", hash, i) 241 } 242 } 243 } 244} 245 246func TestValidateHKDFPRFParams(t *testing.T) { 247 if err := subtle.ValidateHKDFPRFParams("SHA256", 32, []byte{}); err != nil { 248 t.Errorf("Unexpected error for valid HKDF PRF params: %v", err) 249 } 250 if err := subtle.ValidateHKDFPRFParams("SHA256", 32, nil); err != nil { 251 t.Errorf("Unexpected error for valid HKDF PRF params: %v", err) 252 } 253 if err := subtle.ValidateHKDFPRFParams("SHA256", 32, []byte{0xaf, 0xfe, 0xc0, 0xff, 0xee}); err != nil { 254 t.Errorf("Unexpected error for salted valid HKDF PRF params: %v", err) 255 } 256 if err := subtle.ValidateHKDFPRFParams("SHA256", 4, []byte{}); err == nil { 257 t.Errorf("Short key size not detected for HKDF PRF params") 258 } 259 if err := subtle.ValidateHKDFPRFParams("md5", 32, []byte{}); err == nil { 260 t.Errorf("Weak hash function not detected for HKDF PRF params") 261 } 262 if err := subtle.ValidateHKDFPRFParams("SHA1", 32, []byte{}); err == nil { 263 t.Errorf("Weak hash function not detected for HKDF PRF params") 264 } 265} 266