// Copyright 2022 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 // // http://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. // //////////////////////////////////////////////////////////////////////////////// package keyderivation import ( "bytes" "encoding/hex" "fmt" "testing" "google.golang.org/protobuf/proto" "github.com/google/tink/go/aead" "github.com/google/tink/go/core/registry" "github.com/google/tink/go/daead" "github.com/google/tink/go/insecurecleartextkeyset" "github.com/google/tink/go/mac" "github.com/google/tink/go/prf" "github.com/google/tink/go/signature" "github.com/google/tink/go/streamingaead" aesgcmpb "github.com/google/tink/go/proto/aes_gcm_go_proto" commonpb "github.com/google/tink/go/proto/common_go_proto" hkdfpb "github.com/google/tink/go/proto/hkdf_prf_go_proto" tinkpb "github.com/google/tink/go/proto/tink_go_proto" ) func TestPRFBasedDeriver(t *testing.T) { prfs := []struct { name string template *tinkpb.KeyTemplate }{ { name: "HKDF_SHA256", template: prf.HKDFSHA256PRFKeyTemplate(), }, } // Derivation names match KEY_TEMPLATE_NAMES in // https://github.com/google/tink/blob/cd96c47ced3f72199832573cdccf18719dc7c73b/testing/cross_language/util/utilities.py. derivations := []struct { name string template *tinkpb.KeyTemplate }{ { name: "AES128_GCM", template: aead.AES128GCMKeyTemplate(), }, { name: "AES256_GCM", template: aead.AES256GCMKeyTemplate(), }, { name: "AES256_GCM_RAW", template: aead.AES256GCMNoPrefixKeyTemplate(), }, { name: "XCHACHA20_POLY1305", template: aead.XChaCha20Poly1305KeyTemplate(), }, { name: "AES256_SIV", template: daead.AESSIVKeyTemplate(), }, { name: "HMAC_SHA256_128BITTAG", template: mac.HMACSHA256Tag128KeyTemplate(), }, { name: "HMAC_SHA256_256BITTAG", template: mac.HMACSHA256Tag256KeyTemplate(), }, { name: "HMAC_SHA512_256BITTAG", template: mac.HMACSHA512Tag256KeyTemplate(), }, { name: "HMAC_SHA512_512BITTAG", template: mac.HMACSHA512Tag512KeyTemplate(), }, { name: "HKDF_SHA256", template: prf.HKDFSHA256PRFKeyTemplate(), }, { name: "HMAC_SHA256_PRF", template: prf.HMACSHA256PRFKeyTemplate(), }, { name: "HMAC_SHA512_PRF", template: prf.HMACSHA512PRFKeyTemplate(), }, { name: "ED25519", template: signature.ED25519KeyTemplate(), }, { name: "AES128_GCM_HKDF_4KB", template: streamingaead.AES128GCMHKDF4KBKeyTemplate(), }, { name: "AES128_GCM_HKDF_1MB", template: streamingaead.AES128GCMHKDF1MBKeyTemplate(), }, { name: "AES256_GCM_HKDF_4KB", template: streamingaead.AES256GCMHKDF4KBKeyTemplate(), }, { name: "AES256_GCM_HKDF_1MB", template: streamingaead.AES256GCMHKDF1MBKeyTemplate(), }, } salts := [][]byte{nil, []byte("salt")} for _, prf := range prfs { for _, der := range derivations { for _, salt := range salts { name := fmt.Sprintf("%s_%s", prf.name, der.name) if salt != nil { name += "_with_salt" } t.Run(name, func(t *testing.T) { prfKeyData, err := registry.NewKeyData(prf.template) if err != nil { t.Fatalf("registry.NewKeyData() err = %v, want nil", err) } d, err := newPRFBasedDeriver(prfKeyData, der.template) if err != nil { t.Fatalf("newPRFBasedDeriver() err = %v, want nil", err) } if _, err := d.DeriveKeyset(salt); err != nil { t.Errorf("DeriveKeyset() err = %v, want nil", err) } // We cannot test the derived keyset handle because, at this point, it // is filled with placeholder values for the key ID, status, and // output prefix type fields. }) } } } } func TestPRFBasedDeriverWithHKDFRFCVectorForAESGCM(t *testing.T) { // This is the only HKDF vector that uses an accepted hash function and has // key size >= 32-bytes. // https://www.rfc-editor.org/rfc/rfc5869#appendix-A.2 vec := struct { hash commonpb.HashType key string salt string info string outLen int okm string }{ hash: commonpb.HashType_SHA256, key: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", salt: "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", info: "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", outLen: 82, okm: "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87", } prfKeyValue, err := hex.DecodeString(vec.key) if err != nil { t.Fatalf("hex.DecodeString() err = %v, want nil", err) } prfSalt, err := hex.DecodeString(vec.salt) if err != nil { t.Fatalf("hex.DecodeString() err = %v, want nil", err) } derivationSalt, err := hex.DecodeString(vec.info) if err != nil { t.Fatalf("hex.DecodeString() err = %v, want nil", err) } wantKeyValue, err := hex.DecodeString(vec.okm) if err != nil { t.Fatalf("hex.DecodeString() err = %v, want nil", err) } prfKey := &hkdfpb.HkdfPrfKey{ Version: 0, Params: &hkdfpb.HkdfPrfParams{ Hash: vec.hash, Salt: prfSalt, }, KeyValue: prfKeyValue, } serializedPRFKey, err := proto.Marshal(prfKey) if err != nil { t.Fatalf("proto.Marshal() err = %v, want nil", err) } prfKeyData := &tinkpb.KeyData{ TypeUrl: prf.HKDFSHA256PRFKeyTemplate().GetTypeUrl(), Value: serializedPRFKey, KeyMaterialType: tinkpb.KeyData_SYMMETRIC, } for _, test := range []struct { name string derivedKeyTemplate *tinkpb.KeyTemplate }{ { name: "AES128_GCM", derivedKeyTemplate: aead.AES128GCMKeyTemplate(), }, { name: "AES256_GCM", derivedKeyTemplate: aead.AES256GCMKeyTemplate(), }, { name: "AES256_GCM_RAW", derivedKeyTemplate: aead.AES256GCMNoPrefixKeyTemplate(), }, } { t.Run(test.name, func(t *testing.T) { // Derive keyset. d, err := newPRFBasedDeriver(prfKeyData, test.derivedKeyTemplate) if err != nil { t.Fatalf("newPRFBasedDeriver() err = %v, want nil", err) } derivedHandle, err := d.DeriveKeyset(derivationSalt) if err != nil { t.Fatalf("DeriveKeyset() err = %v, want nil", err) } derivedKeyset := insecurecleartextkeyset.KeysetMaterial(derivedHandle) // Verify keyset. if len(derivedKeyset.GetKey()) != 1 { t.Fatalf("len(keyset) = %d, want 1", len(derivedKeyset.GetKey())) } key := derivedKeyset.GetKey()[0] if derivedKeyset.GetPrimaryKeyId() != key.GetKeyId() { t.Fatal("keyset has no primary key") } // Verify key attributes set by prfBasedDeriver. if got, want := key.GetStatus(), tinkpb.KeyStatusType_UNKNOWN_STATUS; got != want { t.Errorf("derived key status = %s, want %s", got, want) } if got, want := key.GetOutputPrefixType(), tinkpb.OutputPrefixType_UNKNOWN_PREFIX; got != want { t.Errorf("derived key output prefix type = %s, want %s", got, want) } // Verify key value. derivedKeyFormat := &aesgcmpb.AesGcmKeyFormat{} if err := proto.Unmarshal(test.derivedKeyTemplate.GetValue(), derivedKeyFormat); err != nil { t.Fatalf("proto.Unmarshal() err = %v, want nil", err) } wantKeySize := int(derivedKeyFormat.GetKeySize()) aesGCMKey := &aesgcmpb.AesGcmKey{} if err := proto.Unmarshal(key.GetKeyData().GetValue(), aesGCMKey); err != nil { t.Fatalf("proto.Unmarshal() err = %v, want nil", err) } gotKeyValue := aesGCMKey.GetKeyValue() if len(gotKeyValue) != wantKeySize { t.Errorf("derived key value length = %d, want %d", len(gotKeyValue), wantKeySize) } if !bytes.Equal(gotKeyValue, wantKeyValue[:wantKeySize]) { t.Errorf("derived key value = %q, want %q", gotKeyValue, wantKeyValue[:wantKeySize]) } }) } } func TestNewPRFBasedDeriverRejectsInvalidInputs(t *testing.T) { validPRFKeyData, err := registry.NewKeyData(prf.HKDFSHA256PRFKeyTemplate()) if err != nil { t.Fatalf("registry.NewKeyData() err = %v, want nil", err) } validDerivedKeyTemplate := aead.AES128GCMKeyTemplate() if _, err := newPRFBasedDeriver(validPRFKeyData, validDerivedKeyTemplate); err != nil { t.Fatalf("newPRFBasedDeriver() err = %v, want nil", err) } invalidPRFKeyData, err := registry.NewKeyData(aead.AES128GCMKeyTemplate()) if err != nil { t.Fatalf("registry.NewKeyData() err = %v, want nil", err) } // The derivation of KeysetDeriver keyset handles is not supported, i.e. a // KeysetDeriver key template cannot be used as the derivedKeyTemplate // argument in newPRFBasedDeriver(). invalidDerivedKeyTemplate, err := CreatePRFBasedKeyTemplate(prf.HKDFSHA256PRFKeyTemplate(), aead.AES128GCMKeyTemplate()) if err != nil { t.Fatalf("CreatePRFBasedKeyTemplate() err = %v, want nil", err) } for _, test := range []struct { name string prfKeyData *tinkpb.KeyData derivedKeyTemplate *tinkpb.KeyTemplate }{ { name: "nil inputs", }, { name: "nil PRF key data", derivedKeyTemplate: validDerivedKeyTemplate, }, { name: "nil derived template", prfKeyData: validPRFKeyData, }, { name: "invalid PRF key data", prfKeyData: invalidPRFKeyData, derivedKeyTemplate: validDerivedKeyTemplate, }, { name: "invalid derived template", prfKeyData: validPRFKeyData, derivedKeyTemplate: invalidDerivedKeyTemplate, }, } { t.Run(test.name, func(t *testing.T) { if _, err := newPRFBasedDeriver(test.prfKeyData, test.derivedKeyTemplate); err == nil { t.Errorf("newPRFBasedDeriver() err = nil, want non-nil") } }) } }