4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-06-27 23:49:25 +00:00

Add dependencies/vendor (whatsapp)

This commit is contained in:
Wim
2022-01-31 00:27:37 +01:00
parent e7b193788a
commit e3cafeaf92
1074 changed files with 3091569 additions and 26075 deletions

View File

@ -0,0 +1,157 @@
package record
import (
"go.mau.fi/libsignal/ecc"
"go.mau.fi/libsignal/kdf"
"go.mau.fi/libsignal/keys/chain"
"go.mau.fi/libsignal/keys/message"
"go.mau.fi/libsignal/util/bytehelper"
)
// NewReceiverChainPair will return a new ReceiverChainPair object.
func NewReceiverChainPair(receiverChain *Chain, index int) *ReceiverChainPair {
return &ReceiverChainPair{
ReceiverChain: receiverChain,
Index: index,
}
}
// ReceiverChainPair is a structure for a receiver chain key and index number.
type ReceiverChainPair struct {
ReceiverChain *Chain
Index int
}
// NewChain returns a new Chain structure for SessionState.
func NewChain(senderRatchetKeyPair *ecc.ECKeyPair, chainKey *chain.Key,
messageKeys []*message.Keys) *Chain {
return &Chain{
senderRatchetKeyPair: senderRatchetKeyPair,
chainKey: chainKey,
messageKeys: messageKeys,
}
}
// NewChainFromStructure will return a new Chain with the given
// chain structure.
func NewChainFromStructure(structure *ChainStructure) (*Chain, error) {
// Alias to SliceToArray
getArray := bytehelper.SliceToArray
// Build the sender ratchet key from bytes.
senderRatchetKeyPublic, err := ecc.DecodePoint(structure.SenderRatchetKeyPublic, 0)
if err != nil {
return nil, err
}
var senderRatchetKeyPrivate ecc.ECPrivateKeyable
if len(structure.SenderRatchetKeyPrivate) == 32 {
senderRatchetKeyPrivate = ecc.NewDjbECPrivateKey(getArray(structure.SenderRatchetKeyPrivate))
}
senderRatchetKeyPair := ecc.NewECKeyPair(senderRatchetKeyPublic, senderRatchetKeyPrivate)
// Build our message keys from the message key structures.
messageKeys := make([]*message.Keys, len(structure.MessageKeys))
for i := range structure.MessageKeys {
messageKeys[i] = message.NewKeysFromStruct(structure.MessageKeys[i])
}
// Build our new chain state.
chainState := NewChain(
senderRatchetKeyPair,
chain.NewKeyFromStruct(structure.ChainKey, kdf.DeriveSecrets),
messageKeys,
)
return chainState, nil
}
// ChainStructure is a serializeable structure for chain states.
type ChainStructure struct {
SenderRatchetKeyPublic []byte
SenderRatchetKeyPrivate []byte
ChainKey *chain.KeyStructure
MessageKeys []*message.KeysStructure
}
// Chain is a structure used inside the SessionState that keeps
// track of an ongoing ratcheting chain for a session.
type Chain struct {
senderRatchetKeyPair *ecc.ECKeyPair
chainKey *chain.Key
messageKeys []*message.Keys
}
// SenderRatchetKey returns the sender's EC keypair.
func (c *Chain) SenderRatchetKey() *ecc.ECKeyPair {
return c.senderRatchetKeyPair
}
// SetSenderRatchetKey will set the chain state with the given EC
// key pair.
func (c *Chain) SetSenderRatchetKey(key *ecc.ECKeyPair) {
c.senderRatchetKeyPair = key
}
// ChainKey will return the chain key in the chain state.
func (c *Chain) ChainKey() *chain.Key {
return c.chainKey
}
// SetChainKey will set the chain state's chain key.
func (c *Chain) SetChainKey(key *chain.Key) {
c.chainKey = key
}
// MessageKeys will return the message keys associated with the
// chain state.
func (c *Chain) MessageKeys() []*message.Keys {
return c.messageKeys
}
// SetMessageKeys will set the chain state with the given message
// keys.
func (c *Chain) SetMessageKeys(keys []*message.Keys) {
c.messageKeys = keys
}
// AddMessageKeys will append the chain state with the given
// message keys.
func (c *Chain) AddMessageKeys(keys *message.Keys) {
c.messageKeys = append(c.messageKeys, keys)
}
// PopFirstMessageKeys will remove the first message key from
// the chain's list of message keys.
func (c *Chain) PopFirstMessageKeys() *message.Keys {
removed := c.messageKeys[0]
c.messageKeys = c.messageKeys[1:]
return removed
}
// structure returns a serializeable structure of the chain state.
func (c *Chain) structure() *ChainStructure {
// Alias to ArrayToSlice
getSlice := bytehelper.ArrayToSlice
// Convert our message keys into a serializeable structure.
messageKeys := make([]*message.KeysStructure, len(c.messageKeys))
for i := range c.messageKeys {
messageKeys[i] = message.NewStructFromKeys(c.messageKeys[i])
}
// Convert our sender ratchet key private
var senderRatchetKeyPrivate []byte
if c.senderRatchetKeyPair.PrivateKey() != nil {
senderRatchetKeyPrivate = getSlice(c.senderRatchetKeyPair.PrivateKey().Serialize())
}
// Build the chain structure.
return &ChainStructure{
SenderRatchetKeyPublic: c.senderRatchetKeyPair.PublicKey().Serialize(),
SenderRatchetKeyPrivate: senderRatchetKeyPrivate,
ChainKey: chain.NewStructFromKey(c.chainKey),
MessageKeys: messageKeys,
}
}

View File

@ -0,0 +1,3 @@
// Package record provides the state and record of an ongoing double
// ratchet session.
package record

View File

@ -0,0 +1,91 @@
package record
import (
"go.mau.fi/libsignal/ecc"
"go.mau.fi/libsignal/keys/identity"
"go.mau.fi/libsignal/util/bytehelper"
)
// NewPendingKeyExchange will return a new PendingKeyExchange object.
func NewPendingKeyExchange(sequence uint32, localBaseKeyPair, localRatchetKeyPair *ecc.ECKeyPair,
localIdentityKeyPair *identity.KeyPair) *PendingKeyExchange {
return &PendingKeyExchange{
sequence: sequence,
localBaseKeyPair: localBaseKeyPair,
localRatchetKeyPair: localRatchetKeyPair,
localIdentityKeyPair: localIdentityKeyPair,
}
}
// NewPendingKeyExchangeFromStruct will return a PendingKeyExchange object from
// the given structure. This is used to get a deserialized pending prekey exchange
// fetched from persistent storage.
func NewPendingKeyExchangeFromStruct(structure *PendingKeyExchangeStructure) *PendingKeyExchange {
// Return nil if no structure was provided.
if structure == nil {
return nil
}
// Alias the SliceToArray method.
getArray := bytehelper.SliceToArray
// Convert the bytes in the given structure to ECC objects.
localBaseKeyPair := ecc.NewECKeyPair(
ecc.NewDjbECPublicKey(getArray(structure.LocalBaseKeyPublic)),
ecc.NewDjbECPrivateKey(getArray(structure.LocalBaseKeyPrivate)),
)
localRatchetKeyPair := ecc.NewECKeyPair(
ecc.NewDjbECPublicKey(getArray(structure.LocalRatchetKeyPublic)),
ecc.NewDjbECPrivateKey(getArray(structure.LocalRatchetKeyPrivate)),
)
localIdentityKeyPair := identity.NewKeyPair(
identity.NewKey(ecc.NewDjbECPublicKey(getArray(structure.LocalIdentityKeyPublic))),
ecc.NewDjbECPrivateKey(getArray(structure.LocalIdentityKeyPrivate)),
)
// Return the PendingKeyExchange with the deserialized keys.
return &PendingKeyExchange{
sequence: structure.Sequence,
localBaseKeyPair: localBaseKeyPair,
localRatchetKeyPair: localRatchetKeyPair,
localIdentityKeyPair: localIdentityKeyPair,
}
}
// PendingKeyExchangeStructure is a serializable structure for pending
// key exchanges. This structure is used for persistent storage of the
// key exchange state.
type PendingKeyExchangeStructure struct {
Sequence uint32
LocalBaseKeyPublic []byte
LocalBaseKeyPrivate []byte
LocalRatchetKeyPublic []byte
LocalRatchetKeyPrivate []byte
LocalIdentityKeyPublic []byte
LocalIdentityKeyPrivate []byte
}
// PendingKeyExchange is a structure for storing a pending
// key exchange for a session state.
type PendingKeyExchange struct {
sequence uint32
localBaseKeyPair *ecc.ECKeyPair
localRatchetKeyPair *ecc.ECKeyPair
localIdentityKeyPair *identity.KeyPair
}
// structre will return a serializable structure of a pending key exchange
// so it can be persistently stored.
func (p *PendingKeyExchange) structure() *PendingKeyExchangeStructure {
getSlice := bytehelper.ArrayToSlice
return &PendingKeyExchangeStructure{
Sequence: p.sequence,
LocalBaseKeyPublic: getSlice(p.localBaseKeyPair.PublicKey().PublicKey()),
LocalBaseKeyPrivate: getSlice(p.localBaseKeyPair.PrivateKey().Serialize()),
LocalRatchetKeyPublic: getSlice(p.localRatchetKeyPair.PublicKey().PublicKey()),
LocalRatchetKeyPrivate: getSlice(p.localRatchetKeyPair.PrivateKey().Serialize()),
LocalIdentityKeyPublic: getSlice(p.localIdentityKeyPair.PublicKey().PublicKey().PublicKey()),
LocalIdentityKeyPrivate: getSlice(p.localIdentityKeyPair.PrivateKey().Serialize()),
}
}

View File

@ -0,0 +1,62 @@
package record
import (
"go.mau.fi/libsignal/ecc"
"go.mau.fi/libsignal/util/optional"
)
// NewPendingPreKey will return a new pending pre key object.
func NewPendingPreKey(preKeyID *optional.Uint32, signedPreKeyID uint32,
baseKey ecc.ECPublicKeyable) *PendingPreKey {
return &PendingPreKey{
preKeyID: preKeyID,
signedPreKeyID: signedPreKeyID,
baseKey: baseKey,
}
}
// NewPendingPreKeyFromStruct will return a new pending prekey object from the
// given structure.
func NewPendingPreKeyFromStruct(preKey *PendingPreKeyStructure) (*PendingPreKey, error) {
baseKey, err := ecc.DecodePoint(preKey.BaseKey, 0)
if err != nil {
return nil, err
}
pendingPreKey := NewPendingPreKey(
preKey.PreKeyID,
preKey.SignedPreKeyID,
baseKey,
)
return pendingPreKey, nil
}
// PendingPreKeyStructure is a serializeable structure for pending
// prekeys.
type PendingPreKeyStructure struct {
PreKeyID *optional.Uint32
SignedPreKeyID uint32
BaseKey []byte
}
// PendingPreKey is a structure for pending pre keys
// for a session state.
type PendingPreKey struct {
preKeyID *optional.Uint32
signedPreKeyID uint32
baseKey ecc.ECPublicKeyable
}
// structure will return a serializeable structure of the pending prekey.
func (p *PendingPreKey) structure() *PendingPreKeyStructure {
if p != nil {
return &PendingPreKeyStructure{
PreKeyID: p.preKeyID,
SignedPreKeyID: p.signedPreKeyID,
BaseKey: p.baseKey.Serialize(),
}
}
return nil
}

View File

@ -0,0 +1,90 @@
package record
import (
"go.mau.fi/libsignal/ecc"
"go.mau.fi/libsignal/util/bytehelper"
"go.mau.fi/libsignal/util/optional"
)
// PreKeySerializer is an interface for serializing and deserializing
// PreKey objects into bytes. An implementation of this interface should be
// used to encode/decode the object into JSON, Protobuffers, etc.
type PreKeySerializer interface {
Serialize(preKey *PreKeyStructure) []byte
Deserialize(serialized []byte) (*PreKeyStructure, error)
}
// NewPreKeyFromBytes will return a prekey record from the given bytes using the given serializer.
func NewPreKeyFromBytes(serialized []byte, serializer PreKeySerializer) (*PreKey, error) {
// Use the given serializer to decode the signal message.
preKeyStructure, err := serializer.Deserialize(serialized)
if err != nil {
return nil, err
}
return NewPreKeyFromStruct(preKeyStructure, serializer)
}
// NewPreKeyFromStruct returns a PreKey record using the given serializable structure.
func NewPreKeyFromStruct(structure *PreKeyStructure, serializer PreKeySerializer) (*PreKey, error) {
// Create the prekey record from the structure.
preKey := &PreKey{
structure: *structure,
serializer: serializer,
}
// Generate the ECC key from bytes.
publicKey := ecc.NewDjbECPublicKey(bytehelper.SliceToArray(structure.PublicKey))
privateKey := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(structure.PrivateKey))
keyPair := ecc.NewECKeyPair(publicKey, privateKey)
preKey.keyPair = keyPair
return preKey, nil
}
// NewPreKey record returns a new pre key record that can
// be stored in a PreKeyStore.
func NewPreKey(id uint32, keyPair *ecc.ECKeyPair, serializer PreKeySerializer) *PreKey {
return &PreKey{
structure: PreKeyStructure{
ID: id,
PublicKey: keyPair.PublicKey().Serialize(),
PrivateKey: bytehelper.ArrayToSlice(keyPair.PrivateKey().Serialize()),
},
keyPair: keyPair,
serializer: serializer,
}
}
// PreKeyStructure is a structure for serializing PreKey records.
type PreKeyStructure struct {
ID uint32
PublicKey []byte
PrivateKey []byte
}
// PreKey record is a structure for storing pre keys inside
// a PreKeyStore.
type PreKey struct {
structure PreKeyStructure
keyPair *ecc.ECKeyPair
serializer PreKeySerializer
}
// ID returns the pre key record's id.
func (p *PreKey) ID() *optional.Uint32 {
// TODO: manually set this to empty if empty
return optional.NewOptionalUint32(p.structure.ID)
}
// KeyPair returns the pre key record's key pair.
func (p *PreKey) KeyPair() *ecc.ECKeyPair {
return p.keyPair
}
// Serialize uses the PreKey serializer to return the PreKey
// as serialized bytes.
func (p *PreKey) Serialize() []byte {
structure := p.structure
return p.serializer.Serialize(&structure)
}

View File

@ -0,0 +1,197 @@
package record
import (
"bytes"
)
// archivedStatesMaxLength describes how many previous session
// states we should keep track of.
const archivedStatesMaxLength int = 40
// SessionSerializer is an interface for serializing and deserializing
// a Signal Session into bytes. An implementation of this interface should be
// used to encode/decode the object into JSON, Protobuffers, etc.
type SessionSerializer interface {
Serialize(state *SessionStructure) []byte
Deserialize(serialized []byte) (*SessionStructure, error)
}
// NewSessionFromBytes will return a Signal Session from the given
// bytes using the given serializer.
func NewSessionFromBytes(serialized []byte, serializer SessionSerializer, stateSerializer StateSerializer) (*Session, error) {
// Use the given serializer to decode the session.
sessionStructure, err := serializer.Deserialize(serialized)
if err != nil {
return nil, err
}
return NewSessionFromStructure(sessionStructure, serializer, stateSerializer)
}
// NewSession creates a new session record and uses the given session and state
// serializers to convert the object into storeable bytes.
func NewSession(serializer SessionSerializer, stateSerializer StateSerializer) *Session {
record := Session{
sessionState: NewState(stateSerializer),
previousStates: []*State{},
fresh: true,
serializer: serializer,
}
return &record
}
// NewSessionFromStructure will return a new Signal Session from the given
// session structure and serializer.
func NewSessionFromStructure(structure *SessionStructure, serializer SessionSerializer,
stateSerializer StateSerializer) (*Session, error) {
// Build our previous states from structure.
previousStates := make([]*State, len(structure.PreviousStates))
for i := range structure.PreviousStates {
var err error
previousStates[i], err = NewStateFromStructure(structure.PreviousStates[i], stateSerializer)
if err != nil {
return nil, err
}
}
// Build our current state from structure.
sessionState, err := NewStateFromStructure(structure.SessionState, stateSerializer)
if err != nil {
return nil, err
}
// Build and return our session.
session := &Session{
previousStates: previousStates,
sessionState: sessionState,
serializer: serializer,
fresh: false,
}
return session, nil
}
// NewSessionFromState creates a new session record from the given
// session state.
func NewSessionFromState(sessionState *State, serializer SessionSerializer) *Session {
record := Session{
sessionState: sessionState,
previousStates: []*State{},
fresh: false,
serializer: serializer,
}
return &record
}
// SessionStructure is a public, serializeable structure for Signal
// Sessions. The states defined in the session are immuteable, as
// they should not be changed by anyone but the serializer.
type SessionStructure struct {
SessionState *StateStructure
PreviousStates []*StateStructure
}
// Session encapsulates the state of an ongoing session.
type Session struct {
serializer SessionSerializer
sessionState *State
previousStates []*State
fresh bool
}
// SetState sets the session record's current state to the given
// one.
func (r *Session) SetState(sessionState *State) {
r.sessionState = sessionState
}
// IsFresh is used to determine if this is a brand new session
// or if a session record has already existed.
func (r *Session) IsFresh() bool {
return r.fresh
}
// SessionState returns the session state object of the current
// session record.
func (r *Session) SessionState() *State {
return r.sessionState
}
// PreviousSessionStates returns a list of all currently maintained
// "previous" session states.
func (r *Session) PreviousSessionStates() []*State {
return r.previousStates
}
// HasSessionState will check this record to see if the sender's
// base key exists in the current and previous states.
func (r *Session) HasSessionState(version int, senderBaseKey []byte) bool {
// Ensure the session state version is identical to this one.
if r.sessionState.Version() == version && (bytes.Compare(senderBaseKey, r.sessionState.SenderBaseKey()) == 0) {
return true
}
// Loop through all of our previous states and see if this
// exists in our state.
for i := range r.previousStates {
if r.previousStates[i].Version() == version && bytes.Compare(senderBaseKey, r.previousStates[i].SenderBaseKey()) == 0 {
return true
}
}
return false
}
// ArchiveCurrentState moves the current session state into the list
// of "previous" session states, and replaces the current session state
// with a fresh reset instance.
func (r *Session) ArchiveCurrentState() {
r.PromoteState(NewState(r.sessionState.serializer))
}
// PromoteState takes the given session state and replaces it with the
// current state, pushing the previous current state to "previousStates".
func (r *Session) PromoteState(promotedState *State) {
r.previousStates = r.prependStates(r.previousStates, r.sessionState)
r.sessionState = promotedState
// Remove the last state if it has reached our maximum length
if len(r.previousStates) > archivedStatesMaxLength {
r.previousStates = r.removeLastState(r.previousStates)
}
}
// Serialize will return the session as serialized bytes so it can be
// persistently stored.
func (r *Session) Serialize() []byte {
return r.serializer.Serialize(r.Structure())
}
// prependStates takes an array/slice of states and prepends it with
// the given session state.
func (r *Session) prependStates(states []*State, sessionState *State) []*State {
return append([]*State{sessionState}, states...)
}
// removeLastState takes an array/slice of states and removes the
// last element from it.
func (r *Session) removeLastState(states []*State) []*State {
return states[:len(states)-1]
}
// Structure will return a simple serializable session structure
// from the given structure. This is used for serialization to persistently
// store a session record.
func (r *Session) Structure() *SessionStructure {
previousStates := make([]*StateStructure, len(r.previousStates))
for i := range r.previousStates {
previousStates[i] = r.previousStates[i].structure()
}
return &SessionStructure{
SessionState: r.sessionState.structure(),
PreviousStates: previousStates,
}
}

View File

@ -0,0 +1,531 @@
package record
import (
"go.mau.fi/libsignal/ecc"
"go.mau.fi/libsignal/kdf"
"go.mau.fi/libsignal/keys/chain"
"go.mau.fi/libsignal/keys/identity"
"go.mau.fi/libsignal/keys/message"
"go.mau.fi/libsignal/keys/root"
"go.mau.fi/libsignal/keys/session"
"go.mau.fi/libsignal/logger"
"go.mau.fi/libsignal/util/errorhelper"
"go.mau.fi/libsignal/util/optional"
)
const maxMessageKeys int = 2000
const maxReceiverChains int = 5
// StateSerializer 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 StateSerializer interface {
Serialize(state *StateStructure) []byte
Deserialize(serialized []byte) (*StateStructure, error)
}
// NewStateFromBytes will return a Signal State from the given
// bytes using the given serializer.
func NewStateFromBytes(serialized []byte, serializer StateSerializer) (*State, error) {
// Use the given serializer to decode the signal message.
stateStructure, err := serializer.Deserialize(serialized)
if err != nil {
return nil, err
}
return NewStateFromStructure(stateStructure, serializer)
}
// NewState returns a new session state.
func NewState(serializer StateSerializer) *State {
return &State{serializer: serializer}
}
// NewStateFromStructure will return a new session state with the
// given state structure.
func NewStateFromStructure(structure *StateStructure, serializer StateSerializer) (*State, error) {
// Keep a list of errors, so they can be handled once.
errors := errorhelper.NewMultiError()
// Convert our ecc keys from bytes into object form.
localIdentityPublic, err := ecc.DecodePoint(structure.LocalIdentityPublic, 0)
errors.Add(err)
remoteIdentityPublic, err := ecc.DecodePoint(structure.RemoteIdentityPublic, 0)
errors.Add(err)
senderBaseKey, err := ecc.DecodePoint(structure.SenderBaseKey, 0)
errors.Add(err)
var pendingPreKey *PendingPreKey
if structure.PendingPreKey != nil {
pendingPreKey, err = NewPendingPreKeyFromStruct(structure.PendingPreKey)
errors.Add(err)
}
senderChain, err := NewChainFromStructure(structure.SenderChain)
errors.Add(err)
// Build our receiver chains from structure.
receiverChains := make([]*Chain, len(structure.ReceiverChains))
for i := range structure.ReceiverChains {
receiverChains[i], err = NewChainFromStructure(structure.ReceiverChains[i])
errors.Add(err)
}
// Handle any errors. The first error will always be returned if there are multiple.
if errors.HasErrors() {
return nil, errors
}
// Build our state object.
state := &State{
localIdentityPublic: identity.NewKey(localIdentityPublic),
localRegistrationID: structure.LocalRegistrationID,
needsRefresh: structure.NeedsRefresh,
pendingKeyExchange: NewPendingKeyExchangeFromStruct(structure.PendingKeyExchange),
pendingPreKey: pendingPreKey,
previousCounter: structure.PreviousCounter,
receiverChains: receiverChains,
remoteIdentityPublic: identity.NewKey(remoteIdentityPublic),
remoteRegistrationID: structure.RemoteRegistrationID,
rootKey: root.NewKey(kdf.DeriveSecrets, structure.RootKey),
senderBaseKey: senderBaseKey,
senderChain: senderChain,
serializer: serializer,
sessionVersion: structure.SessionVersion,
}
return state, nil
}
// StateStructure is the structure of a session state. Fields are public
// to be used for serialization and deserialization.
type StateStructure struct {
LocalIdentityPublic []byte
LocalRegistrationID uint32
NeedsRefresh bool
PendingKeyExchange *PendingKeyExchangeStructure
PendingPreKey *PendingPreKeyStructure
PreviousCounter uint32
ReceiverChains []*ChainStructure
RemoteIdentityPublic []byte
RemoteRegistrationID uint32
RootKey []byte
SenderBaseKey []byte
SenderChain *ChainStructure
SessionVersion int
}
// State is a session state that contains the structure for
// all sessions. Session states are contained inside session records.
// The session state is implemented as a struct rather than protobuffers
// to allow other serialization methods.
type State struct {
localIdentityPublic *identity.Key
localRegistrationID uint32
needsRefresh bool
pendingKeyExchange *PendingKeyExchange
pendingPreKey *PendingPreKey
previousCounter uint32
receiverChains []*Chain
remoteIdentityPublic *identity.Key
remoteRegistrationID uint32
rootKey *root.Key
senderBaseKey ecc.ECPublicKeyable
senderChain *Chain
serializer StateSerializer
sessionVersion int
}
// SenderBaseKey returns the sender's base key in bytes.
func (s *State) SenderBaseKey() []byte {
if s.senderBaseKey == nil {
return nil
}
return s.senderBaseKey.Serialize()
}
// SetSenderBaseKey sets the sender's base key with the given bytes.
func (s *State) SetSenderBaseKey(senderBaseKey []byte) {
s.senderBaseKey, _ = ecc.DecodePoint(senderBaseKey, 0)
}
// Version returns the session's version.
func (s *State) Version() int {
return s.sessionVersion
}
// SetVersion sets the session state's version number.
func (s *State) SetVersion(version int) {
s.sessionVersion = version
}
// RemoteIdentityKey returns the identity key of the remote user.
func (s *State) RemoteIdentityKey() *identity.Key {
return s.remoteIdentityPublic
}
// SetRemoteIdentityKey sets this session's identity key for the remote
// user.
func (s *State) SetRemoteIdentityKey(identityKey *identity.Key) {
s.remoteIdentityPublic = identityKey
}
// LocalIdentityKey returns the session's identity key for the local
// user.
func (s *State) LocalIdentityKey() *identity.Key {
return s.localIdentityPublic
}
// SetLocalIdentityKey sets the session's identity key for the local
// user.
func (s *State) SetLocalIdentityKey(identityKey *identity.Key) {
s.localIdentityPublic = identityKey
}
// PreviousCounter returns the counter of the previous message.
func (s *State) PreviousCounter() uint32 {
return s.previousCounter
}
// SetPreviousCounter sets the counter for the previous message.
func (s *State) SetPreviousCounter(previousCounter uint32) {
s.previousCounter = previousCounter
}
// RootKey returns the root key for the session.
func (s *State) RootKey() session.RootKeyable {
return s.rootKey
}
// SetRootKey sets the root key for the session.
func (s *State) SetRootKey(rootKey session.RootKeyable) {
s.rootKey = rootKey.(*root.Key)
}
// SenderRatchetKey returns the public ratchet key of the sender.
func (s *State) SenderRatchetKey() ecc.ECPublicKeyable {
return s.senderChain.senderRatchetKeyPair.PublicKey()
}
// SenderRatchetKeyPair returns the public/private ratchet key pair
// of the sender.
func (s *State) SenderRatchetKeyPair() *ecc.ECKeyPair {
return s.senderChain.senderRatchetKeyPair
}
// HasReceiverChain will check to see if the session state has
// the given ephemeral key.
func (s *State) HasReceiverChain(senderEphemeral ecc.ECPublicKeyable) bool {
return s.receiverChain(senderEphemeral) != nil
}
// HasSenderChain will check to see if the session state has a
// sender chain.
func (s *State) HasSenderChain() bool {
return s.senderChain != nil
}
// receiverChain will loop through the session state's receiver chains
// and compare the given ephemeral key. If it is found, then the chain
// and index will be returned as a pair.
func (s *State) receiverChain(senderEphemeral ecc.ECPublicKeyable) *ReceiverChainPair {
receiverChains := s.receiverChains
for i, receiverChain := range receiverChains {
chainSenderRatchetKey, err := ecc.DecodePoint(receiverChain.senderRatchetKeyPair.PublicKey().Serialize(), 0)
if err != nil {
logger.Error("Error getting receiverchain: ", err)
}
// If the chainSenderRatchetKey equals our senderEphemeral key, return it.
if chainSenderRatchetKey.PublicKey() == senderEphemeral.PublicKey() {
return NewReceiverChainPair(receiverChain, i)
}
}
return nil
}
// ReceiverChainKey will use the given ephemeral key to generate a new
// chain key.
func (s *State) ReceiverChainKey(senderEphemeral ecc.ECPublicKeyable) *chain.Key {
receiverChainAndIndex := s.receiverChain(senderEphemeral)
receiverChain := receiverChainAndIndex.ReceiverChain
if receiverChainAndIndex == nil || receiverChain == nil {
return nil
}
return chain.NewKey(
kdf.DeriveSecrets,
receiverChain.chainKey.Key(),
receiverChain.chainKey.Index(),
)
}
// AddReceiverChain will add the given ratchet key and chain key to the session
// state.
func (s *State) AddReceiverChain(senderRatchetKey ecc.ECPublicKeyable, chainKey session.ChainKeyable) {
// Create a keypair structure with our sender ratchet key.
senderKey := ecc.NewECKeyPair(senderRatchetKey, nil)
// Create a Chain state object that will hold our sender key, chain key, and
// message keys.
chain := NewChain(senderKey, chainKey.(*chain.Key), []*message.Keys{})
// Add the Chain state to our list of receiver chain states.
s.receiverChains = append(s.receiverChains, chain)
// If our list of receiver chains is too big, delete the oldest entry.
if len(s.receiverChains) > maxReceiverChains {
i := 0
s.receiverChains = append(s.receiverChains[:i], s.receiverChains[i+1:]...)
}
}
// SetSenderChain will set the given ratchet key pair and chain key for this session
// state.
func (s *State) SetSenderChain(senderRatchetKeyPair *ecc.ECKeyPair, chainKey session.ChainKeyable) {
// Create a Chain state object that will hold our sender key, chain key, and
// message keys.
chain := NewChain(senderRatchetKeyPair, chainKey.(*chain.Key), []*message.Keys{})
// Set the sender chain.
s.senderChain = chain
}
// SenderChainKey will return the chain key of the session state.
func (s *State) SenderChainKey() session.ChainKeyable {
chainKey := s.senderChain.chainKey
return chain.NewKey(kdf.DeriveSecrets, chainKey.Key(), chainKey.Index())
}
// SetSenderChainKey will set the chain key in the chain state for this session to
// the given chain key.
func (s *State) SetSenderChainKey(nextChainKey session.ChainKeyable) {
senderChain := s.senderChain
senderChain.SetChainKey(nextChainKey.(*chain.Key))
}
// HasMessageKeys returns true if we have message keys associated with the given
// sender key and counter.
func (s *State) HasMessageKeys(senderEphemeral ecc.ECPublicKeyable, counter uint32) bool {
// Get our chain state that has our chain key.
chainAndIndex := s.receiverChain(senderEphemeral)
receiverChain := chainAndIndex.ReceiverChain
// If the chain is empty, we don't have any message keys.
if receiverChain == nil {
return false
}
// Get our message keys from our receiver chain.
messageKeyList := receiverChain.MessageKeys()
// Loop through our message keys and compare its index with the
// given counter.
for _, messageKey := range messageKeyList {
if messageKey.Index() == counter {
return true
}
}
return false
}
// RemoveMessageKeys removes the message key with the given sender key and
// counter. It will return the removed message key.
func (s *State) RemoveMessageKeys(senderEphemeral ecc.ECPublicKeyable, counter uint32) *message.Keys {
// Get our chain state that has our chain key.
chainAndIndex := s.receiverChain(senderEphemeral)
chainKey := chainAndIndex.ReceiverChain
// If the chain is empty, we don't have any message keys.
if chainKey == nil {
return nil
}
// Get our message keys from our receiver chain.
messageKeyList := chainKey.MessageKeys()
// Loop through our message keys and compare its index with the
// given counter. When we find a match, remove it from our list.
var rmIndex int
for i, messageKey := range messageKeyList {
if messageKey.Index() == counter {
rmIndex = i
break
}
}
// Retrive the message key
messageKey := chainKey.messageKeys[rmIndex]
// Delete the message key from the given position.
chainKey.messageKeys = append(chainKey.messageKeys[:rmIndex], chainKey.messageKeys[rmIndex+1:]...)
return message.NewKeys(
messageKey.CipherKey(),
messageKey.MacKey(),
messageKey.Iv(),
messageKey.Index(),
)
}
// SetMessageKeys will update the chain associated with the given sender key with
// the given message keys.
func (s *State) SetMessageKeys(senderEphemeral ecc.ECPublicKeyable, messageKeys *message.Keys) {
chainAndIndex := s.receiverChain(senderEphemeral)
chainState := chainAndIndex.ReceiverChain
// Add the message keys to our chain state.
chainState.AddMessageKeys(
message.NewKeys(
messageKeys.CipherKey(),
messageKeys.MacKey(),
messageKeys.Iv(),
messageKeys.Index(),
),
)
if len(chainState.MessageKeys()) > maxMessageKeys {
chainState.PopFirstMessageKeys()
}
}
// SetReceiverChainKey sets the session's receiver chain key with the given chain key
// associated with the given senderEphemeral key.
func (s *State) SetReceiverChainKey(senderEphemeral ecc.ECPublicKeyable, chainKey session.ChainKeyable) {
chainAndIndex := s.receiverChain(senderEphemeral)
chainState := chainAndIndex.ReceiverChain
chainState.SetChainKey(chainKey.(*chain.Key))
}
// SetPendingKeyExchange will set the session's pending key exchange state to the given
// sequence and key pairs.
func (s *State) SetPendingKeyExchange(sequence uint32, ourBaseKey, ourRatchetKey *ecc.ECKeyPair,
ourIdentityKey *identity.KeyPair) {
s.pendingKeyExchange = NewPendingKeyExchange(
sequence,
ourBaseKey,
ourRatchetKey,
ourIdentityKey,
)
}
// PendingKeyExchangeSequence will return the session's pending key exchange sequence
// number.
func (s *State) PendingKeyExchangeSequence() uint32 {
return s.pendingKeyExchange.sequence
}
// PendingKeyExchangeBaseKeyPair will return the session's pending key exchange base keypair.
func (s *State) PendingKeyExchangeBaseKeyPair() *ecc.ECKeyPair {
return s.pendingKeyExchange.localBaseKeyPair
}
// PendingKeyExchangeRatchetKeyPair will return the session's pending key exchange ratchet
// keypair.
func (s *State) PendingKeyExchangeRatchetKeyPair() *ecc.ECKeyPair {
return s.pendingKeyExchange.localRatchetKeyPair
}
// PendingKeyExchangeIdentityKeyPair will return the session's pending key exchange identity
// keypair.
func (s *State) PendingKeyExchangeIdentityKeyPair() *identity.KeyPair {
return s.pendingKeyExchange.localIdentityKeyPair
}
// HasPendingKeyExchange will return true if there is a valid pending key exchange waiting.
func (s *State) HasPendingKeyExchange() bool {
return s.pendingKeyExchange != nil
}
// SetUnacknowledgedPreKeyMessage will return unacknowledged pre key message with the
// given key ids and base key.
func (s *State) SetUnacknowledgedPreKeyMessage(preKeyID *optional.Uint32, signedPreKeyID uint32, baseKey ecc.ECPublicKeyable) {
s.pendingPreKey = NewPendingPreKey(
preKeyID,
signedPreKeyID,
baseKey,
)
}
// HasUnacknowledgedPreKeyMessage will return true if this session has an unacknowledged
// pre key message.
func (s *State) HasUnacknowledgedPreKeyMessage() bool {
return s.pendingPreKey != nil
}
// UnackPreKeyMessageItems will return the session's unacknowledged pre key messages.
func (s *State) UnackPreKeyMessageItems() (*UnackPreKeyMessageItems, error) {
preKeyID := s.pendingPreKey.preKeyID
signedPreKeyID := s.pendingPreKey.signedPreKeyID
baseKey, err := ecc.DecodePoint(s.pendingPreKey.baseKey.Serialize(), 0)
if err != nil {
return nil, err
}
return NewUnackPreKeyMessageItems(preKeyID, signedPreKeyID, baseKey), nil
}
// ClearUnackPreKeyMessage will clear the session's pending pre key.
func (s *State) ClearUnackPreKeyMessage() {
s.pendingPreKey = nil
}
// SetRemoteRegistrationID sets the remote user's registration id.
func (s *State) SetRemoteRegistrationID(registrationID uint32) {
s.remoteRegistrationID = registrationID
}
// RemoteRegistrationID returns the remote user's registration id.
func (s *State) RemoteRegistrationID() uint32 {
return s.remoteRegistrationID
}
// SetLocalRegistrationID sets the local user's registration id.
func (s *State) SetLocalRegistrationID(registrationID uint32) {
s.localRegistrationID = registrationID
}
// LocalRegistrationID returns the local user's registration id.
func (s *State) LocalRegistrationID() uint32 {
return s.localRegistrationID
}
// Serialize will return the state as bytes using the given serializer.
func (s *State) Serialize() []byte {
return s.serializer.Serialize(s.structure())
}
// structure will return a serializable structure of the
// the given state so it can be persistently stored.
func (s *State) structure() *StateStructure {
// Convert our receiver chains into a serializeable structure
receiverChains := make([]*ChainStructure, len(s.receiverChains))
for i := range s.receiverChains {
receiverChains[i] = s.receiverChains[i].structure()
}
// Convert our pending key exchange into a serializeable structure
var pendingKeyExchange *PendingKeyExchangeStructure
if s.pendingKeyExchange != nil {
pendingKeyExchange = s.pendingKeyExchange.structure()
}
// Build and return our state structure.
return &StateStructure{
LocalIdentityPublic: s.localIdentityPublic.Serialize(),
LocalRegistrationID: s.localRegistrationID,
NeedsRefresh: s.needsRefresh,
PendingKeyExchange: pendingKeyExchange,
PendingPreKey: s.pendingPreKey.structure(),
PreviousCounter: s.previousCounter,
ReceiverChains: receiverChains,
RemoteIdentityPublic: s.remoteIdentityPublic.Serialize(),
RemoteRegistrationID: s.remoteRegistrationID,
RootKey: s.rootKey.Bytes(),
SenderBaseKey: s.senderBaseKey.Serialize(),
SenderChain: s.senderChain.structure(),
SessionVersion: s.sessionVersion,
}
}

View File

@ -0,0 +1,112 @@
package record
import (
"go.mau.fi/libsignal/ecc"
"go.mau.fi/libsignal/util/bytehelper"
)
// SignedPreKeySerializer is an interface for serializing and deserializing
// SignedPreKey objects into bytes. An implementation of this interface should be
// used to encode/decode the object into JSON, Protobuffers, etc.
type SignedPreKeySerializer interface {
Serialize(signedPreKey *SignedPreKeyStructure) []byte
Deserialize(serialized []byte) (*SignedPreKeyStructure, error)
}
// NewSignedPreKeyFromBytes will return a signed prekey record from the given
// bytes using the given serializer.
func NewSignedPreKeyFromBytes(serialized []byte, serializer SignedPreKeySerializer) (*SignedPreKey, error) {
// Use the given serializer to decode the signal message.
signedPreKeyStructure, err := serializer.Deserialize(serialized)
if err != nil {
return nil, err
}
return NewSignedPreKeyFromStruct(signedPreKeyStructure, serializer)
}
// NewSignedPreKeyFromStruct returns a SignedPreKey record using the given
// serializable structure.
func NewSignedPreKeyFromStruct(structure *SignedPreKeyStructure,
serializer SignedPreKeySerializer) (*SignedPreKey, error) {
// Create the signed prekey record from the structure.
signedPreKey := &SignedPreKey{
structure: *structure,
serializer: serializer,
signature: bytehelper.SliceToArray64(structure.Signature),
}
// Generate the ECC key from bytes.
publicKey := ecc.NewDjbECPublicKey(bytehelper.SliceToArray(structure.PublicKey))
privateKey := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(structure.PrivateKey))
keyPair := ecc.NewECKeyPair(publicKey, privateKey)
signedPreKey.keyPair = keyPair
return signedPreKey, nil
}
// NewSignedPreKey record creates a new signed pre key record
// with the given properties.
func NewSignedPreKey(id uint32, timestamp int64, keyPair *ecc.ECKeyPair,
sig [64]byte, serializer SignedPreKeySerializer) *SignedPreKey {
return &SignedPreKey{
structure: SignedPreKeyStructure{
ID: id,
Timestamp: timestamp,
PublicKey: keyPair.PublicKey().Serialize(),
PrivateKey: bytehelper.ArrayToSlice(keyPair.PrivateKey().Serialize()),
Signature: bytehelper.ArrayToSlice64(sig),
},
keyPair: keyPair,
signature: sig,
serializer: serializer,
}
}
// SignedPreKeyStructure is a flat structure of a signed pre key, used
// for serialization and deserialization.
type SignedPreKeyStructure struct {
ID uint32
PublicKey []byte
PrivateKey []byte
Signature []byte
Timestamp int64
}
// SignedPreKey record is a structure for storing a signed
// pre key in a SignedPreKey store.
type SignedPreKey struct {
structure SignedPreKeyStructure
keyPair *ecc.ECKeyPair
signature [64]byte
serializer SignedPreKeySerializer
}
// ID returns the record's id.
func (s *SignedPreKey) ID() uint32 {
return s.structure.ID
}
// Timestamp returns the record's timestamp
func (s *SignedPreKey) Timestamp() int64 {
return s.structure.Timestamp
}
// KeyPair returns the signed pre key record's key pair.
func (s *SignedPreKey) KeyPair() *ecc.ECKeyPair {
return s.keyPair
}
// Signature returns the record's signed prekey signature.
func (s *SignedPreKey) Signature() [64]byte {
return s.signature
}
// Serialize uses the SignedPreKey serializer to return the SignedPreKey
// as serialized bytes.
func (s *SignedPreKey) Serialize() []byte {
structure := s.structure
return s.serializer.Serialize(&structure)
}

View File

@ -0,0 +1,69 @@
package record
import (
"go.mau.fi/libsignal/ecc"
"go.mau.fi/libsignal/util/optional"
)
// NewUnackPreKeyMessageItems returns message items that are unacknowledged.
func NewUnackPreKeyMessageItems(preKeyID *optional.Uint32, signedPreKeyID uint32,
baseKey ecc.ECPublicKeyable) *UnackPreKeyMessageItems {
return &UnackPreKeyMessageItems{
preKeyID: preKeyID,
signedPreKeyID: signedPreKeyID,
baseKey: baseKey,
}
}
// NewUnackPreKeyMessageItemsFromStruct will return a new unacknowledged prekey
// message items object from the given structure.
func NewUnackPreKeyMessageItemsFromStruct(structure *UnackPreKeyMessageItemsStructure) *UnackPreKeyMessageItems {
baseKey, _ := ecc.DecodePoint(structure.BaseKey, 0)
return NewUnackPreKeyMessageItems(
structure.PreKeyID,
structure.SignedPreKeyID,
baseKey,
)
}
// UnackPreKeyMessageItemsStructure is a serializable structure for unackowledged
// prekey message items.
type UnackPreKeyMessageItemsStructure struct {
PreKeyID *optional.Uint32
SignedPreKeyID uint32
BaseKey []byte
}
// UnackPreKeyMessageItems is a structure for messages that have not been
// acknowledged.
type UnackPreKeyMessageItems struct {
preKeyID *optional.Uint32
signedPreKeyID uint32
baseKey ecc.ECPublicKeyable
}
// PreKeyID returns the prekey id of the unacknowledged message.
func (u *UnackPreKeyMessageItems) PreKeyID() *optional.Uint32 {
return u.preKeyID
}
// SignedPreKeyID returns the signed prekey id of the unacknowledged message.
func (u *UnackPreKeyMessageItems) SignedPreKeyID() uint32 {
return u.signedPreKeyID
}
// BaseKey returns the ECC public key of the unacknowledged message.
func (u *UnackPreKeyMessageItems) BaseKey() ecc.ECPublicKeyable {
return u.baseKey
}
// structure will return a serializable base structure
// for unacknowledged prekey message items.
func (u *UnackPreKeyMessageItems) structure() *UnackPreKeyMessageItemsStructure {
return &UnackPreKeyMessageItemsStructure{
PreKeyID: u.preKeyID,
SignedPreKeyID: u.signedPreKeyID,
BaseKey: u.baseKey.Serialize(),
}
}