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 }