github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/composite/ecdh/subtle/ecdh_aes_aead_composite_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package subtle
     8  
     9  import (
    10  	"encoding/base64"
    11  	"encoding/json"
    12  	"fmt"
    13  	"testing"
    14  
    15  	"github.com/google/tink/go/aead"
    16  	subtleaead "github.com/google/tink/go/aead/subtle"
    17  	"github.com/google/tink/go/keyset"
    18  	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
    19  	"github.com/google/tink/go/subtle/random"
    20  	"github.com/google/tink/go/tink"
    21  	"github.com/stretchr/testify/require"
    22  
    23  	"github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite"
    24  )
    25  
    26  func TestEncryptDecrypt(t *testing.T) {
    27  	aeadPrimitive := getAEADPrimitive(t, aead.AES256GCMKeyTemplate())
    28  
    29  	mEncHelper := &MockEncHelper{
    30  		AEADValue:    aeadPrimitive,
    31  		TagSizeValue: subtleaead.AESGCMTagSize,
    32  		IVSizeValue:  subtleaead.AESGCMIVSize,
    33  	}
    34  
    35  	cek := random.GetRandomBytes(uint32(32))
    36  
    37  	cEnc := NewECDHAEADCompositeEncrypt(mEncHelper, cek)
    38  
    39  	pt := []byte("secret message")
    40  	aad := []byte("aad message")
    41  
    42  	ct, err := cEnc.Encrypt(pt, aad)
    43  	require.NoError(t, err)
    44  
    45  	dEnc := NewECDHAEADCompositeDecrypt(mEncHelper, cek)
    46  
    47  	dpt, err := dEnc.Decrypt(ct, aad)
    48  	require.NoError(t, err)
    49  	require.EqualValues(t, pt, dpt)
    50  }
    51  
    52  func TestEncryptDecryptNegativeTCs(t *testing.T) {
    53  	aeadPrimitive := getAEADPrimitive(t, aead.AES256GCMKeyTemplate())
    54  
    55  	mEncHelper := &MockEncHelper{
    56  		AEADValue:    aeadPrimitive,
    57  		TagSizeValue: subtleaead.AESGCMTagSize,
    58  		IVSizeValue:  subtleaead.AESGCMIVSize,
    59  	}
    60  
    61  	pt := []byte("secret message")
    62  	aad := []byte("aad message")
    63  	cek := random.GetRandomBytes(uint32(32))
    64  
    65  	// test with GetAEAD() returning error
    66  	mEncHelper.AEADErrValue = fmt.Errorf("error from GetAEAD")
    67  
    68  	cEnc := NewECDHAEADCompositeEncrypt(mEncHelper, cek)
    69  
    70  	// Encrypt should fail with AEAD error value
    71  	_, err := cEnc.Encrypt(pt, aad)
    72  	require.EqualError(t, err, "error from GetAEAD")
    73  
    74  	mEncHelper.AEADErrValue = nil
    75  
    76  	// Encrypt should fail with nil cek
    77  	cEncNilCEK := NewECDHAEADCompositeEncrypt(mEncHelper, nil)
    78  	_, err = cEncNilCEK.Encrypt(pt, aad)
    79  	require.EqualError(t, err, "ecdhAEADCompositeEncrypt: missing cek")
    80  
    81  	// create a valid ciphertext to test Decrypt for all recipients
    82  	cEnc = NewECDHAEADCompositeEncrypt(mEncHelper, cek)
    83  
    84  	// test with empty plaintext
    85  	ct, err := cEnc.Encrypt([]byte{}, aad)
    86  	require.NoError(t, err)
    87  
    88  	encData := new(composite.EncryptedData)
    89  	err = json.Unmarshal(ct, encData)
    90  
    91  	require.NoError(t, err)
    92  	// encrypting empty plaintext should result in empty ciphertext
    93  	require.Empty(t, encData.Ciphertext)
    94  	require.Len(t, encData.Tag, subtleaead.AESGCMTagSize)
    95  	require.Len(t, encData.IV, subtleaead.AESGCMIVSize)
    96  
    97  	ct, err = cEnc.Encrypt(pt, aad)
    98  	require.NoError(t, err)
    99  
   100  	// test with GetAEAD() returning error
   101  	mEncHelper.AEADErrValue = fmt.Errorf("error from GetAEAD")
   102  
   103  	dEnc := NewECDHAEADCompositeDecrypt(mEncHelper, cek)
   104  
   105  	_, err = dEnc.Decrypt(ct, aad)
   106  	require.EqualError(t, err, "error from GetAEAD")
   107  
   108  	mEncHelper.AEADErrValue = nil
   109  
   110  	// Decrypt should fail with nil cek
   111  	dEncNilCEK := NewECDHAEADCompositeDecrypt(mEncHelper, nil)
   112  	_, err = dEncNilCEK.Decrypt(ct, aad)
   113  	require.EqualError(t, err, "ecdh decrypt: missing cek")
   114  
   115  	// create a valid Decrypt message and test against ct
   116  	dEnc = NewECDHAEADCompositeDecrypt(mEncHelper, cek)
   117  
   118  	// try decrypting empty ct
   119  	_, err = dEnc.Decrypt([]byte{}, aad)
   120  	require.EqualError(t, err, "unexpected end of JSON input")
   121  
   122  	// finally try successful decrypt
   123  	dpt, err := dEnc.Decrypt(ct, aad)
   124  	require.NoError(t, err)
   125  	require.EqualValues(t, pt, dpt)
   126  }
   127  
   128  func TestEncryptDecryptWithSingleRecipient(t *testing.T) {
   129  	aeadPrimitive := getAEADPrimitive(t, aead.AES256GCMKeyTemplate())
   130  
   131  	mEncHelper := &MockEncHelper{
   132  		AEADValue:    aeadPrimitive,
   133  		TagSizeValue: subtleaead.AESGCMTagSize,
   134  		IVSizeValue:  subtleaead.AESGCMIVSize,
   135  	}
   136  
   137  	pt := []byte("secret message")
   138  	cek := random.GetRandomBytes(uint32(32))
   139  	cEnc := NewECDHAEADCompositeEncrypt(mEncHelper, cek)
   140  	newAAD := base64.RawURLEncoding.EncodeToString([]byte("{\"enc\":\"testAlg\"}"))
   141  
   142  	// Encrypt should pass with base64Url encoded a valid json marshaled aad
   143  	ct, err := cEnc.Encrypt(pt, []byte(newAAD))
   144  	require.NoError(t, err)
   145  
   146  	encData := &composite.EncryptedData{}
   147  	err = json.Unmarshal(ct, encData)
   148  	require.NoError(t, err)
   149  
   150  	dEnc := NewECDHAEADCompositeDecrypt(mEncHelper, cek)
   151  
   152  	dpt, err := dEnc.Decrypt(ct, []byte(newAAD))
   153  	require.NoError(t, err)
   154  	require.EqualValues(t, pt, dpt)
   155  }
   156  
   157  func getAEADPrimitive(t *testing.T, kt *tinkpb.KeyTemplate) tink.AEAD {
   158  	t.Helper()
   159  
   160  	kh, err := keyset.NewHandle(kt)
   161  	require.NoError(t, err)
   162  
   163  	ps, err := kh.Primitives()
   164  	require.NoError(t, err)
   165  
   166  	p, ok := (ps.Primary.Primitive).(tink.AEAD)
   167  	require.True(t, ok)
   168  
   169  	return p
   170  }
   171  
   172  // MockEncHelper an mocked AEAD helper of Composite Encrypt/Decrypt primitives.
   173  type MockEncHelper struct {
   174  	AEADValue    tink.AEAD
   175  	AEADErrValue error
   176  	TagSizeValue int
   177  	IVSizeValue  int
   178  }
   179  
   180  // GetAEAD returns the newly created AEAD primitive used for the content Encryption.
   181  func (m *MockEncHelper) GetAEAD(symmetricKeyValue []byte) (tink.AEAD, error) {
   182  	return m.AEADValue, m.AEADErrValue
   183  }
   184  
   185  // GetTagSize provides the aead primitive tag size.
   186  func (m *MockEncHelper) GetTagSize() int {
   187  	return m.TagSizeValue
   188  }
   189  
   190  // GetIVSize provides the aead primitive nonce size.
   191  func (m *MockEncHelper) GetIVSize() int {
   192  	return m.IVSizeValue
   193  }
   194  
   195  // BuildEncData will build the []byte representing the ciphertext sent to the end user of the Composite primitive.
   196  func (m *MockEncHelper) BuildEncData(ct []byte) ([]byte, error) {
   197  	tagSize := m.GetTagSize()
   198  	ivSize := m.GetIVSize()
   199  	iv := ct[:ivSize]
   200  	ctAndTag := ct[ivSize:]
   201  	tagOffset := len(ctAndTag) - tagSize
   202  
   203  	encData := &composite.EncryptedData{
   204  		Ciphertext: ctAndTag[:tagOffset],
   205  		IV:         iv,
   206  		Tag:        ctAndTag[tagOffset:],
   207  	}
   208  
   209  	return json.Marshal(encData)
   210  }
   211  
   212  // BuildDecData will build the []byte representing the ciphertext coming from encData struct returned as a result of
   213  // Composite Encrypt() call to prepare the Composite Decryption primitive execution.
   214  func (m *MockEncHelper) BuildDecData(encData *composite.EncryptedData) []byte {
   215  	iv := encData.IV
   216  	tag := encData.Tag
   217  	ct := encData.Ciphertext
   218  	finalCT := append(iv, ct...)
   219  	finalCT = append(finalCT, tag...)
   220  
   221  	return finalCT
   222  }