diff options
Diffstat (limited to 'vendor/go.mau.fi/libsignal/serialize/ProtoBufferSerializer.go')
-rw-r--r-- | vendor/go.mau.fi/libsignal/serialize/ProtoBufferSerializer.go | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/vendor/go.mau.fi/libsignal/serialize/ProtoBufferSerializer.go b/vendor/go.mau.fi/libsignal/serialize/ProtoBufferSerializer.go new file mode 100644 index 00000000..81482d31 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/serialize/ProtoBufferSerializer.go @@ -0,0 +1,262 @@ +package serialize + +import ( + "fmt" + "strconv" + + "go.mau.fi/libsignal/logger" + "go.mau.fi/libsignal/protocol" + "go.mau.fi/libsignal/util/bytehelper" + "go.mau.fi/libsignal/util/optional" + proto "google.golang.org/protobuf/proto" +) + +// NewProtoBufSerializer will return a serializer for all Signal objects that will +// be responsible for converting objects to and from ProtoBuf bytes. +func NewProtoBufSerializer() *Serializer { + serializer := NewSerializer() + + serializer.SignalMessage = &ProtoBufSignalMessageSerializer{} + serializer.PreKeySignalMessage = &ProtoBufPreKeySignalMessageSerializer{} + serializer.SenderKeyMessage = &ProtoBufSenderKeyMessageSerializer{} + serializer.SenderKeyDistributionMessage = &ProtoBufSenderKeyDistributionMessageSerializer{} + serializer.SignedPreKeyRecord = &JSONSignedPreKeyRecordSerializer{} + serializer.PreKeyRecord = &JSONPreKeyRecordSerializer{} + serializer.State = &JSONStateSerializer{} + serializer.Session = &JSONSessionSerializer{} + serializer.SenderKeyRecord = &JSONSenderKeySessionSerializer{} + serializer.SenderKeyState = &JSONSenderKeyStateSerializer{} + + return serializer +} + +func highBitsToInt(value byte) int { + return int((value & 0xFF) >> 4) +} + +func intsToByteHighAndLow(highValue, lowValue int) byte { + return byte((highValue<<4 | lowValue) & 0xFF) +} + +// ProtoBufSignalMessageSerializer is a structure for serializing signal messages into +// and from ProtoBuf. +type ProtoBufSignalMessageSerializer struct{} + +// Serialize will take a signal message structure and convert it to ProtoBuf bytes. +func (j *ProtoBufSignalMessageSerializer) Serialize(signalMessage *protocol.SignalMessageStructure) []byte { + sm := &SignalMessage{ + RatchetKey: signalMessage.RatchetKey, + Counter: &signalMessage.Counter, + PreviousCounter: &signalMessage.PreviousCounter, + Ciphertext: signalMessage.CipherText, + } + var serialized []byte + message, err := proto.Marshal(sm) + if err != nil { + logger.Error("Error serializing signal message: ", err) + } + + if signalMessage.Version != 0 { + serialized = append(serialized, []byte(strconv.Itoa(signalMessage.Version))...) + } + serialized = append(serialized, message...) + + if signalMessage.Mac != nil { + serialized = append(serialized, signalMessage.Mac...) + } + + return serialized +} + +// Deserialize will take in ProtoBuf bytes and return a signal message structure. +func (j *ProtoBufSignalMessageSerializer) Deserialize(serialized []byte) (*protocol.SignalMessageStructure, error) { + parts, err := bytehelper.SplitThree(serialized, 1, len(serialized)-1-protocol.MacLength, protocol.MacLength) + if err != nil { + logger.Error("Error split signal message: ", err) + return nil, err + } + version := highBitsToInt(parts[0][0]) + message := parts[1] + mac := parts[2] + + var sm SignalMessage + err = proto.Unmarshal(message, &sm) + if err != nil { + logger.Error("Error deserializing signal message: ", err) + return nil, err + } + + signalMessage := protocol.SignalMessageStructure{ + Version: version, + RatchetKey: sm.GetRatchetKey(), + Counter: sm.GetCounter(), + PreviousCounter: sm.GetPreviousCounter(), + CipherText: sm.GetCiphertext(), + Mac: mac, + } + + return &signalMessage, nil +} + +// ProtoBufPreKeySignalMessageSerializer is a structure for serializing prekey signal messages +// into and from ProtoBuf. +type ProtoBufPreKeySignalMessageSerializer struct{} + +// Serialize will take a prekey signal message structure and convert it to ProtoBuf bytes. +func (j *ProtoBufPreKeySignalMessageSerializer) Serialize(signalMessage *protocol.PreKeySignalMessageStructure) []byte { + preKeyMessage := &PreKeySignalMessage{ + RegistrationId: &signalMessage.RegistrationID, + SignedPreKeyId: &signalMessage.SignedPreKeyID, + BaseKey: signalMessage.BaseKey, + IdentityKey: signalMessage.IdentityKey, + Message: signalMessage.Message, + } + + if !signalMessage.PreKeyID.IsEmpty { + preKeyMessage.PreKeyId = &signalMessage.PreKeyID.Value + } + + message, err := proto.Marshal(preKeyMessage) + if err != nil { + logger.Error("Error serializing prekey signal message: ", err) + } + + serialized := append([]byte(strconv.Itoa(signalMessage.Version)), message...) + logger.Debug("Serialize PreKeySignalMessage result: ", serialized) + return serialized +} + +// Deserialize will take in ProtoBuf bytes and return a prekey signal message structure. +func (j *ProtoBufPreKeySignalMessageSerializer) Deserialize(serialized []byte) (*protocol.PreKeySignalMessageStructure, error) { + version := highBitsToInt(serialized[0]) + message := serialized[1:] + var sm PreKeySignalMessage + err := proto.Unmarshal(message, &sm) + if err != nil { + logger.Error("Error deserializing prekey signal message: ", err) + return nil, err + } + + preKeyId := optional.NewEmptyUint32() + if sm.GetPreKeyId() != 0 { + preKeyId = optional.NewOptionalUint32(sm.GetPreKeyId()) + } + + preKeySignalMessage := protocol.PreKeySignalMessageStructure{ + Version: version, + RegistrationID: sm.GetRegistrationId(), + BaseKey: sm.GetBaseKey(), + IdentityKey: sm.GetIdentityKey(), + SignedPreKeyID: sm.GetSignedPreKeyId(), + Message: sm.GetMessage(), + PreKeyID: preKeyId, + } + + return &preKeySignalMessage, nil +} + +// ProtoBufSenderKeyDistributionMessageSerializer is a structure for serializing senderkey +// distribution records to and from ProtoBuf. +type ProtoBufSenderKeyDistributionMessageSerializer struct{} + +// Serialize will take a senderkey distribution message and convert it to ProtoBuf bytes. +func (j *ProtoBufSenderKeyDistributionMessageSerializer) Serialize(message *protocol.SenderKeyDistributionMessageStructure) []byte { + senderDis := SenderKeyDistributionMessage{ + Id: &message.ID, + Iteration: &message.Iteration, + ChainKey: message.ChainKey, + SigningKey: message.SigningKey, + } + + serialized, err := proto.Marshal(&senderDis) + if err != nil { + logger.Error("Error serializing senderkey distribution message: ", err) + } + + version := strconv.Itoa(int(message.Version)) + serialized = append([]byte(version), serialized...) + logger.Debug("Serialize result: ", serialized) + return serialized +} + +// Deserialize will take in ProtoBuf bytes and return a message structure, which can be +// used to create a new SenderKey Distribution object. +func (j *ProtoBufSenderKeyDistributionMessageSerializer) Deserialize(serialized []byte) (*protocol.SenderKeyDistributionMessageStructure, error) { + version := uint32(highBitsToInt(serialized[0])) + message := serialized[1:] + + var senderKeyDis SenderKeyDistributionMessage + err := proto.Unmarshal(message, &senderKeyDis) + if err != nil { + logger.Error("Error deserializing senderkey distribution message: ", err) + return nil, err + } + + msgStructure := protocol.SenderKeyDistributionMessageStructure{ + ID: senderKeyDis.GetId(), + Iteration: senderKeyDis.GetIteration(), + ChainKey: senderKeyDis.GetChainKey(), + SigningKey: senderKeyDis.GetSigningKey(), + Version: version, + } + return &msgStructure, nil +} + +// ProtoBufSenderKeyMessageSerializer is a structure for serializing senderkey +// messages to and from ProtoBuf. +type ProtoBufSenderKeyMessageSerializer struct{} + +// Serialize will take a senderkey message and convert it to ProtoBuf bytes. +func (j *ProtoBufSenderKeyMessageSerializer) Serialize(message *protocol.SenderKeyMessageStructure) []byte { + senderMessage := &SenderKeyMessage{ + Id: &message.ID, + Iteration: &message.Iteration, + Ciphertext: message.CipherText, + } + + var serialized []byte + m, err := proto.Marshal(senderMessage) + if err != nil { + logger.Error("Error serializing signal message: ", err) + } + + if message.Version != 0 { + serialized = append([]byte(fmt.Sprint(message.Version)), m...) + } + + if message.Signature != nil { + serialized = append(serialized, message.Signature...) + } + logger.Debug("Serialize result: ", serialized) + return serialized +} + +// Deserialize will take in ProtoBuf bytes and return a message structure, which can be +// used to create a new SenderKey message object. +func (j *ProtoBufSenderKeyMessageSerializer) Deserialize(serialized []byte) (*protocol.SenderKeyMessageStructure, error) { + parts, err := bytehelper.SplitThree(serialized, 1, len(serialized)-1-64, 64) + if err != nil { + logger.Error("Error split signal message: ", err) + return nil, err + } + version := uint32(highBitsToInt(parts[0][0])) + message := parts[1] + signature := parts[2] + + var senderKey SenderKeyMessage + err = proto.Unmarshal(message, &senderKey) + if err != nil { + logger.Error("Error deserializing senderkey message: ", err) + return nil, err + } + + msgStructure := protocol.SenderKeyMessageStructure{ + Version: version, + ID: senderKey.GetId(), + Iteration: senderKey.GetIteration(), + CipherText: senderKey.GetCiphertext(), + Signature: signature, + } + + return &msgStructure, nil +} |