1*e7b1675dSTing-Kang Chang// Copyright 2019 Google LLC 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Changpackage keyset_test 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "bytes" 21*e7b1675dSTing-Kang Chang "encoding/base64" 22*e7b1675dSTing-Kang Chang "fmt" 23*e7b1675dSTing-Kang Chang "strings" 24*e7b1675dSTing-Kang Chang "testing" 25*e7b1675dSTing-Kang Chang 26*e7b1675dSTing-Kang Chang "google.golang.org/protobuf/proto" 27*e7b1675dSTing-Kang Chang "github.com/google/tink/go/keyset" 28*e7b1675dSTing-Kang Chang "github.com/google/tink/go/testkeyset" 29*e7b1675dSTing-Kang Chang "github.com/google/tink/go/testutil" 30*e7b1675dSTing-Kang Chang 31*e7b1675dSTing-Kang Chang commonpb "github.com/google/tink/go/proto/common_go_proto" 32*e7b1675dSTing-Kang Chang tinkpb "github.com/google/tink/go/proto/tink_go_proto" 33*e7b1675dSTing-Kang Chang) 34*e7b1675dSTing-Kang Chang 35*e7b1675dSTing-Kang Changfunc TestJSONIOUnencrypted(t *testing.T) { 36*e7b1675dSTing-Kang Chang buf := new(bytes.Buffer) 37*e7b1675dSTing-Kang Chang w := keyset.NewJSONWriter(buf) 38*e7b1675dSTing-Kang Chang r := keyset.NewJSONReader(buf) 39*e7b1675dSTing-Kang Chang 40*e7b1675dSTing-Kang Chang manager := testutil.NewHMACKeysetManager() 41*e7b1675dSTing-Kang Chang h, err := manager.Handle() 42*e7b1675dSTing-Kang Chang if h == nil || err != nil { 43*e7b1675dSTing-Kang Chang t.Fatalf("cannot get keyset handle: %v", err) 44*e7b1675dSTing-Kang Chang } 45*e7b1675dSTing-Kang Chang 46*e7b1675dSTing-Kang Chang ks1 := testkeyset.KeysetMaterial(h) 47*e7b1675dSTing-Kang Chang if err := w.Write(ks1); err != nil { 48*e7b1675dSTing-Kang Chang t.Fatalf("cannot write keyset: %v", err) 49*e7b1675dSTing-Kang Chang } 50*e7b1675dSTing-Kang Chang 51*e7b1675dSTing-Kang Chang ks2, err := r.Read() 52*e7b1675dSTing-Kang Chang if err != nil { 53*e7b1675dSTing-Kang Chang t.Fatalf("cannot read keyset: %v", err) 54*e7b1675dSTing-Kang Chang } 55*e7b1675dSTing-Kang Chang 56*e7b1675dSTing-Kang Chang if !proto.Equal(ks1, ks2) { 57*e7b1675dSTing-Kang Chang t.Errorf("written keyset (%s) doesn't match read keyset (%s)", ks1, ks2) 58*e7b1675dSTing-Kang Chang } 59*e7b1675dSTing-Kang Chang} 60*e7b1675dSTing-Kang Chang 61*e7b1675dSTing-Kang Changfunc TestJSONReader(t *testing.T) { 62*e7b1675dSTing-Kang Chang gcmkey := []byte(testutil.NewAESGCMKey(0, 16).String()) 63*e7b1675dSTing-Kang Chang eaxkey := []byte(testutil.NewHMACKey(commonpb.HashType_SHA512, 32).String()) 64*e7b1675dSTing-Kang Chang jsonKeyset := fmt.Sprintf(`{ 65*e7b1675dSTing-Kang Chang "primaryKeyId":42, 66*e7b1675dSTing-Kang Chang "key":[ 67*e7b1675dSTing-Kang Chang { 68*e7b1675dSTing-Kang Chang "keyData":{ 69*e7b1675dSTing-Kang Chang "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey", 70*e7b1675dSTing-Kang Chang "keyMaterialType":"SYMMETRIC", 71*e7b1675dSTing-Kang Chang "value": %q 72*e7b1675dSTing-Kang Chang }, 73*e7b1675dSTing-Kang Chang "outputPrefixType":"TINK", 74*e7b1675dSTing-Kang Chang "keyId":42, 75*e7b1675dSTing-Kang Chang "status":"ENABLED" 76*e7b1675dSTing-Kang Chang }, 77*e7b1675dSTing-Kang Chang { 78*e7b1675dSTing-Kang Chang "keyData":{ 79*e7b1675dSTing-Kang Chang "typeUrl":"type.googleapis.com/google.crypto.tink.AesEaxKey", 80*e7b1675dSTing-Kang Chang "keyMaterialType":"SYMMETRIC", 81*e7b1675dSTing-Kang Chang "value": %q 82*e7b1675dSTing-Kang Chang }, 83*e7b1675dSTing-Kang Chang "outputPrefixType":"RAW", 84*e7b1675dSTing-Kang Chang "keyId":711, 85*e7b1675dSTing-Kang Chang "status":"ENABLED" 86*e7b1675dSTing-Kang Chang } 87*e7b1675dSTing-Kang Chang ] 88*e7b1675dSTing-Kang Chang }`, base64.StdEncoding.EncodeToString([]byte(gcmkey)), base64.StdEncoding.EncodeToString([]byte(eaxkey))) 89*e7b1675dSTing-Kang Chang r := keyset.NewJSONReader(bytes.NewBufferString(jsonKeyset)) 90*e7b1675dSTing-Kang Chang 91*e7b1675dSTing-Kang Chang got, err := r.Read() 92*e7b1675dSTing-Kang Chang if err != nil { 93*e7b1675dSTing-Kang Chang t.Fatalf("cannot read keyset: %v", err) 94*e7b1675dSTing-Kang Chang } 95*e7b1675dSTing-Kang Chang 96*e7b1675dSTing-Kang Chang want := &tinkpb.Keyset{ 97*e7b1675dSTing-Kang Chang PrimaryKeyId: 42, 98*e7b1675dSTing-Kang Chang Key: []*tinkpb.Keyset_Key{ 99*e7b1675dSTing-Kang Chang { 100*e7b1675dSTing-Kang Chang KeyData: &tinkpb.KeyData{ 101*e7b1675dSTing-Kang Chang TypeUrl: "type.googleapis.com/google.crypto.tink.AesGcmKey", 102*e7b1675dSTing-Kang Chang KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 103*e7b1675dSTing-Kang Chang Value: gcmkey, 104*e7b1675dSTing-Kang Chang }, 105*e7b1675dSTing-Kang Chang OutputPrefixType: tinkpb.OutputPrefixType_TINK, 106*e7b1675dSTing-Kang Chang KeyId: 42, 107*e7b1675dSTing-Kang Chang Status: tinkpb.KeyStatusType_ENABLED, 108*e7b1675dSTing-Kang Chang }, 109*e7b1675dSTing-Kang Chang { 110*e7b1675dSTing-Kang Chang KeyData: &tinkpb.KeyData{ 111*e7b1675dSTing-Kang Chang TypeUrl: "type.googleapis.com/google.crypto.tink.AesEaxKey", 112*e7b1675dSTing-Kang Chang KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 113*e7b1675dSTing-Kang Chang Value: eaxkey, 114*e7b1675dSTing-Kang Chang }, 115*e7b1675dSTing-Kang Chang OutputPrefixType: tinkpb.OutputPrefixType_RAW, 116*e7b1675dSTing-Kang Chang KeyId: 711, 117*e7b1675dSTing-Kang Chang Status: tinkpb.KeyStatusType_ENABLED, 118*e7b1675dSTing-Kang Chang }, 119*e7b1675dSTing-Kang Chang }, 120*e7b1675dSTing-Kang Chang } 121*e7b1675dSTing-Kang Chang 122*e7b1675dSTing-Kang Chang if !proto.Equal(got, want) { 123*e7b1675dSTing-Kang Chang t.Errorf("written keyset %q doesn't match expected keyset %q", got, want) 124*e7b1675dSTing-Kang Chang } 125*e7b1675dSTing-Kang Chang} 126*e7b1675dSTing-Kang Chang 127*e7b1675dSTing-Kang Changfunc TestJSONReaderLargeIds(t *testing.T) { 128*e7b1675dSTing-Kang Chang gcmkey := []byte(testutil.NewAESGCMKey(0, 16).String()) 129*e7b1675dSTing-Kang Chang jsonKeyset := fmt.Sprintf(`{ 130*e7b1675dSTing-Kang Chang "primaryKeyId":4294967275, 131*e7b1675dSTing-Kang Chang "key":[ 132*e7b1675dSTing-Kang Chang { 133*e7b1675dSTing-Kang Chang "keyData":{ 134*e7b1675dSTing-Kang Chang "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey", 135*e7b1675dSTing-Kang Chang "keyMaterialType":"SYMMETRIC", 136*e7b1675dSTing-Kang Chang "value": %q 137*e7b1675dSTing-Kang Chang }, 138*e7b1675dSTing-Kang Chang "outputPrefixType":"TINK", 139*e7b1675dSTing-Kang Chang "keyId":4294967275, 140*e7b1675dSTing-Kang Chang "status":"ENABLED" 141*e7b1675dSTing-Kang Chang } 142*e7b1675dSTing-Kang Chang ] 143*e7b1675dSTing-Kang Chang }`, base64.StdEncoding.EncodeToString([]byte(gcmkey))) 144*e7b1675dSTing-Kang Chang r := keyset.NewJSONReader(bytes.NewBufferString(jsonKeyset)) 145*e7b1675dSTing-Kang Chang 146*e7b1675dSTing-Kang Chang got, err := r.Read() 147*e7b1675dSTing-Kang Chang if err != nil { 148*e7b1675dSTing-Kang Chang t.Fatalf("cannot read keyset: %v", err) 149*e7b1675dSTing-Kang Chang } 150*e7b1675dSTing-Kang Chang 151*e7b1675dSTing-Kang Chang want := &tinkpb.Keyset{ 152*e7b1675dSTing-Kang Chang PrimaryKeyId: 4294967275, 153*e7b1675dSTing-Kang Chang Key: []*tinkpb.Keyset_Key{ 154*e7b1675dSTing-Kang Chang { 155*e7b1675dSTing-Kang Chang KeyData: &tinkpb.KeyData{ 156*e7b1675dSTing-Kang Chang TypeUrl: "type.googleapis.com/google.crypto.tink.AesGcmKey", 157*e7b1675dSTing-Kang Chang KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 158*e7b1675dSTing-Kang Chang Value: gcmkey, 159*e7b1675dSTing-Kang Chang }, 160*e7b1675dSTing-Kang Chang OutputPrefixType: tinkpb.OutputPrefixType_TINK, 161*e7b1675dSTing-Kang Chang KeyId: 4294967275, 162*e7b1675dSTing-Kang Chang Status: tinkpb.KeyStatusType_ENABLED, 163*e7b1675dSTing-Kang Chang }, 164*e7b1675dSTing-Kang Chang }, 165*e7b1675dSTing-Kang Chang } 166*e7b1675dSTing-Kang Chang 167*e7b1675dSTing-Kang Chang if !proto.Equal(got, want) { 168*e7b1675dSTing-Kang Chang t.Errorf("written keyset %q doesn't match expected keyset %q", got, want) 169*e7b1675dSTing-Kang Chang } 170*e7b1675dSTing-Kang Chang} 171*e7b1675dSTing-Kang Chang 172*e7b1675dSTing-Kang Changfunc TestJSONReaderRejectsNegativeKeyIds(t *testing.T) { 173*e7b1675dSTing-Kang Chang gcmkey := []byte(testutil.NewAESGCMKey(0, 16).String()) 174*e7b1675dSTing-Kang Chang jsonKeyset := fmt.Sprintf(`{ 175*e7b1675dSTing-Kang Chang "primaryKeyId": -10, 176*e7b1675dSTing-Kang Chang "key":[ 177*e7b1675dSTing-Kang Chang { 178*e7b1675dSTing-Kang Chang "keyData":{ 179*e7b1675dSTing-Kang Chang "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey", 180*e7b1675dSTing-Kang Chang "keyMaterialType":"SYMMETRIC", 181*e7b1675dSTing-Kang Chang "value": %q 182*e7b1675dSTing-Kang Chang }, 183*e7b1675dSTing-Kang Chang "outputPrefixType":"TINK", 184*e7b1675dSTing-Kang Chang "keyId": -10, 185*e7b1675dSTing-Kang Chang "status":"ENABLED" 186*e7b1675dSTing-Kang Chang } 187*e7b1675dSTing-Kang Chang ] 188*e7b1675dSTing-Kang Chang }`, base64.StdEncoding.EncodeToString(gcmkey)) 189*e7b1675dSTing-Kang Chang r := keyset.NewJSONReader(bytes.NewBufferString(jsonKeyset)) 190*e7b1675dSTing-Kang Chang 191*e7b1675dSTing-Kang Chang _, err := r.Read() 192*e7b1675dSTing-Kang Chang if err == nil { 193*e7b1675dSTing-Kang Chang t.Fatalf("Expected failure due to negative key id") 194*e7b1675dSTing-Kang Chang } 195*e7b1675dSTing-Kang Chang} 196*e7b1675dSTing-Kang Chang 197*e7b1675dSTing-Kang Changfunc TestJSONReaderRejectsKeyIdLargerThanUint32(t *testing.T) { 198*e7b1675dSTing-Kang Chang // 4294967296 = 2^32, which is too large for uint32. 199*e7b1675dSTing-Kang Chang gcmkey := []byte(testutil.NewAESGCMKey(0, 16).String()) 200*e7b1675dSTing-Kang Chang jsonKeyset := fmt.Sprintf(`{ 201*e7b1675dSTing-Kang Chang "primaryKeyId": 4294967296, 202*e7b1675dSTing-Kang Chang "key":[ 203*e7b1675dSTing-Kang Chang { 204*e7b1675dSTing-Kang Chang "keyData":{ 205*e7b1675dSTing-Kang Chang "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey", 206*e7b1675dSTing-Kang Chang "keyMaterialType":"SYMMETRIC", 207*e7b1675dSTing-Kang Chang "value": %q 208*e7b1675dSTing-Kang Chang }, 209*e7b1675dSTing-Kang Chang "outputPrefixType":"TINK", 210*e7b1675dSTing-Kang Chang "keyId": 4294967296, 211*e7b1675dSTing-Kang Chang "status":"ENABLED" 212*e7b1675dSTing-Kang Chang } 213*e7b1675dSTing-Kang Chang ] 214*e7b1675dSTing-Kang Chang }`, base64.StdEncoding.EncodeToString(gcmkey)) 215*e7b1675dSTing-Kang Chang r := keyset.NewJSONReader(bytes.NewBufferString(jsonKeyset)) 216*e7b1675dSTing-Kang Chang 217*e7b1675dSTing-Kang Chang _, err := r.Read() 218*e7b1675dSTing-Kang Chang if err == nil { 219*e7b1675dSTing-Kang Chang t.Fatalf("Expected failure due to negative key id") 220*e7b1675dSTing-Kang Chang } 221*e7b1675dSTing-Kang Chang} 222*e7b1675dSTing-Kang Chang 223*e7b1675dSTing-Kang Chang// Tests that large IDs (>2^31) are written correctly. 224*e7b1675dSTing-Kang Changfunc TestJSONWriterLargeId(t *testing.T) { 225*e7b1675dSTing-Kang Chang eaxkey := []byte(testutil.NewHMACKey(commonpb.HashType_SHA512, 32).String()) 226*e7b1675dSTing-Kang Chang 227*e7b1675dSTing-Kang Chang ks := tinkpb.Keyset{ 228*e7b1675dSTing-Kang Chang PrimaryKeyId: 4294967275, 229*e7b1675dSTing-Kang Chang Key: []*tinkpb.Keyset_Key{ 230*e7b1675dSTing-Kang Chang { 231*e7b1675dSTing-Kang Chang KeyData: &tinkpb.KeyData{ 232*e7b1675dSTing-Kang Chang TypeUrl: "type.googleapis.com/google.crypto.tink.AesEaxKey", 233*e7b1675dSTing-Kang Chang KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 234*e7b1675dSTing-Kang Chang Value: eaxkey, 235*e7b1675dSTing-Kang Chang }, 236*e7b1675dSTing-Kang Chang OutputPrefixType: tinkpb.OutputPrefixType_RAW, 237*e7b1675dSTing-Kang Chang KeyId: 4294967275, 238*e7b1675dSTing-Kang Chang Status: tinkpb.KeyStatusType_ENABLED, 239*e7b1675dSTing-Kang Chang }, 240*e7b1675dSTing-Kang Chang }, 241*e7b1675dSTing-Kang Chang } 242*e7b1675dSTing-Kang Chang 243*e7b1675dSTing-Kang Chang buf := new(bytes.Buffer) 244*e7b1675dSTing-Kang Chang w := keyset.NewJSONWriter(buf) 245*e7b1675dSTing-Kang Chang if err := w.Write(&ks); err != nil { 246*e7b1675dSTing-Kang Chang t.Fatalf("cannot write keyset: %v", err) 247*e7b1675dSTing-Kang Chang } 248*e7b1675dSTing-Kang Chang 249*e7b1675dSTing-Kang Chang if !strings.Contains(buf.String(), `"keyId":4294967275`) { 250*e7b1675dSTing-Kang Chang t.Errorf("written keyset %q does not contain a key with keyId 4294967275", buf.Bytes()) 251*e7b1675dSTing-Kang Chang } 252*e7b1675dSTing-Kang Chang if !strings.Contains(buf.String(), "\"primaryKeyId\":4294967275") { 253*e7b1675dSTing-Kang Chang t.Errorf("written keyset %q does not contain have primaryKeyId 4294967275", buf.Bytes()) 254*e7b1675dSTing-Kang Chang } 255*e7b1675dSTing-Kang Chang} 256*e7b1675dSTing-Kang Chang 257*e7b1675dSTing-Kang Changfunc TestJSONIOEncrypted(t *testing.T) { 258*e7b1675dSTing-Kang Chang buf := new(bytes.Buffer) 259*e7b1675dSTing-Kang Chang w := keyset.NewJSONWriter(buf) 260*e7b1675dSTing-Kang Chang r := keyset.NewJSONReader(buf) 261*e7b1675dSTing-Kang Chang 262*e7b1675dSTing-Kang Chang kse1 := &tinkpb.EncryptedKeyset{EncryptedKeyset: []byte(strings.Repeat("A", 32))} 263*e7b1675dSTing-Kang Chang 264*e7b1675dSTing-Kang Chang if err := w.WriteEncrypted(kse1); err != nil { 265*e7b1675dSTing-Kang Chang t.Fatalf("cannot write encrypted keyset: %v", err) 266*e7b1675dSTing-Kang Chang } 267*e7b1675dSTing-Kang Chang 268*e7b1675dSTing-Kang Chang kse2, err := r.ReadEncrypted() 269*e7b1675dSTing-Kang Chang if err != nil { 270*e7b1675dSTing-Kang Chang t.Fatalf("cannot read encryped keyset: %v", err) 271*e7b1675dSTing-Kang Chang } 272*e7b1675dSTing-Kang Chang 273*e7b1675dSTing-Kang Chang if !proto.Equal(kse1, kse2) { 274*e7b1675dSTing-Kang Chang t.Errorf("written encryped keyset %q doesn't match read encryped keyset %q", kse1, kse2) 275*e7b1675dSTing-Kang Chang } 276*e7b1675dSTing-Kang Chang} 277