xref: /aosp_15_r20/external/tink/go/testing/fakekms/fakekms.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2017 Google Inc.
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
17// Package fakekms provides a fake implementation of registry.KMSClient.
18//
19// Normally, a 'keyURI' identifies a key that is stored remotely by the KMS,
20// and every operation is executed remotely using a RPC call to the KMS, since
21// the key should not be sent to the client.
22// In this fake implementation we want to avoid these RPC calls. We achieve this
23// by encoding the key in the 'keyURI'. So the client simply needs to decode
24// the key and generate an AEAD out of it. This is of course insecure and should
25// only be used in testing.
26package fakekms
27
28import (
29	"bytes"
30	"encoding/base64"
31	"fmt"
32	"strings"
33
34	"github.com/google/tink/go/aead"
35	"github.com/google/tink/go/core/registry"
36	"github.com/google/tink/go/keyset"
37	"github.com/google/tink/go/testkeyset"
38	"github.com/google/tink/go/tink"
39)
40
41const fakePrefix = "fake-kms://"
42
43var _ registry.KMSClient = (*fakeClient)(nil)
44
45type fakeClient struct {
46	uriPrefix string
47}
48
49// NewClient returns a fake KMS client which will handle keys with uriPrefix prefix.
50// keyURI must have the following format: 'fake-kms://<base64 encoded aead keyset>'.
51func NewClient(uriPrefix string) (registry.KMSClient, error) {
52	if !strings.HasPrefix(strings.ToLower(uriPrefix), fakePrefix) {
53		return nil, fmt.Errorf("uriPrefix must start with %s, but got %s", fakePrefix, uriPrefix)
54	}
55	return &fakeClient{
56		uriPrefix: uriPrefix,
57	}, nil
58}
59
60// Supported returns true if this client does support keyURI.
61func (c *fakeClient) Supported(keyURI string) bool {
62	return strings.HasPrefix(keyURI, c.uriPrefix)
63}
64
65// GetAEAD returns an AEAD by keyURI.
66func (c *fakeClient) GetAEAD(keyURI string) (tink.AEAD, error) {
67	if !c.Supported(keyURI) {
68		return nil, fmt.Errorf("keyURI must start with prefix %s, but got %s", c.uriPrefix, keyURI)
69	}
70	encodeKeyset := strings.TrimPrefix(keyURI, fakePrefix)
71	keysetData, err := base64.RawURLEncoding.DecodeString(encodeKeyset)
72	if err != nil {
73		return nil, err
74	}
75	reader := keyset.NewBinaryReader(bytes.NewReader(keysetData))
76	handle, err := testkeyset.Read(reader)
77	if err != nil {
78		return nil, err
79	}
80	return aead.New(handle)
81}
82
83// NewKeyURI returns a new, random fake KMS key URI.
84func NewKeyURI() (string, error) {
85	handle, err := keyset.NewHandle(aead.AES128GCMKeyTemplate())
86	if err != nil {
87		return "", err
88	}
89	buf := new(bytes.Buffer)
90	writer := keyset.NewBinaryWriter(buf)
91	err = testkeyset.Write(handle, writer)
92	if err != nil {
93		return "", err
94	}
95	return fakePrefix + base64.RawURLEncoding.EncodeToString(buf.Bytes()), nil
96}
97