blob: d863fff8e2d2932bd1b45a3af93bbae1082259db [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
package services_test
import (
"bytes"
"context"
"errors"
"fmt"
"strings"
"testing"
"github.com/golang/protobuf/proto"
"github.com/google/tink/go/aead"
"github.com/google/tink/go/daead"
"github.com/google/tink/go/hybrid"
"github.com/google/tink/go/keyset"
"github.com/google/tink/go/mac"
"github.com/google/tink/go/signature"
"github.com/google/tink/go/streamingaead"
pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
"github.com/google/tink/testing/go/services"
)
func genKeyset(ctx context.Context, keysetService *services.KeysetService, template []byte) ([]byte, error) {
genRequest := &pb.KeysetGenerateRequest{Template: template}
genResponse, err := keysetService.Generate(ctx, genRequest)
if err != nil {
return nil, err
}
switch r := genResponse.Result.(type) {
case *pb.KeysetGenerateResponse_Keyset:
return r.Keyset, nil
case *pb.KeysetGenerateResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("genResponse.Result has unexpected type %T", r)
}
}
func pubKeyset(ctx context.Context, keysetService *services.KeysetService, privateKeyset []byte) ([]byte, error) {
request := &pb.KeysetPublicRequest{PrivateKeyset: privateKeyset}
response, err := keysetService.Public(ctx, request)
if err != nil {
return nil, err
}
switch r := response.Result.(type) {
case *pb.KeysetPublicResponse_PublicKeyset:
return r.PublicKeyset, nil
case *pb.KeysetPublicResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("response.Result has unexpected type %T", r)
}
}
func keysetFromJSON(ctx context.Context, keysetService *services.KeysetService, jsonKeyset string) ([]byte, error) {
request := &pb.KeysetFromJsonRequest{JsonKeyset: jsonKeyset}
response, err := keysetService.FromJson(ctx, request)
if err != nil {
return nil, err
}
switch r := response.Result.(type) {
case *pb.KeysetFromJsonResponse_Keyset:
return r.Keyset, nil
case *pb.KeysetFromJsonResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("response.Result has unexpected type %T", r)
}
}
func keysetToJSON(ctx context.Context, keysetService *services.KeysetService, keyset []byte) (string, error) {
request := &pb.KeysetToJsonRequest{Keyset: keyset}
response, err := keysetService.ToJson(ctx, request)
if err != nil {
return "", err
}
switch r := response.Result.(type) {
case *pb.KeysetToJsonResponse_JsonKeyset:
return r.JsonKeyset, nil
case *pb.KeysetToJsonResponse_Err:
return "", errors.New(r.Err)
default:
return "", fmt.Errorf("response.Result has unexpected type %T", r)
}
}
func TestFromJSON(t *testing.T) {
keysetService := &services.KeysetService{}
ctx := context.Background()
jsonKeyset := `
{
"primaryKeyId": 42,
"key": [
{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
"keyMaterialType": "SYMMETRIC",
"value": "GhCS/1+ejWpx68NfGt6ziYHd"
},
"outputPrefixType": "TINK",
"keyId": 42,
"status": "ENABLED"
}
]
}`
keysetData, err := keysetFromJSON(ctx, keysetService, jsonKeyset)
if err != nil {
t.Fatalf("keysetFromJSON failed: %v", err)
}
reader := keyset.NewBinaryReader(bytes.NewReader(keysetData))
keyset, err := reader.Read()
if err != nil {
t.Fatalf("reader.Read() failed: %v", err)
}
if keyset.GetPrimaryKeyId() != 42 {
t.Fatalf("Got keyset.GetPrimaryKeyId() == %d, want 42", keyset.GetPrimaryKeyId())
}
}
func TestGenerateToFromJSON(t *testing.T) {
keysetService := &services.KeysetService{}
ctx := context.Background()
template, err := proto.Marshal(aead.AES128GCMKeyTemplate())
if err != nil {
t.Fatalf("proto.Marshal(aead.AES128GCMKeyTemplate()) failed: %v", err)
}
keyset, err := genKeyset(ctx, keysetService, template)
if err != nil {
t.Fatalf("genKeyset failed: %v", err)
}
jsonKeyset, err := keysetToJSON(ctx, keysetService, keyset)
if err != nil {
t.Fatalf("keysetToJSON failed: %v", err)
}
output, err := keysetFromJSON(ctx, keysetService, jsonKeyset)
if err != nil {
t.Fatalf("keysetFromJSON failed: %v", err)
}
if bytes.Compare(output, keyset) != 0 {
t.Fatalf("output is %v, want %v", output, keyset)
}
}
func TestKeysetFromJSONFail(t *testing.T) {
keysetService := &services.KeysetService{}
ctx := context.Background()
if _, err := keysetFromJSON(ctx, keysetService, "bad JSON"); err == nil {
t.Fatalf("keysetFromJSON from bad JSON succeeded unexpectedly.")
}
}
func TestKeysetToJSONFail(t *testing.T) {
keysetService := &services.KeysetService{}
ctx := context.Background()
if _, err := keysetToJSON(ctx, keysetService, []byte("badKeyset")); err == nil {
t.Fatalf("keysetToJSON with bad keyset succeeded unexpectedly.")
}
}
func aeadEncrypt(ctx context.Context, aeadService *services.AEADService, keyset []byte, plaintext []byte, associatedData []byte) ([]byte, error) {
encRequest := &pb.AeadEncryptRequest{
Keyset: keyset,
Plaintext: plaintext,
AssociatedData: associatedData,
}
encResponse, err := aeadService.Encrypt(ctx, encRequest)
if err != nil {
return nil, err
}
switch r := encResponse.Result.(type) {
case *pb.AeadEncryptResponse_Ciphertext:
return r.Ciphertext, nil
case *pb.AeadEncryptResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
}
}
func aeadDecrypt(ctx context.Context, aeadService *services.AEADService, keyset []byte, ciphertext []byte, associatedData []byte) ([]byte, error) {
decRequest := &pb.AeadDecryptRequest{
Keyset: keyset,
Ciphertext: ciphertext,
AssociatedData: associatedData,
}
decResponse, err := aeadService.Decrypt(ctx, decRequest)
if err != nil {
return nil, err
}
switch r := decResponse.Result.(type) {
case *pb.AeadDecryptResponse_Plaintext:
return r.Plaintext, nil
case *pb.AeadDecryptResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
}
}
func TestGenerateEncryptDecrypt(t *testing.T) {
keysetService := &services.KeysetService{}
aeadService := &services.AEADService{}
ctx := context.Background()
template, err := proto.Marshal(aead.AES128GCMKeyTemplate())
if err != nil {
t.Fatalf("proto.Marshal(aead.AES128GCMKeyTemplate()) failed: %v", err)
}
keyset, err := genKeyset(ctx, keysetService, template)
if err != nil {
t.Fatalf("genKeyset failed: %v", err)
}
plaintext := []byte("The quick brown fox jumps over the lazy dog")
associatedData := []byte("Associated Data")
ciphertext, err := aeadEncrypt(ctx, aeadService, keyset, plaintext, associatedData)
if err != nil {
t.Fatalf("Aead Encrypt failed: %v", err)
}
output, err := aeadDecrypt(ctx, aeadService, keyset, ciphertext, associatedData)
if err != nil {
t.Fatalf("aeadDecrypt failed: %v", err)
}
if bytes.Compare(output, plaintext) != 0 {
t.Fatalf("Decrypted ciphertext is %v, want %v", output, plaintext)
}
if _, err := genKeyset(ctx, keysetService, []byte("badTemplate")); err == nil {
t.Fatalf("genKeyset from bad template succeeded unexpectedly.")
}
if _, err := aeadEncrypt(ctx, aeadService, []byte("badKeyset"), plaintext, associatedData); err == nil {
t.Fatalf("aeadEncrypt with bad keyset succeeded unexpectedly.")
}
if _, err := aeadDecrypt(ctx, aeadService, keyset, []byte("badCiphertext"), associatedData); err == nil {
t.Fatalf("aeadDecrypt of bad ciphertext succeeded unexpectedly.")
}
}
func daeadEncrypt(ctx context.Context, daeadService *services.DeterministicAEADService, keyset []byte, plaintext []byte, associatedData []byte) ([]byte, error) {
encRequest := &pb.DeterministicAeadEncryptRequest{
Keyset: keyset,
Plaintext: plaintext,
AssociatedData: associatedData,
}
encResponse, err := daeadService.EncryptDeterministically(ctx, encRequest)
if err != nil {
return nil, err
}
switch r := encResponse.Result.(type) {
case *pb.DeterministicAeadEncryptResponse_Ciphertext:
return r.Ciphertext, nil
case *pb.DeterministicAeadEncryptResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
}
}
func daeadDecrypt(ctx context.Context, daeadService *services.DeterministicAEADService, keyset []byte, ciphertext []byte, associatedData []byte) ([]byte, error) {
decRequest := &pb.DeterministicAeadDecryptRequest{
Keyset: keyset,
Ciphertext: ciphertext,
AssociatedData: associatedData,
}
decResponse, err := daeadService.DecryptDeterministically(ctx, decRequest)
if err != nil {
return nil, err
}
switch r := decResponse.Result.(type) {
case *pb.DeterministicAeadDecryptResponse_Plaintext:
return r.Plaintext, nil
case *pb.DeterministicAeadDecryptResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
}
}
func TestGenerateEncryptDecryptDeterministically(t *testing.T) {
keysetService := &services.KeysetService{}
daeadService := &services.DeterministicAEADService{}
ctx := context.Background()
template, err := proto.Marshal(daead.AESSIVKeyTemplate())
if err != nil {
t.Fatalf("proto.Marshal(daead.AESSIVKeyTemplate()) failed: %v", err)
}
keyset, err := genKeyset(ctx, keysetService, template)
if err != nil {
t.Fatalf("genKeyset failed: %v", err)
}
plaintext := []byte("The quick brown fox jumps over the lazy dog")
associatedData := []byte("Associated Data")
ciphertext, err := daeadEncrypt(ctx, daeadService, keyset, plaintext, associatedData)
if err != nil {
t.Fatalf("Aead Encrypt failed: %v", err)
}
output, err := daeadDecrypt(ctx, daeadService, keyset, ciphertext, associatedData)
if err != nil {
t.Fatalf("daeadDecrypt failed: %v", err)
}
if bytes.Compare(output, plaintext) != 0 {
t.Fatalf("Decrypted ciphertext is %v, want %v", output, plaintext)
}
if _, err := genKeyset(ctx, keysetService, []byte("badTemplate")); err == nil {
t.Fatalf("genKeyset from bad template succeeded unexpectedly.")
}
if _, err := daeadEncrypt(ctx, daeadService, []byte("badKeyset"), plaintext, associatedData); err == nil {
t.Fatalf("daeadEncrypt with bad keyset succeeded unexpectedly.")
}
if _, err := daeadDecrypt(ctx, daeadService, keyset, []byte("badCiphertext"), associatedData); err == nil {
t.Fatalf("daeadDecrypt of bad ciphertext succeeded unexpectedly.")
}
}
func streamingAEADEncrypt(ctx context.Context, streamingAEADService *services.StreamingAEADService, keyset []byte, plaintext []byte, associatedData []byte) ([]byte, error) {
encRequest := &pb.StreamingAeadEncryptRequest{
Keyset: keyset,
Plaintext: plaintext,
AssociatedData: associatedData,
}
encResponse, err := streamingAEADService.Encrypt(ctx, encRequest)
if err != nil {
return nil, err
}
switch r := encResponse.Result.(type) {
case *pb.StreamingAeadEncryptResponse_Ciphertext:
return r.Ciphertext, nil
case *pb.StreamingAeadEncryptResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
}
}
func streamingAEADDecrypt(ctx context.Context, streamingAEADService *services.StreamingAEADService, keyset []byte, ciphertext []byte, associatedData []byte) ([]byte, error) {
decRequest := &pb.StreamingAeadDecryptRequest{
Keyset: keyset,
Ciphertext: ciphertext,
AssociatedData: associatedData,
}
decResponse, err := streamingAEADService.Decrypt(ctx, decRequest)
if err != nil {
return nil, err
}
switch r := decResponse.Result.(type) {
case *pb.StreamingAeadDecryptResponse_Plaintext:
return r.Plaintext, nil
case *pb.StreamingAeadDecryptResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
}
}
func TestGenerateEncryptDecryptStreaming(t *testing.T) {
keysetService := &services.KeysetService{}
streamingAEADService := &services.StreamingAEADService{}
ctx := context.Background()
template, err := proto.Marshal(streamingaead.AES128GCMHKDF4KBKeyTemplate())
if err != nil {
t.Fatalf("proto.Marshal(streamingaead.AES128GCMHKDF4KBKeyTemplate()) failed: %v", err)
}
keyset, err := genKeyset(ctx, keysetService, template)
if err != nil {
t.Fatalf("genKeyset failed: %v", err)
}
plaintext := []byte("The quick brown fox jumps over the lazy dog")
associatedData := []byte("Associated Data")
ciphertext, err := streamingAEADEncrypt(ctx, streamingAEADService, keyset, plaintext, associatedData)
if err != nil {
t.Fatalf("streamingAEADEncrypt failed: %v", err)
}
output, err := streamingAEADDecrypt(ctx, streamingAEADService, keyset, ciphertext, associatedData)
if err != nil {
t.Fatalf("streamingAEADDecrypt failed: %v", err)
}
if bytes.Compare(output, plaintext) != 0 {
t.Errorf("Decrypted ciphertext is %v, want %v", output, plaintext)
}
if _, err := genKeyset(ctx, keysetService, []byte("badTemplate")); err == nil {
t.Fatalf("genKeyset from bad template succeeded unexpectedly.")
}
if _, err := streamingAEADEncrypt(ctx, streamingAEADService, []byte("badKeyset"), plaintext, associatedData); err == nil {
t.Fatalf("streamingAEADEncrypt with bad keyset succeeded unexpectedly.")
}
if _, err := streamingAEADDecrypt(ctx, streamingAEADService, keyset, []byte("badCiphertext"), associatedData); err == nil {
t.Fatalf("streamingAEADDecrypt of bad ciphertext succeeded unexpectedly.")
}
}
func computeMAC(ctx context.Context, macService *services.MacService, keyset []byte, data []byte) ([]byte, error) {
encRequest := &pb.ComputeMacRequest{
Keyset: keyset,
Data: data,
}
response, err := macService.ComputeMac(ctx, encRequest)
if err != nil {
return nil, err
}
switch r := response.Result.(type) {
case *pb.ComputeMacResponse_MacValue:
return r.MacValue, nil
case *pb.ComputeMacResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("response.Result has unexpected type %T", r)
}
}
func verifyMAC(ctx context.Context, macService *services.MacService, keyset []byte, macValue []byte, data []byte) error {
request := &pb.VerifyMacRequest{
Keyset: keyset,
MacValue: macValue,
Data: data,
}
response, err := macService.VerifyMac(ctx, request)
if err != nil {
return err
}
if response.Err != "" {
return errors.New(response.Err)
}
return nil
}
func TestComputeVerifyMac(t *testing.T) {
keysetService := &services.KeysetService{}
macService := &services.MacService{}
ctx := context.Background()
template, err := proto.Marshal(mac.HMACSHA256Tag128KeyTemplate())
if err != nil {
t.Fatalf("proto.Marshal(mac.HMACSHA256Tag128KeyTemplate()) failed: %v", err)
}
keyset, err := genKeyset(ctx, keysetService, template)
if err != nil {
t.Fatalf("genKeyset failed: %v", err)
}
data := []byte("The quick brown fox jumps over the lazy dog")
macValue, err := computeMAC(ctx, macService, keyset, data)
if err != nil {
t.Fatalf("computeMAC failed: %v", err)
}
if err := verifyMAC(ctx, macService, keyset, macValue, data); err != nil {
t.Fatalf("verifyMAC failed: %v", err)
}
if _, err := computeMAC(ctx, macService, []byte("badKeyset"), data); err == nil {
t.Fatalf("computeMAC with bad keyset succeeded unexpectedly.")
}
if err := verifyMAC(ctx, macService, keyset, []byte("badMacValue"), data); err == nil {
t.Fatalf("verifyMAC of bad MAC value succeeded unexpectedly.")
}
}
func hybridEncrypt(ctx context.Context, hybridService *services.HybridService, publicKeyset []byte, plaintext []byte, contextInfo []byte) ([]byte, error) {
encRequest := &pb.HybridEncryptRequest{
PublicKeyset: publicKeyset,
Plaintext: plaintext,
ContextInfo: contextInfo,
}
encResponse, err := hybridService.Encrypt(ctx, encRequest)
if err != nil {
return nil, err
}
switch r := encResponse.Result.(type) {
case *pb.HybridEncryptResponse_Ciphertext:
return r.Ciphertext, nil
case *pb.HybridEncryptResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
}
}
func hybridDecrypt(ctx context.Context, hybridService *services.HybridService, privateKeyset []byte, ciphertext []byte, contextInfo []byte) ([]byte, error) {
decRequest := &pb.HybridDecryptRequest{
PrivateKeyset: privateKeyset,
Ciphertext: ciphertext,
ContextInfo: contextInfo,
}
decResponse, err := hybridService.Decrypt(ctx, decRequest)
if err != nil {
return nil, err
}
switch r := decResponse.Result.(type) {
case *pb.HybridDecryptResponse_Plaintext:
return r.Plaintext, nil
case *pb.HybridDecryptResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("decResponse.Result has unexpected type %T", r)
}
}
func TestHybridGenerateEncryptDecrypt(t *testing.T) {
keysetService := &services.KeysetService{}
hybridService := &services.HybridService{}
ctx := context.Background()
template, err := proto.Marshal(hybrid.ECIESHKDFAES128GCMKeyTemplate())
if err != nil {
t.Fatalf("proto.Marshal(hybrid.ECIESHKDFAES128GCMKeyTemplate()) failed: %v", err)
}
privateKeyset, err := genKeyset(ctx, keysetService, template)
if err != nil {
t.Fatalf("genKeyset failed: %v", err)
}
publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
if err != nil {
t.Fatalf("pubKeyset failed: %v", err)
}
plaintext := []byte("The quick brown fox jumps over the lazy dog")
associatedData := []byte("Associated Data")
ciphertext, err := hybridEncrypt(ctx, hybridService, publicKeyset, plaintext, associatedData)
if err != nil {
t.Fatalf("hybridEncrypt failed: %v", err)
}
output, err := hybridDecrypt(ctx, hybridService, privateKeyset, ciphertext, associatedData)
if err != nil {
t.Fatalf("hybridDecrypt failed: %v", err)
}
if bytes.Compare(output, plaintext) != 0 {
t.Fatalf("Decrypted ciphertext is %v, want %v", output, plaintext)
}
if _, err := pubKeyset(ctx, keysetService, []byte("badPrivateKeyset")); err == nil {
t.Fatalf("pubKeyset from bad private keyset succeeded unexpectedly.")
}
if _, err := hybridEncrypt(ctx, hybridService, []byte("badPublicKeyset"), plaintext, associatedData); err == nil {
t.Fatalf("hybridEncrypt with bad public keyset succeeded unexpectedly.")
}
if _, err := hybridDecrypt(ctx, hybridService, []byte("badPrivateKeyset"), ciphertext, associatedData); err == nil {
t.Fatalf("hybridDecrypt with bad private keyset succeeded unexpectedly.")
}
if _, err := hybridDecrypt(ctx, hybridService, privateKeyset, []byte("badCiphertext"), associatedData); err == nil {
t.Fatalf("hybridDecrypt of bad ciphertext succeeded unexpectedly.")
}
}
func signatureSign(ctx context.Context, signatureService *services.SignatureService, privateKeyset []byte, data []byte) ([]byte, error) {
encRequest := &pb.SignatureSignRequest{
PrivateKeyset: privateKeyset,
Data: data,
}
response, err := signatureService.Sign(ctx, encRequest)
if err != nil {
return nil, err
}
switch r := response.Result.(type) {
case *pb.SignatureSignResponse_Signature:
return r.Signature, nil
case *pb.SignatureSignResponse_Err:
return nil, errors.New(r.Err)
default:
return nil, fmt.Errorf("response.Result has unexpected type %T", r)
}
}
func signatureVerify(ctx context.Context, signatureService *services.SignatureService, publicKeyset []byte, signatureValue []byte, data []byte) error {
request := &pb.SignatureVerifyRequest{
PublicKeyset: publicKeyset,
Signature: signatureValue,
Data: data,
}
response, err := signatureService.Verify(ctx, request)
if err != nil {
return err
}
if response.Err != "" {
return errors.New(response.Err)
}
return nil
}
func TestSignatureSignVerify(t *testing.T) {
keysetService := &services.KeysetService{}
signatureService := &services.SignatureService{}
ctx := context.Background()
template, err := proto.Marshal(signature.ECDSAP256KeyTemplate())
if err != nil {
t.Fatalf("proto.Marshal(signature.ECDSAP256KeyTemplate()) failed: %v", err)
}
privateKeyset, err := genKeyset(ctx, keysetService, template)
if err != nil {
t.Fatalf("genKeyset failed: %v", err)
}
publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
if err != nil {
t.Fatalf("pubKeyset failed: %v", err)
}
data := []byte("The quick brown fox jumps over the lazy dog")
signatureValue, err := signatureSign(ctx, signatureService, privateKeyset, data)
if err != nil {
t.Fatalf("signatureSign failed: %v", err)
}
if err := signatureVerify(ctx, signatureService, publicKeyset, signatureValue, data); err != nil {
t.Fatalf("signatureVerify failed: %v", err)
}
if _, err := signatureSign(ctx, signatureService, []byte("badPrivateKeyset"), data); err == nil {
t.Fatalf("signatureSign with bad private keyset succeeded unexpectedly.")
}
if err := signatureVerify(ctx, signatureService, publicKeyset, []byte("badSignature"), data); err == nil {
t.Fatalf("signatureVerify of bad signature succeeded unexpectedly.")
}
if err := signatureVerify(ctx, signatureService, []byte("badPublicKeyset"), signatureValue, data); err == nil {
t.Fatalf("signatureVerify of bad public keyset succeeded unexpectedly.")
}
}
func TestServerInfo(t *testing.T) {
metadataService := &services.MetadataService{}
ctx := context.Background()
req := &pb.ServerInfoRequest{}
rsp, err := metadataService.GetServerInfo(ctx, req)
if err != nil {
t.Fatalf("GetServerInfo failed: %v", err)
}
if strings.Compare(rsp.GetLanguage(), "go") != 0 {
t.Fatalf("Expected language 'go', got: %v", rsp.GetLanguage())
}
}