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 prf_test 18 19import ( 20 "bytes" 21 "encoding/hex" 22 "fmt" 23 "testing" 24 25 "github.com/google/go-cmp/cmp" 26 "github.com/google/go-cmp/cmp/cmpopts" 27 "github.com/google/tink/go/insecurecleartextkeyset" 28 "github.com/google/tink/go/internal/internalregistry" 29 "github.com/google/tink/go/keyset" 30 "github.com/google/tink/go/mac" 31 "github.com/google/tink/go/monitoring" 32 "github.com/google/tink/go/prf" 33 "github.com/google/tink/go/testing/fakemonitoring" 34 "github.com/google/tink/go/testutil" 35 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 36) 37 38const ( 39 maxAutocorrelation = 100 40) 41 42func addKeyAndReturnID(m *keyset.Manager, template *tinkpb.KeyTemplate) (uint32, error) { 43 keyID, err := m.Add(template) 44 if err != nil { 45 return 0, fmt.Errorf("Could not add key from the given template: %v", err) 46 } 47 err = m.SetPrimary(keyID) 48 if err != nil { 49 return 0, fmt.Errorf("Could set key as primary: %v", err) 50 } 51 return keyID, nil 52} 53 54func TestFactoryBasic(t *testing.T) { 55 manager := keyset.NewManager() 56 aescmacID, err := addKeyAndReturnID(manager, prf.AESCMACPRFKeyTemplate()) 57 if err != nil { 58 t.Errorf("Could not add AES CMAC PRF key: %v", err) 59 } 60 61 hmacsha256ID, err := addKeyAndReturnID(manager, prf.HMACSHA256PRFKeyTemplate()) 62 if err != nil { 63 t.Errorf("Could not add HMAC SHA256 PRF key: %v", err) 64 } 65 hkdfsha256ID, err := addKeyAndReturnID(manager, prf.HKDFSHA256PRFKeyTemplate()) 66 if err != nil { 67 t.Errorf("Could not add HKDF SHA256 PRF key: %v", err) 68 } 69 hmacsha512ID, err := addKeyAndReturnID(manager, prf.HMACSHA512PRFKeyTemplate()) 70 if err != nil { 71 t.Errorf("Could not add HMAC SHA512 PRF key: %v", err) 72 } 73 handle, err := manager.Handle() 74 if err != nil { 75 t.Errorf("Could not obtain handle: %v", err) 76 } 77 prfSet, err := prf.NewPRFSet(handle) 78 if err != nil { 79 t.Errorf("Could not create prf.Set with standard key templates: %v", err) 80 } 81 primaryID := prfSet.PrimaryID 82 if primaryID != hmacsha512ID { 83 t.Errorf("Primary ID %d should be the ID %d, which was added last", primaryID, hmacsha512ID) 84 } 85 for _, length := range []uint32{1, 10, 16, 17, 32, 33, 64, 65, 100, 8160, 8161} { 86 results := [][]byte{} 87 for id, prf := range prfSet.PRFs { 88 ok := true 89 switch { 90 case length > 16 && id == aescmacID: 91 ok = false 92 case length > 32 && id == hmacsha256ID: 93 ok = false 94 case length > 64 && id == hmacsha512ID: 95 ok = false 96 case length > 8160 && id == hkdfsha256ID: 97 ok = false 98 } 99 100 result1, err := prf.ComputePRF([]byte("The input"), length) 101 switch { 102 case err != nil && !ok: 103 continue 104 case err != nil: 105 t.Errorf("Expected to be able to compute %d bytes of PRF output: %v", length, err) 106 continue 107 case !ok: 108 t.Errorf("Expected to be unable to compute %d bytes PRF output", length) 109 continue 110 } 111 result2, err := prf.ComputePRF([]byte("The different input"), length) 112 switch { 113 case err != nil && !ok: 114 continue 115 case err != nil: 116 t.Errorf("Expected to be able to compute %d bytes of PRF output: %v", length, err) 117 continue 118 case !ok: 119 t.Errorf("Expected to be unable to compute %d bytes PRF output", length) 120 continue 121 } 122 result3, err := prf.ComputePRF([]byte("The input"), length) 123 switch { 124 case err != nil && !ok: 125 continue 126 case err != nil: 127 t.Errorf("Expected to be able to compute %d bytes of PRF output: %v", length, err) 128 continue 129 case !ok: 130 t.Errorf("Expected to be unable to compute %d bytes PRF output", length) 131 continue 132 } 133 if id == primaryID { 134 primaryResult, err := prfSet.ComputePrimaryPRF([]byte("The input"), length) 135 switch { 136 case err != nil && !ok: 137 continue 138 case err != nil: 139 t.Errorf("Expected to be able to compute %d bytes of PRF output: %v", length, err) 140 continue 141 case !ok: 142 t.Errorf("Expected to be unable to compute %d bytes PRF output", length) 143 continue 144 } 145 if hex.EncodeToString(result1) != hex.EncodeToString(primaryResult) { 146 t.Errorf("Expected manual call of ComputePRF of primary PRF and ComputePrimaryPRF with the same input to produce the same output, but got %q and %q", result1, primaryResult) 147 } 148 } 149 if hex.EncodeToString(result1) != hex.EncodeToString(result3) { 150 t.Errorf("Expected different calls with the same input to produce the same output, but got %q and %q", result1, result3) 151 } 152 results = append(results, result1) 153 results = append(results, result2) 154 } 155 runZTests(results, t) 156 } 157} 158 159func TestNonRawKeys(t *testing.T) { 160 template := prf.AESCMACPRFKeyTemplate() 161 template.OutputPrefixType = tinkpb.OutputPrefixType_TINK 162 h, err := keyset.NewHandle(template) 163 if err != nil { 164 t.Errorf("Couldn't create keyset: %v", err) 165 } 166 _, err = prf.NewPRFSet(h) 167 if err == nil { 168 t.Errorf("Expected non RAW prefix to fail to create prf.Set") 169 } 170 m := keyset.NewManagerFromHandle(h) 171 _, err = addKeyAndReturnID(m, prf.HMACSHA256PRFKeyTemplate()) 172 if err != nil { 173 t.Errorf("Expected to be able to add keys to the keyset: %v", err) 174 } 175 h, err = m.Handle() 176 if err != nil { 177 t.Errorf("Expected to be able to create keyset handle: %v", err) 178 } 179 _, err = prf.NewPRFSet(h) 180 if err == nil { 181 t.Errorf("Expected mixed prefix keyset to fail to create prf.Set") 182 } 183} 184 185func TestNonPRFPrimitives(t *testing.T) { 186 template := mac.AESCMACTag128KeyTemplate() 187 template.OutputPrefixType = tinkpb.OutputPrefixType_RAW 188 h, err := keyset.NewHandle(template) 189 if err != nil { 190 t.Errorf("Couldn't create keyset: %v", err) 191 } 192 _, err = prf.NewPRFSet(h) 193 if err == nil { 194 t.Errorf("Expected non PRF primitive to fail to create prf.Set") 195 } 196 m := keyset.NewManagerFromHandle(h) 197 _, err = addKeyAndReturnID(m, prf.HMACSHA256PRFKeyTemplate()) 198 if err != nil { 199 t.Errorf("Expected to be able to add keys to the keyset: %v", err) 200 } 201 h, err = m.Handle() 202 if err != nil { 203 t.Errorf("Expected to be able to create keyset handle: %v", err) 204 } 205 _, err = prf.NewPRFSet(h) 206 if err == nil { 207 t.Errorf("Expected mixed primitive keyset to fail to create prf.Set") 208 } 209} 210 211func runZTests(results [][]byte, t *testing.T) { 212 for i, result1 := range results { 213 if err := testutil.ZTestUniformString(result1); err != nil { 214 t.Errorf("Expected PRF output to pass uniformity z test: %v", err) 215 } 216 if len(result1) <= maxAutocorrelation { 217 if err := testutil.ZTestAutocorrelationUniformString(result1); err != nil { 218 t.Errorf("Expected PRF output to pass autocorrelation test: %v", err) 219 } 220 } 221 for j := i + 1; j < len(results); j++ { 222 result2 := results[j] 223 if err := testutil.ZTestCrosscorrelationUniformStrings(result1, result2); err != nil { 224 t.Errorf("Expected different PRF outputs to be uncorrelated: %v", err) 225 } 226 } 227 } 228} 229 230func TestPrimitiveFactoryComputePRFWithoutAnnotationsDoesNothing(t *testing.T) { 231 defer internalregistry.ClearMonitoringClient() 232 client := fakemonitoring.NewClient("fake-client") 233 if err := internalregistry.RegisterMonitoringClient(client); err != nil { 234 t.Fatalf("internalregistry.RegisterMonitoringClient() err = %v, want nil", err) 235 } 236 kh, err := keyset.NewHandle(prf.HMACSHA256PRFKeyTemplate()) 237 if err != nil { 238 t.Fatalf("keyset.NewHandle() err = %v, want nil", err) 239 } 240 prfSet, err := prf.NewPRFSet(kh) 241 if err != nil { 242 t.Fatalf("prf.NewPRFSet() err = %v, want nil", err) 243 } 244 if _, err := prfSet.ComputePrimaryPRF([]byte("input_data"), 32); err != nil { 245 t.Fatalf("prfSet.ComputePrimaryPRF() err = %v, want nil", err) 246 } 247 failures := len(client.Failures()) 248 if failures != 0 { 249 t.Errorf("len(client.Failures()) = %d, want 0", failures) 250 } 251 got := client.Events() 252 if got != nil { 253 t.Errorf("client.Events() = %v, want nil", got) 254 } 255} 256 257func TestPrimitiveFactoryMonitoringWithAnnotationsComputePRFFailureIsLogged(t *testing.T) { 258 defer internalregistry.ClearMonitoringClient() 259 client := fakemonitoring.NewClient("fake-client") 260 if err := internalregistry.RegisterMonitoringClient(client); err != nil { 261 t.Fatalf("internalregistry.RegisterMonitoringClient() err = %v, want nil", err) 262 } 263 kh, err := keyset.NewHandle(prf.HMACSHA256PRFKeyTemplate()) 264 if err != nil { 265 t.Fatalf("keyset.NewHandle() err = %v, want nil", err) 266 } 267 buff := &bytes.Buffer{} 268 if err := insecurecleartextkeyset.Write(kh, keyset.NewBinaryWriter(buff)); err != nil { 269 t.Fatalf("insecurecleartextkeyset.Write() err = %v, want nil", err) 270 } 271 annotations := map[string]string{"foo": "bar"} 272 mh, err := insecurecleartextkeyset.Read(keyset.NewBinaryReader(buff), keyset.WithAnnotations(annotations)) 273 if err != nil { 274 t.Fatalf("insecurecleartextkeyset.Read() err = %v, want nil", err) 275 } 276 prfSet, err := prf.NewPRFSet(mh) 277 if err != nil { 278 t.Fatalf("prf.NewPRFSet() err = %v, want nil", err) 279 } 280 data := []byte("input_data") 281 if _, err := prfSet.ComputePrimaryPRF(data, 64); err == nil { 282 t.Fatalf("prfSet.ComputePrimaryPRF() err = nil, want non-nil errors") 283 } 284 got := client.Failures() 285 want := []*fakemonitoring.LogFailure{ 286 { 287 Context: monitoring.NewContext( 288 "prf", 289 "compute", 290 &monitoring.KeysetInfo{ 291 Annotations: annotations, 292 Entries: []*monitoring.Entry{ 293 { 294 KeyID: kh.KeysetInfo().GetPrimaryKeyId(), 295 Status: monitoring.Enabled, 296 KeyType: "tink.HmacPrfKey", 297 KeyPrefix: "RAW", 298 }, 299 }, 300 PrimaryKeyID: kh.KeysetInfo().GetPrimaryKeyId(), 301 }, 302 ), 303 }, 304 } 305 if diff := cmp.Diff(want, got); diff != "" { 306 t.Errorf("%v", diff) 307 } 308} 309 310func TestPrimitiveFactoryIndividualPrfWithAnnotatonsLogsCompute(t *testing.T) { 311 defer internalregistry.ClearMonitoringClient() 312 client := fakemonitoring.NewClient("fake-client") 313 if err := internalregistry.RegisterMonitoringClient(client); err != nil { 314 t.Fatalf("internalregistry.RegisterMonitoringClient() err = %v, want nil", err) 315 } 316 kh, err := keyset.NewHandle(prf.HMACSHA256PRFKeyTemplate()) 317 if err != nil { 318 t.Fatalf("keyset.NewHandle() err = %v, want nil", err) 319 } 320 manager := keyset.NewManagerFromHandle(kh) 321 hmac512KeyID, err := manager.Add(prf.HMACSHA512PRFKeyTemplate()) 322 if err != nil { 323 t.Fatalf("manager.Add() err = %v, want nil", err) 324 } 325 aesKeyID, err := manager.Add(prf.AESCMACPRFKeyTemplate()) 326 if err != nil { 327 t.Fatalf("manager.Add() err = %v, want nil", err) 328 } 329 kh, err = manager.Handle() 330 if err != nil { 331 t.Fatalf("manager.Handle() err = %v, want nil", err) 332 } 333 buff := &bytes.Buffer{} 334 if err := insecurecleartextkeyset.Write(kh, keyset.NewBinaryWriter(buff)); err != nil { 335 t.Fatalf("insecurecleartextkeyset.Write() err = %v, want nil", err) 336 } 337 annotations := map[string]string{"foo": "bar"} 338 mh, err := insecurecleartextkeyset.Read(keyset.NewBinaryReader(buff), keyset.WithAnnotations(annotations)) 339 if err != nil { 340 t.Fatalf("insecurecleartextkeyset.Read() err = %v, want nil", err) 341 } 342 prfSet, err := prf.NewPRFSet(mh) 343 if err != nil { 344 t.Fatalf("prf.NewPRFSet() err = %v, want nil", err) 345 } 346 for _, p := range prfSet.PRFs { 347 if _, err := p.ComputePRF([]byte("input_data"), 16); err != nil { 348 t.Fatalf("p.ComputePRF() err = %v, want nil", err) 349 } 350 351 } 352 got := client.Events() 353 wantKeysetInfo := &monitoring.KeysetInfo{ 354 PrimaryKeyID: kh.KeysetInfo().GetPrimaryKeyId(), 355 Entries: []*monitoring.Entry{ 356 { 357 KeyID: kh.KeysetInfo().GetPrimaryKeyId(), 358 Status: monitoring.Enabled, 359 KeyType: "tink.HmacPrfKey", 360 KeyPrefix: "RAW", 361 }, 362 { 363 KeyID: hmac512KeyID, 364 Status: monitoring.Enabled, 365 KeyType: "tink.HmacPrfKey", 366 KeyPrefix: "RAW", 367 }, 368 { 369 KeyID: aesKeyID, 370 Status: monitoring.Enabled, 371 KeyType: "tink.AesCmacPrfKey", 372 KeyPrefix: "RAW", 373 }, 374 }, 375 Annotations: annotations, 376 } 377 want := []*fakemonitoring.LogEvent{ 378 { 379 Context: monitoring.NewContext("prf", "compute", wantKeysetInfo), 380 KeyID: kh.KeysetInfo().GetKeyInfo()[0].GetKeyId(), 381 NumBytes: len("input_data"), 382 }, 383 { 384 Context: monitoring.NewContext("prf", "compute", wantKeysetInfo), 385 KeyID: kh.KeysetInfo().GetKeyInfo()[1].GetKeyId(), 386 NumBytes: len("input_data"), 387 }, 388 { 389 Context: monitoring.NewContext("prf", "compute", wantKeysetInfo), 390 KeyID: kh.KeysetInfo().GetKeyInfo()[2].GetKeyId(), 391 NumBytes: len("input_data"), 392 }, 393 } 394 eventCmp := func(a, b *fakemonitoring.LogEvent) bool { 395 return a.KeyID < b.KeyID 396 } 397 if !cmp.Equal(got, want, cmpopts.SortSlices(eventCmp)) { 398 t.Errorf("got = %v, want = %v, with diff: %v", got, want, cmp.Diff(got, want)) 399 } 400 401} 402 403func TestPrimitiveFactoryWithMonitoringAnnotationsLogsComputePRF(t *testing.T) { 404 defer internalregistry.ClearMonitoringClient() 405 client := fakemonitoring.NewClient("fake-client") 406 if err := internalregistry.RegisterMonitoringClient(client); err != nil { 407 t.Fatalf("internalregistry.RegisterMonitoringClient() err = %v, want nil", err) 408 } 409 kh, err := keyset.NewHandle(prf.HMACSHA256PRFKeyTemplate()) 410 if err != nil { 411 t.Fatalf("keyset.NewHandle() err = %v, want nil", err) 412 } 413 buff := &bytes.Buffer{} 414 if err := insecurecleartextkeyset.Write(kh, keyset.NewBinaryWriter(buff)); err != nil { 415 t.Fatalf("insecurecleartextkeyset.Write() err = %v, want nil", err) 416 } 417 annotations := map[string]string{"foo": "bar"} 418 mh, err := insecurecleartextkeyset.Read(keyset.NewBinaryReader(buff), keyset.WithAnnotations(annotations)) 419 if err != nil { 420 t.Fatalf("insecurecleartextkeyset.Read() err = %v, want nil", err) 421 } 422 prfSet, err := prf.NewPRFSet(mh) 423 if err != nil { 424 t.Fatalf("prf.NewPRFSet() err = %v, want nil", err) 425 } 426 data := []byte("some_data") 427 if _, err := prfSet.ComputePrimaryPRF(data, 20); err != nil { 428 t.Fatalf("prfSet.ComputePrimaryPRF() err = %v, want nil", err) 429 } 430 got := client.Events() 431 wantKeysetInfo := &monitoring.KeysetInfo{ 432 PrimaryKeyID: kh.KeysetInfo().GetPrimaryKeyId(), 433 Entries: []*monitoring.Entry{ 434 { 435 KeyID: kh.KeysetInfo().GetPrimaryKeyId(), 436 Status: monitoring.Enabled, 437 KeyType: "tink.HmacPrfKey", 438 KeyPrefix: "RAW", 439 }, 440 }, 441 Annotations: annotations, 442 } 443 want := []*fakemonitoring.LogEvent{ 444 { 445 Context: monitoring.NewContext("prf", "compute", wantKeysetInfo), 446 KeyID: kh.KeysetInfo().GetPrimaryKeyId(), 447 NumBytes: len(data), 448 }, 449 } 450 if !cmp.Equal(got, want) { 451 t.Errorf("got = %v, want = %v, with diff: %v", got, want, cmp.Diff(got, want)) 452 } 453} 454