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