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 }