github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/composite/register_ecdh_aead_enc_helper.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package composite 8 9 import ( 10 "encoding/json" 11 "errors" 12 "fmt" 13 14 aead "github.com/google/tink/go/aead/subtle" 15 "github.com/google/tink/go/core/registry" 16 gcmpb "github.com/google/tink/go/proto/aes_gcm_go_proto" 17 chachapb "github.com/google/tink/go/proto/chacha20_poly1305_go_proto" 18 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 19 xchachapb "github.com/google/tink/go/proto/xchacha20_poly1305_go_proto" 20 "github.com/google/tink/go/tink" 21 "golang.org/x/crypto/chacha20poly1305" 22 "golang.org/x/crypto/poly1305" 23 "google.golang.org/protobuf/proto" 24 25 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/aead/subtle" 26 cbchmacpb "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/proto/aes_cbc_hmac_aead_go_proto" 27 ) 28 29 const ( 30 // AESCBCHMACAEADTypeURL for AESCBC+HMAC AEAD content encryption URL. 31 AESCBCHMACAEADTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.AesCbcHmacAeadKey" 32 // AESGCMTypeURL for AESGCM content encryption URL identifier. 33 AESGCMTypeURL = "type.googleapis.com/google.crypto.tink.AesGcmKey" 34 // ChaCha20Poly1305TypeURL for Chacha20Poly1305 content encryption URL identifier. 35 ChaCha20Poly1305TypeURL = "type.googleapis.com/google.crypto.tink.ChaCha20Poly1305Key" 36 // XChaCha20Poly1305TypeURL for XChachaPoly1305 content encryption URL identifier. 37 XChaCha20Poly1305TypeURL = "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key" 38 ) 39 40 type marshalFunc func(interface{}) ([]byte, error) 41 42 // RegisterCompositeAEADEncHelper registers a content encryption helper. 43 type RegisterCompositeAEADEncHelper struct { 44 encKeyURL string 45 keyData []byte 46 tagSize int 47 ivSize int 48 marshalFunc marshalFunc 49 } 50 51 var _ EncrypterHelper = (*RegisterCompositeAEADEncHelper)(nil) 52 53 // NewRegisterCompositeAEADEncHelper initializes and returns a RegisterCompositeAEADEncHelper. 54 // 55 //nolint:gocyclo 56 func NewRegisterCompositeAEADEncHelper(k *tinkpb.KeyTemplate) (*RegisterCompositeAEADEncHelper, error) { 57 var ( 58 tagSize, ivSize int 59 skf []byte 60 err error 61 ) 62 63 switch k.TypeUrl { 64 case AESCBCHMACAEADTypeURL: 65 cbcHMACKeyFormat := new(cbchmacpb.AesCbcHmacAeadKeyFormat) 66 67 err = proto.Unmarshal(k.Value, cbcHMACKeyFormat) 68 if err != nil { 69 return nil, fmt.Errorf("compositeAEADEncHelper: failed to unmarshal cbcHMACKeyFormat: %w", err) 70 } 71 72 tagSize = int(cbcHMACKeyFormat.HmacKeyFormat.Params.TagSize) 73 ivSize = subtle.AESCBCIVSize 74 75 skf, err = proto.Marshal(cbcHMACKeyFormat) 76 if err != nil { 77 return nil, fmt.Errorf("compositeAEADEncHelper: failed to serialize cbcHMAC key format, error: %w", err) 78 } 79 case AESGCMTypeURL: 80 gcmKeyFormat := new(gcmpb.AesGcmKeyFormat) 81 82 err = proto.Unmarshal(k.Value, gcmKeyFormat) 83 if err != nil { 84 return nil, fmt.Errorf("compositeAEADEncHelper: failed to unmarshal gcmKeyFormat: %w", err) 85 } 86 87 tagSize = aead.AESGCMTagSize 88 ivSize = aead.AESGCMIVSize 89 90 skf, err = proto.Marshal(gcmKeyFormat) 91 if err != nil { 92 return nil, fmt.Errorf("compositeAEADEncHelper: failed to serialize gcm key format, error: %w", err) 93 } 94 case ChaCha20Poly1305TypeURL: 95 tagSize = poly1305.TagSize 96 ivSize = chacha20poly1305.NonceSize 97 98 skf, err = buildChachaSKF(k) 99 if err != nil { 100 return nil, err 101 } 102 case XChaCha20Poly1305TypeURL: 103 tagSize = poly1305.TagSize 104 ivSize = chacha20poly1305.NonceSizeX 105 106 skf, err = buildXChachaSKF(k) 107 if err != nil { 108 return nil, err 109 } 110 default: 111 return nil, fmt.Errorf("compositeAEADEncHelper: unsupported AEAD content encryption key type: %s", 112 k.TypeUrl) 113 } 114 115 return buildRegisterCompositeAEADEncHelper(k, skf, tagSize, ivSize) 116 } 117 118 func buildChachaSKF(k *tinkpb.KeyTemplate) ([]byte, error) { 119 chachaKeyFormat := new(chachapb.ChaCha20Poly1305KeyFormat) 120 121 err := proto.Unmarshal(k.Value, chachaKeyFormat) 122 if err != nil { 123 return nil, fmt.Errorf("compositeAEADEncHelper: failed to unmarshal chachaKeyFormat: %w", err) 124 } 125 126 skf, err := proto.Marshal(chachaKeyFormat) 127 if err != nil { 128 return nil, fmt.Errorf("compositeAEADEncHelper: failed to serialize chacha key format, error: %w", err) 129 } 130 131 return skf, nil 132 } 133 134 func buildXChachaSKF(k *tinkpb.KeyTemplate) ([]byte, error) { 135 xChachaKeyFormat := new(xchachapb.XChaCha20Poly1305KeyFormat) 136 137 err := proto.Unmarshal(k.Value, xChachaKeyFormat) 138 if err != nil { 139 return nil, fmt.Errorf("compositeAEADEncHelper: failed to unmarshal xChachaKeyFormat: %w", err) 140 } 141 142 skf, err := proto.Marshal(xChachaKeyFormat) 143 if err != nil { 144 return nil, fmt.Errorf("compositeAEADEncHelper: failed to serialize xChacha key format, error: %w", err) 145 } 146 147 return skf, nil 148 } 149 150 func buildRegisterCompositeAEADEncHelper(k *tinkpb.KeyTemplate, skf []byte, 151 tagSize, ivSize int) (*RegisterCompositeAEADEncHelper, error) { 152 km, err := registry.GetKeyManager(k.TypeUrl) 153 if err != nil { 154 return nil, fmt.Errorf("compositeAEADEncHelper: failed to fetch KeyManager, error: %w", err) 155 } 156 157 key, err := km.NewKey(skf) 158 if err != nil { 159 return nil, fmt.Errorf("compositeAEADEncHelper: failed to fetch key, error: %w", err) 160 } 161 162 sk, err := proto.Marshal(key) 163 if err != nil { 164 return nil, fmt.Errorf("compositeAEADEncHelper: failed to serialize key, error: %w", err) 165 } 166 167 return &RegisterCompositeAEADEncHelper{ 168 encKeyURL: k.TypeUrl, 169 keyData: sk, 170 tagSize: tagSize, 171 ivSize: ivSize, 172 marshalFunc: json.Marshal, 173 }, nil 174 } 175 176 // GetTagSize returns the primitive tag size. 177 func (r *RegisterCompositeAEADEncHelper) GetTagSize() int { 178 return r.tagSize 179 } 180 181 // GetIVSize returns the primitive IV size. 182 func (r *RegisterCompositeAEADEncHelper) GetIVSize() int { 183 return r.ivSize 184 } 185 186 // GetAEAD returns the AEAD primitive from the DEM. 187 func (r *RegisterCompositeAEADEncHelper) GetAEAD(symmetricKeyValue []byte) (tink.AEAD, error) { 188 sk, err := r.getSerializedKey(symmetricKeyValue) 189 if err != nil { 190 return nil, err 191 } 192 193 p, err := registry.Primitive(r.encKeyURL, sk) 194 if err != nil { 195 return nil, err 196 } 197 198 g, ok := p.(tink.AEAD) 199 if !ok { 200 return nil, fmt.Errorf("invalid primitive") 201 } 202 203 return g, nil 204 } 205 206 func (r *RegisterCompositeAEADEncHelper) getSerializedKey(symmetricKeyValue []byte) ([]byte, error) { //nolint:gocyclo 207 var ( 208 sk []byte 209 err error 210 ) 211 212 switch r.encKeyURL { 213 case AESCBCHMACAEADTypeURL: 214 sk, err = r.getSerializedAESCBCHMACKey(symmetricKeyValue) 215 if err != nil { 216 return nil, fmt.Errorf("registerCompositeAEADEncHelper: failed to serialize key, error: %w", err) 217 } 218 case AESGCMTypeURL: 219 sk, err = r.getSerializedAESGCMKey(symmetricKeyValue) 220 if err != nil { 221 return nil, fmt.Errorf("registerCompositeAEADEncHelper: failed to serialize key, error: %w", err) 222 } 223 case ChaCha20Poly1305TypeURL: 224 chachaKey := new(chachapb.ChaCha20Poly1305Key) 225 226 err = proto.Unmarshal(r.keyData, chachaKey) 227 if err != nil { 228 return nil, fmt.Errorf("registerCompositeAEADEncHelper: failed to unmarshal chacha key: %w", err) 229 } 230 231 chachaKey.KeyValue = symmetricKeyValue 232 233 sk, err = proto.Marshal(chachaKey) 234 if err != nil { 235 return nil, fmt.Errorf("registerCompositeAEADEncHelper: failed to serialize key, error: %w", err) 236 } 237 case XChaCha20Poly1305TypeURL: 238 xChachaKey := new(xchachapb.XChaCha20Poly1305Key) 239 240 err = proto.Unmarshal(r.keyData, xChachaKey) 241 if err != nil { 242 return nil, fmt.Errorf("registerCompositeAEADEncHelper: failed to unmarshal xchacha key: %w", err) 243 } 244 245 xChachaKey.KeyValue = symmetricKeyValue 246 247 sk, err = proto.Marshal(xChachaKey) 248 if err != nil { 249 return nil, fmt.Errorf("registerCompositeAEADEncHelper: failed to serialize key, error: %w", err) 250 } 251 default: 252 return nil, fmt.Errorf("registerCompositeAEADEncHelper: unsupported AEAD content encryption key type: %s", 253 r.encKeyURL) 254 } 255 256 return sk, err 257 } 258 259 func (r *RegisterCompositeAEADEncHelper) getSerializedAESGCMKey(symmetricKeyValue []byte) ([]byte, error) { 260 gcmKey := new(gcmpb.AesGcmKey) 261 262 err := proto.Unmarshal(r.keyData, gcmKey) 263 if err != nil { 264 return nil, fmt.Errorf("failed to unmarshal gcmKeyFormat: %w", err) 265 } 266 267 gcmKey.KeyValue = symmetricKeyValue 268 269 return proto.Marshal(gcmKey) 270 } 271 272 func (r *RegisterCompositeAEADEncHelper) getSerializedAESCBCHMACKey(symmetricKeyValue []byte) ([]byte, error) { 273 cbcHMACKey := new(cbchmacpb.AesCbcHmacAeadKey) 274 275 err := proto.Unmarshal(r.keyData, cbcHMACKey) 276 if err != nil { 277 return nil, fmt.Errorf("failed to unmarshal cbcHMACKeyFormat: %w", err) 278 } 279 280 var ( 281 keySize int 282 twoKeys = 2 283 ) 284 285 switch len(symmetricKeyValue) { 286 case subtle.AES128Size * twoKeys: 287 keySize = subtle.AES128Size 288 case subtle.AES192Size * twoKeys: 289 keySize = subtle.AES192Size 290 case subtle.AES256Size + subtle.AES192Size: 291 keySize = subtle.AES256Size 292 case subtle.AES256Size * twoKeys: 293 keySize = subtle.AES256Size 294 default: 295 return nil, errors.New("AES-CBC+HMAC-SHA key must be either 32, 48, 56 or 64 bytes") 296 } 297 298 cbcHMACKey.HmacKey.KeyValue = symmetricKeyValue[:keySize] 299 cbcHMACKey.AesCbcKey.KeyValue = symmetricKeyValue[keySize:] 300 301 return proto.Marshal(cbcHMACKey) 302 } 303 304 // BuildEncData will build the []byte representing the ciphertext sent to the end user as a result of the Composite 305 // Encryption primitive execution. 306 func (r *RegisterCompositeAEADEncHelper) BuildEncData(ct []byte) ([]byte, error) { 307 tagSize := r.GetTagSize() 308 ivSize := r.GetIVSize() 309 iv := ct[:ivSize] 310 ctAndTag := ct[ivSize:] 311 tagOffset := len(ctAndTag) - tagSize 312 313 encData := &EncryptedData{ 314 Ciphertext: ctAndTag[:tagOffset], 315 IV: iv, 316 Tag: ctAndTag[tagOffset:], 317 } 318 319 return r.marshalFunc(encData) 320 } 321 322 // BuildDecData will build the []byte representing the ciphertext coming from encData struct returned as a result of 323 // Composite Encrypt() call to prepare the Composite Decryption primitive execution. 324 func (r *RegisterCompositeAEADEncHelper) BuildDecData(encData *EncryptedData) []byte { 325 iv := encData.IV 326 tag := encData.Tag 327 ct := encData.Ciphertext 328 finalCT := append(iv, ct...) 329 finalCT = append(finalCT, tag...) 330 331 return finalCT 332 }