Switched encryption of payload and keys to AES

Added Encrypted field to the protobuf
This commit is contained in:
Samuel Hawksby-Robinson 2021-02-11 17:07:11 +00:00 committed by Andrea Maria Piana
parent 0080de754e
commit b009bac5fb
6 changed files with 213 additions and 51 deletions

View File

@ -9,11 +9,17 @@ import (
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/eth-node/types"
) )
const nonceLength = 12 const(
nonceLength = 12
defaultECHDSharedKeyLength = 16
defaultECHDMACLength = 16
)
var ErrInvalidCiphertextLength = errors.New("invalid cyphertext length") var ErrInvalidCiphertextLength = errors.New("invalid cyphertext length")
@ -86,3 +92,11 @@ func HexToPubkey(pk string) (*ecdsa.PublicKey, error) {
} }
return crypto.UnmarshalPubkey(bytes) return crypto.UnmarshalPubkey(bytes)
} }
func MakeECDHSharedKey(yourPrivateKey *ecdsa.PrivateKey, theirPubKey *ecdsa.PublicKey) ([]byte, error) {
return ecies.ImportECDSA(yourPrivateKey).GenerateShared(
ecies.ImportECDSAPublic(theirPubKey),
defaultECHDSharedKeyLength,
defaultECHDMACLength,
)
}

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
crand "crypto/rand" crand "crypto/rand"
"crypto/x509"
"database/sql" "database/sql"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
@ -23,8 +22,6 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/status-im/status-go/appdatabase" "github.com/status-im/status-go/appdatabase"
"github.com/status-im/status-go/appmetrics" "github.com/status-im/status-go/appmetrics"
"github.com/status-im/status-go/connection" "github.com/status-im/status-go/connection"
@ -780,6 +777,7 @@ func (m *Messenger) attachIdentityImagesToChatIdentity(context chatContext, ci *
return err return err
} }
// TODO remove the use of ProfilePicturesVisibility and create a new settings field,
if s.ProfilePicturesVisibility == accounts.ProfilePicturesVisibilityNone { if s.ProfilePicturesVisibility == accounts.ProfilePicturesVisibilityNone {
m.logger.Info(fmt.Sprintf("settings.ProfilePicturesVisibility is set to '%d', skipping attaching IdentityImages", s.ProfilePicturesVisibility)) m.logger.Info(fmt.Sprintf("settings.ProfilePicturesVisibility is set to '%d', skipping attaching IdentityImages", s.ProfilePicturesVisibility))
return nil return nil
@ -832,46 +830,95 @@ func (m *Messenger) attachIdentityImagesToChatIdentity(context chatContext, ci *
return nil return nil
} }
func (m *Messenger) encryptIdentityImagesWithContactPubKeys(ciis map[string]*protobuf.IdentityImage) error { func (m *Messenger) encryptIdentityImagesWithContactPubKeys(iis map[string]*protobuf.IdentityImage) (err error) {
// Make ephemeral key // Make AES key
pk, err := crypto.GenerateKey() AESKey := make([]byte, 32)
_, err = crand.Read(AESKey)
if err != nil { if err != nil {
return err return err
} }
// Marshal the ephemeral private key into bytes for _, ii := range iis {
mpk, err := x509.MarshalECPrivateKey(pk) // Encrypt image payload with the AES key
if err != nil { encryptedPayload, err := common.Encrypt(ii.Payload, AESKey, crand.Reader)
return err
}
for _, ii := range ciis {
// Encrypt image payloads with the ephemeral public key
encryptedPayload, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(&pk.PublicKey), ii.Payload, nil, nil)
if err != nil { if err != nil {
return err return err
} }
// Overwrite the unencrypted payload with the newly encrypted payload // Overwrite the unencrypted payload with the newly encrypted payload
ii.Payload = encryptedPayload ii.Payload = encryptedPayload
for _, c := range m.allContacts { ii.Encrypted = true
m.allContacts.Range(func(contactID string, c *Contact) (shouldContinue bool) {
if !c.IsAdded() { if !c.IsAdded() {
continue return false
} }
pubK, err := c.PublicKey() pubK, err := c.PublicKey()
if err != nil { if err != nil {
return err return false
}
// Generate a Diffie-Helman (DH) between the sender private key and the recipient's public key
sharedKey, err := common.MakeECDHSharedKey(m.identity, pubK)
if err != nil {
return false
} }
// Encrypt the marshalled ephemeral private key with the contact's public key // Encrypt the main AES key with AES encryption using the DH key
empk, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(pubK), mpk, nil, nil) eAESKey, err := common.Encrypt(AESKey, sharedKey, crand.Reader)
if err != nil {
return false
}
// Append the the encrypted main AES key to the IdentityImage's EncryptionKeys slice.
ii.EncryptionKeys = append(ii.EncryptionKeys, eAESKey)
return true
})
if err != nil {
return err
}
}
return nil
}
func (m *Messenger) decryptIdentityImagesWithIdentityPrivateKey(iis map[string]*protobuf.IdentityImage, senderPubKey *ecdsa.PublicKey) error {
image:
for _, ii := range iis {
for _, empk := range ii.EncryptionKeys {
// Generate a Diffie-Helman (DH) between the recipient's private key and the sender's public key
sharedKey, err := common.MakeECDHSharedKey(m.identity, senderPubKey)
if err != nil { if err != nil {
return err return err
} }
// Append the the encrypted private key to the IdentityImage's EncryptionKeys slice. // Decrypt the main encryption AES key with AES encryption using the DH key
ii.EncryptionKeys = append(ii.EncryptionKeys, empk) dAESKey, err := common.Decrypt(empk, sharedKey)
if err != nil {
if err.Error() == "cipher: message authentication failed" {
continue
}
return err
}
if dAESKey == nil{
return errors.New("decrypting the payload encryption key resulted in no error and a nil key")
}
// Decrypt the payload with the newly decrypted main encryption AES key
payload, err := common.Decrypt(ii.Payload, dAESKey)
if err != nil {
return err
}
if payload == nil {
// TODO should this be a logger warn? A payload could theoretically be validly empty
return errors.New("decrypting the payload resulted in no error and a nil payload")
}
// Overwrite the payload with the decrypted data
ii.Payload = payload
ii.Encrypted = false // TODO handle the encryption state in the consuming code
continue image
} }
} }

View File

@ -79,6 +79,16 @@ func (cm *contactMap) Delete(contactID string) {
cm.sm.Delete(contactID) cm.sm.Delete(contactID)
} }
func (cm *contactMap) Len() int {
count := 0
cm.Range(func(key string, value *Contact) (shouldContinue bool) {
count++
return true
})
return count
}
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| systemMessageTranslationsMap | systemMessageTranslationsMap

View File

@ -2564,3 +2564,81 @@ func (s *MessengerSuite) TestPublicMessageOnCommunityChat() {
s.Require().Error(err) s.Require().Error(err)
s.Require().Equal(ErrMessageForWrongChatType, err) s.Require().Equal(ErrMessageForWrongChatType, err)
} }
func (s *MessengerSuite) TestEncryptDecryptIdentityImagesWithContactPubKeys() {
smPayload := "hello small image"
lgPayload := "hello large image"
ci := protobuf.ChatIdentity{
Clock: uint64(time.Now().Unix()),
Images: map[string]*protobuf.IdentityImage{
"small": {
Payload: []byte(smPayload),
},
"large": {
Payload: []byte(lgPayload),
},
},
}
// Make contact keys and Contacts, set the Contacts to added
var contactKeys []*ecdsa.PrivateKey
for i:=0; i < 10; i++ {
contactKey, err := crypto.GenerateKey()
s.Require().NoError(err)
contactKeys = append(contactKeys, contactKey)
contact, err := BuildContactFromPublicKey(&contactKey.PublicKey)
s.Require().NoError(err)
contact.SystemTags = append(contact.SystemTags, contactAdded)
s.m.allContacts.Store(contact.ID, contact)
}
// Test encryptIdentityImagesWithContactPubKeys
err := s.m.encryptIdentityImagesWithContactPubKeys(ci.Images)
s.Require().NoError(err)
for _, ii := range ci.Images {
s.Require().Equal(s.m.allContacts.Len, len(ii.EncryptionKeys))
}
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
// Switch messenger identities
sender := s.m.identity
s.m.identity = contactKeys[2]
// Test decryptIdentityImagesWithIdentityPrivateKey
err = s.m.decryptIdentityImagesWithIdentityPrivateKey(ci.Images, &sender.PublicKey)
s.Require().NoError(err)
s.Require().Equal(smPayload, string(ci.Images["small"].Payload))
s.Require().Equal(lgPayload, string(ci.Images["large"].Payload))
// RESET Messenger identity, Contacts and IdentityImage.EncryptionKeys
s.m.identity = sender
s.m.allContacts = nil
ci.Images["small"].EncryptionKeys = nil
ci.Images["large"].EncryptionKeys = nil
// Test encryptIdentityImagesWithContactPubKeys with no contacts
err = s.m.encryptIdentityImagesWithContactPubKeys(ci.Images)
s.Require().NoError(err)
for _, ii := range ci.Images {
s.Require().Equal(0, len(ii.EncryptionKeys))
}
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
// Switch messenger identities
s.m.identity = contactKeys[2]
// Test decryptIdentityImagesWithIdentityPrivateKey with no valid identity
err = s.m.decryptIdentityImagesWithIdentityPrivateKey(ci.Images, &sender.PublicKey)
s.Require().NoError(err)
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
}

View File

@ -150,6 +150,8 @@ type IdentityImage struct {
ImageType ImageType `protobuf:"varint,3,opt,name=image_type,json=imageType,proto3,enum=protobuf.ImageType" json:"image_type,omitempty"` ImageType ImageType `protobuf:"varint,3,opt,name=image_type,json=imageType,proto3,enum=protobuf.ImageType" json:"image_type,omitempty"`
// encryption_keys is a list of encrypted keys that can be used to decrypted an encrypted payload // encryption_keys is a list of encrypted keys that can be used to decrypted an encrypted payload
EncryptionKeys [][]byte `protobuf:"bytes,4,rep,name=encryption_keys,json=encryptionKeys,proto3" json:"encryption_keys,omitempty"` EncryptionKeys [][]byte `protobuf:"bytes,4,rep,name=encryption_keys,json=encryptionKeys,proto3" json:"encryption_keys,omitempty"`
// encrypted signals the encryption state of the payload, default is false.
Encrypted bool `protobuf:"varint,5,opt,name=encrypted,proto3" json:"encrypted,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -208,6 +210,13 @@ func (m *IdentityImage) GetEncryptionKeys() [][]byte {
return nil return nil
} }
func (m *IdentityImage) GetEncrypted() bool {
if m != nil {
return m.Encrypted
}
return false
}
func init() { func init() {
proto.RegisterEnum("protobuf.IdentityImage_SourceType", IdentityImage_SourceType_name, IdentityImage_SourceType_value) proto.RegisterEnum("protobuf.IdentityImage_SourceType", IdentityImage_SourceType_name, IdentityImage_SourceType_value)
proto.RegisterType((*ChatIdentity)(nil), "protobuf.ChatIdentity") proto.RegisterType((*ChatIdentity)(nil), "protobuf.ChatIdentity")
@ -220,31 +229,32 @@ func init() {
} }
var fileDescriptor_7a652489000a5879 = []byte{ var fileDescriptor_7a652489000a5879 = []byte{
// 414 bytes of a gzipped FileDescriptorProto // 425 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xdf, 0x6e, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xc1, 0x6e, 0xd3, 0x40,
0x14, 0xc6, 0x49, 0xd2, 0x76, 0xeb, 0x71, 0xd7, 0x55, 0x2e, 0xd2, 0xc2, 0xae, 0x42, 0x6f, 0xe8, 0x10, 0x86, 0xb1, 0x9d, 0xa4, 0xc9, 0x6c, 0x9a, 0x46, 0x1b, 0xa4, 0x9a, 0x8a, 0x83, 0xc9, 0x85,
0x0d, 0x41, 0x2a, 0x37, 0x68, 0x5c, 0x85, 0x52, 0xa4, 0x69, 0x28, 0x9d, 0xdc, 0x8e, 0x69, 0xdc, 0x5c, 0x30, 0x52, 0xb8, 0xa0, 0x72, 0x32, 0x21, 0x48, 0x55, 0x91, 0x53, 0x6d, 0x52, 0xaa, 0x72,
0x58, 0x5e, 0x6a, 0x58, 0xd4, 0xd4, 0x8e, 0x62, 0x17, 0xc9, 0xcf, 0xc1, 0x5b, 0xf0, 0x94, 0x68, 0xb1, 0xb6, 0xf6, 0x42, 0xad, 0x38, 0xb6, 0xe5, 0xdd, 0x20, 0xed, 0x2b, 0x71, 0xe3, 0x0d, 0x51,
0x76, 0xb3, 0xa4, 0x57, 0x3e, 0x7f, 0xbe, 0xf3, 0x3b, 0x9f, 0x0f, 0x8c, 0xb3, 0x27, 0xa6, 0x69, 0x67, 0x6d, 0xec, 0x9e, 0x76, 0xe6, 0x9f, 0x99, 0x6f, 0xfe, 0x1d, 0x98, 0xc5, 0x8f, 0x5c, 0x45,
0xbe, 0xe1, 0x42, 0xe7, 0xda, 0xc4, 0x65, 0x25, 0xb5, 0xc4, 0xa7, 0xf6, 0x79, 0xdc, 0xff, 0xba, 0x69, 0x22, 0x72, 0x95, 0x2a, 0xed, 0x97, 0x55, 0xa1, 0x0a, 0x3a, 0xc4, 0xe7, 0xe1, 0xf8, 0xf3,
0x44, 0x5c, 0xec, 0x77, 0xca, 0x95, 0x27, 0xff, 0x7c, 0x18, 0xcc, 0x9f, 0x98, 0xbe, 0x3e, 0xa8, 0x82, 0x88, 0xfc, 0x78, 0x90, 0x46, 0x9e, 0xff, 0xb1, 0x61, 0xbc, 0x7a, 0xe4, 0xea, 0xaa, 0xee,
0xf1, 0x6b, 0xe8, 0x66, 0x85, 0xcc, 0xb6, 0xa1, 0x17, 0x79, 0xd3, 0x0e, 0x71, 0x09, 0x7e, 0x03, 0xa6, 0x2f, 0xa1, 0x1f, 0x67, 0x45, 0xbc, 0x77, 0x2d, 0xcf, 0x5a, 0xf4, 0x98, 0x49, 0xe8, 0x2b,
0xa7, 0x5c, 0x28, 0x2a, 0xd8, 0x8e, 0x87, 0x7e, 0xe4, 0x4d, 0xfb, 0xe4, 0x84, 0x0b, 0x95, 0xb2, 0x18, 0x8a, 0x5c, 0x46, 0x39, 0x3f, 0x08, 0xd7, 0xf6, 0xac, 0xc5, 0x88, 0x9d, 0x88, 0x5c, 0x86,
0x1d, 0xc7, 0x57, 0xd0, 0xcb, 0x77, 0xec, 0x37, 0x57, 0x61, 0x10, 0x05, 0x53, 0x34, 0x9b, 0xc4, 0xfc, 0x20, 0xe8, 0x25, 0x0c, 0xd2, 0x03, 0xff, 0x25, 0xa4, 0xeb, 0x78, 0xce, 0x82, 0x2c, 0xe7,
0xf5, 0xa6, 0xb8, 0x0d, 0x8e, 0xaf, 0xad, 0x68, 0x21, 0x74, 0x65, 0xc8, 0x61, 0x02, 0xbf, 0x85, 0x7e, 0xb3, 0xc9, 0xef, 0x82, 0xfd, 0x2b, 0x6c, 0x5a, 0xe7, 0xaa, 0xd2, 0xac, 0x9e, 0xa0, 0x6f,
0xc1, 0x26, 0x57, 0x65, 0xc1, 0x8c, 0x43, 0x77, 0x2c, 0x1a, 0x1d, 0x6a, 0x16, 0x1f, 0x01, 0xda, 0x60, 0x9c, 0xa4, 0xb2, 0xcc, 0xb8, 0x36, 0xe8, 0x1e, 0xa2, 0x49, 0xad, 0x21, 0xde, 0x03, 0x92,
0x70, 0x95, 0x55, 0x79, 0xa9, 0x73, 0x29, 0xc2, 0xee, 0x41, 0xd1, 0x94, 0xac, 0x63, 0x59, 0xc8, 0x08, 0x19, 0x57, 0x69, 0xa9, 0xd2, 0x22, 0x77, 0xfb, 0x75, 0x47, 0x2b, 0xa1, 0xe3, 0x22, 0x2b,
0x2a, 0xec, 0xd9, 0x9e, 0x4b, 0x2e, 0x09, 0xa0, 0xd6, 0x46, 0x3c, 0x82, 0x60, 0xcb, 0x8d, 0xfd, 0x2a, 0x77, 0x80, 0x35, 0x93, 0x5c, 0x30, 0x20, 0x9d, 0x8d, 0x74, 0x0a, 0xce, 0x5e, 0x68, 0xfc,
0x54, 0x9f, 0x3c, 0x87, 0xf8, 0x3d, 0x74, 0xff, 0xb0, 0x62, 0xef, 0xfe, 0x83, 0x66, 0x17, 0x8d, 0xd4, 0x88, 0x3d, 0x85, 0xf4, 0x1d, 0xf4, 0x7f, 0xf3, 0xec, 0x68, 0xfe, 0x43, 0x96, 0xe7, 0xad,
0xed, 0xda, 0xb2, 0x9d, 0x27, 0x4e, 0x75, 0xe5, 0x7f, 0xf2, 0x26, 0x7f, 0x7d, 0x38, 0x3b, 0x6a, 0xed, 0xc6, 0x32, 0xce, 0x33, 0xd3, 0x75, 0x69, 0x7f, 0xb4, 0xe6, 0x7f, 0x6d, 0x38, 0x7d, 0x56,
0xe2, 0x10, 0x4e, 0x4a, 0x66, 0x0a, 0xc9, 0x36, 0x16, 0x3d, 0x20, 0x75, 0x8a, 0xe7, 0x80, 0x94, 0xa4, 0x2e, 0x9c, 0x94, 0x5c, 0x67, 0x05, 0x4f, 0x10, 0x3d, 0x66, 0x4d, 0x4a, 0x57, 0x40, 0x64,
0xdc, 0x57, 0x19, 0xa7, 0xda, 0x94, 0x6e, 0xc9, 0xb0, 0x7d, 0x9b, 0x23, 0x4e, 0xbc, 0xb2, 0xd2, 0x71, 0xac, 0x62, 0x11, 0x29, 0x5d, 0x9a, 0x25, 0x93, 0xee, 0x6d, 0x9e, 0x71, 0xfc, 0x2d, 0xb6,
0xb5, 0x29, 0x39, 0x01, 0xf5, 0x12, 0xe3, 0x19, 0x80, 0xbd, 0x94, 0x63, 0x04, 0x96, 0x31, 0x6e, 0xee, 0x74, 0x29, 0x18, 0xc8, 0xff, 0x31, 0x5d, 0x02, 0xe0, 0xa5, 0x0c, 0xc3, 0x41, 0xc6, 0xac,
0x31, 0x9e, 0x7b, 0x76, 0xa8, 0x9f, 0xd7, 0x21, 0x7e, 0x07, 0xe7, 0x5c, 0x64, 0x95, 0xb1, 0xc7, 0xc3, 0x78, 0xaa, 0xe1, 0xd0, 0x28, 0x6d, 0x42, 0xfa, 0x16, 0xce, 0x44, 0x1e, 0x57, 0x1a, 0x8f,
0xa1, 0x5b, 0x6e, 0x54, 0xd8, 0x89, 0x82, 0xe9, 0x80, 0x0c, 0x9b, 0xf2, 0x0d, 0x37, 0x6a, 0xf2, 0x13, 0xed, 0x85, 0x96, 0x6e, 0xcf, 0x73, 0x16, 0x63, 0x36, 0x69, 0xe5, 0x6b, 0xa1, 0x25, 0x7d,
0x0d, 0xa0, 0x59, 0x8b, 0x2f, 0x60, 0x7c, 0x97, 0xde, 0xa4, 0xcb, 0xfb, 0x94, 0xae, 0x96, 0x77, 0x0d, 0xa3, 0x5a, 0x11, 0x09, 0xde, 0x75, 0xc8, 0x5a, 0x61, 0xfe, 0x15, 0xa0, 0x35, 0x45, 0xcf,
0x64, 0xbe, 0xa0, 0xeb, 0x87, 0xdb, 0xc5, 0xe8, 0x15, 0x3e, 0x07, 0x44, 0x92, 0x7b, 0x7a, 0x9b, 0x61, 0x76, 0x1b, 0x5e, 0x87, 0x9b, 0xbb, 0x30, 0xda, 0x6e, 0x6e, 0xd9, 0x6a, 0x1d, 0xed, 0xee,
0x3c, 0x7c, 0x5f, 0x26, 0x5f, 0x47, 0x1e, 0x1e, 0x02, 0x2c, 0xd2, 0x15, 0x4d, 0x7e, 0x24, 0xeb, 0x6f, 0xd6, 0xd3, 0x17, 0xf4, 0x0c, 0x08, 0x0b, 0xee, 0xa2, 0x9b, 0xe0, 0xfe, 0xdb, 0x26, 0xf8,
0x84, 0x8c, 0xfc, 0x2f, 0x67, 0x3f, 0x51, 0xfc, 0xe1, 0x73, 0x6d, 0xea, 0xb1, 0x67, 0xa3, 0x8f, 0x32, 0xb5, 0xe8, 0x04, 0x60, 0x1d, 0x6e, 0xa3, 0xe0, 0x7b, 0xb0, 0x0b, 0xd8, 0xd4, 0xfe, 0x7c,
0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x8e, 0x12, 0x2e, 0x02, 0x86, 0x02, 0x00, 0x00, 0xfa, 0x83, 0xf8, 0xef, 0x3f, 0x35, 0x96, 0x1f, 0x06, 0x18, 0x7d, 0xf8, 0x17, 0x00, 0x00, 0xff,
0xff, 0xc9, 0xd1, 0xd6, 0xde, 0xa4, 0x02, 0x00, 0x00,
} }

View File

@ -41,6 +41,9 @@ message IdentityImage {
// encryption_keys is a list of encrypted keys that can be used to decrypted an encrypted payload // encryption_keys is a list of encrypted keys that can be used to decrypted an encrypted payload
repeated bytes encryption_keys = 4; repeated bytes encryption_keys = 4;
// encrypted signals the encryption state of the payload, default is false.
bool encrypted = 5;
// SourceType are the predefined types of image source allowed // SourceType are the predefined types of image source allowed
enum SourceType { enum SourceType {
UNKNOWN_SOURCE_TYPE = 0; UNKNOWN_SOURCE_TYPE = 0;