1// Copyright 2022 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 subtle_test 18 19import ( 20 "bytes" 21 "testing" 22 23 "google.golang.org/protobuf/proto" 24 "github.com/google/tink/go/hybrid" 25 "github.com/google/tink/go/hybrid/subtle" 26 "github.com/google/tink/go/keyset" 27 "github.com/google/tink/go/subtle/random" 28 "github.com/google/tink/go/testutil" 29 hpkepb "github.com/google/tink/go/proto/hpke_go_proto" 30 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 31) 32 33func TestHPKEPublicKeySerialization(t *testing.T) { 34 // Obtain private and public keyset handles via key template. 35 keyTemplate := hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_Raw_Key_Template() 36 privHandle, err := keyset.NewHandle(keyTemplate) 37 if err != nil { 38 t.Fatalf("NewHandle(%v) err = %v, want nil", keyTemplate, err) 39 } 40 pubHandle, err := privHandle.Public() 41 if err != nil { 42 t.Fatalf("Public() err = %v, want nil", err) 43 } 44 45 // Export public key as bytes. 46 pubKeyBytes, err := subtle.SerializePrimaryPublicKey(pubHandle, keyTemplate) 47 if err != nil { 48 t.Fatalf("SerializePrimaryPublicKey(%v) err = %v, want nil", pubHandle, err) 49 } 50 51 // Import public key bytes as keyset handle. 52 gotPubHandle, err := subtle.KeysetHandleFromSerializedPublicKey(pubKeyBytes, keyTemplate) 53 if err != nil { 54 t.Fatalf("KeysetHandleFromSerializedPublicKey(%v, %v) err = %v, want nil", pubKeyBytes, keyTemplate, err) 55 } 56 57 plaintext := random.GetRandomBytes(200) 58 ctxInfo := random.GetRandomBytes(100) 59 60 // Encrypt with public keyset handle constructed from public key bytes. 61 enc, err := hybrid.NewHybridEncrypt(gotPubHandle) 62 if err != nil { 63 t.Fatalf("NewHybridEncrypt(%v) err = %v, want nil", gotPubHandle, err) 64 } 65 ciphertext, err := enc.Encrypt(plaintext, ctxInfo) 66 if err != nil { 67 t.Fatalf("Encrypt(%x, %x) err = %v, want nil", plaintext, ctxInfo, err) 68 } 69 70 // Decrypt with original private keyset handle. 71 dec, err := hybrid.NewHybridDecrypt(privHandle) 72 if err != nil { 73 t.Fatalf("NewHybridDecrypt(%v) err = %v, want nil", privHandle, err) 74 } 75 gotPlaintext, err := dec.Decrypt(ciphertext, ctxInfo) 76 if err != nil { 77 t.Fatalf("Decrypt(%x, %x) err = %v, want nil", plaintext, ctxInfo, err) 78 } 79 if !bytes.Equal(gotPlaintext, plaintext) { 80 t.Errorf("Decrypt(%x, %x) = %x, want %x", plaintext, ctxInfo, gotPlaintext, plaintext) 81 } 82} 83 84func TestSerializePrimaryPublicKeyInvalidTemplateFails(t *testing.T) { 85 keyTemplate := hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_Raw_Key_Template() 86 privHandle, err := keyset.NewHandle(keyTemplate) 87 if err != nil { 88 t.Fatalf("NewHandle(%v) err = %v, want nil", keyTemplate, err) 89 } 90 pubHandle, err := privHandle.Public() 91 if err != nil { 92 t.Fatalf("Public() err = %v, want nil", err) 93 } 94 95 tests := []struct { 96 name string 97 template *tinkpb.KeyTemplate 98 }{ 99 {"AES_128_GCM", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM_Key_Template()}, 100 {"AES_128_GCM_Raw", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM_Raw_Key_Template()}, 101 {"AES_256_GCM", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM_Key_Template()}, 102 {"AES_256_GCM_Raw", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM_Raw_Key_Template()}, 103 {"CHACHA20_POLY1305", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_Key_Template()}, 104 {"invalid type URL", &tinkpb.KeyTemplate{ 105 TypeUrl: "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey", 106 Value: keyTemplate.GetValue(), 107 OutputPrefixType: tinkpb.OutputPrefixType_RAW, 108 }}, 109 } 110 for _, test := range tests { 111 t.Run(test.name, func(t *testing.T) { 112 if _, err := subtle.SerializePrimaryPublicKey(pubHandle, test.template); err == nil { 113 t.Errorf("SerializePrimaryPublicKey(%v, %v) err = nil, want error", pubHandle, test.template) 114 } 115 }) 116 } 117} 118 119func TestSerializePrimaryPublicKeyInvalidHandleFails(t *testing.T) { 120 // Build valid key data. 121 keyTemplate := hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_Raw_Key_Template() 122 privHandle, err := keyset.NewHandle(keyTemplate) 123 if err != nil { 124 t.Fatalf("NewHandle(%v) err = %v, want nil", keyTemplate, err) 125 } 126 pubHandle, err := privHandle.Public() 127 if err != nil { 128 t.Fatalf("Public() err = %v, want nil", err) 129 } 130 pubKeyBytes, err := subtle.SerializePrimaryPublicKey(pubHandle, keyTemplate) 131 if err != nil { 132 t.Fatalf("SerializePrimaryPublicKey(%v, %v) err = %v, want nil", pubHandle, keyTemplate, err) 133 } 134 typeURL := "type.googleapis.com/google.crypto.tink.HpkePublicKey" 135 validKD, err := keyDataFromBytes(t, pubKeyBytes, hpkepb.HpkeAead_CHACHA20_POLY1305, typeURL) 136 if err != nil { 137 t.Fatalf("keyDataFromBytes(%v, %v, %v) err = %v, want nil", pubKeyBytes, hpkepb.HpkeAead_CHACHA20_POLY1305, typeURL, err) 138 } 139 140 // Build key data with invalid type URL. 141 invalidTypeURL := "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey" 142 invalidTypeURLKD, err := keyDataFromBytes(t, pubKeyBytes, hpkepb.HpkeAead_CHACHA20_POLY1305, invalidTypeURL) 143 if err != nil { 144 t.Fatalf("keyDataFromBytes(%v, %v, %v) err = %v, want nil", pubKeyBytes, hpkepb.HpkeAead_CHACHA20_POLY1305, invalidTypeURL, err) 145 } 146 147 // Build key data with invalid HPKE params. 148 randomPubKeyBytes := random.GetRandomBytes(32) 149 invalidAEAD := hpkepb.HpkeAead_AES_128_GCM 150 invalidParamsKD, err := keyDataFromBytes(t, randomPubKeyBytes, invalidAEAD, typeURL) 151 if err != nil { 152 t.Fatalf("keyDataFromBytes(%v, %v, %v) err = %v, want nil", randomPubKeyBytes, invalidAEAD, typeURL, err) 153 } 154 155 tests := []struct { 156 name string 157 primaryKeyID uint32 158 key *tinkpb.Keyset_Key 159 }{ 160 { 161 "empty", 162 123, 163 nil, 164 }, 165 { 166 "invalid status type", 167 123, 168 testutil.NewKey(validKD, tinkpb.KeyStatusType_DISABLED, 123, tinkpb.OutputPrefixType_RAW), 169 }, 170 { 171 "invalid prefix type", 172 123, 173 testutil.NewKey(validKD, tinkpb.KeyStatusType_ENABLED, 123, tinkpb.OutputPrefixType_TINK), 174 }, 175 { 176 "no primary key", 177 0, 178 testutil.NewKey(validKD, tinkpb.KeyStatusType_ENABLED, 123, tinkpb.OutputPrefixType_RAW), 179 }, 180 { 181 "invalid type URL", 182 123, 183 testutil.NewKey(invalidTypeURLKD, tinkpb.KeyStatusType_ENABLED, 123, tinkpb.OutputPrefixType_RAW), 184 }, 185 { 186 "invalid HPKE params", 187 123, 188 testutil.NewKey(invalidParamsKD, tinkpb.KeyStatusType_ENABLED, 123, tinkpb.OutputPrefixType_RAW), 189 }, 190 } 191 192 for _, test := range tests { 193 t.Run(test.name, func(t *testing.T) { 194 ks := testutil.NewKeyset(test.primaryKeyID, []*tinkpb.Keyset_Key{test.key}) 195 handle, err := keyset.NewHandleWithNoSecrets(ks) 196 if err != nil { 197 t.Fatalf("NewHandleWithNoSecrets(%v) err = %v, want nil", ks, err) 198 } 199 if _, err := subtle.SerializePrimaryPublicKey(handle, keyTemplate); err == nil { 200 t.Errorf("SerializePrimaryPublicKey(%v, %v) err = nil, want error", handle, keyTemplate) 201 } 202 }) 203 } 204} 205 206func TestKeysetHandleFromSerializedPublicKeyInvalidTemplateFails(t *testing.T) { 207 keyTemplate := hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_Raw_Key_Template() 208 privHandle, err := keyset.NewHandle(keyTemplate) 209 if err != nil { 210 t.Fatalf("NewHandle(%v) err = %v, want nil", keyTemplate, err) 211 } 212 pubHandle, err := privHandle.Public() 213 if err != nil { 214 t.Fatalf("Public() err = %v, want nil", err) 215 } 216 pubKeyBytes, err := subtle.SerializePrimaryPublicKey(pubHandle, keyTemplate) 217 if err != nil { 218 t.Fatalf("SerializePrimaryPublicKey(%v) err = %v, want nil", pubHandle, err) 219 } 220 221 tests := []struct { 222 name string 223 template *tinkpb.KeyTemplate 224 }{ 225 {"AES_128_GCM", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM_Key_Template()}, 226 {"AES_128_GCM_Raw", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM_Raw_Key_Template()}, 227 {"AES_256_GCM", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM_Key_Template()}, 228 {"AES_256_GCM_Raw", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM_Raw_Key_Template()}, 229 {"CHACHA20_POLY1305", hybrid.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_Key_Template()}, 230 {"invalid type URL", &tinkpb.KeyTemplate{ 231 TypeUrl: "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey", 232 Value: keyTemplate.GetValue(), 233 OutputPrefixType: tinkpb.OutputPrefixType_RAW, 234 }}, 235 } 236 for _, test := range tests { 237 t.Run(test.name, func(t *testing.T) { 238 if _, err := subtle.KeysetHandleFromSerializedPublicKey(pubKeyBytes, test.template); err == nil { 239 t.Errorf("KeysetHandleFromSerializedPublicKey(%v, %v) err = nil, want error", pubKeyBytes, test.template) 240 } 241 }) 242 } 243} 244 245func keyDataFromBytes(t *testing.T, pubKeyBytes []byte, aeadID hpkepb.HpkeAead, typeURL string) (*tinkpb.KeyData, error) { 246 t.Helper() 247 248 pubKey := &hpkepb.HpkePublicKey{ 249 Version: 0, 250 Params: &hpkepb.HpkeParams{ 251 Kem: hpkepb.HpkeKem_DHKEM_X25519_HKDF_SHA256, 252 Kdf: hpkepb.HpkeKdf_HKDF_SHA256, 253 Aead: aeadID, 254 }, 255 PublicKey: pubKeyBytes, 256 } 257 258 serializedPubKey, err := proto.Marshal(pubKey) 259 if err != nil { 260 return nil, err 261 } 262 263 return testutil.NewKeyData(typeURL, serializedPubKey, tinkpb.KeyData_ASYMMETRIC_PUBLIC), nil 264} 265