package crypto import ( "github.com/go-faster/errors" "go.mau.fi/mautrix-telegram/pkg/gotd/bin" ) // EncryptedMessageData is stored in EncryptedMessage.EncryptedData. type EncryptedMessageData struct { Salt int64 SessionID int64 MessageID int64 SeqNo int32 MessageDataLen int32 MessageDataWithPadding []byte // Message to encode to MessageDataWithPadding. // Needed to prevent unnecessary allocations in EncodeWithoutCopy. Message bin.Encoder } // Encode implements bin.Encoder. func (e EncryptedMessageData) Encode(b *bin.Buffer) error { b.PutLong(e.Salt) b.PutLong(e.SessionID) b.PutLong(e.MessageID) b.PutInt32(e.SeqNo) b.PutInt32(e.MessageDataLen) b.Put(e.MessageDataWithPadding) return nil } // EncodeWithoutCopy is like Encode, but tries to encode Message and uses only one buffer // to encode. If Message is nil, fallbacks to Encode. func (e EncryptedMessageData) EncodeWithoutCopy(b *bin.Buffer) error { if e.Message == nil { return e.Encode(b) } b.PutLong(e.Salt) b.PutLong(e.SessionID) b.PutLong(e.MessageID) b.PutInt32(e.SeqNo) lengthOffset := b.Len() b.PutInt32(0) originalLength := b.Len() if err := b.Encode(e.Message); err != nil { return errors.Wrap(err, "encode inner message") } msgLen := b.Len() - originalLength (&bin.Buffer{Buf: b.Buf[lengthOffset:lengthOffset]}).PutInt(msgLen) return nil } // Decode implements bin.Decoder. func (e *EncryptedMessageData) Decode(b *bin.Buffer) error { { v, err := b.Long() if err != nil { return err } e.Salt = v } { v, err := b.Long() if err != nil { return err } e.SessionID = v } { v, err := b.Long() if err != nil { return err } e.MessageID = v } { v, err := b.Int32() if err != nil { return err } e.SeqNo = v } { v, err := b.Int32() if err != nil { return err } e.MessageDataLen = v } e.MessageDataWithPadding = append(e.MessageDataWithPadding[:0], b.Buf...) if int(e.MessageDataLen) > len(e.MessageDataWithPadding) { return errors.Errorf( "MessageDataLen field is bigger then MessageDataWithPadding length (%d > %d)", int(e.MessageDataLen), len(e.MessageDataWithPadding), ) } return nil } // DecodeWithoutCopy is like Decode, but MessageDataWithPadding references to given buffer instead of // copying. func (e *EncryptedMessageData) DecodeWithoutCopy(b *bin.Buffer) error { { v, err := b.Long() if err != nil { return err } e.Salt = v } { v, err := b.Long() if err != nil { return err } e.SessionID = v } { v, err := b.Long() if err != nil { return err } e.MessageID = v } { v, err := b.Int32() if err != nil { return err } e.SeqNo = v } { v, err := b.Int32() if err != nil { return err } e.MessageDataLen = v } e.MessageDataWithPadding = b.Buf if int(e.MessageDataLen) > len(e.MessageDataWithPadding) { return errors.Errorf( "MessageDataLen field is bigger then MessageDataWithPadding length (%d > %d)", int(e.MessageDataLen), len(e.MessageDataWithPadding), ) } return nil } // Data returns message data without hash. func (e *EncryptedMessageData) Data() []byte { return e.MessageDataWithPadding[:e.MessageDataLen] }