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 }