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 "golang.org/x/crypto/chacha20poly1305" 25 "google.golang.org/protobuf/proto" 26 "github.com/google/tink/go/core/registry" 27 "github.com/google/tink/go/subtle/random" 28 "github.com/google/tink/go/testutil" 29 30 "github.com/google/tink/go/aead/subtle" 31 cppb "github.com/google/tink/go/proto/chacha20_poly1305_go_proto" 32 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 33) 34 35func TestChaCha20Poly1305GetPrimitive(t *testing.T) { 36 km, err := registry.GetKeyManager(testutil.ChaCha20Poly1305TypeURL) 37 if err != nil { 38 t.Errorf("cannot obtain ChaCha20Poly1305 key manager: %s", err) 39 } 40 m, _ := km.NewKey(nil) 41 key, _ := m.(*cppb.ChaCha20Poly1305Key) 42 serializedKey, _ := proto.Marshal(key) 43 p, err := km.Primitive(serializedKey) 44 if err != nil { 45 t.Errorf("km.Primitive(%v) = %v; want nil", serializedKey, err) 46 } 47 if err := validateChaCha20Poly1305Primitive(p, key); err != nil { 48 t.Errorf("validateChaCha20Poly1305Primitive(p, key) = %v; want nil", err) 49 } 50} 51 52func TestChaCha20Poly1305GetPrimitiveWithInvalidKeys(t *testing.T) { 53 km, err := registry.GetKeyManager(testutil.ChaCha20Poly1305TypeURL) 54 if err != nil { 55 t.Errorf("cannot obtain ChaCha20Poly1305 key manager: %s", err) 56 } 57 invalidKeys := genInvalidChaCha20Poly1305Keys() 58 for _, key := range invalidKeys { 59 serializedKey, _ := proto.Marshal(key) 60 if _, err := km.Primitive(serializedKey); err == nil { 61 t.Errorf("km.Primitive(%v) = _, nil; want _, err", serializedKey) 62 } 63 } 64} 65 66func TestChaCha20Poly1305NewKey(t *testing.T) { 67 km, err := registry.GetKeyManager(testutil.ChaCha20Poly1305TypeURL) 68 if err != nil { 69 t.Errorf("cannot obtain ChaCha20Poly1305 key manager: %s", err) 70 } 71 m, err := km.NewKey(nil) 72 if err != nil { 73 t.Errorf("km.NewKey(nil) = _, %v; want _, nil", err) 74 } 75 key, _ := m.(*cppb.ChaCha20Poly1305Key) 76 if err := validateChaCha20Poly1305Key(key); err != nil { 77 t.Errorf("validateChaCha20Poly1305Key(%v) = %v; want nil", key, err) 78 } 79} 80 81func TestChaCha20Poly1305NewKeyData(t *testing.T) { 82 km, err := registry.GetKeyManager(testutil.ChaCha20Poly1305TypeURL) 83 if err != nil { 84 t.Errorf("cannot obtain ChaCha20Poly1305 key manager: %s", err) 85 } 86 kd, err := km.NewKeyData(nil) 87 if err != nil { 88 t.Errorf("km.NewKeyData(nil) = _, %v; want _, nil", err) 89 } 90 if kd.TypeUrl != testutil.ChaCha20Poly1305TypeURL { 91 t.Errorf("TypeUrl: %v != %v", kd.TypeUrl, testutil.ChaCha20Poly1305TypeURL) 92 } 93 if kd.KeyMaterialType != tinkpb.KeyData_SYMMETRIC { 94 t.Errorf("KeyMaterialType: %v != SYMMETRIC", kd.KeyMaterialType) 95 } 96 key := new(cppb.ChaCha20Poly1305Key) 97 if err := proto.Unmarshal(kd.Value, key); err != nil { 98 t.Errorf("proto.Unmarshal(%v, key) = %v; want nil", kd.Value, err) 99 } 100 if err := validateChaCha20Poly1305Key(key); err != nil { 101 t.Errorf("validateChaCha20Poly1305Key(%v) = %v; want nil", key, err) 102 } 103} 104 105func TestChaCha20Poly1305DoesSupport(t *testing.T) { 106 km, err := registry.GetKeyManager(testutil.ChaCha20Poly1305TypeURL) 107 if err != nil { 108 t.Errorf("cannot obtain ChaCha20Poly1305 key manager: %s", err) 109 } 110 if !km.DoesSupport(testutil.ChaCha20Poly1305TypeURL) { 111 t.Errorf("ChaCha20Poly1305KeyManager must support %s", testutil.ChaCha20Poly1305TypeURL) 112 } 113 if km.DoesSupport("some bad type") { 114 t.Errorf("ChaCha20Poly1305KeyManager must only support %s", testutil.ChaCha20Poly1305TypeURL) 115 } 116} 117 118func TestChaCha20Poly1305TypeURL(t *testing.T) { 119 km, err := registry.GetKeyManager(testutil.ChaCha20Poly1305TypeURL) 120 if err != nil { 121 t.Errorf("cannot obtain ChaCha20Poly1305 key manager: %s", err) 122 } 123 if kt := km.TypeURL(); kt != testutil.ChaCha20Poly1305TypeURL { 124 t.Errorf("km.TypeURL() = %s; want %s", kt, testutil.ChaCha20Poly1305TypeURL) 125 } 126} 127 128func genInvalidChaCha20Poly1305Keys() []*cppb.ChaCha20Poly1305Key { 129 return []*cppb.ChaCha20Poly1305Key{ 130 // Bad key size. 131 &cppb.ChaCha20Poly1305Key{ 132 Version: testutil.ChaCha20Poly1305KeyVersion, 133 KeyValue: random.GetRandomBytes(17), 134 }, 135 &cppb.ChaCha20Poly1305Key{ 136 Version: testutil.ChaCha20Poly1305KeyVersion, 137 KeyValue: random.GetRandomBytes(25), 138 }, 139 &cppb.ChaCha20Poly1305Key{ 140 Version: testutil.ChaCha20Poly1305KeyVersion, 141 KeyValue: random.GetRandomBytes(33), 142 }, 143 // Bad version. 144 &cppb.ChaCha20Poly1305Key{ 145 Version: testutil.ChaCha20Poly1305KeyVersion + 1, 146 KeyValue: random.GetRandomBytes(chacha20poly1305.KeySize), 147 }, 148 } 149} 150 151func validateChaCha20Poly1305Primitive(p interface{}, key *cppb.ChaCha20Poly1305Key) error { 152 cipher := p.(*subtle.ChaCha20Poly1305) 153 if !bytes.Equal(cipher.Key, key.KeyValue) { 154 return fmt.Errorf("key and primitive don't match") 155 } 156 157 // Try to encrypt and decrypt. 158 pt := random.GetRandomBytes(32) 159 aad := random.GetRandomBytes(32) 160 ct, err := cipher.Encrypt(pt, aad) 161 if err != nil { 162 return fmt.Errorf("encryption failed") 163 } 164 decrypted, err := cipher.Decrypt(ct, aad) 165 if err != nil { 166 return fmt.Errorf("decryption failed") 167 } 168 if !bytes.Equal(decrypted, pt) { 169 return fmt.Errorf("decryption failed") 170 } 171 return nil 172} 173 174func validateChaCha20Poly1305Key(key *cppb.ChaCha20Poly1305Key) error { 175 if key.Version != testutil.ChaCha20Poly1305KeyVersion { 176 return fmt.Errorf("incorrect key version: keyVersion != %d", testutil.ChaCha20Poly1305KeyVersion) 177 } 178 if uint32(len(key.KeyValue)) != chacha20poly1305.KeySize { 179 return fmt.Errorf("incorrect key size: keySize != %d", chacha20poly1305.KeySize) 180 } 181 182 // Try to encrypt and decrypt. 183 p, err := subtle.NewChaCha20Poly1305(key.KeyValue) 184 if err != nil { 185 return fmt.Errorf("invalid key: %v", key.KeyValue) 186 } 187 return validateChaCha20Poly1305Primitive(p, key) 188} 189