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 aead_test 18 19import ( 20 "bytes" 21 "fmt" 22 "testing" 23 24 "github.com/google/tink/go/aead" 25 "github.com/google/tink/go/core/registry" 26 "github.com/google/tink/go/internal/tinkerror/tinkerrortest" 27 "github.com/google/tink/go/keyset" 28 "github.com/google/tink/go/mac" 29 "github.com/google/tink/go/testing/fakekms" 30 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 31) 32 33func TestKeyTemplates(t *testing.T) { 34 var testCases = []struct { 35 name string 36 template *tinkpb.KeyTemplate 37 }{ 38 { 39 name: "AES128_GCM", 40 template: aead.AES128GCMKeyTemplate(), 41 }, { 42 name: "AES256_GCM", 43 template: aead.AES256GCMKeyTemplate(), 44 }, { 45 name: "AES256_GCM_NO_PREFIX", 46 template: aead.AES256GCMNoPrefixKeyTemplate(), 47 }, { 48 name: "AES128_GCM_SIV", 49 template: aead.AES128GCMSIVKeyTemplate(), 50 }, { 51 name: "AES256_GCM_SIV", 52 template: aead.AES256GCMSIVKeyTemplate(), 53 }, { 54 name: "AES256_GCM_SIV_NO_PREFIX", 55 template: aead.AES256GCMSIVNoPrefixKeyTemplate(), 56 }, { 57 name: "AES128_CTR_HMAC_SHA256", 58 template: aead.AES128CTRHMACSHA256KeyTemplate(), 59 }, { 60 name: "AES256_CTR_HMAC_SHA256", 61 template: aead.AES256CTRHMACSHA256KeyTemplate(), 62 }, { 63 name: "CHACHA20_POLY1305", 64 template: aead.ChaCha20Poly1305KeyTemplate(), 65 }, { 66 name: "XCHACHA20_POLY1305", 67 template: aead.XChaCha20Poly1305KeyTemplate(), 68 }, 69 } 70 for _, tc := range testCases { 71 t.Run(tc.name, func(t *testing.T) { 72 if err := testEncryptDecrypt(tc.template); err != nil { 73 t.Errorf("%v", err) 74 } 75 }) 76 } 77} 78 79func TestKMSEnvelopeAEADKeyTemplate(t *testing.T) { 80 fakeKmsClient, err := fakekms.NewClient("fake-kms://") 81 if err != nil { 82 t.Fatalf("fakekms.NewClient('fake-kms://') failed: %v", err) 83 } 84 registry.RegisterKMSClient(fakeKmsClient) 85 86 fixedKeyURI := "fake-kms://CM2b3_MDElQKSAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EhIaEIK75t5L-adlUwVhWvRuWUwYARABGM2b3_MDIAE" 87 newKeyURI, err := fakekms.NewKeyURI() 88 if err != nil { 89 t.Fatalf("fakekms.NewKeyURI() failed: %v", err) 90 } 91 fixedKeyTemplate, err := aead.CreateKMSEnvelopeAEADKeyTemplate(fixedKeyURI, aead.AES128GCMKeyTemplate()) 92 if err != nil { 93 t.Fatalf("CreateKMSEnvelopeAEADKeyTemplate() err = %v", err) 94 } 95 newKeyTemplate, err := aead.CreateKMSEnvelopeAEADKeyTemplate(newKeyURI, aead.AES128GCMKeyTemplate()) 96 if err != nil { 97 t.Fatalf("CreateKMSEnvelopeAEADKeyTemplate() err = %v", err) 98 } 99 100 var testCases = []struct { 101 name string 102 template *tinkpb.KeyTemplate 103 }{ 104 { 105 name: "Fixed Fake KMS Envelope AEAD Key with AES128_GCM", 106 template: fixedKeyTemplate, 107 }, { 108 name: "New Fake KMS Envelope AEAD Key with AES128_GCM", 109 template: newKeyTemplate, 110 }, 111 } 112 for _, tc := range testCases { 113 t.Run(tc.name, func(t *testing.T) { 114 if tc.template.GetOutputPrefixType() != tinkpb.OutputPrefixType_RAW { 115 t.Errorf("KMS envelope template %s does not use RAW prefix, found '%s'", tc.name, tc.template.GetOutputPrefixType()) 116 } 117 if err := testEncryptDecrypt(tc.template); err != nil { 118 t.Errorf("%v", err) 119 } 120 }) 121 } 122} 123 124// Tests that two KMSEnvelopeAEAD keys that use the same KEK and DEK template 125// should be able to decrypt each other's ciphertexts. 126func TestKMSEnvelopeAEADKeyTemplateMultipleKeysSameKEK(t *testing.T) { 127 fakeKmsClient, err := fakekms.NewClient("fake-kms://") 128 if err != nil { 129 t.Fatalf("fakekms.NewClient('fake-kms://') failed: %v", err) 130 } 131 registry.RegisterKMSClient(fakeKmsClient) 132 133 fixedKeyURI := "fake-kms://CM2b3_MDElQKSAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EhIaEIK75t5L-adlUwVhWvRuWUwYARABGM2b3_MDIAE" 134 template1, err := aead.CreateKMSEnvelopeAEADKeyTemplate(fixedKeyURI, aead.AES128GCMKeyTemplate()) 135 if err != nil { 136 t.Fatalf("CreateKMSEnvelopeAEADKeyTemplate() err = %v", err) 137 } 138 template2, err := aead.CreateKMSEnvelopeAEADKeyTemplate(fixedKeyURI, aead.AES128GCMKeyTemplate()) 139 if err != nil { 140 t.Fatalf("CreateKMSEnvelopeAEADKeyTemplate() err = %v", err) 141 } 142 143 handle1, err := keyset.NewHandle(template1) 144 if err != nil { 145 t.Fatalf("keyset.NewHandle(template1) failed: %v", err) 146 } 147 aead1, err := aead.New(handle1) 148 if err != nil { 149 t.Fatalf("aead.New(handle) failed: %v", err) 150 } 151 152 handle2, err := keyset.NewHandle(template2) 153 if err != nil { 154 t.Fatalf("keyset.NewHandle(template2) failed: %v", err) 155 } 156 aead2, err := aead.New(handle2) 157 if err != nil { 158 t.Fatalf("aead.New(handle) failed: %v", err) 159 } 160 161 plaintext := []byte("some data to encrypt") 162 aad := []byte("extra data to authenticate") 163 164 ciphertext, err := aead1.Encrypt(plaintext, aad) 165 if err != nil { 166 t.Fatalf("encryption failed, error: %v", err) 167 } 168 decrypted, err := aead2.Decrypt(ciphertext, aad) 169 if err != nil { 170 t.Fatalf("decryption failed, error: %v", err) 171 } 172 if !bytes.Equal(plaintext, decrypted) { 173 t.Fatalf("decrypted data doesn't match plaintext, got: %q, want: %q", decrypted, plaintext) 174 } 175} 176 177// Testing deprecated function, ignoring GoDeprecated. 178func TestCreateKMSEnvelopeAEADKeyTemplateCompatibleWithKMSEnevelopeAEADKeyTemplate(t *testing.T) { 179 fakeKmsClient, err := fakekms.NewClient("fake-kms://") 180 if err != nil { 181 t.Fatalf("fakekms.NewClient('fake-kms://') failed: %v", err) 182 } 183 registry.RegisterKMSClient(fakeKmsClient) 184 185 fixedKeyURI := "fake-kms://CM2b3_MDElQKSAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EhIaEIK75t5L-adlUwVhWvRuWUwYARABGM2b3_MDIAE" 186 template1, err := aead.CreateKMSEnvelopeAEADKeyTemplate(fixedKeyURI, aead.AES128GCMKeyTemplate()) 187 if err != nil { 188 t.Fatalf("CreateKMSEnvelopeAEADKeyTemplate() err = %v", err) 189 } 190 template2 := aead.KMSEnvelopeAEADKeyTemplate(fixedKeyURI, aead.AES128GCMKeyTemplate()) 191 192 handle1, err := keyset.NewHandle(template1) 193 if err != nil { 194 t.Fatalf("keyset.NewHandle(template1) failed: %v", err) 195 } 196 aead1, err := aead.New(handle1) 197 if err != nil { 198 t.Fatalf("aead.New(handle) failed: %v", err) 199 } 200 201 handle2, err := keyset.NewHandle(template2) 202 if err != nil { 203 t.Fatalf("keyset.NewHandle(template2) failed: %v", err) 204 } 205 aead2, err := aead.New(handle2) 206 if err != nil { 207 t.Fatalf("aead.New(handle) failed: %v", err) 208 } 209 210 plaintext := []byte("some data to encrypt") 211 aad := []byte("extra data to authenticate") 212 213 ciphertext, err := aead1.Encrypt(plaintext, aad) 214 if err != nil { 215 t.Fatalf("encryption failed, error: %v", err) 216 } 217 decrypted, err := aead2.Decrypt(ciphertext, aad) 218 if err != nil { 219 t.Fatalf("decryption failed, error: %v", err) 220 } 221 if !bytes.Equal(plaintext, decrypted) { 222 t.Fatalf("decrypted data doesn't match plaintext, got: %q, want: %q", decrypted, plaintext) 223 } 224} 225 226// Testing deprecated function, ignoring GoDeprecated. 227func TestKMSEnvelopeAEADKeyTemplateFails(t *testing.T) { 228 keyURI, err := fakekms.NewKeyURI() 229 if err != nil { 230 t.Fatalf("fakekms.NewKeyURI() err = %v", err) 231 } 232 invalidTemplate := &tinkpb.KeyTemplate{ 233 // String fields cannot contain invalid UTF-8 characters. 234 TypeUrl: "\xff", 235 } 236 var template *tinkpb.KeyTemplate 237 err = tinkerrortest.RecoverFromFail(func() { 238 template = aead.KMSEnvelopeAEADKeyTemplate(keyURI, invalidTemplate) 239 }) 240 if err == nil { 241 t.Errorf("aead.KMSEnvelopAEADKeyTemplate() err = nil, want non-nil") 242 } 243 t.Logf("template: %+v", template) 244} 245 246func TestCreateKMSEnvelopeAEADKeyTemplateFails(t *testing.T) { 247 keyURI, err := fakekms.NewKeyURI() 248 if err != nil { 249 t.Fatalf("fakekms.NewKeyURI() err = %v", err) 250 } 251 invalidTemplate := &tinkpb.KeyTemplate{ 252 // String fields cannot contain invalid UTF-8 characters. 253 TypeUrl: "\xff", 254 } 255 if _, err := aead.CreateKMSEnvelopeAEADKeyTemplate(keyURI, invalidTemplate); err == nil { 256 t.Errorf("aead.CreateKMSEnvelopAEADKeyTemplate(keyURI, invalidTemplate) err = nil, want non-nil") 257 } 258} 259 260func TestCreateKMSEnvelopeAEADKeyTemplateWithUnsupportedTemplateFails(t *testing.T) { 261 keyURI, err := fakekms.NewKeyURI() 262 if err != nil { 263 t.Fatalf("fakekms.NewKeyURI() err = %v", err) 264 } 265 unsupportedTemplate := mac.HMACSHA256Tag128KeyTemplate() 266 if _, err := aead.CreateKMSEnvelopeAEADKeyTemplate(keyURI, unsupportedTemplate); err == nil { 267 t.Errorf("aead.CreateKMSEnvelopAEADKeyTemplate(keyURI, unsupportedTemplate) err = nil, want non-nil") 268 } 269} 270 271func testEncryptDecrypt(template *tinkpb.KeyTemplate) error { 272 handle, err := keyset.NewHandle(template) 273 if err != nil { 274 return fmt.Errorf("keyset.NewHandle(template) failed: %v", err) 275 } 276 primitive, err := aead.New(handle) 277 if err != nil { 278 return fmt.Errorf("aead.New(handle) failed: %v", err) 279 } 280 281 var testInputs = []struct { 282 plaintext []byte 283 aad1 []byte 284 aad2 []byte 285 }{ 286 { 287 plaintext: []byte("some data to encrypt"), 288 aad1: []byte("extra data to authenticate"), 289 aad2: []byte("extra data to authenticate"), 290 }, { 291 plaintext: []byte("some data to encrypt"), 292 aad1: []byte(""), 293 aad2: []byte(""), 294 }, { 295 plaintext: []byte("some data to encrypt"), 296 aad1: nil, 297 aad2: nil, 298 }, { 299 plaintext: []byte(""), 300 aad1: nil, 301 aad2: nil, 302 }, { 303 plaintext: nil, 304 aad1: []byte("extra data to authenticate"), 305 aad2: []byte("extra data to authenticate"), 306 }, { 307 plaintext: nil, 308 aad1: []byte(""), 309 aad2: []byte(""), 310 }, { 311 plaintext: nil, 312 aad1: nil, 313 aad2: nil, 314 }, { 315 plaintext: []byte("some data to encrypt"), 316 aad1: []byte(""), 317 aad2: nil, 318 }, { 319 plaintext: []byte("some data to encrypt"), 320 aad1: nil, 321 aad2: []byte(""), 322 }, 323 } 324 for _, ti := range testInputs { 325 ciphertext, err := primitive.Encrypt(ti.plaintext, ti.aad1) 326 if err != nil { 327 return fmt.Errorf("encryption failed, error: %v", err) 328 } 329 decrypted, err := primitive.Decrypt(ciphertext, ti.aad2) 330 if err != nil { 331 return fmt.Errorf("decryption failed, error: %v", err) 332 } 333 if !bytes.Equal(ti.plaintext, decrypted) { 334 return fmt.Errorf("decrypted data doesn't match plaintext, got: %q, want: %q", decrypted, ti.plaintext) 335 } 336 } 337 return nil 338} 339