diff options
author | Wim <wim@42.be> | 2022-01-31 00:27:37 +0100 |
---|---|---|
committer | Wim <wim@42.be> | 2022-03-20 14:57:48 +0100 |
commit | e3cafeaf9292f67459ff1d186f68283bfaedf2ae (patch) | |
tree | b69c39620aa91dba695b3b935c6651c0fb37ce75 /vendor/go.mau.fi/libsignal/protocol | |
parent | e7b193788a56ee7cdb02a87a9db0ad6724ef66d5 (diff) | |
download | matterbridge-msglm-e3cafeaf9292f67459ff1d186f68283bfaedf2ae.tar.gz matterbridge-msglm-e3cafeaf9292f67459ff1d186f68283bfaedf2ae.tar.bz2 matterbridge-msglm-e3cafeaf9292f67459ff1d186f68283bfaedf2ae.zip |
Add dependencies/vendor (whatsapp)
Diffstat (limited to 'vendor/go.mau.fi/libsignal/protocol')
8 files changed, 778 insertions, 0 deletions
diff --git a/vendor/go.mau.fi/libsignal/protocol/CiphertextMessage.go b/vendor/go.mau.fi/libsignal/protocol/CiphertextMessage.go new file mode 100644 index 00000000..c8bd759a --- /dev/null +++ b/vendor/go.mau.fi/libsignal/protocol/CiphertextMessage.go @@ -0,0 +1,19 @@ +package protocol + +type CiphertextMessage interface { + Serialize() []byte + Type() uint32 +} + +type GroupCiphertextMessage interface { + CiphertextMessage + SignedSerialize() []byte +} + +const UnsupportedVersion = 1 +const CurrentVersion = 3 + +const WHISPER_TYPE = 2 +const PREKEY_TYPE = 3 +const SENDERKEY_TYPE = 4 +const SENDERKEY_DISTRIBUTION_TYPE = 5 diff --git a/vendor/go.mau.fi/libsignal/protocol/Doc.go b/vendor/go.mau.fi/libsignal/protocol/Doc.go new file mode 100644 index 00000000..3486bdfb --- /dev/null +++ b/vendor/go.mau.fi/libsignal/protocol/Doc.go @@ -0,0 +1,3 @@ +// Package protocol provides address, group, and message structures that +// the Signal protocol uses for sending encrypted messages. +package protocol diff --git a/vendor/go.mau.fi/libsignal/protocol/PreKeySignalMessage.go b/vendor/go.mau.fi/libsignal/protocol/PreKeySignalMessage.go new file mode 100644 index 00000000..841d9d17 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/protocol/PreKeySignalMessage.go @@ -0,0 +1,152 @@ +package protocol + +import ( + "fmt" + + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/keys/identity" + "go.mau.fi/libsignal/signalerror" + "go.mau.fi/libsignal/util/optional" +) + +// PreKeySignalMessageSerializer is an interface for serializing and deserializing +// PreKeySignalMessages into bytes. An implementation of this interface should be +// used to encode/decode the object into JSON, Protobuffers, etc. +type PreKeySignalMessageSerializer interface { + Serialize(signalMessage *PreKeySignalMessageStructure) []byte + Deserialize(serialized []byte) (*PreKeySignalMessageStructure, error) +} + +// NewPreKeySignalMessageFromBytes will return a Signal Ciphertext message from the given +// bytes using the given serializer. +func NewPreKeySignalMessageFromBytes(serialized []byte, serializer PreKeySignalMessageSerializer, + msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { + // Use the given serializer to decode the signal message. + signalMessageStructure, err := serializer.Deserialize(serialized) + if err != nil { + return nil, err + } + + return NewPreKeySignalMessageFromStruct(signalMessageStructure, serializer, msgSerializer) +} + +// NewPreKeySignalMessageFromStruct will return a new PreKeySignalMessage from the given +// PreKeySignalMessageStructure. +func NewPreKeySignalMessageFromStruct(structure *PreKeySignalMessageStructure, + serializer PreKeySignalMessageSerializer, msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { + + // Throw an error if the given message structure is an unsupported version. + if structure.Version <= UnsupportedVersion { + return nil, fmt.Errorf("%w %d (prekey message)", signalerror.ErrOldMessageVersion, structure.Version) + } + + // Throw an error if the given message structure is a future version. + if structure.Version > CurrentVersion { + return nil, fmt.Errorf("%w %d (prekey message)", signalerror.ErrUnknownMessageVersion, structure.Version) + } + + // Throw an error if the structure is missing critical fields. + if structure.BaseKey == nil || structure.IdentityKey == nil || structure.Message == nil { + return nil, fmt.Errorf("%w (prekey message)", signalerror.ErrIncompleteMessage) + } + + // Create the signal message object from the structure. + preKeyWhisperMessage := &PreKeySignalMessage{structure: *structure, serializer: serializer} + + // Generate the base ECC key from bytes. + var err error + preKeyWhisperMessage.baseKey, err = ecc.DecodePoint(structure.BaseKey, 0) + if err != nil { + return nil, err + } + + // Generate the identity key from bytes + var identityKey ecc.ECPublicKeyable + identityKey, err = ecc.DecodePoint(structure.IdentityKey, 0) + if err != nil { + return nil, err + } + preKeyWhisperMessage.identityKey = identity.NewKey(identityKey) + + // Generate the SignalMessage object from bytes. + preKeyWhisperMessage.message, err = NewSignalMessageFromBytes(structure.Message, msgSerializer) + if err != nil { + return nil, err + } + + return preKeyWhisperMessage, nil +} + +// NewPreKeySignalMessage will return a new PreKeySignalMessage object. +func NewPreKeySignalMessage(version int, registrationID uint32, preKeyID *optional.Uint32, signedPreKeyID uint32, + baseKey ecc.ECPublicKeyable, identityKey *identity.Key, message *SignalMessage, serializer PreKeySignalMessageSerializer, + msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { + structure := &PreKeySignalMessageStructure{ + Version: version, + RegistrationID: registrationID, + PreKeyID: preKeyID, + SignedPreKeyID: signedPreKeyID, + BaseKey: baseKey.Serialize(), + IdentityKey: identityKey.PublicKey().Serialize(), + Message: message.Serialize(), + } + return NewPreKeySignalMessageFromStruct(structure, serializer, msgSerializer) +} + +// PreKeySignalMessageStructure is a serializable structure for +// PreKeySignalMessages. +type PreKeySignalMessageStructure struct { + RegistrationID uint32 + PreKeyID *optional.Uint32 + SignedPreKeyID uint32 + BaseKey []byte + IdentityKey []byte + Message []byte + Version int +} + +// PreKeySignalMessage is an encrypted Signal message that is designed +// to be used when building a session with someone for the first time. +type PreKeySignalMessage struct { + structure PreKeySignalMessageStructure + baseKey ecc.ECPublicKeyable + identityKey *identity.Key + message *SignalMessage + serializer PreKeySignalMessageSerializer +} + +func (p *PreKeySignalMessage) MessageVersion() int { + return p.structure.Version +} + +func (p *PreKeySignalMessage) IdentityKey() *identity.Key { + return p.identityKey +} + +func (p *PreKeySignalMessage) RegistrationID() uint32 { + return p.structure.RegistrationID +} + +func (p *PreKeySignalMessage) PreKeyID() *optional.Uint32 { + return p.structure.PreKeyID +} + +func (p *PreKeySignalMessage) SignedPreKeyID() uint32 { + return p.structure.SignedPreKeyID +} + +func (p *PreKeySignalMessage) BaseKey() ecc.ECPublicKeyable { + return p.baseKey +} + +func (p *PreKeySignalMessage) WhisperMessage() *SignalMessage { + return p.message +} + +func (p *PreKeySignalMessage) Serialize() []byte { + return p.serializer.Serialize(&p.structure) +} + +func (p *PreKeySignalMessage) Type() uint32 { + return PREKEY_TYPE +} diff --git a/vendor/go.mau.fi/libsignal/protocol/SenderKeyDistributionMessage.go b/vendor/go.mau.fi/libsignal/protocol/SenderKeyDistributionMessage.go new file mode 100644 index 00000000..55adcede --- /dev/null +++ b/vendor/go.mau.fi/libsignal/protocol/SenderKeyDistributionMessage.go @@ -0,0 +1,147 @@ +package protocol + +import ( + "fmt" + + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/signalerror" +) + +// SenderKeyDistributionMessageSerializer is an interface for serializing and deserializing +// SenderKeyDistributionMessages into bytes. An implementation of this interface should be +// used to encode/decode the object into JSON, Protobuffers, etc. +type SenderKeyDistributionMessageSerializer interface { + Serialize(signalMessage *SenderKeyDistributionMessageStructure) []byte + Deserialize(serialized []byte) (*SenderKeyDistributionMessageStructure, error) +} + +// NewSenderKeyDistributionMessageFromBytes will return a Signal Ciphertext message from the given +// bytes using the given serializer. +func NewSenderKeyDistributionMessageFromBytes(serialized []byte, + serializer SenderKeyDistributionMessageSerializer) (*SenderKeyDistributionMessage, error) { + + // Use the given serializer to decode the signal message. + signalMessageStructure, err := serializer.Deserialize(serialized) + if err != nil { + return nil, err + } + + return NewSenderKeyDistributionMessageFromStruct(signalMessageStructure, serializer) +} + +// NewSenderKeyDistributionMessageFromStruct returns a Signal Ciphertext message from the +// given serializable structure. +func NewSenderKeyDistributionMessageFromStruct(structure *SenderKeyDistributionMessageStructure, + serializer SenderKeyDistributionMessageSerializer) (*SenderKeyDistributionMessage, error) { + + // Throw an error if the given message structure is an unsupported version. + if structure.Version <= UnsupportedVersion { + return nil, fmt.Errorf("%w %d (sender key distribution)", signalerror.ErrOldMessageVersion, structure.Version) + } + + // Throw an error if the given message structure is a future version. + if structure.Version > CurrentVersion { + return nil, fmt.Errorf("%w %d (sender key distribution)", signalerror.ErrUnknownMessageVersion, structure.Version) + } + + // Throw an error if the structure is missing critical fields. + if structure.SigningKey == nil || structure.ChainKey == nil { + return nil, fmt.Errorf("%w (sender key distribution)", signalerror.ErrIncompleteMessage) + } + + // Get the signing key object from bytes. + signingKey, err := ecc.DecodePoint(structure.SigningKey, 0) + if err != nil { + return nil, err + } + + // Create the signal message object from the structure. + message := &SenderKeyDistributionMessage{ + id: structure.ID, + iteration: structure.Iteration, + chainKey: structure.ChainKey, + version: structure.Version, + signatureKey: signingKey, + serializer: serializer, + } + + // Generate the ECC key from bytes. + message.signatureKey, err = ecc.DecodePoint(structure.SigningKey, 0) + if err != nil { + return nil, err + } + + return message, nil +} + +// NewSenderKeyDistributionMessage returns a Signal Ciphertext message. +func NewSenderKeyDistributionMessage(id uint32, iteration uint32, + chainKey []byte, signatureKey ecc.ECPublicKeyable, + serializer SenderKeyDistributionMessageSerializer) *SenderKeyDistributionMessage { + + return &SenderKeyDistributionMessage{ + id: id, + iteration: iteration, + chainKey: chainKey, + signatureKey: signatureKey, + serializer: serializer, + } +} + +// SenderKeyDistributionMessageStructure is a serializeable structure for senderkey +// distribution messages. +type SenderKeyDistributionMessageStructure struct { + ID uint32 + Iteration uint32 + ChainKey []byte + SigningKey []byte + Version uint32 +} + +// SenderKeyDistributionMessage is a structure for senderkey distribution messages. +type SenderKeyDistributionMessage struct { + id uint32 + iteration uint32 + chainKey []byte + version uint32 + signatureKey ecc.ECPublicKeyable + serializer SenderKeyDistributionMessageSerializer +} + +// ID will return the message's id. +func (p *SenderKeyDistributionMessage) ID() uint32 { + return p.id +} + +// Iteration will return the message's iteration. +func (p *SenderKeyDistributionMessage) Iteration() uint32 { + return p.iteration +} + +// ChainKey will return the message's chain key in bytes. +func (p *SenderKeyDistributionMessage) ChainKey() []byte { + return p.chainKey +} + +// SignatureKey will return the message's signature public key +func (p *SenderKeyDistributionMessage) SignatureKey() ecc.ECPublicKeyable { + return p.signatureKey +} + +// Serialize will use the given serializer and return the message as +// bytes. +func (p *SenderKeyDistributionMessage) Serialize() []byte { + structure := &SenderKeyDistributionMessageStructure{ + ID: p.id, + Iteration: p.iteration, + ChainKey: p.chainKey, + SigningKey: p.signatureKey.Serialize(), + Version: CurrentVersion, + } + return p.serializer.Serialize(structure) +} + +// Type will return the message's type. +func (p *SenderKeyDistributionMessage) Type() uint32 { + return SENDERKEY_DISTRIBUTION_TYPE +} diff --git a/vendor/go.mau.fi/libsignal/protocol/SenderKeyMessage.go b/vendor/go.mau.fi/libsignal/protocol/SenderKeyMessage.go new file mode 100644 index 00000000..cd69cea4 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/protocol/SenderKeyMessage.go @@ -0,0 +1,168 @@ +package protocol + +import ( + "fmt" + + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/signalerror" + "go.mau.fi/libsignal/util/bytehelper" +) + +// SenderKeyMessageSerializer is an interface for serializing and deserializing +// SenderKeyMessages into bytes. An implementation of this interface should be +// used to encode/decode the object into JSON, Protobuffers, etc. +type SenderKeyMessageSerializer interface { + Serialize(signalMessage *SenderKeyMessageStructure) []byte + Deserialize(serialized []byte) (*SenderKeyMessageStructure, error) +} + +// NewSenderKeyMessageFromBytes will return a Signal Ciphertext message from the given +// bytes using the given serializer. +func NewSenderKeyMessageFromBytes(serialized []byte, + serializer SenderKeyMessageSerializer) (*SenderKeyMessage, error) { + + // Use the given serializer to decode the signal message. + senderKeyMessageStructure, err := serializer.Deserialize(serialized) + if err != nil { + return nil, err + } + + return NewSenderKeyMessageFromStruct(senderKeyMessageStructure, serializer) +} + +// NewSenderKeyMessageFromStruct returns a Signal Ciphertext message from the +// given serializable structure. +func NewSenderKeyMessageFromStruct(structure *SenderKeyMessageStructure, + serializer SenderKeyMessageSerializer) (*SenderKeyMessage, error) { + + // Throw an error if the given message structure is an unsupported version. + if structure.Version <= UnsupportedVersion { + return nil, fmt.Errorf("%w %d (sender key message)", signalerror.ErrOldMessageVersion, structure.Version) + } + + // Throw an error if the given message structure is a future version. + if structure.Version > CurrentVersion { + return nil, fmt.Errorf("%w %d (sender key message)", signalerror.ErrUnknownMessageVersion, structure.Version) + } + + // Throw an error if the structure is missing critical fields. + if structure.CipherText == nil { + return nil, fmt.Errorf("%w (sender key message)", signalerror.ErrIncompleteMessage) + } + + // Create the signal message object from the structure. + whisperMessage := &SenderKeyMessage{ + keyID: structure.ID, + version: structure.Version, + iteration: structure.Iteration, + ciphertext: structure.CipherText, + signature: structure.Signature, + serializer: serializer, + } + + return whisperMessage, nil +} + +// NewSenderKeyMessage returns a SenderKeyMessage. +func NewSenderKeyMessage(keyID uint32, iteration uint32, ciphertext []byte, + signatureKey ecc.ECPrivateKeyable, serializer SenderKeyMessageSerializer) *SenderKeyMessage { + + // Ensure we have a valid signature key + if signatureKey == nil { + panic("Signature is nil. Unable to sign new senderkey message.") + } + + // Build our SenderKeyMessage. + senderKeyMessage := &SenderKeyMessage{ + keyID: keyID, + iteration: iteration, + ciphertext: ciphertext, + version: CurrentVersion, + serializer: serializer, + } + + // Sign the serialized message and include it in the message. This will be included + // in the signed serialized version of the message. + signature := ecc.CalculateSignature(signatureKey, senderKeyMessage.Serialize()) + senderKeyMessage.signature = bytehelper.ArrayToSlice64(signature) + + return senderKeyMessage +} + +// SenderKeyMessageStructure is a serializeable structure for SenderKey messages. +type SenderKeyMessageStructure struct { + ID uint32 + Iteration uint32 + CipherText []byte + Version uint32 + Signature []byte +} + +// SenderKeyMessage is a structure for messages using senderkey groups. +type SenderKeyMessage struct { + version uint32 + keyID uint32 + iteration uint32 + ciphertext []byte + signature []byte + serializer SenderKeyMessageSerializer +} + +// KeyID returns the SenderKeyMessage key ID. +func (p *SenderKeyMessage) KeyID() uint32 { + return p.keyID +} + +// Iteration returns the SenderKeyMessage iteration. +func (p *SenderKeyMessage) Iteration() uint32 { + return p.iteration +} + +// Ciphertext returns the SenderKeyMessage encrypted ciphertext. +func (p *SenderKeyMessage) Ciphertext() []byte { + return p.ciphertext +} + +// Version returns the Signal message version of the message. +func (p *SenderKeyMessage) Version() uint32 { + return p.version +} + +// Serialize will use the given serializer to return the message as bytes +// excluding the signature. This should be used for signing and verifying +// message signatures. +func (p *SenderKeyMessage) Serialize() []byte { + structure := &SenderKeyMessageStructure{ + ID: p.keyID, + Iteration: p.iteration, + CipherText: p.ciphertext, + Version: p.version, + } + + return p.serializer.Serialize(structure) +} + +// SignedSerialize will use the given serializer to return the message as +// bytes with the message signature included. This should be used when +// sending the message over the network. +func (p *SenderKeyMessage) SignedSerialize() []byte { + structure := &SenderKeyMessageStructure{ + ID: p.keyID, + Iteration: p.iteration, + CipherText: p.ciphertext, + Version: p.version, + Signature: p.signature, + } + + return p.serializer.Serialize(structure) +} + +// Signature returns the SenderKeyMessage signature +func (p *SenderKeyMessage) Signature() [64]byte { + return bytehelper.SliceToArray64(p.signature) +} + +// Type returns the sender key type. +func (p *SenderKeyMessage) Type() uint32 { + return SENDERKEY_TYPE +} diff --git a/vendor/go.mau.fi/libsignal/protocol/SenderKeyName.go b/vendor/go.mau.fi/libsignal/protocol/SenderKeyName.go new file mode 100644 index 00000000..d9b6b684 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/protocol/SenderKeyName.go @@ -0,0 +1,25 @@ +package protocol + +// NewSenderKeyName returns a new SenderKeyName object. +func NewSenderKeyName(groupID string, sender *SignalAddress) *SenderKeyName { + return &SenderKeyName{ + groupID: groupID, + sender: sender, + } +} + +// SenderKeyName is a structure for a group session address. +type SenderKeyName struct { + groupID string + sender *SignalAddress +} + +// GroupID returns the sender key group id +func (n *SenderKeyName) GroupID() string { + return n.groupID +} + +// Sender returns the Signal address of sending user in the group. +func (n *SenderKeyName) Sender() *SignalAddress { + return n.sender +} diff --git a/vendor/go.mau.fi/libsignal/protocol/SignalMessage.go b/vendor/go.mau.fi/libsignal/protocol/SignalMessage.go new file mode 100644 index 00000000..fd348a3e --- /dev/null +++ b/vendor/go.mau.fi/libsignal/protocol/SignalMessage.go @@ -0,0 +1,226 @@ +package protocol + +import ( + "crypto/hmac" + "crypto/sha256" + "fmt" + "strconv" + + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/keys/identity" + "go.mau.fi/libsignal/logger" + "go.mau.fi/libsignal/signalerror" + "go.mau.fi/libsignal/util/bytehelper" +) + +const MacLength int = 8 + +// SignalMessageSerializer is an interface for serializing and deserializing +// SignalMessages into bytes. An implementation of this interface should be +// used to encode/decode the object into JSON, Protobuffers, etc. +type SignalMessageSerializer interface { + Serialize(signalMessage *SignalMessageStructure) []byte + Deserialize(serialized []byte) (*SignalMessageStructure, error) +} + +// NewSignalMessageFromBytes will return a Signal Ciphertext message from the given +// bytes using the given serializer. +func NewSignalMessageFromBytes(serialized []byte, serializer SignalMessageSerializer) (*SignalMessage, error) { + // Use the given serializer to decode the signal message. + signalMessageStructure, err := serializer.Deserialize(serialized) + if err != nil { + return nil, err + } + + return NewSignalMessageFromStruct(signalMessageStructure, serializer) +} + +// NewSignalMessageFromStruct returns a Signal Ciphertext message from the +// given serializable structure. +func NewSignalMessageFromStruct(structure *SignalMessageStructure, serializer SignalMessageSerializer) (*SignalMessage, error) { + // Throw an error if the given message structure is an unsupported version. + if structure.Version <= UnsupportedVersion { + return nil, fmt.Errorf("%w %d (normal message)", signalerror.ErrOldMessageVersion, structure.Version) + } + + // Throw an error if the given message structure is a future version. + if structure.Version > CurrentVersion { + return nil, fmt.Errorf("%w %d (normal message)", signalerror.ErrUnknownMessageVersion, structure.Version) + } + + // Throw an error if the structure is missing critical fields. + if structure.CipherText == nil || structure.RatchetKey == nil { + return nil, fmt.Errorf("%w (normal message)", signalerror.ErrIncompleteMessage) + } + + // Create the signal message object from the structure. + whisperMessage := &SignalMessage{structure: *structure, serializer: serializer} + + // Generate the ECC key from bytes. + var err error + whisperMessage.senderRatchetKey, err = ecc.DecodePoint(structure.RatchetKey, 0) + if err != nil { + return nil, err + } + + return whisperMessage, nil +} + +// NewSignalMessage returns a Signal Ciphertext message. +func NewSignalMessage(messageVersion int, counter, previousCounter uint32, macKey []byte, + senderRatchetKey ecc.ECPublicKeyable, ciphertext []byte, senderIdentityKey, + receiverIdentityKey *identity.Key, serializer SignalMessageSerializer) (*SignalMessage, error) { + + version := []byte(strconv.Itoa(messageVersion)) + // Build the signal message structure with the given data. + structure := &SignalMessageStructure{ + Counter: counter, + PreviousCounter: previousCounter, + RatchetKey: senderRatchetKey.Serialize(), + CipherText: ciphertext, + } + + serialized := append(version, serializer.Serialize(structure)...) + // Get the message authentication code from the serialized structure. + mac, err := getMac( + messageVersion, senderIdentityKey, receiverIdentityKey, + macKey, serialized, + ) + if err != nil { + return nil, err + } + structure.Mac = mac + structure.Version = messageVersion + + // Generate a SignalMessage with the structure. + whisperMessage, err := NewSignalMessageFromStruct(structure, serializer) + if err != nil { + return nil, err + } + + return whisperMessage, nil +} + +// SignalMessageStructure is a serializeable structure of a signal message +// object. +type SignalMessageStructure struct { + RatchetKey []byte + Counter uint32 + PreviousCounter uint32 + CipherText []byte + Version int + Mac []byte +} + +// SignalMessage is a cipher message that contains a message encrypted +// with the Signal protocol. +type SignalMessage struct { + structure SignalMessageStructure + senderRatchetKey ecc.ECPublicKeyable + serializer SignalMessageSerializer +} + +// SenderRatchetKey returns the SignalMessage's sender ratchet key. This +// key is used for ratcheting the chain forward to negotiate a new shared +// secret that cannot be derived from previous chains. +func (s *SignalMessage) SenderRatchetKey() ecc.ECPublicKeyable { + return s.senderRatchetKey +} + +// MessageVersion returns the message version this SignalMessage supports. +func (s *SignalMessage) MessageVersion() int { + return s.structure.Version +} + +// Counter will return the SignalMessage counter. +func (s *SignalMessage) Counter() uint32 { + return s.structure.Counter +} + +// Body will return the SignalMessage's ciphertext in bytes. +func (s *SignalMessage) Body() []byte { + return s.structure.CipherText +} + +// VerifyMac will return an error if the message's message authentication code +// is invalid. This should be used on SignalMessages that have been constructed +// from a sent message. +func (s *SignalMessage) VerifyMac(messageVersion int, senderIdentityKey, + receiverIdentityKey *identity.Key, macKey []byte) error { + + // Create a copy of the message without the mac. We'll use this to calculate + // the message authentication code. + structure := s.structure + signalMessage, err := NewSignalMessageFromStruct(&structure, s.serializer) + if err != nil { + return err + } + signalMessage.structure.Mac = nil + signalMessage.structure.Version = 0 + version := []byte(strconv.Itoa(s.MessageVersion())) + serialized := append(version, signalMessage.Serialize()...) + + // Calculate the message authentication code from the serialized structure. + ourMac, err := getMac( + messageVersion, + senderIdentityKey, + receiverIdentityKey, + macKey, + serialized, + ) + if err != nil { + logger.Error(err) + return err + } + + // Get the message authentication code that was sent to us as part of + // the signal message structure. + theirMac := s.structure.Mac + + logger.Debug("Verifying macs...") + logger.Debug(" Our MAC: ", ourMac) + logger.Debug(" Their MAC: ", theirMac) + + // Return an error if our calculated mac doesn't match the mac sent to us. + if !hmac.Equal(ourMac, theirMac) { + return signalerror.ErrBadMAC + } + + return nil +} + +// Serialize will return the Signal Message as bytes. +func (s *SignalMessage) Serialize() []byte { + return s.serializer.Serialize(&s.structure) +} + +// Structure will return a serializeable structure of the Signal Message. +func (s *SignalMessage) Structure() *SignalMessageStructure { + structure := s.structure + return &structure +} + +// Type will return the type of Signal Message this is. +func (s *SignalMessage) Type() uint32 { + return WHISPER_TYPE +} + +// getMac will calculate the mac using the given message version, identity +// keys, macKey and SignalMessageStructure. The MAC key is a private key held +// by both parties that is concatenated with the message and hashed. +func getMac(messageVersion int, senderIdentityKey, receiverIdentityKey *identity.Key, + macKey, serialized []byte) ([]byte, error) { + + mac := hmac.New(sha256.New, macKey[:]) + + if messageVersion >= 3 { + mac.Write(senderIdentityKey.PublicKey().Serialize()) + mac.Write(receiverIdentityKey.PublicKey().Serialize()) + } + + mac.Write(serialized) + + fullMac := mac.Sum(nil) + + return bytehelper.Trim(fullMac, MacLength), nil +} diff --git a/vendor/go.mau.fi/libsignal/protocol/SignalProtocolAddress.go b/vendor/go.mau.fi/libsignal/protocol/SignalProtocolAddress.go new file mode 100644 index 00000000..468a3087 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/protocol/SignalProtocolAddress.go @@ -0,0 +1,38 @@ +package protocol + +import ( + "fmt" +) + +const ADDRESS_SEPARATOR = ":" + +// NewSignalAddress returns a new signal address. +func NewSignalAddress(name string, deviceID uint32) *SignalAddress { + addr := SignalAddress{ + name: name, + deviceID: deviceID, + } + + return &addr +} + +// SignalAddress is a combination of a name and a device ID. +type SignalAddress struct { + name string + deviceID uint32 +} + +// Name returns the signal address's name. +func (s *SignalAddress) Name() string { + return s.name +} + +// DeviceID returns the signal address's device ID. +func (s *SignalAddress) DeviceID() uint32 { + return s.deviceID +} + +// String returns a string of both the address name and device id. +func (s *SignalAddress) String() string { + return fmt.Sprintf("%s%s%d", s.name, ADDRESS_SEPARATOR, s.deviceID) +} |