github.com/status-im/status-go@v1.1.0/protocol/encryption/protocol.go (about)

     1  package encryption
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"crypto/rand"
     7  	"database/sql"
     8  	"fmt"
     9  
    10  	"go.uber.org/zap"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/pkg/errors"
    14  
    15  	"github.com/status-im/status-go/eth-node/crypto"
    16  	"github.com/status-im/status-go/eth-node/types"
    17  
    18  	"github.com/status-im/status-go/protocol/encryption/multidevice"
    19  	"github.com/status-im/status-go/protocol/encryption/publisher"
    20  	"github.com/status-im/status-go/protocol/encryption/sharedsecret"
    21  )
    22  
    23  //go:generate protoc --go_out=. ./protocol_message.proto
    24  
    25  const (
    26  	protocolVersion                = 1
    27  	sharedSecretNegotiationVersion = 1
    28  	partitionedTopicMinVersion     = 1
    29  	defaultMinVersion              = 0
    30  	maxKeysChannelSize             = 10000
    31  )
    32  
    33  type PartitionTopicMode int
    34  
    35  const (
    36  	PartitionTopicNoSupport PartitionTopicMode = iota
    37  	PartitionTopicV1
    38  )
    39  
    40  type ProtocolMessageSpec struct {
    41  	Message *ProtocolMessage
    42  	// Installations is the targeted devices
    43  	Installations []*multidevice.Installation
    44  	// SharedSecret is a shared secret established among the installations
    45  	SharedSecret *sharedsecret.Secret
    46  	// AgreedSecret indicates whether the shared secret has been agreed
    47  	AgreedSecret bool
    48  	// Public means that the spec contains a public wrapped message
    49  	Public bool
    50  }
    51  
    52  func (p *ProtocolMessageSpec) MinVersion() uint32 {
    53  	if len(p.Installations) == 0 {
    54  		return defaultMinVersion
    55  	}
    56  
    57  	version := p.Installations[0].Version
    58  
    59  	for _, installation := range p.Installations[1:] {
    60  		if installation.Version < version {
    61  			version = installation.Version
    62  		}
    63  	}
    64  	return version
    65  }
    66  
    67  func (p *ProtocolMessageSpec) PartitionedTopicMode() PartitionTopicMode {
    68  	if p.MinVersion() >= partitionedTopicMinVersion {
    69  		return PartitionTopicV1
    70  	}
    71  	return PartitionTopicNoSupport
    72  }
    73  
    74  type Protocol struct {
    75  	encryptor     *encryptor
    76  	secret        *sharedsecret.SharedSecret
    77  	multidevice   *multidevice.Multidevice
    78  	publisher     *publisher.Publisher
    79  	subscriptions *Subscriptions
    80  
    81  	logger *zap.Logger
    82  }
    83  
    84  var (
    85  	// ErrNoPayload means that there was no payload found in the received protocol message.
    86  	ErrNoPayload    = errors.New("no payload")
    87  	ErrNoRatchetKey = errors.New("no ratchet key for given keyID")
    88  )
    89  
    90  // New creates a new ProtocolService instance
    91  func New(
    92  	db *sql.DB,
    93  	installationID string,
    94  	logger *zap.Logger,
    95  ) *Protocol {
    96  	return NewWithEncryptorConfig(
    97  		db,
    98  		installationID,
    99  		defaultEncryptorConfig(installationID, logger),
   100  		logger,
   101  	)
   102  }
   103  
   104  // DB and migrations are shared between encryption package
   105  // and its sub-packages.
   106  func NewWithEncryptorConfig(
   107  	db *sql.DB,
   108  	installationID string,
   109  	encryptorConfig encryptorConfig,
   110  	logger *zap.Logger,
   111  ) *Protocol {
   112  	return &Protocol{
   113  		encryptor: newEncryptor(db, encryptorConfig),
   114  		secret:    sharedsecret.New(db, logger),
   115  		multidevice: multidevice.New(db, &multidevice.Config{
   116  			MaxInstallations: 3,
   117  			ProtocolVersion:  protocolVersion,
   118  			InstallationID:   installationID,
   119  		}),
   120  		publisher: publisher.New(logger),
   121  		logger:    logger.With(zap.Namespace("Protocol")),
   122  	}
   123  }
   124  
   125  type Subscriptions struct {
   126  	SharedSecrets      []*sharedsecret.Secret
   127  	SendContactCode    <-chan struct{}
   128  	NewHashRatchetKeys chan []*HashRatchetInfo
   129  	Quit               chan struct{}
   130  }
   131  
   132  func (p *Protocol) Start(myIdentity *ecdsa.PrivateKey) (*Subscriptions, error) {
   133  	// Propagate currently cached shared secrets.
   134  	secrets, err := p.secret.All()
   135  	if err != nil {
   136  		return nil, errors.Wrap(err, "failed to get all secrets")
   137  	}
   138  	p.subscriptions = &Subscriptions{
   139  		SharedSecrets:      secrets,
   140  		SendContactCode:    p.publisher.Start(),
   141  		NewHashRatchetKeys: make(chan []*HashRatchetInfo, maxKeysChannelSize),
   142  		Quit:               make(chan struct{}),
   143  	}
   144  	return p.subscriptions, nil
   145  }
   146  
   147  func (p *Protocol) Stop() error {
   148  	p.publisher.Stop()
   149  	if p.subscriptions != nil {
   150  		close(p.subscriptions.Quit)
   151  	}
   152  	return nil
   153  }
   154  
   155  func (p *Protocol) addBundle(myIdentityKey *ecdsa.PrivateKey, msg *ProtocolMessage) error {
   156  	// Get a bundle
   157  	installations, err := p.multidevice.GetOurActiveInstallations(&myIdentityKey.PublicKey)
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	bundle, err := p.encryptor.CreateBundle(myIdentityKey, installations)
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	msg.Bundles = []*Bundle{bundle}
   168  
   169  	return nil
   170  }
   171  
   172  // BuildPublicMessage marshals a public chat message given the user identity private key and a payload
   173  func (p *Protocol) BuildPublicMessage(myIdentityKey *ecdsa.PrivateKey, payload []byte) (*ProtocolMessageSpec, error) {
   174  	// Build message not encrypted
   175  	message := &ProtocolMessage{
   176  		InstallationId: p.encryptor.config.InstallationID,
   177  		PublicMessage:  payload,
   178  	}
   179  
   180  	err := p.addBundle(myIdentityKey, message)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	return &ProtocolMessageSpec{Message: message, Public: true}, nil
   186  }
   187  
   188  // BuildEncryptedMessage returns a 1:1 chat message and optionally a negotiated topic given the user identity private key, the recipient's public key, and a payload
   189  func (p *Protocol) BuildEncryptedMessage(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, payload []byte) (*ProtocolMessageSpec, error) {
   190  
   191  	// Get recipients installations.
   192  	activeInstallations, err := p.multidevice.GetActiveInstallations(publicKey)
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  
   197  	// Encrypt payload
   198  	encryptedMessagesByInstalls, installations, err := p.encryptor.EncryptPayload(publicKey, myIdentityKey, activeInstallations, payload)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  
   203  	// Build message
   204  	message := &ProtocolMessage{
   205  		InstallationId:   p.encryptor.config.InstallationID,
   206  		EncryptedMessage: encryptedMessagesByInstalls,
   207  	}
   208  
   209  	err = p.addBundle(myIdentityKey, message)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	// Check who we are sending the message to, and see if we have a shared secret
   215  	// across devices
   216  	var installationIDs []string
   217  	for installationID := range message.GetEncryptedMessage() {
   218  		if installationID != noInstallationID {
   219  			installationIDs = append(installationIDs, installationID)
   220  		}
   221  	}
   222  
   223  	sharedSecret, agreed, err := p.secret.Agreed(myIdentityKey, p.encryptor.config.InstallationID, publicKey, installationIDs)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  
   228  	spec := &ProtocolMessageSpec{
   229  		SharedSecret:  sharedSecret,
   230  		AgreedSecret:  agreed,
   231  		Message:       message,
   232  		Installations: installations,
   233  	}
   234  	return spec, nil
   235  }
   236  
   237  func (p *Protocol) GenerateHashRatchetKey(groupID []byte) (*HashRatchetKeyCompatibility, error) {
   238  	return p.encryptor.GenerateHashRatchetKey(groupID)
   239  }
   240  
   241  // Deprecated: This function is deprecated as it does not marshal groupID. Kept for backward compatibility.
   242  func (p *Protocol) GetAllHRKeysMarshaledV1(groupID []byte) ([]byte, error) {
   243  	keys, err := p.GetAllHRKeys(groupID)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	if keys == nil {
   248  		return nil, nil
   249  	}
   250  
   251  	return proto.Marshal(keys)
   252  }
   253  
   254  func (p *Protocol) GetAllHRKeysMarshaledV2(groupID []byte) ([]byte, error) {
   255  	keys, err := p.GetAllHRKeys(groupID)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  	if keys == nil {
   260  		return nil, nil
   261  	}
   262  
   263  	header := &HRHeader{
   264  		SeqNo:   0,
   265  		GroupId: groupID,
   266  		Keys:    keys,
   267  	}
   268  	return proto.Marshal(header)
   269  }
   270  
   271  func (p *Protocol) GetAllHRKeys(groupID []byte) (*HRKeys, error) {
   272  	ratchets, err := p.encryptor.persistence.GetKeysForGroup(groupID)
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  	if len(ratchets) == 0 {
   277  		return nil, nil
   278  	}
   279  	return p.GetHRKeys(ratchets), nil
   280  }
   281  
   282  // GetKeyIDsForGroup returns a slice of key IDs belonging to a given group ID
   283  func (p *Protocol) GetKeysForGroup(groupID []byte) ([]*HashRatchetKeyCompatibility, error) {
   284  	return p.encryptor.persistence.GetKeysForGroup(groupID)
   285  }
   286  
   287  func (p *Protocol) GetHRKeys(ratchets []*HashRatchetKeyCompatibility) *HRKeys {
   288  	keys := &HRKeys{}
   289  	for _, ratchet := range ratchets {
   290  		key := &HRKey{
   291  			DeprecatedKeyId: ratchet.DeprecatedKeyID(),
   292  			Key:             ratchet.Key,
   293  			Timestamp:       ratchet.Timestamp,
   294  		}
   295  		keys.Keys = append(keys.Keys, key)
   296  	}
   297  
   298  	return keys
   299  }
   300  
   301  // BuildHashRatchetRekeyGroup builds a public message
   302  // with the new key
   303  func (p *Protocol) BuildHashRatchetReKeyGroupMessage(myIdentityKey *ecdsa.PrivateKey, recipients []*ecdsa.PublicKey, groupID []byte, payload []byte, ratchet *HashRatchetKeyCompatibility) (*ProtocolMessageSpec, error) {
   304  
   305  	var err error
   306  	if ratchet == nil {
   307  		ratchet, err = p.GenerateHashRatchetKey(groupID)
   308  		if err != nil {
   309  			return nil, err
   310  		}
   311  	}
   312  
   313  	message, err := buildGroupRekeyMessage(myIdentityKey, groupID, ratchet.Timestamp, ratchet.Key, recipients)
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  
   318  	keys := &HRKeys{
   319  		RekeyGroup: message,
   320  	}
   321  	spec := &ProtocolMessageSpec{
   322  		Public: true,
   323  		Message: &ProtocolMessage{
   324  			InstallationId: p.encryptor.config.InstallationID,
   325  			EncryptedMessage: map[string]*EncryptedMessageProtocol{noInstallationID: &EncryptedMessageProtocol{
   326  				HRHeader: &HRHeader{
   327  					SeqNo:   0,
   328  					GroupId: groupID,
   329  					Keys:    keys,
   330  				},
   331  				Payload: payload,
   332  			},
   333  			},
   334  		},
   335  	}
   336  
   337  	return spec, nil
   338  }
   339  
   340  // BuildHashRatchetKeyExchangeMessage builds a 1:1 message
   341  // containing newly generated hash ratchet key
   342  func (p *Protocol) BuildHashRatchetKeyExchangeMessage(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, groupID []byte, ratchets []*HashRatchetKeyCompatibility) (*ProtocolMessageSpec, error) {
   343  
   344  	keys := p.GetHRKeys(ratchets)
   345  
   346  	encodedKeys, err := proto.Marshal(keys)
   347  	if err != nil {
   348  		return nil, err
   349  	}
   350  
   351  	response, err := p.BuildEncryptedMessage(myIdentityKey, publicKey, encodedKeys)
   352  	if err != nil {
   353  		return nil, err
   354  	}
   355  
   356  	// Loop through installations and assign HRHeader
   357  	// SeqNo=0 has a special meaning for HandleMessage
   358  	// and signifies a message with hash ratchet key payload
   359  	for _, v := range response.Message.EncryptedMessage {
   360  		v.HRHeader = &HRHeader{
   361  			SeqNo:   0,
   362  			GroupId: groupID,
   363  			Keys:    keys,
   364  		}
   365  
   366  	}
   367  
   368  	return response, err
   369  }
   370  
   371  func (p *Protocol) BuildHashRatchetKeyExchangeMessageWithPayload(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, groupID []byte, ratchets []*HashRatchetKeyCompatibility, payload []byte) (*ProtocolMessageSpec, error) {
   372  
   373  	keys := p.GetHRKeys(ratchets)
   374  
   375  	response, err := p.BuildEncryptedMessage(myIdentityKey, publicKey, payload)
   376  	if err != nil {
   377  		return nil, err
   378  	}
   379  
   380  	// Loop through installations and assign HRHeader
   381  	// SeqNo=0 has a special meaning for HandleMessage
   382  	// and signifies a message with hash ratchet key payload
   383  	for _, v := range response.Message.EncryptedMessage {
   384  		v.HRHeader = &HRHeader{
   385  			SeqNo:   0,
   386  			GroupId: groupID,
   387  			Keys:    keys,
   388  		}
   389  
   390  	}
   391  
   392  	return response, err
   393  }
   394  
   395  func (p *Protocol) GetCurrentKeyForGroup(groupID []byte) (*HashRatchetKeyCompatibility, error) {
   396  	return p.encryptor.persistence.GetCurrentKeyForGroup(groupID)
   397  
   398  }
   399  
   400  // BuildHashRatchetMessage returns a hash ratchet chat message
   401  func (p *Protocol) BuildHashRatchetMessage(groupID []byte, payload []byte) (*ProtocolMessageSpec, error) {
   402  
   403  	ratchet, err := p.encryptor.persistence.GetCurrentKeyForGroup(groupID)
   404  	if err != nil {
   405  		return nil, err
   406  	}
   407  
   408  	// Encrypt payload
   409  	encryptedMessagesByInstalls, err := p.encryptor.EncryptHashRatchetPayload(ratchet, payload)
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  
   414  	// Build message
   415  	message := &ProtocolMessage{
   416  		InstallationId:   p.encryptor.config.InstallationID,
   417  		EncryptedMessage: encryptedMessagesByInstalls,
   418  	}
   419  
   420  	spec := &ProtocolMessageSpec{
   421  		Message: message,
   422  	}
   423  	return spec, nil
   424  }
   425  
   426  func (p *Protocol) EncryptCommunityGrants(privateKey *ecdsa.PrivateKey, recipientGrants map[*ecdsa.PublicKey][]byte) (map[uint32][]byte, error) {
   427  	grants := make(map[uint32][]byte)
   428  
   429  	for recipientKey, grant := range recipientGrants {
   430  		sharedKey, err := GenerateSharedKey(privateKey, recipientKey)
   431  		if err != nil {
   432  			return nil, err
   433  		}
   434  
   435  		encryptedGrant, err := encrypt(grant, sharedKey, rand.Reader)
   436  		if err != nil {
   437  			return nil, err
   438  		}
   439  
   440  		kBytes := publicKeyMostRelevantBytes(recipientKey)
   441  		grants[kBytes] = encryptedGrant
   442  	}
   443  
   444  	return grants, nil
   445  }
   446  
   447  func (p *Protocol) DecryptCommunityGrant(myIdentityKey *ecdsa.PrivateKey, senderKey *ecdsa.PublicKey, grants map[uint32][]byte) ([]byte, error) {
   448  	kBytes := publicKeyMostRelevantBytes(&myIdentityKey.PublicKey)
   449  
   450  	ecryptedGrant, ok := grants[kBytes]
   451  	if !ok {
   452  		return nil, errors.New("can't find related grant in the map")
   453  	}
   454  
   455  	sharedKey, err := GenerateSharedKey(myIdentityKey, senderKey)
   456  	if err != nil {
   457  		return nil, err
   458  	}
   459  
   460  	return decrypt(ecryptedGrant, sharedKey)
   461  }
   462  
   463  func (p *Protocol) GetKeyExMessageSpecs(groupID []byte, identity *ecdsa.PrivateKey, recipients []*ecdsa.PublicKey, forceRekey bool) ([]*ProtocolMessageSpec, error) {
   464  	var ratchets []*HashRatchetKeyCompatibility
   465  	var err error
   466  	if !forceRekey {
   467  		ratchets, err = p.encryptor.persistence.GetKeysForGroup(groupID)
   468  		if err != nil {
   469  			return nil, err
   470  		}
   471  	}
   472  	if len(ratchets) == 0 || forceRekey {
   473  		ratchet, err := p.GenerateHashRatchetKey(groupID)
   474  		if err != nil {
   475  			return nil, err
   476  		}
   477  		ratchets = []*HashRatchetKeyCompatibility{ratchet}
   478  	}
   479  	specs := make([]*ProtocolMessageSpec, len(recipients))
   480  	for i, recipient := range recipients {
   481  		keyExMsg, err := p.BuildHashRatchetKeyExchangeMessage(identity, recipient, groupID, ratchets)
   482  		if err != nil {
   483  			return nil, err
   484  		}
   485  		specs[i] = keyExMsg
   486  
   487  	}
   488  
   489  	return specs, nil
   490  }
   491  
   492  // BuildDHMessage builds a message with DH encryption so that it can be decrypted by any other device.
   493  func (p *Protocol) BuildDHMessage(myIdentityKey *ecdsa.PrivateKey, destination *ecdsa.PublicKey, payload []byte) (*ProtocolMessageSpec, error) {
   494  	// Encrypt payload
   495  	encryptionResponse, err := p.encryptor.EncryptPayloadWithDH(destination, payload)
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  
   500  	// Build message
   501  	message := &ProtocolMessage{
   502  		InstallationId:   p.encryptor.config.InstallationID,
   503  		EncryptedMessage: encryptionResponse,
   504  	}
   505  
   506  	err = p.addBundle(myIdentityKey, message)
   507  	if err != nil {
   508  		return nil, err
   509  	}
   510  
   511  	return &ProtocolMessageSpec{Message: message}, nil
   512  }
   513  
   514  // ProcessPublicBundle processes a received X3DH bundle.
   515  func (p *Protocol) ProcessPublicBundle(myIdentityKey *ecdsa.PrivateKey, bundle *Bundle) ([]*multidevice.Installation, error) {
   516  	logger := p.logger.With(zap.String("site", "ProcessPublicBundle"))
   517  
   518  	if err := p.encryptor.ProcessPublicBundle(myIdentityKey, bundle); err != nil {
   519  		return nil, err
   520  	}
   521  
   522  	installations, enabled, err := p.recoverInstallationsFromBundle(myIdentityKey, bundle)
   523  	if err != nil {
   524  		return nil, err
   525  	}
   526  
   527  	// TODO(adam): why do we add installations using identity obtained from GetIdentity()
   528  	// instead of the output of crypto.CompressPubkey()? I tried the second option
   529  	// and the unit tests TestTopic and TestMaxDevices fail.
   530  	identityFromBundle := bundle.GetIdentity()
   531  	theirIdentity, err := ExtractIdentity(bundle)
   532  	if err != nil {
   533  		logger.Panic("unrecoverable error extracting identity", zap.Error(err))
   534  	}
   535  	compressedIdentity := crypto.CompressPubkey(theirIdentity)
   536  	if !bytes.Equal(identityFromBundle, compressedIdentity) {
   537  		logger.Panic("identity from bundle and compressed are not equal")
   538  	}
   539  
   540  	return p.multidevice.AddInstallations(bundle.GetIdentity(), bundle.GetTimestamp(), installations, enabled)
   541  }
   542  
   543  func (p *Protocol) AddInstallation(identity []byte, timestamp int64, installation *multidevice.Installation, enabled bool) ([]*multidevice.Installation, error) {
   544  	return p.multidevice.AddInstallations(identity, timestamp, []*multidevice.Installation{installation}, enabled)
   545  }
   546  
   547  func (p *Protocol) GetMultiDevice() *multidevice.Multidevice {
   548  	return p.multidevice
   549  }
   550  
   551  // recoverInstallationsFromBundle extracts installations from the bundle.
   552  // It returns extracted installations and true if the installations
   553  // are ours, i.e. the bundle was created by our identity key.
   554  func (p *Protocol) recoverInstallationsFromBundle(myIdentityKey *ecdsa.PrivateKey, bundle *Bundle) ([]*multidevice.Installation, bool, error) {
   555  	var installations []*multidevice.Installation
   556  
   557  	theirIdentity, err := ExtractIdentity(bundle)
   558  	if err != nil {
   559  		return nil, false, err
   560  	}
   561  
   562  	myIdentityStr := fmt.Sprintf("0x%x", crypto.FromECDSAPub(&myIdentityKey.PublicKey))
   563  	theirIdentityStr := fmt.Sprintf("0x%x", crypto.FromECDSAPub(theirIdentity))
   564  	// Any device from other peers will be considered enabled, ours needs to
   565  	// be explicitly enabled.
   566  	enabled := theirIdentityStr != myIdentityStr
   567  	signedPreKeys := bundle.GetSignedPreKeys()
   568  
   569  	for installationID, signedPreKey := range signedPreKeys {
   570  		if installationID != p.multidevice.InstallationID() {
   571  			installations = append(installations, &multidevice.Installation{
   572  				Identity: theirIdentityStr,
   573  				ID:       installationID,
   574  				Version:  signedPreKey.GetProtocolVersion(),
   575  			})
   576  		}
   577  	}
   578  
   579  	return installations, enabled, nil
   580  }
   581  
   582  // GetBundle retrieves or creates a X3DH bundle, given a private identity key.
   583  func (p *Protocol) GetBundle(myIdentityKey *ecdsa.PrivateKey) (*Bundle, error) {
   584  	installations, err := p.multidevice.GetOurActiveInstallations(&myIdentityKey.PublicKey)
   585  	if err != nil {
   586  		return nil, err
   587  	}
   588  
   589  	return p.encryptor.CreateBundle(myIdentityKey, installations)
   590  }
   591  
   592  // EnableInstallation enables an installation for multi-device sync.
   593  func (p *Protocol) EnableInstallation(myIdentityKey *ecdsa.PublicKey, installationID string) error {
   594  	return p.multidevice.EnableInstallation(myIdentityKey, installationID)
   595  }
   596  
   597  // DisableInstallation disables an installation for multi-device sync.
   598  func (p *Protocol) DisableInstallation(myIdentityKey *ecdsa.PublicKey, installationID string) error {
   599  	return p.multidevice.DisableInstallation(myIdentityKey, installationID)
   600  }
   601  
   602  // GetOurInstallations returns all the installations available given an identity
   603  func (p *Protocol) GetOurInstallations(myIdentityKey *ecdsa.PublicKey) ([]*multidevice.Installation, error) {
   604  	return p.multidevice.GetOurInstallations(myIdentityKey)
   605  }
   606  
   607  // GetOurActiveInstallations returns all the active installations available given an identity
   608  func (p *Protocol) GetOurActiveInstallations(myIdentityKey *ecdsa.PublicKey) ([]*multidevice.Installation, error) {
   609  	return p.multidevice.GetOurActiveInstallations(myIdentityKey)
   610  }
   611  
   612  // SetInstallationMetadata sets the metadata for our own installation
   613  func (p *Protocol) SetInstallationMetadata(myIdentityKey *ecdsa.PublicKey, installationID string, data *multidevice.InstallationMetadata) error {
   614  	return p.multidevice.SetInstallationMetadata(myIdentityKey, installationID, data)
   615  }
   616  
   617  // SetInstallationName sets the metadata for our own installation
   618  func (p *Protocol) SetInstallationName(myIdentityKey *ecdsa.PublicKey, installationID string, name string) error {
   619  	return p.multidevice.SetInstallationName(myIdentityKey, installationID, name)
   620  }
   621  
   622  // GetPublicBundle retrieves a public bundle given an identity
   623  func (p *Protocol) GetPublicBundle(theirIdentityKey *ecdsa.PublicKey) (*Bundle, error) {
   624  	installations, err := p.multidevice.GetActiveInstallations(theirIdentityKey)
   625  	if err != nil {
   626  		return nil, err
   627  	}
   628  	return p.encryptor.GetPublicBundle(theirIdentityKey, installations)
   629  }
   630  
   631  // ConfirmMessageProcessed confirms and deletes message keys for the given messages
   632  func (p *Protocol) ConfirmMessageProcessed(messageID []byte) error {
   633  	logger := p.logger.With(zap.String("site", "ConfirmMessageProcessed"))
   634  	logger.Debug("confirming message", zap.String("messageID", types.EncodeHex(messageID)))
   635  	return p.encryptor.ConfirmMessageProcessed(messageID)
   636  }
   637  
   638  type HashRatchetInfo struct {
   639  	GroupID []byte
   640  	KeyID   []byte
   641  }
   642  type DecryptMessageResponse struct {
   643  	DecryptedMessage []byte
   644  	Installations    []*multidevice.Installation
   645  	SharedSecrets    []*sharedsecret.Secret
   646  	HashRatchetInfo  []*HashRatchetInfo
   647  }
   648  
   649  func (p *Protocol) HandleHashRatchetKeysPayload(groupID, encodedKeys []byte, myIdentityKey *ecdsa.PrivateKey, theirIdentityKey *ecdsa.PublicKey) ([]*HashRatchetInfo, error) {
   650  	keys := &HRKeys{}
   651  	err := proto.Unmarshal(encodedKeys, keys)
   652  	if err != nil {
   653  		return nil, err
   654  	}
   655  	return p.HandleHashRatchetKeys(groupID, keys, myIdentityKey, theirIdentityKey)
   656  }
   657  
   658  func (p *Protocol) HandleHashRatchetHeadersPayload(encodedHeaders [][]byte) error {
   659  	for _, encodedHeader := range encodedHeaders {
   660  		header := &HRHeader{}
   661  		err := proto.Unmarshal(encodedHeader, header)
   662  		if err != nil {
   663  			return err
   664  		}
   665  		_, err = p.HandleHashRatchetKeys(header.GroupId, header.Keys, nil, nil)
   666  		if err != nil {
   667  			return err
   668  		}
   669  	}
   670  	return nil
   671  }
   672  
   673  func (p *Protocol) HandleHashRatchetKeys(groupID []byte, keys *HRKeys, myIdentityKey *ecdsa.PrivateKey, theirIdentityKey *ecdsa.PublicKey) ([]*HashRatchetInfo, error) {
   674  	if keys == nil {
   675  		return nil, nil
   676  	}
   677  
   678  	var info []*HashRatchetInfo
   679  
   680  	for _, key := range keys.Keys {
   681  		ratchet := &HashRatchetKeyCompatibility{
   682  			GroupID:   groupID,
   683  			Timestamp: key.Timestamp,
   684  			Key:       key.Key,
   685  		}
   686  
   687  		// If there's no timestamp, is coming from an older client
   688  		if key.Timestamp == 0 {
   689  			ratchet.Timestamp = uint64(key.DeprecatedKeyId)
   690  		}
   691  		keyID, err := ratchet.GetKeyID()
   692  		if err != nil {
   693  			return nil, err
   694  		}
   695  		p.logger.Debug("retrieved keys", zap.String("keyID", types.Bytes2Hex(keyID)))
   696  
   697  		// Payload contains hash ratchet key
   698  		err = p.encryptor.persistence.SaveHashRatchetKey(ratchet)
   699  		if err != nil {
   700  			return nil, err
   701  		}
   702  		info = append(info, &HashRatchetInfo{GroupID: groupID, KeyID: keyID})
   703  	}
   704  
   705  	if keys.RekeyGroup != nil {
   706  		if keys.RekeyGroup.Timestamp == 0 {
   707  			return nil, errors.New("timestamp can't be nil")
   708  		}
   709  
   710  		encryptionKey, err := decryptGroupRekeyMessage(myIdentityKey, theirIdentityKey, keys.RekeyGroup)
   711  		if err != nil {
   712  			return nil, err
   713  		}
   714  
   715  		if len(encryptionKey) != 0 {
   716  
   717  			ratchet := &HashRatchetKeyCompatibility{
   718  				GroupID:   groupID,
   719  				Timestamp: keys.RekeyGroup.Timestamp,
   720  				Key:       encryptionKey,
   721  			}
   722  
   723  			keyID, err := ratchet.GetKeyID()
   724  			if err != nil {
   725  				return nil, err
   726  			}
   727  			p.logger.Debug("retrieved group keys", zap.String("keyID", types.Bytes2Hex(keyID)))
   728  			// Payload contains hash ratchet key
   729  			err = p.encryptor.persistence.SaveHashRatchetKey(ratchet)
   730  			if err != nil {
   731  				return nil, err
   732  			}
   733  
   734  			info = append(info, &HashRatchetInfo{GroupID: groupID, KeyID: keyID})
   735  
   736  		}
   737  	}
   738  
   739  	if p.subscriptions != nil {
   740  		p.subscriptions.NewHashRatchetKeys <- info
   741  	}
   742  
   743  	return info, nil
   744  }
   745  
   746  // HandleMessage unmarshals a message and processes it, decrypting it if it is a 1:1 message.
   747  func (p *Protocol) HandleMessage(
   748  	myIdentityKey *ecdsa.PrivateKey,
   749  	theirPublicKey *ecdsa.PublicKey,
   750  	protocolMessage *ProtocolMessage,
   751  	messageID []byte,
   752  ) (*DecryptMessageResponse, error) {
   753  	logger := p.logger.With(zap.String("site", "HandleMessage"))
   754  	response := &DecryptMessageResponse{}
   755  
   756  	logger.Debug("received a protocol message",
   757  		zap.String("sender-public-key",
   758  			types.EncodeHex(crypto.FromECDSAPub(theirPublicKey))),
   759  		zap.String("my-installation-id", p.encryptor.config.InstallationID),
   760  		zap.String("messageID", types.EncodeHex(messageID)))
   761  
   762  	if p.encryptor == nil {
   763  		return nil, errors.New("encryption service not initialized")
   764  	}
   765  
   766  	// Process bundles
   767  	for _, bundle := range protocolMessage.GetBundles() {
   768  		// Should we stop processing if the bundle cannot be verified?
   769  		newInstallations, err := p.ProcessPublicBundle(myIdentityKey, bundle)
   770  		if err != nil {
   771  			return nil, err
   772  		}
   773  		response.Installations = newInstallations
   774  	}
   775  
   776  	// Check if it's a public message
   777  	if publicMessage := protocolMessage.GetPublicMessage(); publicMessage != nil {
   778  		// Nothing to do, as already in cleartext
   779  		response.DecryptedMessage = publicMessage
   780  		return response, nil
   781  	}
   782  
   783  	// Decrypt message
   784  	if encryptedMessage := protocolMessage.GetEncryptedMessage(); encryptedMessage != nil {
   785  		message, err := p.encryptor.DecryptPayload(
   786  			myIdentityKey,
   787  			theirPublicKey,
   788  			protocolMessage.GetInstallationId(),
   789  			encryptedMessage,
   790  			messageID,
   791  		)
   792  
   793  		if err == ErrHashRatchetGroupIDNotFound {
   794  			msg := p.encryptor.GetMessage(encryptedMessage)
   795  
   796  			if msg != nil {
   797  				if header := msg.GetHRHeader(); header != nil {
   798  					response.HashRatchetInfo = append(response.HashRatchetInfo, &HashRatchetInfo{GroupID: header.GroupId, KeyID: header.KeyId})
   799  				}
   800  			}
   801  			return response, err
   802  		}
   803  
   804  		if err != nil {
   805  			return nil, err
   806  		}
   807  
   808  		dmProtocol := encryptedMessage[p.encryptor.config.InstallationID]
   809  		if dmProtocol == nil {
   810  			dmProtocol = encryptedMessage[noInstallationID]
   811  		}
   812  		if dmProtocol != nil {
   813  			hrHeader := dmProtocol.HRHeader
   814  			if hrHeader != nil && hrHeader.SeqNo == 0 {
   815  				var hashRatchetKeys []*HashRatchetInfo
   816  				if hrHeader.Keys != nil {
   817  					hashRatchetKeys, err = p.HandleHashRatchetKeys(hrHeader.GroupId, hrHeader.Keys, myIdentityKey, theirPublicKey)
   818  					if err != nil {
   819  						return nil, err
   820  					}
   821  
   822  				} else {
   823  					// For backward compatibility
   824  					hashRatchetKeys, err = p.HandleHashRatchetKeysPayload(hrHeader.GroupId, message, myIdentityKey, theirPublicKey)
   825  					if err != nil {
   826  						return nil, err
   827  					}
   828  				}
   829  				response.HashRatchetInfo = hashRatchetKeys
   830  			}
   831  		}
   832  
   833  		bundles := protocolMessage.GetBundles()
   834  		version := getProtocolVersion(bundles, protocolMessage.GetInstallationId())
   835  		if version >= sharedSecretNegotiationVersion {
   836  			sharedSecret, err := p.secret.Generate(myIdentityKey, theirPublicKey, protocolMessage.GetInstallationId())
   837  			if err != nil {
   838  				return nil, err
   839  			}
   840  
   841  			response.SharedSecrets = []*sharedsecret.Secret{sharedSecret}
   842  		}
   843  		response.DecryptedMessage = message
   844  		return response, nil
   845  	}
   846  
   847  	// Return error
   848  	return nil, ErrNoPayload
   849  }
   850  
   851  func (p *Protocol) ShouldAdvertiseBundle(publicKey *ecdsa.PublicKey, time int64) (bool, error) {
   852  	return p.publisher.ShouldAdvertiseBundle(publicKey, time)
   853  }
   854  
   855  func (p *Protocol) ConfirmBundleAdvertisement(publicKey *ecdsa.PublicKey, time int64) {
   856  	p.publisher.SetLastAck(publicKey, time)
   857  }
   858  
   859  func (p *Protocol) BuildBundleAdvertiseMessage(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey) (*ProtocolMessageSpec, error) {
   860  	return p.BuildDHMessage(myIdentityKey, publicKey, nil)
   861  }
   862  
   863  func getProtocolVersion(bundles []*Bundle, installationID string) uint32 {
   864  	if installationID == "" {
   865  		return defaultMinVersion
   866  	}
   867  
   868  	for _, bundle := range bundles {
   869  		if bundle != nil {
   870  			signedPreKeys := bundle.GetSignedPreKeys()
   871  			if signedPreKeys == nil {
   872  				continue
   873  			}
   874  
   875  			signedPreKey := signedPreKeys[installationID]
   876  			if signedPreKey == nil {
   877  				return defaultMinVersion
   878  			}
   879  
   880  			return signedPreKey.GetProtocolVersion()
   881  		}
   882  	}
   883  
   884  	return defaultMinVersion
   885  }
   886  
   887  func (p *Protocol) EncryptWithHashRatchet(groupID []byte, payload []byte) ([]byte, *HashRatchetKeyCompatibility, uint32, error) {
   888  	ratchet, err := p.encryptor.persistence.GetCurrentKeyForGroup(groupID)
   889  	if err != nil {
   890  		return nil, nil, 0, err
   891  	}
   892  
   893  	encryptedPayload, newSeqNo, err := p.encryptor.EncryptWithHR(ratchet, payload)
   894  	if err != nil {
   895  		return nil, nil, 0, err
   896  	}
   897  
   898  	return encryptedPayload, ratchet, newSeqNo, nil
   899  }
   900  
   901  func (p *Protocol) DecryptWithHashRatchet(keyID []byte, seqNo uint32, payload []byte) ([]byte, error) {
   902  	ratchet, err := p.encryptor.persistence.GetHashRatchetKeyByID(keyID)
   903  	if err != nil {
   904  		return nil, err
   905  	}
   906  	if ratchet == nil {
   907  		return nil, ErrNoRatchetKey
   908  	}
   909  
   910  	return p.encryptor.DecryptWithHR(ratchet, seqNo, payload)
   911  }