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 streamingaead_test 18 19import ( 20 "bytes" 21 "fmt" 22 "io" 23 "log" 24 "strings" 25 "testing" 26 27 "google.golang.org/protobuf/proto" 28 "github.com/google/tink/go/keyset" 29 "github.com/google/tink/go/mac" 30 "github.com/google/tink/go/streamingaead" 31 "github.com/google/tink/go/subtle/random" 32 "github.com/google/tink/go/testkeyset" 33 "github.com/google/tink/go/testutil" 34 "github.com/google/tink/go/tink" 35 ghpb "github.com/google/tink/go/proto/aes_gcm_hkdf_streaming_go_proto" 36 commonpb "github.com/google/tink/go/proto/common_go_proto" 37 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 38) 39 40const ( 41 aesGCMHKDFTypeURL = "type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey" 42) 43 44func TestFactoryMultipleKeys(t *testing.T) { 45 keyset := testutil.NewTestAESGCMHKDFKeyset() 46 47 keysetHandle, err := testkeyset.NewHandle(keyset) 48 if err != nil { 49 log.Fatal(err) 50 } 51 52 a, err := streamingaead.New(keysetHandle) 53 if err != nil { 54 t.Errorf("streamingaead.New failed: %s", err) 55 } 56 57 t.Run("Encrypt with a primary RAW key and decrypt with the keyset", func(t *testing.T) { 58 if err := validateFactoryCipher(a, a); err != nil { 59 t.Errorf("invalid cipher: %s", err) 60 } 61 }) 62 63 t.Run("Encrypt with a non-primary RAW key and decrypt with the keyset", func(t *testing.T) { 64 rawKey := keyset.Key[1] 65 if rawKey.OutputPrefixType != tinkpb.OutputPrefixType_RAW { 66 t.Errorf("expect a raw key") 67 } 68 keyset2 := testutil.NewKeyset(rawKey.KeyId, []*tinkpb.Keyset_Key{rawKey}) 69 keysetHandle2, _ := testkeyset.NewHandle(keyset2) 70 a2, err := streamingaead.New(keysetHandle2) 71 if err != nil { 72 t.Errorf("streamingaead.New failed: %s", err) 73 } 74 if err := validateFactoryCipher(a2, a); err != nil { 75 t.Errorf("invalid cipher: %s", err) 76 } 77 }) 78 79 t.Run("Encrypt with a random key not in the keyset, decrypt with the keyset should fail", func(t *testing.T) { 80 keyset2 := testutil.NewTestAESGCMHKDFKeyset() 81 keysetHandle2, _ := testkeyset.NewHandle(keyset2) 82 a2, err := streamingaead.New(keysetHandle2) 83 if err != nil { 84 t.Errorf("streamingaead.New failed: %s", err) 85 } 86 err = validateFactoryCipher(a2, a) 87 if err == nil || !strings.Contains(err.Error(), "decryption failed") { 88 t.Errorf("expect decryption to fail with random key: %s", err) 89 } 90 }) 91} 92 93func validateFactoryCipher(encryptCipher tink.StreamingAEAD, decryptCipher tink.StreamingAEAD) error { 94 tt := []int{1, 16, 4095, 4096, 4097, 16384} 95 96 for _, t := range tt { 97 if err := encryptDecrypt(encryptCipher, decryptCipher, t, 32); err != nil { 98 return fmt.Errorf("failed plaintext-size=%d: %s", t, err) 99 } 100 } 101 return nil 102} 103 104func encryptDecrypt(encryptCipher, decryptCipher tink.StreamingAEAD, ptSize, aadSize int) error { 105 pt := random.GetRandomBytes(uint32(ptSize)) 106 aad := random.GetRandomBytes(uint32(aadSize)) 107 108 buf := &bytes.Buffer{} 109 w, err := encryptCipher.NewEncryptingWriter(buf, aad) 110 if err != nil { 111 return fmt.Errorf("cannot create encrypt writer: %v", err) 112 } 113 if _, err := w.Write(pt); err != nil { 114 return fmt.Errorf("error writing data: %v", err) 115 } 116 if err := w.Close(); err != nil { 117 return fmt.Errorf("error closing writer: %v", err) 118 } 119 120 r, err := decryptCipher.NewDecryptingReader(buf, aad) 121 if err != nil { 122 return fmt.Errorf("cannot create decrypt reader: %v", err) 123 } 124 ptGot := make([]byte, len(pt)+1) 125 n, err := io.ReadFull(r, ptGot) 126 if err != nil && err != io.ErrUnexpectedEOF { 127 return fmt.Errorf("decryption failed: %v", err) 128 } 129 ptGot = ptGot[:n] 130 if !bytes.Equal(pt, ptGot) { 131 return fmt.Errorf("decryption failed") 132 } 133 return nil 134} 135 136func TestFactoryWithInvalidPrimitiveSetType(t *testing.T) { 137 wrongKH, err := keyset.NewHandle(mac.HMACSHA256Tag128KeyTemplate()) 138 if err != nil { 139 t.Fatalf("failed to build *keyset.Handle: %s", err) 140 } 141 142 _, err = streamingaead.New(wrongKH) 143 if err == nil { 144 t.Fatal("New() should fail with wrong *keyset.Handle") 145 } 146} 147 148func TestFactoryWithValidPrimitiveSetType(t *testing.T) { 149 goodKH, err := keyset.NewHandle(streamingaead.AES128GCMHKDF4KBKeyTemplate()) 150 if err != nil { 151 t.Fatalf("failed to build *keyset.Handle: %s", err) 152 } 153 154 _, err = streamingaead.New(goodKH) 155 if err != nil { 156 t.Fatalf("New() failed with good *keyset.Handle: %s", err) 157 } 158} 159 160func TestFactoryWithKeysetWithTinkKeys(t *testing.T) { 161 key := &ghpb.AesGcmHkdfStreamingKey{ 162 Version: 0, 163 KeyValue: []byte("0123456789abcdef"), 164 Params: &ghpb.AesGcmHkdfStreamingParams{ 165 CiphertextSegmentSize: 512, 166 DerivedKeySize: 16, 167 HkdfHashType: commonpb.HashType_SHA1, 168 }, 169 } 170 value1, err := proto.Marshal(key) 171 if err != nil { 172 t.Fatalf("proto.Marshal(key) err = %q, want nil", err) 173 } 174 key.KeyValue = []byte("ABCDEF0123456789") 175 value2, err := proto.Marshal(key) 176 if err != nil { 177 t.Fatalf("proto.Marshal(key) err = %q, want nil", err) 178 } 179 180 keyset := &tinkpb.Keyset{ 181 PrimaryKeyId: 1, 182 Key: []*tinkpb.Keyset_Key{{ 183 KeyData: &tinkpb.KeyData{ 184 TypeUrl: aesGCMHKDFTypeURL, 185 Value: value1, 186 KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 187 }, 188 OutputPrefixType: tinkpb.OutputPrefixType_TINK, 189 KeyId: 1, 190 Status: tinkpb.KeyStatusType_ENABLED, 191 }, &tinkpb.Keyset_Key{ 192 KeyData: &tinkpb.KeyData{ 193 TypeUrl: aesGCMHKDFTypeURL, 194 Value: value2, 195 KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 196 }, 197 OutputPrefixType: tinkpb.OutputPrefixType_RAW, 198 KeyId: 2, 199 Status: tinkpb.KeyStatusType_ENABLED, 200 }}, 201 } 202 203 keysetHandle, err := testkeyset.NewHandle(keyset) 204 if err != nil { 205 t.Fatalf("testkeyset.NewHandle(keyset) err = %q, want nil", err) 206 } 207 a, err := streamingaead.New(keysetHandle) 208 if err != nil { 209 t.Errorf("streamingaead.New(keysetHandle) err = %q, want nil", err) 210 } 211 212 if err := validateFactoryCipher(a, a); err != nil { 213 t.Errorf("Encryption & Decryption with TINK key should succeed") 214 } 215} 216