status-im/status-go

View on GitHub
protocol/identity_images.go

Summary

Maintainability
A
0 mins
Test Coverage
D
66%
package protocol

import (
    "crypto/ecdsa"
    crand "crypto/rand"
    "errors"

    "github.com/status-im/status-go/protocol/common"
    "github.com/status-im/status-go/protocol/protobuf"
)

var ErrCipherMessageAutentificationFailed = "cipher: message authentication failed"

func EncryptIdentityImagesWithContactPubKeys(iis map[string]*protobuf.IdentityImage, m *Messenger) (err error) {
    // Make AES key
    AESKey := make([]byte, 32)
    _, err = crand.Read(AESKey)
    if err != nil {
        return err
    }

    for _, ii := range iis {
        // Encrypt image payload with the AES key
        var encryptedPayload []byte
        encryptedPayload, err = common.Encrypt(ii.Payload, AESKey, crand.Reader)
        if err != nil {
            return err
        }

        // Overwrite the unencrypted payload with the newly encrypted payload
        ii.Payload = encryptedPayload
        ii.Encrypted = true
        m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
            if !contact.added() {
                return true
            }
            var pubK *ecdsa.PublicKey
            var sharedKey []byte
            var eAESKey []byte

            pubK, err = contact.PublicKey()
            if err != nil {
                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 main AES key with AES encryption using the DH key
            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 DecryptIdentityImagesWithIdentityPrivateKey(iis map[string]*protobuf.IdentityImage, recipientIdentity *ecdsa.PrivateKey, 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(recipientIdentity, senderPubKey)
            if err != nil {
                return err
            }

            // Decrypt the main encryption AES key with AES encryption using the DH key
            dAESKey, err := common.Decrypt(empk, sharedKey)
            if err != nil {
                if err.Error() == ErrCipherMessageAutentificationFailed {
                    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
            continue image
        }
    }

    return nil
}