summaryrefslogtreecommitdiffstats
path: root/vendor/go.mau.fi/libsignal/protocol
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.mau.fi/libsignal/protocol')
-rw-r--r--vendor/go.mau.fi/libsignal/protocol/CiphertextMessage.go19
-rw-r--r--vendor/go.mau.fi/libsignal/protocol/Doc.go3
-rw-r--r--vendor/go.mau.fi/libsignal/protocol/PreKeySignalMessage.go152
-rw-r--r--vendor/go.mau.fi/libsignal/protocol/SenderKeyDistributionMessage.go147
-rw-r--r--vendor/go.mau.fi/libsignal/protocol/SenderKeyMessage.go168
-rw-r--r--vendor/go.mau.fi/libsignal/protocol/SenderKeyName.go25
-rw-r--r--vendor/go.mau.fi/libsignal/protocol/SignalMessage.go226
-rw-r--r--vendor/go.mau.fi/libsignal/protocol/SignalProtocolAddress.go38
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)
+}