refactor to mautrix 0.17.x; update deps
This commit is contained in:
70
vendor/maunium.net/go/mautrix/crypto/goolm/message/decoder.go
generated
vendored
Normal file
70
vendor/maunium.net/go/mautrix/crypto/goolm/message/decoder.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
)
|
||||
|
||||
// checkDecodeErr checks if there was an error during decode.
|
||||
func checkDecodeErr(readBytes int) error {
|
||||
if readBytes == 0 {
|
||||
//end reached
|
||||
return goolm.ErrInputToSmall
|
||||
}
|
||||
if readBytes < 0 {
|
||||
return goolm.ErrOverflow
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// decodeVarInt decodes a single big-endian encoded varint.
|
||||
func decodeVarInt(input []byte) (uint32, int) {
|
||||
value, readBytes := binary.Uvarint(input)
|
||||
return uint32(value), readBytes
|
||||
}
|
||||
|
||||
// decodeVarString decodes the length of the string (varint) and returns the actual string
|
||||
func decodeVarString(input []byte) ([]byte, int) {
|
||||
stringLen, readBytes := decodeVarInt(input)
|
||||
if readBytes <= 0 {
|
||||
return nil, readBytes
|
||||
}
|
||||
input = input[readBytes:]
|
||||
value := input[:stringLen]
|
||||
readBytes += int(stringLen)
|
||||
return value, readBytes
|
||||
}
|
||||
|
||||
// encodeVarIntByteLength returns the number of bytes needed to encode the uint32.
|
||||
func encodeVarIntByteLength(input uint32) int {
|
||||
result := 1
|
||||
for input >= 128 {
|
||||
result++
|
||||
input >>= 7
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// encodeVarStringByteLength returns the number of bytes needed to encode the input.
|
||||
func encodeVarStringByteLength(input []byte) int {
|
||||
result := encodeVarIntByteLength(uint32(len(input)))
|
||||
result += len(input)
|
||||
return result
|
||||
}
|
||||
|
||||
// encodeVarInt encodes a single uint32
|
||||
func encodeVarInt(input uint32) []byte {
|
||||
out := make([]byte, encodeVarIntByteLength(input))
|
||||
binary.PutUvarint(out, uint64(input))
|
||||
return out
|
||||
}
|
||||
|
||||
// encodeVarString encodes the length of the input (varint) and appends the actual input
|
||||
func encodeVarString(input []byte) []byte {
|
||||
out := make([]byte, encodeVarStringByteLength(input))
|
||||
length := encodeVarInt(uint32(len(input)))
|
||||
copy(out, length)
|
||||
copy(out[len(length):], input)
|
||||
return out
|
||||
}
|
||||
144
vendor/maunium.net/go/mautrix/crypto/goolm/message/group_message.go
generated
vendored
Normal file
144
vendor/maunium.net/go/mautrix/crypto/goolm/message/group_message.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm/cipher"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
messageIndexTag = 0x08
|
||||
cipherTextTag = 0x12
|
||||
countMACBytesGroupMessage = 8
|
||||
)
|
||||
|
||||
// GroupMessage represents a message in the group message format.
|
||||
type GroupMessage struct {
|
||||
Version byte `json:"version"`
|
||||
MessageIndex uint32 `json:"index"`
|
||||
Ciphertext []byte `json:"ciphertext"`
|
||||
HasMessageIndex bool `json:"has_index"`
|
||||
}
|
||||
|
||||
// Decodes decodes the input and populates the corresponding fileds. MAC and signature are ignored but have to be present.
|
||||
func (r *GroupMessage) Decode(input []byte) error {
|
||||
r.Version = 0
|
||||
r.MessageIndex = 0
|
||||
r.Ciphertext = nil
|
||||
if len(input) == 0 {
|
||||
return nil
|
||||
}
|
||||
//first Byte is always version
|
||||
r.Version = input[0]
|
||||
curPos := 1
|
||||
for curPos < len(input)-countMACBytesGroupMessage-crypto.ED25519SignatureSize {
|
||||
//Read Key
|
||||
curKey, readBytes := decodeVarInt(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
if (curKey & 0b111) == 0 {
|
||||
//The value is of type varint
|
||||
value, readBytes := decodeVarInt(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
switch curKey {
|
||||
case messageIndexTag:
|
||||
r.MessageIndex = value
|
||||
r.HasMessageIndex = true
|
||||
}
|
||||
} else if (curKey & 0b111) == 2 {
|
||||
//The value is of type string
|
||||
value, readBytes := decodeVarString(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
switch curKey {
|
||||
case cipherTextTag:
|
||||
r.Ciphertext = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeAndMacAndSign encodes the message, creates the mac with the key and the cipher and signs the message.
|
||||
// If macKey or cipher is nil, no mac is appended. If signKey is nil, no signature is appended.
|
||||
func (r *GroupMessage) EncodeAndMacAndSign(macKey []byte, cipher cipher.Cipher, signKey *crypto.Ed25519KeyPair) ([]byte, error) {
|
||||
var lengthOfMessage int
|
||||
lengthOfMessage += 1 //Version
|
||||
lengthOfMessage += encodeVarIntByteLength(messageIndexTag) + encodeVarIntByteLength(r.MessageIndex)
|
||||
lengthOfMessage += encodeVarIntByteLength(cipherTextTag) + encodeVarStringByteLength(r.Ciphertext)
|
||||
out := make([]byte, lengthOfMessage)
|
||||
out[0] = r.Version
|
||||
curPos := 1
|
||||
encodedTag := encodeVarInt(messageIndexTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue := encodeVarInt(r.MessageIndex)
|
||||
copy(out[curPos:], encodedValue)
|
||||
curPos += len(encodedValue)
|
||||
encodedTag = encodeVarInt(cipherTextTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue = encodeVarString(r.Ciphertext)
|
||||
copy(out[curPos:], encodedValue)
|
||||
curPos += len(encodedValue)
|
||||
if len(macKey) != 0 && cipher != nil {
|
||||
mac, err := r.MAC(macKey, cipher, out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, mac[:countMACBytesGroupMessage]...)
|
||||
}
|
||||
if signKey != nil {
|
||||
signature := signKey.Sign(out)
|
||||
out = append(out, signature...)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// MAC returns the MAC of the message calculated with cipher and key. The length of the MAC is truncated to the correct length.
|
||||
func (r *GroupMessage) MAC(key []byte, cipher cipher.Cipher, message []byte) ([]byte, error) {
|
||||
mac, err := cipher.MAC(key, message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mac[:countMACBytesGroupMessage], nil
|
||||
}
|
||||
|
||||
// VerifySignature verifies the givenSignature to the calculated signature of the message.
|
||||
func (r *GroupMessage) VerifySignature(key crypto.Ed25519PublicKey, message, givenSignature []byte) bool {
|
||||
return key.Verify(message, givenSignature)
|
||||
}
|
||||
|
||||
// VerifySignature verifies the signature taken from the message to the calculated signature of the message.
|
||||
func (r *GroupMessage) VerifySignatureInline(key crypto.Ed25519PublicKey, message []byte) bool {
|
||||
signature := message[len(message)-crypto.ED25519SignatureSize:]
|
||||
message = message[:len(message)-crypto.ED25519SignatureSize]
|
||||
return key.Verify(message, signature)
|
||||
}
|
||||
|
||||
// VerifyMAC verifies the givenMAC to the calculated MAC of the message.
|
||||
func (r *GroupMessage) VerifyMAC(key []byte, cipher cipher.Cipher, message, givenMAC []byte) (bool, error) {
|
||||
checkMac, err := r.MAC(key, cipher, message)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return bytes.Equal(checkMac[:countMACBytesGroupMessage], givenMAC), nil
|
||||
}
|
||||
|
||||
// VerifyMACInline verifies the MAC taken from the message to the calculated MAC of the message.
|
||||
func (r *GroupMessage) VerifyMACInline(key []byte, cipher cipher.Cipher, message []byte) (bool, error) {
|
||||
startMAC := len(message) - countMACBytesGroupMessage - crypto.ED25519SignatureSize
|
||||
endMAC := startMAC + countMACBytesGroupMessage
|
||||
suplMac := message[startMAC:endMAC]
|
||||
message = message[:startMAC]
|
||||
return r.VerifyMAC(key, cipher, message, suplMac)
|
||||
}
|
||||
129
vendor/maunium.net/go/mautrix/crypto/goolm/message/message.go
generated
vendored
Normal file
129
vendor/maunium.net/go/mautrix/crypto/goolm/message/message.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm/cipher"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
ratchetKeyTag = 0x0A
|
||||
counterTag = 0x10
|
||||
cipherTextKeyTag = 0x22
|
||||
countMACBytesMessage = 8
|
||||
)
|
||||
|
||||
// GroupMessage represents a message in the message format.
|
||||
type Message struct {
|
||||
Version byte `json:"version"`
|
||||
HasCounter bool `json:"has_counter"`
|
||||
Counter uint32 `json:"counter"`
|
||||
RatchetKey crypto.Curve25519PublicKey `json:"ratchet_key"`
|
||||
Ciphertext []byte `json:"ciphertext"`
|
||||
}
|
||||
|
||||
// Decodes decodes the input and populates the corresponding fileds. MAC is ignored but has to be present.
|
||||
func (r *Message) Decode(input []byte) error {
|
||||
r.Version = 0
|
||||
r.HasCounter = false
|
||||
r.Counter = 0
|
||||
r.RatchetKey = nil
|
||||
r.Ciphertext = nil
|
||||
if len(input) == 0 {
|
||||
return nil
|
||||
}
|
||||
//first Byte is always version
|
||||
r.Version = input[0]
|
||||
curPos := 1
|
||||
for curPos < len(input)-countMACBytesMessage {
|
||||
//Read Key
|
||||
curKey, readBytes := decodeVarInt(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
if (curKey & 0b111) == 0 {
|
||||
//The value is of type varint
|
||||
value, readBytes := decodeVarInt(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
switch curKey {
|
||||
case counterTag:
|
||||
r.HasCounter = true
|
||||
r.Counter = value
|
||||
}
|
||||
} else if (curKey & 0b111) == 2 {
|
||||
//The value is of type string
|
||||
value, readBytes := decodeVarString(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
switch curKey {
|
||||
case ratchetKeyTag:
|
||||
r.RatchetKey = value
|
||||
case cipherTextKeyTag:
|
||||
r.Ciphertext = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeAndMAC encodes the message and creates the MAC with the key and the cipher.
|
||||
// If key or cipher is nil, no MAC is appended.
|
||||
func (r *Message) EncodeAndMAC(key []byte, cipher cipher.Cipher) ([]byte, error) {
|
||||
var lengthOfMessage int
|
||||
lengthOfMessage += 1 //Version
|
||||
lengthOfMessage += encodeVarIntByteLength(ratchetKeyTag) + encodeVarStringByteLength(r.RatchetKey)
|
||||
lengthOfMessage += encodeVarIntByteLength(counterTag) + encodeVarIntByteLength(r.Counter)
|
||||
lengthOfMessage += encodeVarIntByteLength(cipherTextKeyTag) + encodeVarStringByteLength(r.Ciphertext)
|
||||
out := make([]byte, lengthOfMessage)
|
||||
out[0] = r.Version
|
||||
curPos := 1
|
||||
encodedTag := encodeVarInt(ratchetKeyTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue := encodeVarString(r.RatchetKey)
|
||||
copy(out[curPos:], encodedValue)
|
||||
curPos += len(encodedValue)
|
||||
encodedTag = encodeVarInt(counterTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue = encodeVarInt(r.Counter)
|
||||
copy(out[curPos:], encodedValue)
|
||||
curPos += len(encodedValue)
|
||||
encodedTag = encodeVarInt(cipherTextKeyTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue = encodeVarString(r.Ciphertext)
|
||||
copy(out[curPos:], encodedValue)
|
||||
curPos += len(encodedValue)
|
||||
if len(key) != 0 && cipher != nil {
|
||||
mac, err := cipher.MAC(key, out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, mac[:countMACBytesMessage]...)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// VerifyMAC verifies the givenMAC to the calculated MAC of the message.
|
||||
func (r *Message) VerifyMAC(key []byte, cipher cipher.Cipher, message, givenMAC []byte) (bool, error) {
|
||||
checkMAC, err := cipher.MAC(key, message)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return bytes.Equal(checkMAC[:countMACBytesMessage], givenMAC), nil
|
||||
}
|
||||
|
||||
// VerifyMACInline verifies the MAC taken from the message to the calculated MAC of the message.
|
||||
func (r *Message) VerifyMACInline(key []byte, cipher cipher.Cipher, message []byte) (bool, error) {
|
||||
givenMAC := message[len(message)-countMACBytesMessage:]
|
||||
return r.VerifyMAC(key, cipher, message[:len(message)-countMACBytesMessage], givenMAC)
|
||||
}
|
||||
120
vendor/maunium.net/go/mautrix/crypto/goolm/message/prekey_message.go
generated
vendored
Normal file
120
vendor/maunium.net/go/mautrix/crypto/goolm/message/prekey_message.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
oneTimeKeyIdTag = 0x0A
|
||||
baseKeyTag = 0x12
|
||||
identityKeyTag = 0x1A
|
||||
messageTag = 0x22
|
||||
)
|
||||
|
||||
type PreKeyMessage struct {
|
||||
Version byte `json:"version"`
|
||||
IdentityKey crypto.Curve25519PublicKey `json:"id_key"`
|
||||
BaseKey crypto.Curve25519PublicKey `json:"base_key"`
|
||||
OneTimeKey crypto.Curve25519PublicKey `json:"one_time_key"`
|
||||
Message []byte `json:"message"`
|
||||
}
|
||||
|
||||
// Decodes decodes the input and populates the corresponding fileds.
|
||||
func (r *PreKeyMessage) Decode(input []byte) error {
|
||||
r.Version = 0
|
||||
r.IdentityKey = nil
|
||||
r.BaseKey = nil
|
||||
r.OneTimeKey = nil
|
||||
r.Message = nil
|
||||
if len(input) == 0 {
|
||||
return nil
|
||||
}
|
||||
//first Byte is always version
|
||||
r.Version = input[0]
|
||||
curPos := 1
|
||||
for curPos < len(input) {
|
||||
//Read Key
|
||||
curKey, readBytes := decodeVarInt(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
if (curKey & 0b111) == 0 {
|
||||
//The value is of type varint
|
||||
_, readBytes := decodeVarInt(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
} else if (curKey & 0b111) == 2 {
|
||||
//The value is of type string
|
||||
value, readBytes := decodeVarString(input[curPos:])
|
||||
if err := checkDecodeErr(readBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
curPos += readBytes
|
||||
switch curKey {
|
||||
case oneTimeKeyIdTag:
|
||||
r.OneTimeKey = value
|
||||
case baseKeyTag:
|
||||
r.BaseKey = value
|
||||
case identityKeyTag:
|
||||
r.IdentityKey = value
|
||||
case messageTag:
|
||||
r.Message = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckField verifies the fields. If theirIdentityKey is nil, it is not compared to the key in the message.
|
||||
func (r *PreKeyMessage) CheckFields(theirIdentityKey *crypto.Curve25519PublicKey) bool {
|
||||
ok := true
|
||||
ok = ok && (theirIdentityKey != nil || r.IdentityKey != nil)
|
||||
if r.IdentityKey != nil {
|
||||
ok = ok && (len(r.IdentityKey) == crypto.Curve25519KeyLength)
|
||||
}
|
||||
ok = ok && len(r.Message) != 0
|
||||
ok = ok && len(r.BaseKey) == crypto.Curve25519KeyLength
|
||||
ok = ok && len(r.OneTimeKey) == crypto.Curve25519KeyLength
|
||||
return ok
|
||||
}
|
||||
|
||||
// Encode encodes the message.
|
||||
func (r *PreKeyMessage) Encode() ([]byte, error) {
|
||||
var lengthOfMessage int
|
||||
lengthOfMessage += 1 //Version
|
||||
lengthOfMessage += encodeVarIntByteLength(oneTimeKeyIdTag) + encodeVarStringByteLength(r.OneTimeKey)
|
||||
lengthOfMessage += encodeVarIntByteLength(identityKeyTag) + encodeVarStringByteLength(r.IdentityKey)
|
||||
lengthOfMessage += encodeVarIntByteLength(baseKeyTag) + encodeVarStringByteLength(r.BaseKey)
|
||||
lengthOfMessage += encodeVarIntByteLength(messageTag) + encodeVarStringByteLength(r.Message)
|
||||
out := make([]byte, lengthOfMessage)
|
||||
out[0] = r.Version
|
||||
curPos := 1
|
||||
encodedTag := encodeVarInt(oneTimeKeyIdTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue := encodeVarString(r.OneTimeKey)
|
||||
copy(out[curPos:], encodedValue)
|
||||
curPos += len(encodedValue)
|
||||
encodedTag = encodeVarInt(identityKeyTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue = encodeVarString(r.IdentityKey)
|
||||
copy(out[curPos:], encodedValue)
|
||||
curPos += len(encodedValue)
|
||||
encodedTag = encodeVarInt(baseKeyTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue = encodeVarString(r.BaseKey)
|
||||
copy(out[curPos:], encodedValue)
|
||||
curPos += len(encodedValue)
|
||||
encodedTag = encodeVarInt(messageTag)
|
||||
copy(out[curPos:], encodedTag)
|
||||
curPos += len(encodedTag)
|
||||
encodedValue = encodeVarString(r.Message)
|
||||
copy(out[curPos:], encodedValue)
|
||||
return out, nil
|
||||
}
|
||||
44
vendor/maunium.net/go/mautrix/crypto/goolm/message/session_export.go
generated
vendored
Normal file
44
vendor/maunium.net/go/mautrix/crypto/goolm/message/session_export.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
sessionExportVersion = 0x01
|
||||
)
|
||||
|
||||
// MegolmSessionExport represents a message in the session export format.
|
||||
type MegolmSessionExport struct {
|
||||
Counter uint32 `json:"counter"`
|
||||
RatchetData [128]byte `json:"data"`
|
||||
PublicKey crypto.Ed25519PublicKey `json:"public_key"`
|
||||
}
|
||||
|
||||
// Encode returns the encoded message in the correct format.
|
||||
func (s MegolmSessionExport) Encode() []byte {
|
||||
output := make([]byte, 165)
|
||||
output[0] = sessionExportVersion
|
||||
binary.BigEndian.PutUint32(output[1:], s.Counter)
|
||||
copy(output[5:], s.RatchetData[:])
|
||||
copy(output[133:], s.PublicKey)
|
||||
return output
|
||||
}
|
||||
|
||||
// Decode populates the struct with the data encoded in input.
|
||||
func (s *MegolmSessionExport) Decode(input []byte) error {
|
||||
if len(input) != 165 {
|
||||
return fmt.Errorf("decrypt: %w", goolm.ErrBadInput)
|
||||
}
|
||||
if input[0] != sessionExportVersion {
|
||||
return fmt.Errorf("decrypt: %w", goolm.ErrBadVersion)
|
||||
}
|
||||
s.Counter = binary.BigEndian.Uint32(input[1:5])
|
||||
copy(s.RatchetData[:], input[5:133])
|
||||
s.PublicKey = input[133:]
|
||||
return nil
|
||||
}
|
||||
50
vendor/maunium.net/go/mautrix/crypto/goolm/message/session_sharing.go
generated
vendored
Normal file
50
vendor/maunium.net/go/mautrix/crypto/goolm/message/session_sharing.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
sessionSharingVersion = 0x02
|
||||
)
|
||||
|
||||
// MegolmSessionSharing represents a message in the session sharing format.
|
||||
type MegolmSessionSharing struct {
|
||||
Counter uint32 `json:"counter"`
|
||||
RatchetData [128]byte `json:"data"`
|
||||
PublicKey crypto.Ed25519PublicKey `json:"-"` //only used when decrypting messages
|
||||
}
|
||||
|
||||
// Encode returns the encoded message in the correct format with the signature by key appended.
|
||||
func (s MegolmSessionSharing) EncodeAndSign(key crypto.Ed25519KeyPair) []byte {
|
||||
output := make([]byte, 229)
|
||||
output[0] = sessionSharingVersion
|
||||
binary.BigEndian.PutUint32(output[1:], s.Counter)
|
||||
copy(output[5:], s.RatchetData[:])
|
||||
copy(output[133:], key.PublicKey)
|
||||
signature := key.Sign(output[:165])
|
||||
copy(output[165:], signature)
|
||||
return output
|
||||
}
|
||||
|
||||
// VerifyAndDecode verifies the input and populates the struct with the data encoded in input.
|
||||
func (s *MegolmSessionSharing) VerifyAndDecode(input []byte) error {
|
||||
if len(input) != 229 {
|
||||
return fmt.Errorf("verify: %w", goolm.ErrBadInput)
|
||||
}
|
||||
publicKey := crypto.Ed25519PublicKey(input[133:165])
|
||||
if !publicKey.Verify(input[:165], input[165:]) {
|
||||
return fmt.Errorf("verify: %w", goolm.ErrBadVerification)
|
||||
}
|
||||
s.PublicKey = publicKey
|
||||
if input[0] != sessionSharingVersion {
|
||||
return fmt.Errorf("verify: %w", goolm.ErrBadVersion)
|
||||
}
|
||||
s.Counter = binary.BigEndian.Uint32(input[1:5])
|
||||
copy(s.RatchetData[:], input[5:133])
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user