diff options
Diffstat (limited to 'vendor/go.mau.fi/libsignal/groups')
10 files changed, 736 insertions, 0 deletions
diff --git a/vendor/go.mau.fi/libsignal/groups/GroupCipher.go b/vendor/go.mau.fi/libsignal/groups/GroupCipher.go new file mode 100644 index 00000000..b821f3c3 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/GroupCipher.go @@ -0,0 +1,141 @@ +package groups + +import ( + "fmt" + + "go.mau.fi/libsignal/cipher" + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/groups/ratchet" + "go.mau.fi/libsignal/groups/state/record" + "go.mau.fi/libsignal/groups/state/store" + "go.mau.fi/libsignal/protocol" + "go.mau.fi/libsignal/signalerror" +) + +// NewGroupCipher will return a new group message cipher that can be used for +// encrypt/decrypt operations. +func NewGroupCipher(builder *SessionBuilder, senderKeyID *protocol.SenderKeyName, + senderKeyStore store.SenderKey) *GroupCipher { + + return &GroupCipher{ + senderKeyID: senderKeyID, + senderKeyStore: senderKeyStore, + sessionBuilder: builder, + } +} + +// GroupCipher is the main entry point for group encrypt/decrypt operations. +// Once a session has been established, this can be used for +// all encrypt/decrypt operations within that session. +type GroupCipher struct { + senderKeyID *protocol.SenderKeyName + senderKeyStore store.SenderKey + sessionBuilder *SessionBuilder +} + +// Encrypt will take the given message in bytes and return encrypted bytes. +func (c *GroupCipher) Encrypt(plaintext []byte) (protocol.GroupCiphertextMessage, error) { + // Load the sender key based on id from our store. + keyRecord := c.senderKeyStore.LoadSenderKey(c.senderKeyID) + senderKeyState, err := keyRecord.SenderKeyState() + if err != nil { + return nil, err + } + + // Get the message key from the senderkey state. + senderKey, err := senderKeyState.SenderChainKey().SenderMessageKey() + if err != nil { + return nil, err + } + + // Encrypt the plaintext. + ciphertext, err := cipher.EncryptCbc(senderKey.Iv(), senderKey.CipherKey(), plaintext) + if err != nil { + return nil, err + } + + senderKeyMessage := protocol.NewSenderKeyMessage( + senderKeyState.KeyID(), + senderKey.Iteration(), + ciphertext, + senderKeyState.SigningKey().PrivateKey(), + c.sessionBuilder.serializer.SenderKeyMessage, + ) + + senderKeyState.SetSenderChainKey(senderKeyState.SenderChainKey().Next()) + c.senderKeyStore.StoreSenderKey(c.senderKeyID, keyRecord) + + return senderKeyMessage, nil +} + +// Decrypt decrypts the given message using an existing session that +// is stored in the senderKey store. +func (c *GroupCipher) Decrypt(senderKeyMessage *protocol.SenderKeyMessage) ([]byte, error) { + keyRecord := c.senderKeyStore.LoadSenderKey(c.senderKeyID) + + if keyRecord.IsEmpty() { + return nil, fmt.Errorf("%w for %s in %s", signalerror.ErrNoSenderKeyForUser, c.senderKeyID.Sender().String(), c.senderKeyID.GroupID()) + } + + // Get the senderkey state by id. + senderKeyState, err := keyRecord.GetSenderKeyStateByID(senderKeyMessage.KeyID()) + if err != nil { + return nil, err + } + + // Verify the signature of the senderkey message. + verified := c.verifySignature(senderKeyState.SigningKey().PublicKey(), senderKeyMessage) + if !verified { + return nil, signalerror.ErrSenderKeyStateVerificationFailed + } + + senderKey, err := c.getSenderKey(senderKeyState, senderKeyMessage.Iteration()) + if err != nil { + return nil, err + } + + // Decrypt the message ciphertext. + plaintext, err := cipher.DecryptCbc(senderKey.Iv(), senderKey.CipherKey(), senderKeyMessage.Ciphertext()) + if err != nil { + return nil, err + } + + // Store the sender key by id. + c.senderKeyStore.StoreSenderKey(c.senderKeyID, keyRecord) + + return plaintext, nil +} + +// verifySignature will verify the signature of the senderkey message with +// the given public key. +func (c *GroupCipher) verifySignature(signingPubKey ecc.ECPublicKeyable, + senderKeyMessage *protocol.SenderKeyMessage) bool { + + return ecc.VerifySignature(signingPubKey, senderKeyMessage.Serialize(), senderKeyMessage.Signature()) +} + +func (c *GroupCipher) getSenderKey(senderKeyState *record.SenderKeyState, iteration uint32) (*ratchet.SenderMessageKey, error) { + senderChainKey := senderKeyState.SenderChainKey() + if senderChainKey.Iteration() > iteration { + if senderKeyState.HasSenderMessageKey(iteration) { + return senderKeyState.RemoveSenderMessageKey(iteration), nil + } + return nil, fmt.Errorf("%w (current: %d, received: %d)", signalerror.ErrOldCounter, senderChainKey.Iteration(), iteration) + } + + if iteration-senderChainKey.Iteration() > 2000 { + return nil, signalerror.ErrTooFarIntoFuture + } + + for senderChainKey.Iteration() < iteration { + senderMessageKey, err := senderChainKey.SenderMessageKey() + if err != nil { + return nil, err + } + senderKeyState.AddSenderMessageKey(senderMessageKey) + senderChainKey = senderChainKey.Next() + } + + senderKeyState.SetSenderChainKey(senderChainKey.Next()) + return senderChainKey.SenderMessageKey() +} diff --git a/vendor/go.mau.fi/libsignal/groups/GroupSessionBuilder.go b/vendor/go.mau.fi/libsignal/groups/GroupSessionBuilder.go new file mode 100644 index 00000000..2a5569b7 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/GroupSessionBuilder.go @@ -0,0 +1,84 @@ +// Package groups is responsible for setting up group SenderKey encrypted sessions. +// Once a session has been established, GroupCipher can be used to encrypt/decrypt +// messages in that session. +// +// The built sessions are unidirectional: they can be used either for sending or +// for receiving, but not both. Sessions are constructed per (groupId + senderId + +// deviceId) tuple. Remote logical users are identified by their senderId, and each +// logical recipientId can have multiple physical devices. +package groups + +import ( + "go.mau.fi/libsignal/groups/state/record" + "go.mau.fi/libsignal/groups/state/store" + "go.mau.fi/libsignal/protocol" + "go.mau.fi/libsignal/serialize" + "go.mau.fi/libsignal/util/keyhelper" +) + +// NewGroupSessionBuilder will return a new group session builder. +func NewGroupSessionBuilder(senderKeyStore store.SenderKey, + serializer *serialize.Serializer) *SessionBuilder { + + return &SessionBuilder{ + senderKeyStore: senderKeyStore, + serializer: serializer, + } +} + +// SessionBuilder is a structure for building group sessions. +type SessionBuilder struct { + senderKeyStore store.SenderKey + serializer *serialize.Serializer +} + +// Process will process an incoming group message and set up the corresponding +// session for it. +func (b *SessionBuilder) Process(senderKeyName *protocol.SenderKeyName, + msg *protocol.SenderKeyDistributionMessage) { + + senderKeyRecord := b.senderKeyStore.LoadSenderKey(senderKeyName) + if senderKeyRecord == nil { + senderKeyRecord = record.NewSenderKey(b.serializer.SenderKeyRecord, b.serializer.SenderKeyState) + } + senderKeyRecord.AddSenderKeyState(msg.ID(), msg.Iteration(), msg.ChainKey(), msg.SignatureKey()) + b.senderKeyStore.StoreSenderKey(senderKeyName, senderKeyRecord) +} + +// Create will create a new group session for the given name. +func (b *SessionBuilder) Create(senderKeyName *protocol.SenderKeyName) (*protocol.SenderKeyDistributionMessage, error) { + // Load the senderkey by name + senderKeyRecord := b.senderKeyStore.LoadSenderKey(senderKeyName) + + // If the record is empty, generate new keys. + if senderKeyRecord == nil || senderKeyRecord.IsEmpty() { + senderKeyRecord = record.NewSenderKey(b.serializer.SenderKeyRecord, b.serializer.SenderKeyState) + signingKey, err := keyhelper.GenerateSenderSigningKey() + if err != nil { + return nil, err + } + senderKeyRecord.SetSenderKeyState( + keyhelper.GenerateSenderKeyID(), 0, + keyhelper.GenerateSenderKey(), + signingKey, + ) + b.senderKeyStore.StoreSenderKey(senderKeyName, senderKeyRecord) + } + + // Get the senderkey state. + state, err := senderKeyRecord.SenderKeyState() + if err != nil { + return nil, err + } + + // Create the group message to return. + senderKeyDistributionMessage := protocol.NewSenderKeyDistributionMessage( + state.KeyID(), + state.SenderChainKey().Iteration(), + state.SenderChainKey().Seed(), + state.SigningKey().PublicKey(), + b.serializer.SenderKeyDistributionMessage, + ) + + return senderKeyDistributionMessage, nil +} diff --git a/vendor/go.mau.fi/libsignal/groups/ratchet/Doc.go b/vendor/go.mau.fi/libsignal/groups/ratchet/Doc.go new file mode 100644 index 00000000..6d374465 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/ratchet/Doc.go @@ -0,0 +1,3 @@ +// Package ratchet provides the methods necessary to establish a ratchet +// session for group messaging. +package ratchet diff --git a/vendor/go.mau.fi/libsignal/groups/ratchet/SenderChainKey.go b/vendor/go.mau.fi/libsignal/groups/ratchet/SenderChainKey.go new file mode 100644 index 00000000..a9530143 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/ratchet/SenderChainKey.go @@ -0,0 +1,68 @@ +package ratchet + +import ( + "crypto/hmac" + "crypto/sha256" +) + +var messageKeySeed = []byte{0x01} +var chainKeySeed = []byte{0x02} + +// NewSenderChainKey will return a new SenderChainKey. +func NewSenderChainKey(iteration uint32, chainKey []byte) *SenderChainKey { + return &SenderChainKey{ + iteration: iteration, + chainKey: chainKey, + } +} + +// NewSenderChainKeyFromStruct will return a new chain key object from the +// given serializeable structure. +func NewSenderChainKeyFromStruct(structure *SenderChainKeyStructure) *SenderChainKey { + return &SenderChainKey{ + iteration: structure.Iteration, + chainKey: structure.ChainKey, + } +} + +// NewStructFromSenderChainKeys returns a serializeable structure of chain keys. +func NewStructFromSenderChainKey(key *SenderChainKey) *SenderChainKeyStructure { + return &SenderChainKeyStructure{ + Iteration: key.iteration, + ChainKey: key.chainKey, + } +} + +// SenderChainKeyStructure is a serializeable structure of SenderChainKeys. +type SenderChainKeyStructure struct { + Iteration uint32 + ChainKey []byte +} + +type SenderChainKey struct { + iteration uint32 + chainKey []byte +} + +func (k *SenderChainKey) Iteration() uint32 { + return k.iteration +} + +func (k *SenderChainKey) SenderMessageKey() (*SenderMessageKey, error) { + return NewSenderMessageKey(k.iteration, k.getDerivative(messageKeySeed, k.chainKey)) +} + +func (k *SenderChainKey) Next() *SenderChainKey { + return NewSenderChainKey(k.iteration+1, k.getDerivative(chainKeySeed, k.chainKey)) +} + +func (k *SenderChainKey) Seed() []byte { + return k.chainKey +} + +func (k *SenderChainKey) getDerivative(seed []byte, key []byte) []byte { + mac := hmac.New(sha256.New, key[:]) + mac.Write(seed) + + return mac.Sum(nil) +} diff --git a/vendor/go.mau.fi/libsignal/groups/ratchet/SenderMessageKey.go b/vendor/go.mau.fi/libsignal/groups/ratchet/SenderMessageKey.go new file mode 100644 index 00000000..724059f2 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/ratchet/SenderMessageKey.go @@ -0,0 +1,89 @@ +package ratchet + +import ( + "go.mau.fi/libsignal/kdf" + "go.mau.fi/libsignal/util/bytehelper" +) + +// KdfInfo is optional bytes to include in deriving secrets with KDF. +const KdfInfo string = "WhisperGroup" + +// NewSenderMessageKey will return a new sender message key using the given +// iteration and seed. +func NewSenderMessageKey(iteration uint32, seed []byte) (*SenderMessageKey, error) { + derivative, err := kdf.DeriveSecrets(seed, nil, []byte(KdfInfo), 48) + if err != nil { + return nil, err + } + + // Split our derived secrets into 2 parts + parts := bytehelper.Split(derivative, 16, 32) + + // Build the message key. + senderKeyMessage := &SenderMessageKey{ + iteration: iteration, + seed: seed, + iv: parts[0], + cipherKey: parts[1], + } + + return senderKeyMessage, nil +} + +// NewSenderMessageKeyFromStruct will return a new message key object from the +// given serializeable structure. +func NewSenderMessageKeyFromStruct(structure *SenderMessageKeyStructure) *SenderMessageKey { + return &SenderMessageKey{ + iteration: structure.Iteration, + iv: structure.IV, + cipherKey: structure.CipherKey, + seed: structure.Seed, + } +} + +// NewStructFromSenderMessageKey returns a serializeable structure of message keys. +func NewStructFromSenderMessageKey(key *SenderMessageKey) *SenderMessageKeyStructure { + return &SenderMessageKeyStructure{ + CipherKey: key.cipherKey, + Iteration: key.iteration, + IV: key.iv, + Seed: key.seed, + } +} + +// SenderMessageKeyStructure is a serializeable structure of SenderMessageKeys. +type SenderMessageKeyStructure struct { + Iteration uint32 + IV []byte + CipherKey []byte + Seed []byte +} + +// SenderMessageKey is a structure for sender message keys used in group +// messaging. +type SenderMessageKey struct { + iteration uint32 + iv []byte + cipherKey []byte + seed []byte +} + +// Iteration will return the sender message key's iteration. +func (k *SenderMessageKey) Iteration() uint32 { + return k.iteration +} + +// Iv will return the sender message key's initialization vector. +func (k *SenderMessageKey) Iv() []byte { + return k.iv +} + +// CipherKey will return the key in bytes. +func (k *SenderMessageKey) CipherKey() []byte { + return k.cipherKey +} + +// Seed will return the sender message key's seed. +func (k *SenderMessageKey) Seed() []byte { + return k.seed +} diff --git a/vendor/go.mau.fi/libsignal/groups/state/record/Doc.go b/vendor/go.mau.fi/libsignal/groups/state/record/Doc.go new file mode 100644 index 00000000..5a7d7307 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/state/record/Doc.go @@ -0,0 +1,2 @@ +// Package record provides the state and record of a group session. +package record diff --git a/vendor/go.mau.fi/libsignal/groups/state/record/SenderKeyRecord.go b/vendor/go.mau.fi/libsignal/groups/state/record/SenderKeyRecord.go new file mode 100644 index 00000000..64d59068 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/state/record/SenderKeyRecord.go @@ -0,0 +1,149 @@ +package record + +import ( + "fmt" + + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/signalerror" +) + +const maxStates = 5 + +// SenderKeySerializer is an interface for serializing and deserializing +// SenderKey objects into bytes. An implementation of this interface should be +// used to encode/decode the object into JSON, Protobuffers, etc. +type SenderKeySerializer interface { + Serialize(preKey *SenderKeyStructure) []byte + Deserialize(serialized []byte) (*SenderKeyStructure, error) +} + +// NewSenderKeyFromBytes will return a prekey record from the given bytes using the given serializer. +func NewSenderKeyFromBytes(serialized []byte, serializer SenderKeySerializer, + stateSerializer SenderKeyStateSerializer) (*SenderKey, error) { + + // Use the given serializer to decode the senderkey record + senderKeyStructure, err := serializer.Deserialize(serialized) + if err != nil { + return nil, err + } + + return NewSenderKeyFromStruct(senderKeyStructure, serializer, stateSerializer) +} + +// NewSenderKeyFromStruct returns a SenderKey record using the given serializable structure. +func NewSenderKeyFromStruct(structure *SenderKeyStructure, serializer SenderKeySerializer, + stateSerializer SenderKeyStateSerializer) (*SenderKey, error) { + + // Build our sender key states from structure. + senderKeyStates := make([]*SenderKeyState, len(structure.SenderKeyStates)) + for i := range structure.SenderKeyStates { + var err error + senderKeyStates[i], err = NewSenderKeyStateFromStructure(structure.SenderKeyStates[i], stateSerializer) + if err != nil { + return nil, err + } + } + + // Build and return our session. + senderKey := &SenderKey{ + senderKeyStates: senderKeyStates, + serializer: serializer, + } + + return senderKey, nil + +} + +// NewSenderKey record returns a new sender key record that can +// be stored in a SenderKeyStore. +func NewSenderKey(serializer SenderKeySerializer, + stateSerializer SenderKeyStateSerializer) *SenderKey { + + return &SenderKey{ + senderKeyStates: []*SenderKeyState{}, + serializer: serializer, + stateSerializer: stateSerializer, + } +} + +// SenderKeyStructure is a structure for serializing SenderKey records. +type SenderKeyStructure struct { + SenderKeyStates []*SenderKeyStateStructure +} + +// SenderKey record is a structure for storing pre keys inside +// a SenderKeyStore. +type SenderKey struct { + senderKeyStates []*SenderKeyState + serializer SenderKeySerializer + stateSerializer SenderKeyStateSerializer +} + +// SenderKeyState will return the first sender key state in the record's +// list of sender key states. +func (k *SenderKey) SenderKeyState() (*SenderKeyState, error) { + if len(k.senderKeyStates) > 0 { + return k.senderKeyStates[0], nil + } + return nil, signalerror.ErrNoSenderKeyStatesInRecord +} + +// GetSenderKeyStateByID will return the sender key state with the given +// key id. +func (k *SenderKey) GetSenderKeyStateByID(keyID uint32) (*SenderKeyState, error) { + for i := 0; i < len(k.senderKeyStates); i++ { + if k.senderKeyStates[i].KeyID() == keyID { + return k.senderKeyStates[i], nil + } + } + + return nil, fmt.Errorf("%w %d", signalerror.ErrNoSenderKeyStateForID, keyID) +} + +// IsEmpty will return false if there is more than one state in this +// senderkey record. +func (k *SenderKey) IsEmpty() bool { + return len(k.senderKeyStates) == 0 +} + +// AddSenderKeyState will add a new state to this senderkey record with the given +// id, iteration, chainkey, and signature key. +func (k *SenderKey) AddSenderKeyState(id uint32, iteration uint32, + chainKey []byte, signatureKey ecc.ECPublicKeyable) { + + newState := NewSenderKeyStateFromPublicKey(id, iteration, chainKey, signatureKey, k.stateSerializer) + k.senderKeyStates = append([]*SenderKeyState{newState}, k.senderKeyStates...) + + if len(k.senderKeyStates) > maxStates { + k.senderKeyStates = k.senderKeyStates[:len(k.senderKeyStates)-1] + } +} + +// SetSenderKeyState will replace the current senderkey states with the given +// senderkey state. +func (k *SenderKey) SetSenderKeyState(id uint32, iteration uint32, + chainKey []byte, signatureKey *ecc.ECKeyPair) { + + newState := NewSenderKeyState(id, iteration, chainKey, signatureKey, k.stateSerializer) + k.senderKeyStates = make([]*SenderKeyState, 0, maxStates/2) + k.senderKeyStates = append(k.senderKeyStates, newState) +} + +// Serialize will return the record as serialized bytes so it can be +// persistently stored. +func (k *SenderKey) Serialize() []byte { + return k.serializer.Serialize(k.Structure()) +} + +// Structure will return a simple serializable record structure. +// This is used for serialization to persistently +// store a session record. +func (k *SenderKey) Structure() *SenderKeyStructure { + senderKeyStates := make([]*SenderKeyStateStructure, len(k.senderKeyStates)) + for i := range k.senderKeyStates { + senderKeyStates[i] = k.senderKeyStates[i].structure() + } + return &SenderKeyStructure{ + SenderKeyStates: senderKeyStates, + } +} diff --git a/vendor/go.mau.fi/libsignal/groups/state/record/SenderKeyState.go b/vendor/go.mau.fi/libsignal/groups/state/record/SenderKeyState.go new file mode 100644 index 00000000..e3187c30 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/state/record/SenderKeyState.go @@ -0,0 +1,186 @@ +package record + +import ( + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/groups/ratchet" + "go.mau.fi/libsignal/util/bytehelper" +) + +const maxMessageKeys = 2000 + +// SenderKeyStateSerializer is an interface for serializing and deserializing +// a Signal State into bytes. An implementation of this interface should be +// used to encode/decode the object into JSON, Protobuffers, etc. +type SenderKeyStateSerializer interface { + Serialize(state *SenderKeyStateStructure) []byte + Deserialize(serialized []byte) (*SenderKeyStateStructure, error) +} + +// NewSenderKeyStateFromBytes will return a Signal State from the given +// bytes using the given serializer. +func NewSenderKeyStateFromBytes(serialized []byte, serializer SenderKeyStateSerializer) (*SenderKeyState, error) { + // Use the given serializer to decode the signal message. + stateStructure, err := serializer.Deserialize(serialized) + if err != nil { + return nil, err + } + + return NewSenderKeyStateFromStructure(stateStructure, serializer) +} + +// NewSenderKeyState returns a new SenderKeyState. +func NewSenderKeyState(keyID uint32, iteration uint32, chainKey []byte, + signatureKey *ecc.ECKeyPair, serializer SenderKeyStateSerializer) *SenderKeyState { + + return &SenderKeyState{ + keys: make([]*ratchet.SenderMessageKey, 0, maxMessageKeys/2), + keyID: keyID, + senderChainKey: ratchet.NewSenderChainKey(iteration, chainKey), + signingKeyPair: signatureKey, + serializer: serializer, + } +} + +// NewSenderKeyStateFromPublicKey returns a new SenderKeyState with the given publicKey. +func NewSenderKeyStateFromPublicKey(keyID uint32, iteration uint32, chainKey []byte, + signatureKey ecc.ECPublicKeyable, serializer SenderKeyStateSerializer) *SenderKeyState { + + keyPair := ecc.NewECKeyPair(signatureKey, nil) + + return &SenderKeyState{ + keys: make([]*ratchet.SenderMessageKey, 0, maxMessageKeys/2), + keyID: keyID, + senderChainKey: ratchet.NewSenderChainKey(iteration, chainKey), + signingKeyPair: keyPair, + serializer: serializer, + } +} + +// NewSenderKeyStateFromStructure will return a new session state with the +// given state structure. This structure is given back from an +// implementation of the sender key state serializer. +func NewSenderKeyStateFromStructure(structure *SenderKeyStateStructure, + serializer SenderKeyStateSerializer) (*SenderKeyState, error) { + + // Convert our ecc keys from bytes into object form. + signingKeyPublic, err := ecc.DecodePoint(structure.SigningKeyPublic, 0) + if err != nil { + return nil, err + } + signingKeyPrivate := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(structure.SigningKeyPrivate)) + + // Build our sender message keys from structure + senderMessageKeys := make([]*ratchet.SenderMessageKey, len(structure.Keys)) + for i := range structure.Keys { + senderMessageKeys[i] = ratchet.NewSenderMessageKeyFromStruct(structure.Keys[i]) + } + + // Build our state object. + state := &SenderKeyState{ + keys: senderMessageKeys, + keyID: structure.KeyID, + senderChainKey: ratchet.NewSenderChainKeyFromStruct(structure.SenderChainKey), + signingKeyPair: ecc.NewECKeyPair(signingKeyPublic, signingKeyPrivate), + serializer: serializer, + } + + return state, nil +} + +// SenderKeyStateStructure is a serializeable structure of SenderKeyState. +type SenderKeyStateStructure struct { + Keys []*ratchet.SenderMessageKeyStructure + KeyID uint32 + SenderChainKey *ratchet.SenderChainKeyStructure + SigningKeyPrivate []byte + SigningKeyPublic []byte +} + +// SenderKeyState is a structure for maintaining a senderkey session state. +type SenderKeyState struct { + keys []*ratchet.SenderMessageKey + keyID uint32 + senderChainKey *ratchet.SenderChainKey + signingKeyPair *ecc.ECKeyPair + serializer SenderKeyStateSerializer +} + +// SigningKey returns the signing key pair of the sender key state. +func (k *SenderKeyState) SigningKey() *ecc.ECKeyPair { + return k.signingKeyPair +} + +// SenderChainKey returns the sender chain key of the state. +func (k *SenderKeyState) SenderChainKey() *ratchet.SenderChainKey { + return k.senderChainKey +} + +// KeyID returns the state's key id. +func (k *SenderKeyState) KeyID() uint32 { + return k.keyID +} + +// HasSenderMessageKey will return true if the state has a key with the +// given iteration. +func (k *SenderKeyState) HasSenderMessageKey(iteration uint32) bool { + for i := 0; i < len(k.keys); i++ { + if k.keys[i].Iteration() == iteration { + return true + } + } + return false +} + +// AddSenderMessageKey will add the given sender message key to the state. +func (k *SenderKeyState) AddSenderMessageKey(senderMsgKey *ratchet.SenderMessageKey) { + k.keys = append(k.keys, senderMsgKey) + + if len(k.keys) > maxMessageKeys { + k.keys = k.keys[1:] + } +} + +// SetSenderChainKey will set the state's sender chain key with the given key. +func (k *SenderKeyState) SetSenderChainKey(senderChainKey *ratchet.SenderChainKey) { + k.senderChainKey = senderChainKey +} + +// RemoveSenderMessageKey will remove the key in this state with the given iteration number. +func (k *SenderKeyState) RemoveSenderMessageKey(iteration uint32) *ratchet.SenderMessageKey { + for i := 0; i < len(k.keys); i++ { + if k.keys[i].Iteration() == iteration { + removed := k.keys[i] + k.keys = append(k.keys[0:i], k.keys[i+1:]...) + return removed + } + } + + return nil +} + +// Serialize will return the state as bytes using the given serializer. +func (k *SenderKeyState) Serialize() []byte { + return k.serializer.Serialize(k.structure()) +} + +// structure will return a serializable structure of the +// the given state so it can be persistently stored. +func (k *SenderKeyState) structure() *SenderKeyStateStructure { + // Convert our sender message keys into a serializeable structure + keys := make([]*ratchet.SenderMessageKeyStructure, len(k.keys)) + for i := range k.keys { + keys[i] = ratchet.NewStructFromSenderMessageKey(k.keys[i]) + } + + // Build and return our state structure. + s := &SenderKeyStateStructure{ + Keys: keys, + KeyID: k.keyID, + SenderChainKey: ratchet.NewStructFromSenderChainKey(k.senderChainKey), + SigningKeyPublic: k.signingKeyPair.PublicKey().Serialize(), + } + if k.signingKeyPair.PrivateKey() != nil { + s.SigningKeyPrivate = bytehelper.ArrayToSlice(k.signingKeyPair.PrivateKey().Serialize()) + } + return s +} diff --git a/vendor/go.mau.fi/libsignal/groups/state/store/Doc.go b/vendor/go.mau.fi/libsignal/groups/state/store/Doc.go new file mode 100644 index 00000000..8a23b446 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/state/store/Doc.go @@ -0,0 +1,3 @@ +// Package store provides the storage interfaces for storing group sender +// key records. +package store diff --git a/vendor/go.mau.fi/libsignal/groups/state/store/SenderKeyStore.go b/vendor/go.mau.fi/libsignal/groups/state/store/SenderKeyStore.go new file mode 100644 index 00000000..a068df7c --- /dev/null +++ b/vendor/go.mau.fi/libsignal/groups/state/store/SenderKeyStore.go @@ -0,0 +1,11 @@ +package store + +import ( + "go.mau.fi/libsignal/groups/state/record" + "go.mau.fi/libsignal/protocol" +) + +type SenderKey interface { + StoreSenderKey(senderKeyName *protocol.SenderKeyName, keyRecord *record.SenderKey) + LoadSenderKey(senderKeyName *protocol.SenderKeyName) *record.SenderKey +} |