1// Copyright 2018 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 mac_test 18 19import ( 20 "bytes" 21 "encoding/hex" 22 "fmt" 23 "reflect" 24 "testing" 25 26 "github.com/google/go-cmp/cmp" 27 "google.golang.org/protobuf/proto" 28 "github.com/google/tink/go/core/registry" 29 "github.com/google/tink/go/internal/internalregistry" 30 subtleMac "github.com/google/tink/go/mac/subtle" 31 "github.com/google/tink/go/subtle/random" 32 "github.com/google/tink/go/subtle" 33 "github.com/google/tink/go/testutil" 34 commonpb "github.com/google/tink/go/proto/common_go_proto" 35 hmacpb "github.com/google/tink/go/proto/hmac_go_proto" 36 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 37) 38 39func TestGetPrimitiveBasic(t *testing.T) { 40 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 41 if err != nil { 42 t.Errorf("HMAC key manager not found: %s", err) 43 } 44 testKeys := genValidHMACKeys() 45 for i := 0; i < len(testKeys); i++ { 46 serializedKey, _ := proto.Marshal(testKeys[i]) 47 p, err := km.Primitive(serializedKey) 48 if err != nil { 49 t.Errorf("unexpected error in test case %d: %s", i, err) 50 } 51 if err := validateHMACPrimitive(p, testKeys[i]); err != nil { 52 t.Errorf("%s", err) 53 } 54 } 55} 56 57func TestGetPrimitiveWithInvalidInput(t *testing.T) { 58 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 59 if err != nil { 60 t.Errorf("cannot obtain HMAC key manager: %s", err) 61 } 62 // invalid key 63 testKeys := genInvalidHMACKeys() 64 for i := 0; i < len(testKeys); i++ { 65 serializedKey, _ := proto.Marshal(testKeys[i]) 66 if _, err := km.Primitive(serializedKey); err == nil { 67 t.Errorf("expect an error in test case %d", i) 68 } 69 } 70 if _, err := km.Primitive(nil); err == nil { 71 t.Errorf("expect an error when input is nil") 72 } 73 // empty input 74 if _, err := km.Primitive([]byte{}); err == nil { 75 t.Errorf("expect an error when input is empty") 76 } 77} 78 79func TestNewKeyMultipleTimes(t *testing.T) { 80 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 81 if err != nil { 82 t.Errorf("cannot obtain HMAC key manager: %s", err) 83 } 84 serializedFormat, _ := proto.Marshal(testutil.NewHMACKeyFormat(commonpb.HashType_SHA256, 32)) 85 keys := make(map[string]bool) 86 nTest := 26 87 for i := 0; i < nTest; i++ { 88 key, _ := km.NewKey(serializedFormat) 89 serializedKey, _ := proto.Marshal(key) 90 keys[string(serializedKey)] = true 91 92 keyData, _ := km.NewKeyData(serializedFormat) 93 serializedKey = keyData.Value 94 keys[string(serializedKey)] = true 95 } 96 if len(keys) != nTest*2 { 97 t.Errorf("key is repeated") 98 } 99} 100 101func TestNewKeyBasic(t *testing.T) { 102 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 103 if err != nil { 104 t.Errorf("cannot obtain HMAC key manager: %s", err) 105 } 106 testFormats := genValidHMACKeyFormats() 107 for i := 0; i < len(testFormats); i++ { 108 serializedFormat, _ := proto.Marshal(testFormats[i]) 109 key, err := km.NewKey(serializedFormat) 110 if err != nil { 111 t.Errorf("unexpected error in test case %d: %s", i, err) 112 } 113 if err := validateHMACKey(testFormats[i], key.(*hmacpb.HmacKey)); err != nil { 114 t.Errorf("%s", err) 115 } 116 } 117} 118 119func TestNewKeyWithInvalidInput(t *testing.T) { 120 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 121 if err != nil { 122 t.Errorf("cannot obtain HMAC key manager: %s", err) 123 } 124 // invalid key formats 125 testFormats := genInvalidHMACKeyFormats() 126 for i := 0; i < len(testFormats); i++ { 127 serializedFormat, err := proto.Marshal(testFormats[i]) 128 if err != nil { 129 fmt.Println("Error!") 130 } 131 if _, err := km.NewKey(serializedFormat); err == nil { 132 t.Errorf("expect an error in test case %d: %s", i, err) 133 } 134 } 135 if _, err := km.NewKey(nil); err == nil { 136 t.Errorf("expect an error when input is nil") 137 } 138 // empty input 139 if _, err := km.NewKey([]byte{}); err == nil { 140 t.Errorf("expect an error when input is empty") 141 } 142} 143 144func TestNewKeyDataBasic(t *testing.T) { 145 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 146 if err != nil { 147 t.Errorf("cannot obtain HMAC key manager: %s", err) 148 } 149 testFormats := genValidHMACKeyFormats() 150 for i := 0; i < len(testFormats); i++ { 151 serializedFormat, _ := proto.Marshal(testFormats[i]) 152 keyData, err := km.NewKeyData(serializedFormat) 153 if err != nil { 154 t.Errorf("unexpected error in test case %d: %s", i, err) 155 } 156 if keyData.TypeUrl != testutil.HMACTypeURL { 157 t.Errorf("incorrect type url in test case %d", i) 158 } 159 if keyData.KeyMaterialType != tinkpb.KeyData_SYMMETRIC { 160 t.Errorf("incorrect key material type in test case %d", i) 161 } 162 key := new(hmacpb.HmacKey) 163 if err := proto.Unmarshal(keyData.Value, key); err != nil { 164 t.Errorf("invalid key value") 165 } 166 if err := validateHMACKey(testFormats[i], key); err != nil { 167 t.Errorf("invalid key") 168 } 169 } 170} 171 172func TestNewKeyDataWithInvalidInput(t *testing.T) { 173 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 174 if err != nil { 175 t.Errorf("HMAC key manager not found: %s", err) 176 } 177 // invalid key formats 178 testFormats := genInvalidHMACKeyFormats() 179 for i := 0; i < len(testFormats); i++ { 180 serializedFormat, _ := proto.Marshal(testFormats[i]) 181 if _, err := km.NewKeyData(serializedFormat); err == nil { 182 t.Errorf("expect an error in test case %d", i) 183 } 184 } 185 // nil input 186 if _, err := km.NewKeyData(nil); err == nil { 187 t.Errorf("expect an error when input is nil") 188 } 189} 190 191func TestDoesSupport(t *testing.T) { 192 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 193 if err != nil { 194 t.Errorf("HMAC key manager not found: %s", err) 195 } 196 if !km.DoesSupport(testutil.HMACTypeURL) { 197 t.Errorf("HMACKeyManager must support %s", testutil.HMACTypeURL) 198 } 199 if km.DoesSupport("some bad type") { 200 t.Errorf("HMACKeyManager must support only %s", testutil.HMACTypeURL) 201 } 202} 203 204func TestTypeURL(t *testing.T) { 205 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 206 if err != nil { 207 t.Errorf("HMAC key manager not found: %s", err) 208 } 209 if km.TypeURL() != testutil.HMACTypeURL { 210 t.Errorf("incorrect GetKeyType()") 211 } 212} 213 214func TestHMACKeyMaterialType(t *testing.T) { 215 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 216 if err != nil { 217 t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testutil.HMACTypeURL, err) 218 } 219 keyManager, ok := km.(internalregistry.DerivableKeyManager) 220 if !ok { 221 t.Fatalf("key manager is not DerivableKeyManager") 222 } 223 if got, want := keyManager.KeyMaterialType(), tinkpb.KeyData_SYMMETRIC; got != want { 224 t.Errorf("KeyMaterialType() = %v, want %v", got, want) 225 } 226} 227 228func TestHMACDeriveKey(t *testing.T) { 229 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 230 if err != nil { 231 t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testutil.HMACTypeURL, err) 232 } 233 keyManager, ok := km.(internalregistry.DerivableKeyManager) 234 if !ok { 235 t.Fatalf("key manager is not DerivableKeyManager") 236 } 237 keyFormat, err := proto.Marshal(&hmacpb.HmacKeyFormat{ 238 Version: testutil.HMACKeyVersion, 239 KeySize: 16, 240 Params: &hmacpb.HmacParams{ 241 Hash: commonpb.HashType_SHA256, 242 TagSize: 10, 243 }, 244 }) 245 if err != nil { 246 t.Fatalf("proto.Marshal() err = %v, want nil", err) 247 } 248 rand := random.GetRandomBytes(16) 249 buf := &bytes.Buffer{} 250 buf.Write(rand) // never returns a non-nil error 251 k, err := keyManager.DeriveKey(keyFormat, buf) 252 if err != nil { 253 t.Fatalf("keyManager.DeriveKey() err = %v, want nil", err) 254 } 255 key := k.(*hmacpb.HmacKey) 256 if got, want := len(key.GetKeyValue()), 16; got != want { 257 t.Errorf("key length = %d, want %d", got, want) 258 } 259 if diff := cmp.Diff(key.GetKeyValue(), rand); diff != "" { 260 t.Errorf("incorrect derived key: diff = %v", diff) 261 } 262} 263 264func TestHMACDeriveKeyFailsWithInvalidKeyFormats(t *testing.T) { 265 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 266 if err != nil { 267 t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testutil.HMACTypeURL, err) 268 } 269 keyManager, ok := km.(internalregistry.DerivableKeyManager) 270 if !ok { 271 t.Fatalf("key manager is not DerivableKeyManager") 272 } 273 274 validKeyFormat := &hmacpb.HmacKeyFormat{ 275 Version: testutil.HMACKeyVersion, 276 KeySize: 16, 277 Params: &hmacpb.HmacParams{ 278 Hash: commonpb.HashType_SHA256, 279 TagSize: 10, 280 }, 281 } 282 serializedValidKeyFormat, err := proto.Marshal(validKeyFormat) 283 if err != nil { 284 t.Fatalf("proto.Marshal(%v) err = %v, want nil", validKeyFormat, err) 285 } 286 buf := bytes.NewBuffer(random.GetRandomBytes(validKeyFormat.KeySize)) 287 if _, err := keyManager.DeriveKey(serializedValidKeyFormat, buf); err != nil { 288 t.Fatalf("keyManager.DeriveKey() err = %v, want nil", err) 289 } 290 291 for _, test := range []struct { 292 name string 293 version uint32 294 keySize uint32 295 hash commonpb.HashType 296 tagSize uint32 297 }{ 298 { 299 name: "invalid version", 300 version: 10, 301 keySize: validKeyFormat.KeySize, 302 hash: validKeyFormat.Params.Hash, 303 tagSize: validKeyFormat.Params.TagSize, 304 }, 305 { 306 name: "invalid key size", 307 version: validKeyFormat.Version, 308 keySize: 10, 309 hash: validKeyFormat.Params.Hash, 310 tagSize: validKeyFormat.Params.TagSize, 311 }, 312 { 313 name: "invalid hash", 314 version: validKeyFormat.Version, 315 keySize: validKeyFormat.KeySize, 316 hash: commonpb.HashType_UNKNOWN_HASH, 317 tagSize: validKeyFormat.Params.TagSize, 318 }, 319 { 320 name: "invalid tag size", 321 version: validKeyFormat.Version, 322 keySize: validKeyFormat.KeySize, 323 hash: validKeyFormat.Params.Hash, 324 tagSize: 9, 325 }, 326 } { 327 t.Run(test.name, func(t *testing.T) { 328 keyFormat, err := proto.Marshal(&hmacpb.HmacKeyFormat{ 329 Version: test.version, 330 KeySize: test.keySize, 331 Params: &hmacpb.HmacParams{ 332 Hash: test.hash, 333 TagSize: test.tagSize, 334 }, 335 }) 336 if err != nil { 337 t.Fatalf("proto.Marshal() err = %v, want nil", err) 338 } 339 buf := bytes.NewBuffer(random.GetRandomBytes(test.keySize)) 340 if _, err := keyManager.DeriveKey(keyFormat, buf); err == nil { 341 t.Errorf("keyManager.DeriveKey() err = nil, want non-nil") 342 } 343 }) 344 } 345} 346 347func TestHMACDeriveKeyFailsWithMalformedKeyFormats(t *testing.T) { 348 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 349 if err != nil { 350 t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testutil.HMACTypeURL, err) 351 } 352 keyManager, ok := km.(internalregistry.DerivableKeyManager) 353 if !ok { 354 t.Fatalf("key manager is not DerivableKeyManager") 355 } 356 // Proto messages start with a VarInt, which always ends with a byte with the 357 // MSB unset, so 0x80 is invalid. 358 invalidSerialization, err := hex.DecodeString("80") 359 if err != nil { 360 t.Errorf("hex.DecodeString() err = %v, want nil", err) 361 } 362 for _, test := range []struct { 363 name string 364 keyFormat []byte 365 }{ 366 { 367 name: "nil", 368 keyFormat: nil, 369 }, 370 { 371 name: "empty", 372 keyFormat: []byte{}, 373 }, 374 { 375 name: "invalid serialization", 376 keyFormat: invalidSerialization, 377 }, 378 } { 379 t.Run(test.name, func(t *testing.T) { 380 buf := bytes.NewBuffer(random.GetRandomBytes(16)) 381 if _, err := keyManager.DeriveKey(test.keyFormat, buf); err == nil { 382 t.Errorf("keyManager.DeriveKey() err = nil, want non-nil") 383 } 384 }) 385 } 386} 387 388func TestHMACDeriveKeyFailsWithInsufficientRandomness(t *testing.T) { 389 km, err := registry.GetKeyManager(testutil.HMACTypeURL) 390 if err != nil { 391 t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testutil.HMACTypeURL, err) 392 } 393 keyManager, ok := km.(internalregistry.DerivableKeyManager) 394 if !ok { 395 t.Fatalf("key manager is not DerivableKeyManager") 396 } 397 keyFormat, err := proto.Marshal(&hmacpb.HmacKeyFormat{ 398 Version: testutil.HMACKeyVersion, 399 KeySize: 16, 400 Params: &hmacpb.HmacParams{ 401 Hash: commonpb.HashType_SHA256, 402 TagSize: 10, 403 }, 404 }) 405 if err != nil { 406 t.Fatalf("proto.Marshal(%v) err = %v, want nil", keyFormat, err) 407 } 408 { 409 buf := bytes.NewBuffer(random.GetRandomBytes(16)) 410 if _, err := keyManager.DeriveKey(keyFormat, buf); err != nil { 411 t.Errorf("keyManager.DeriveKey() err = %v, want nil", err) 412 } 413 } 414 { 415 insufficientBuf := bytes.NewBuffer(random.GetRandomBytes(15)) 416 if _, err := keyManager.DeriveKey(keyFormat, insufficientBuf); err == nil { 417 t.Errorf("keyManager.DeriveKey() err = nil, want non-nil") 418 } 419 } 420} 421 422func genInvalidHMACKeys() []proto.Message { 423 badVersionKey := testutil.NewHMACKey(commonpb.HashType_SHA256, 32) 424 badVersionKey.Version++ 425 shortKey := testutil.NewHMACKey(commonpb.HashType_SHA256, 32) 426 shortKey.KeyValue = []byte{1, 1} 427 return []proto.Message{ 428 // not a HMACKey 429 testutil.NewHMACParams(commonpb.HashType_SHA256, 32), 430 // bad version 431 badVersionKey, 432 // tag size too big 433 testutil.NewHMACKey(commonpb.HashType_SHA1, 21), 434 testutil.NewHMACKey(commonpb.HashType_SHA256, 33), 435 testutil.NewHMACKey(commonpb.HashType_SHA512, 65), 436 // tag size too small 437 testutil.NewHMACKey(commonpb.HashType_SHA256, 1), 438 // key too short 439 shortKey, 440 // unknown hash type 441 testutil.NewHMACKey(commonpb.HashType_UNKNOWN_HASH, 32), 442 } 443} 444 445func genInvalidHMACKeyFormats() []proto.Message { 446 shortKeyFormat := testutil.NewHMACKeyFormat(commonpb.HashType_SHA256, 32) 447 shortKeyFormat.KeySize = 1 448 return []proto.Message{ 449 // not a HMACKeyFormat 450 testutil.NewHMACParams(commonpb.HashType_SHA256, 32), 451 // tag size too big 452 testutil.NewHMACKeyFormat(commonpb.HashType_SHA1, 21), 453 testutil.NewHMACKeyFormat(commonpb.HashType_SHA256, 33), 454 testutil.NewHMACKeyFormat(commonpb.HashType_SHA512, 65), 455 // tag size too small 456 testutil.NewHMACKeyFormat(commonpb.HashType_SHA256, 1), 457 // key too short 458 shortKeyFormat, 459 // unknown hash type 460 testutil.NewHMACKeyFormat(commonpb.HashType_UNKNOWN_HASH, 32), 461 } 462} 463 464func genValidHMACKeyFormats() []*hmacpb.HmacKeyFormat { 465 return []*hmacpb.HmacKeyFormat{ 466 testutil.NewHMACKeyFormat(commonpb.HashType_SHA1, 20), 467 testutil.NewHMACKeyFormat(commonpb.HashType_SHA256, 32), 468 testutil.NewHMACKeyFormat(commonpb.HashType_SHA512, 64), 469 } 470} 471 472func genValidHMACKeys() []*hmacpb.HmacKey { 473 return []*hmacpb.HmacKey{ 474 testutil.NewHMACKey(commonpb.HashType_SHA1, 20), 475 testutil.NewHMACKey(commonpb.HashType_SHA256, 32), 476 testutil.NewHMACKey(commonpb.HashType_SHA512, 64), 477 } 478} 479 480// Checks whether the given HMACKey matches the given key HMACKeyFormat 481func validateHMACKey(format *hmacpb.HmacKeyFormat, key *hmacpb.HmacKey) error { 482 if format.KeySize != uint32(len(key.KeyValue)) || 483 key.Params.TagSize != format.Params.TagSize || 484 key.Params.Hash != format.Params.Hash { 485 return fmt.Errorf("key format and generated key do not match") 486 } 487 p, err := subtleMac.NewHMAC(commonpb.HashType_name[int32(key.Params.Hash)], key.KeyValue, key.Params.TagSize) 488 if err != nil { 489 return fmt.Errorf("cannot create primitive from key: %s", err) 490 } 491 return validateHMACPrimitive(p, key) 492} 493 494// validateHMACPrimitive checks whether the given primitive matches the given HMACKey 495func validateHMACPrimitive(p interface{}, key *hmacpb.HmacKey) error { 496 hmacPrimitive := p.(*subtleMac.HMAC) 497 if !bytes.Equal(hmacPrimitive.Key, key.KeyValue) || 498 hmacPrimitive.TagSize != key.Params.TagSize || 499 reflect.ValueOf(hmacPrimitive.HashFunc).Pointer() != 500 reflect.ValueOf(subtle.GetHashFunc(commonpb.HashType_name[int32(key.Params.Hash)])).Pointer() { 501 return fmt.Errorf("primitive and key do not match") 502 } 503 data := random.GetRandomBytes(20) 504 mac, err := hmacPrimitive.ComputeMAC(data) 505 if err != nil { 506 return fmt.Errorf("mac computation failed: %s", err) 507 } 508 if err = hmacPrimitive.VerifyMAC(mac, data); err != nil { 509 return fmt.Errorf("mac verification failed: %s", err) 510 } 511 return nil 512} 513