summary refs log tree commit diff
path: root/vendor/maunium.net/go/mautrix/crypto/goolm
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-10-25 15:55:50 +0200
committerEmile <git@emile.space>2024-10-25 15:55:50 +0200
commitc90f36e3dd179d2de96f4f5fe38d8dc9a9de6dfe (patch)
tree89e9afb41c5bf76f48cfb09305a2d3db8d302b06 /vendor/maunium.net/go/mautrix/crypto/goolm
parent98bbb0f559a8883bc47bae80607dbe326a448e61 (diff)
vendor HEAD main
Diffstat (limited to 'vendor/maunium.net/go/mautrix/crypto/goolm')
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/goolm/crypto/curve25519.go186
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/goolm/crypto/doc.go2
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/goolm/crypto/ed25519.go184
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/goolm/crypto/hmac.go29
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/goolm/crypto/one_time_key.go95
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/goolm/libolmpickle/pickle.go41
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/goolm/libolmpickle/unpickle.go53
7 files changed, 590 insertions, 0 deletions
diff --git a/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/curve25519.go b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/curve25519.go
new file mode 100644
index 0000000..1c182ca
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/curve25519.go
@@ -0,0 +1,186 @@
+package crypto
+
+import (
+	"bytes"
+	"crypto/rand"
+	"encoding/base64"
+	"fmt"
+	"io"
+
+	"golang.org/x/crypto/curve25519"
+
+	"maunium.net/go/mautrix/crypto/goolm/libolmpickle"
+	"maunium.net/go/mautrix/crypto/olm"
+	"maunium.net/go/mautrix/id"
+)
+
+const (
+	Curve25519KeyLength    = curve25519.ScalarSize //The length of the private key.
+	curve25519PubKeyLength = 32
+)
+
+// Curve25519GenerateKey creates a new curve25519 key pair. If reader is nil, the random data is taken from crypto/rand.
+func Curve25519GenerateKey(reader io.Reader) (Curve25519KeyPair, error) {
+	privateKeyByte := make([]byte, Curve25519KeyLength)
+	if reader == nil {
+		_, err := rand.Read(privateKeyByte)
+		if err != nil {
+			return Curve25519KeyPair{}, err
+		}
+	} else {
+		_, err := reader.Read(privateKeyByte)
+		if err != nil {
+			return Curve25519KeyPair{}, err
+		}
+	}
+
+	privateKey := Curve25519PrivateKey(privateKeyByte)
+
+	publicKey, err := privateKey.PubKey()
+	if err != nil {
+		return Curve25519KeyPair{}, err
+	}
+	return Curve25519KeyPair{
+		PrivateKey: Curve25519PrivateKey(privateKey),
+		PublicKey:  Curve25519PublicKey(publicKey),
+	}, nil
+}
+
+// Curve25519GenerateFromPrivate creates a new curve25519 key pair with the private key given.
+func Curve25519GenerateFromPrivate(private Curve25519PrivateKey) (Curve25519KeyPair, error) {
+	publicKey, err := private.PubKey()
+	if err != nil {
+		return Curve25519KeyPair{}, err
+	}
+	return Curve25519KeyPair{
+		PrivateKey: private,
+		PublicKey:  Curve25519PublicKey(publicKey),
+	}, nil
+}
+
+// Curve25519KeyPair stores both parts of a curve25519 key.
+type Curve25519KeyPair struct {
+	PrivateKey Curve25519PrivateKey `json:"private,omitempty"`
+	PublicKey  Curve25519PublicKey  `json:"public,omitempty"`
+}
+
+// B64Encoded returns a base64 encoded string of the public key.
+func (c Curve25519KeyPair) B64Encoded() id.Curve25519 {
+	return c.PublicKey.B64Encoded()
+}
+
+// SharedSecret returns the shared secret between the key pair and the given public key.
+func (c Curve25519KeyPair) SharedSecret(pubKey Curve25519PublicKey) ([]byte, error) {
+	return c.PrivateKey.SharedSecret(pubKey)
+}
+
+// PickleLibOlm encodes the key pair into target. target has to have a size of at least PickleLen() and is written to from index 0.
+// It returns the number of bytes written.
+func (c Curve25519KeyPair) PickleLibOlm(target []byte) (int, error) {
+	if len(target) < c.PickleLen() {
+		return 0, fmt.Errorf("pickle curve25519 key pair: %w", olm.ErrValueTooShort)
+	}
+	written, err := c.PublicKey.PickleLibOlm(target)
+	if err != nil {
+		return 0, fmt.Errorf("pickle curve25519 key pair: %w", err)
+	}
+	if len(c.PrivateKey) != Curve25519KeyLength {
+		written += libolmpickle.PickleBytes(make([]byte, Curve25519KeyLength), target[written:])
+	} else {
+		written += libolmpickle.PickleBytes(c.PrivateKey, target[written:])
+	}
+	return written, nil
+}
+
+// UnpickleLibOlm decodes the unencryted value and populates the key pair accordingly. It returns the number of bytes read.
+func (c *Curve25519KeyPair) UnpickleLibOlm(value []byte) (int, error) {
+	//unpickle PubKey
+	read, err := c.PublicKey.UnpickleLibOlm(value)
+	if err != nil {
+		return 0, err
+	}
+	//unpickle PrivateKey
+	privKey, readPriv, err := libolmpickle.UnpickleBytes(value[read:], Curve25519KeyLength)
+	if err != nil {
+		return read, err
+	}
+	c.PrivateKey = privKey
+	return read + readPriv, nil
+}
+
+// PickleLen returns the number of bytes the pickled key pair will have.
+func (c Curve25519KeyPair) PickleLen() int {
+	lenPublic := c.PublicKey.PickleLen()
+	var lenPrivate int
+	if len(c.PrivateKey) != Curve25519KeyLength {
+		lenPrivate = libolmpickle.PickleBytesLen(make([]byte, Curve25519KeyLength))
+	} else {
+		lenPrivate = libolmpickle.PickleBytesLen(c.PrivateKey)
+	}
+	return lenPublic + lenPrivate
+}
+
+// Curve25519PrivateKey represents the private key for curve25519 usage
+type Curve25519PrivateKey []byte
+
+// Equal compares the private key to the given private key.
+func (c Curve25519PrivateKey) Equal(x Curve25519PrivateKey) bool {
+	return bytes.Equal(c, x)
+}
+
+// PubKey returns the public key derived from the private key.
+func (c Curve25519PrivateKey) PubKey() (Curve25519PublicKey, error) {
+	publicKey, err := curve25519.X25519(c, curve25519.Basepoint)
+	if err != nil {
+		return nil, err
+	}
+	return publicKey, nil
+}
+
+// SharedSecret returns the shared secret between the private key and the given public key.
+func (c Curve25519PrivateKey) SharedSecret(pubKey Curve25519PublicKey) ([]byte, error) {
+	return curve25519.X25519(c, pubKey)
+}
+
+// Curve25519PublicKey represents the public key for curve25519 usage
+type Curve25519PublicKey []byte
+
+// Equal compares the public key to the given public key.
+func (c Curve25519PublicKey) Equal(x Curve25519PublicKey) bool {
+	return bytes.Equal(c, x)
+}
+
+// B64Encoded returns a base64 encoded string of the public key.
+func (c Curve25519PublicKey) B64Encoded() id.Curve25519 {
+	return id.Curve25519(base64.RawStdEncoding.EncodeToString(c))
+}
+
+// PickleLibOlm encodes the public key into target. target has to have a size of at least PickleLen() and is written to from index 0.
+// It returns the number of bytes written.
+func (c Curve25519PublicKey) PickleLibOlm(target []byte) (int, error) {
+	if len(target) < c.PickleLen() {
+		return 0, fmt.Errorf("pickle curve25519 public key: %w", olm.ErrValueTooShort)
+	}
+	if len(c) != curve25519PubKeyLength {
+		return libolmpickle.PickleBytes(make([]byte, curve25519PubKeyLength), target), nil
+	}
+	return libolmpickle.PickleBytes(c, target), nil
+}
+
+// UnpickleLibOlm decodes the unencryted value and populates the public key accordingly. It returns the number of bytes read.
+func (c *Curve25519PublicKey) UnpickleLibOlm(value []byte) (int, error) {
+	unpickled, readBytes, err := libolmpickle.UnpickleBytes(value, curve25519PubKeyLength)
+	if err != nil {
+		return 0, err
+	}
+	*c = unpickled
+	return readBytes, nil
+}
+
+// PickleLen returns the number of bytes the pickled public key will have.
+func (c Curve25519PublicKey) PickleLen() int {
+	if len(c) != curve25519PubKeyLength {
+		return libolmpickle.PickleBytesLen(make([]byte, curve25519PubKeyLength))
+	}
+	return libolmpickle.PickleBytesLen(c)
+}
diff --git a/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/doc.go b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/doc.go
new file mode 100644
index 0000000..5bdb01d
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/doc.go
@@ -0,0 +1,2 @@
+// Package crpyto provides the nessesary encryption methods for olm/megolm
+package crypto
diff --git a/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/ed25519.go b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/ed25519.go
new file mode 100644
index 0000000..57fc25f
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/ed25519.go
@@ -0,0 +1,184 @@
+package crypto
+
+import (
+	"encoding/base64"
+	"fmt"
+	"io"
+
+	"maunium.net/go/mautrix/crypto/ed25519"
+	"maunium.net/go/mautrix/crypto/goolm/libolmpickle"
+	"maunium.net/go/mautrix/crypto/olm"
+	"maunium.net/go/mautrix/id"
+)
+
+const (
+	ED25519SignatureSize = ed25519.SignatureSize //The length of a signature
+)
+
+// Ed25519GenerateKey creates a new ed25519 key pair. If reader is nil, the random data is taken from crypto/rand.
+func Ed25519GenerateKey(reader io.Reader) (Ed25519KeyPair, error) {
+	publicKey, privateKey, err := ed25519.GenerateKey(reader)
+	if err != nil {
+		return Ed25519KeyPair{}, err
+	}
+	return Ed25519KeyPair{
+		PrivateKey: Ed25519PrivateKey(privateKey),
+		PublicKey:  Ed25519PublicKey(publicKey),
+	}, nil
+}
+
+// Ed25519GenerateFromPrivate creates a new ed25519 key pair with the private key given.
+func Ed25519GenerateFromPrivate(privKey Ed25519PrivateKey) Ed25519KeyPair {
+	return Ed25519KeyPair{
+		PrivateKey: privKey,
+		PublicKey:  privKey.PubKey(),
+	}
+}
+
+// Ed25519GenerateFromSeed creates a new ed25519 key pair with a given seed.
+func Ed25519GenerateFromSeed(seed []byte) Ed25519KeyPair {
+	privKey := Ed25519PrivateKey(ed25519.NewKeyFromSeed(seed))
+	return Ed25519KeyPair{
+		PrivateKey: privKey,
+		PublicKey:  privKey.PubKey(),
+	}
+}
+
+// Ed25519KeyPair stores both parts of a ed25519 key.
+type Ed25519KeyPair struct {
+	PrivateKey Ed25519PrivateKey `json:"private,omitempty"`
+	PublicKey  Ed25519PublicKey  `json:"public,omitempty"`
+}
+
+// B64Encoded returns a base64 encoded string of the public key.
+func (c Ed25519KeyPair) B64Encoded() id.Ed25519 {
+	return id.Ed25519(base64.RawStdEncoding.EncodeToString(c.PublicKey))
+}
+
+// Sign returns the signature for the message.
+func (c Ed25519KeyPair) Sign(message []byte) []byte {
+	return c.PrivateKey.Sign(message)
+}
+
+// Verify checks the signature of the message against the givenSignature
+func (c Ed25519KeyPair) Verify(message, givenSignature []byte) bool {
+	return c.PublicKey.Verify(message, givenSignature)
+}
+
+// PickleLibOlm encodes the key pair into target. target has to have a size of at least PickleLen() and is written to from index 0.
+// It returns the number of bytes written.
+func (c Ed25519KeyPair) PickleLibOlm(target []byte) (int, error) {
+	if len(target) < c.PickleLen() {
+		return 0, fmt.Errorf("pickle ed25519 key pair: %w", olm.ErrValueTooShort)
+	}
+	written, err := c.PublicKey.PickleLibOlm(target)
+	if err != nil {
+		return 0, fmt.Errorf("pickle ed25519 key pair: %w", err)
+	}
+
+	if len(c.PrivateKey) != ed25519.PrivateKeySize {
+		written += libolmpickle.PickleBytes(make([]byte, ed25519.PrivateKeySize), target[written:])
+	} else {
+		written += libolmpickle.PickleBytes(c.PrivateKey, target[written:])
+	}
+	return written, nil
+}
+
+// UnpickleLibOlm decodes the unencryted value and populates the key pair accordingly. It returns the number of bytes read.
+func (c *Ed25519KeyPair) UnpickleLibOlm(value []byte) (int, error) {
+	//unpickle PubKey
+	read, err := c.PublicKey.UnpickleLibOlm(value)
+	if err != nil {
+		return 0, err
+	}
+	//unpickle PrivateKey
+	privKey, readPriv, err := libolmpickle.UnpickleBytes(value[read:], ed25519.PrivateKeySize)
+	if err != nil {
+		return read, err
+	}
+	c.PrivateKey = privKey
+	return read + readPriv, nil
+}
+
+// PickleLen returns the number of bytes the pickled key pair will have.
+func (c Ed25519KeyPair) PickleLen() int {
+	lenPublic := c.PublicKey.PickleLen()
+	var lenPrivate int
+	if len(c.PrivateKey) != ed25519.PrivateKeySize {
+		lenPrivate = libolmpickle.PickleBytesLen(make([]byte, ed25519.PrivateKeySize))
+	} else {
+		lenPrivate = libolmpickle.PickleBytesLen(c.PrivateKey)
+	}
+	return lenPublic + lenPrivate
+}
+
+// Curve25519PrivateKey represents the private key for ed25519 usage. This is just a wrapper.
+type Ed25519PrivateKey ed25519.PrivateKey
+
+// Equal compares the private key to the given private key.
+func (c Ed25519PrivateKey) Equal(x Ed25519PrivateKey) bool {
+	return ed25519.PrivateKey(c).Equal(ed25519.PrivateKey(x))
+}
+
+// PubKey returns the public key derived from the private key.
+func (c Ed25519PrivateKey) PubKey() Ed25519PublicKey {
+	publicKey := ed25519.PrivateKey(c).Public()
+	return Ed25519PublicKey(publicKey.([]byte))
+}
+
+// Sign returns the signature for the message.
+func (c Ed25519PrivateKey) Sign(message []byte) []byte {
+	signature, err := ed25519.PrivateKey(c).Sign(nil, message, &ed25519.Options{})
+	if err != nil {
+		panic(err)
+	}
+	return signature
+}
+
+// Ed25519PublicKey represents the public key for ed25519 usage. This is just a wrapper.
+type Ed25519PublicKey ed25519.PublicKey
+
+// Equal compares the public key to the given public key.
+func (c Ed25519PublicKey) Equal(x Ed25519PublicKey) bool {
+	return ed25519.PublicKey(c).Equal(ed25519.PublicKey(x))
+}
+
+// B64Encoded returns a base64 encoded string of the public key.
+func (c Ed25519PublicKey) B64Encoded() id.Curve25519 {
+	return id.Curve25519(base64.RawStdEncoding.EncodeToString(c))
+}
+
+// Verify checks the signature of the message against the givenSignature
+func (c Ed25519PublicKey) Verify(message, givenSignature []byte) bool {
+	return ed25519.Verify(ed25519.PublicKey(c), message, givenSignature)
+}
+
+// PickleLibOlm encodes the public key into target. target has to have a size of at least PickleLen() and is written to from index 0.
+// It returns the number of bytes written.
+func (c Ed25519PublicKey) PickleLibOlm(target []byte) (int, error) {
+	if len(target) < c.PickleLen() {
+		return 0, fmt.Errorf("pickle ed25519 public key: %w", olm.ErrValueTooShort)
+	}
+	if len(c) != ed25519.PublicKeySize {
+		return libolmpickle.PickleBytes(make([]byte, ed25519.PublicKeySize), target), nil
+	}
+	return libolmpickle.PickleBytes(c, target), nil
+}
+
+// UnpickleLibOlm decodes the unencryted value and populates the public key accordingly. It returns the number of bytes read.
+func (c *Ed25519PublicKey) UnpickleLibOlm(value []byte) (int, error) {
+	unpickled, readBytes, err := libolmpickle.UnpickleBytes(value, ed25519.PublicKeySize)
+	if err != nil {
+		return 0, err
+	}
+	*c = unpickled
+	return readBytes, nil
+}
+
+// PickleLen returns the number of bytes the pickled public key will have.
+func (c Ed25519PublicKey) PickleLen() int {
+	if len(c) != ed25519.PublicKeySize {
+		return libolmpickle.PickleBytesLen(make([]byte, ed25519.PublicKeySize))
+	}
+	return libolmpickle.PickleBytesLen(c)
+}
diff --git a/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/hmac.go b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/hmac.go
new file mode 100644
index 0000000..8542f7c
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/hmac.go
@@ -0,0 +1,29 @@
+package crypto
+
+import (
+	"crypto/hmac"
+	"crypto/sha256"
+	"io"
+
+	"golang.org/x/crypto/hkdf"
+)
+
+// HMACSHA256 returns the hash message authentication code with SHA-256 of the input with the key.
+func HMACSHA256(key, input []byte) []byte {
+	hash := hmac.New(sha256.New, key)
+	hash.Write(input)
+	return hash.Sum(nil)
+}
+
+// SHA256 return the SHA-256 of the value.
+func SHA256(value []byte) []byte {
+	hash := sha256.New()
+	hash.Write(value)
+	return hash.Sum(nil)
+}
+
+// HKDFSHA256 is the key deivation function based on HMAC and returns a reader based on input. salt and info can both be nil.
+// The reader can be used to read an arbitary length of bytes which are based on all parameters.
+func HKDFSHA256(input, salt, info []byte) io.Reader {
+	return hkdf.New(sha256.New, input, salt, info)
+}
diff --git a/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/one_time_key.go b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/one_time_key.go
new file mode 100644
index 0000000..aaa253d
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/one_time_key.go
@@ -0,0 +1,95 @@
+package crypto
+
+import (
+	"encoding/base64"
+	"encoding/binary"
+	"fmt"
+
+	"maunium.net/go/mautrix/crypto/goolm/libolmpickle"
+	"maunium.net/go/mautrix/crypto/olm"
+	"maunium.net/go/mautrix/id"
+)
+
+// OneTimeKey stores the information about a one time key.
+type OneTimeKey struct {
+	ID        uint32            `json:"id"`
+	Published bool              `json:"published"`
+	Key       Curve25519KeyPair `json:"key,omitempty"`
+}
+
+// Equal compares the one time key to the given one.
+func (otk OneTimeKey) Equal(s OneTimeKey) bool {
+	if otk.ID != s.ID {
+		return false
+	}
+	if otk.Published != s.Published {
+		return false
+	}
+	if !otk.Key.PrivateKey.Equal(s.Key.PrivateKey) {
+		return false
+	}
+	if !otk.Key.PublicKey.Equal(s.Key.PublicKey) {
+		return false
+	}
+	return true
+}
+
+// PickleLibOlm encodes the key pair into target. target has to have a size of at least PickleLen() and is written to from index 0.
+// It returns the number of bytes written.
+func (c OneTimeKey) PickleLibOlm(target []byte) (int, error) {
+	if len(target) < c.PickleLen() {
+		return 0, fmt.Errorf("pickle one time key: %w", olm.ErrValueTooShort)
+	}
+	written := libolmpickle.PickleUInt32(uint32(c.ID), target)
+	written += libolmpickle.PickleBool(c.Published, target[written:])
+	writtenKey, err := c.Key.PickleLibOlm(target[written:])
+	if err != nil {
+		return 0, fmt.Errorf("pickle one time key: %w", err)
+	}
+	written += writtenKey
+	return written, nil
+}
+
+// UnpickleLibOlm decodes the unencryted value and populates the OneTimeKey accordingly. It returns the number of bytes read.
+func (c *OneTimeKey) UnpickleLibOlm(value []byte) (int, error) {
+	totalReadBytes := 0
+	id, readBytes, err := libolmpickle.UnpickleUInt32(value)
+	if err != nil {
+		return 0, err
+	}
+	totalReadBytes += readBytes
+	c.ID = id
+	published, readBytes, err := libolmpickle.UnpickleBool(value[totalReadBytes:])
+	if err != nil {
+		return 0, err
+	}
+	totalReadBytes += readBytes
+	c.Published = published
+	readBytes, err = c.Key.UnpickleLibOlm(value[totalReadBytes:])
+	if err != nil {
+		return 0, err
+	}
+	totalReadBytes += readBytes
+	return totalReadBytes, nil
+}
+
+// PickleLen returns the number of bytes the pickled OneTimeKey will have.
+func (c OneTimeKey) PickleLen() int {
+	length := 0
+	length += libolmpickle.PickleUInt32Len(c.ID)
+	length += libolmpickle.PickleBoolLen(c.Published)
+	length += c.Key.PickleLen()
+	return length
+}
+
+// KeyIDEncoded returns the base64 encoded id.
+func (c OneTimeKey) KeyIDEncoded() string {
+	resSlice := make([]byte, 4)
+	binary.BigEndian.PutUint32(resSlice, c.ID)
+	return base64.RawStdEncoding.EncodeToString(resSlice)
+}
+
+// PublicKeyEncoded returns the base64 encoded public key
+func (c OneTimeKey) PublicKeyEncoded() id.Curve25519 {
+	return c.Key.PublicKey.B64Encoded()
+}
diff --git a/vendor/maunium.net/go/mautrix/crypto/goolm/libolmpickle/pickle.go b/vendor/maunium.net/go/mautrix/crypto/goolm/libolmpickle/pickle.go
new file mode 100644
index 0000000..ec125a3
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/goolm/libolmpickle/pickle.go
@@ -0,0 +1,41 @@
+package libolmpickle
+
+import (
+	"encoding/binary"
+)
+
+func PickleUInt8(value uint8, target []byte) int {
+	target[0] = value
+	return 1
+}
+func PickleUInt8Len(value uint8) int {
+	return 1
+}
+
+func PickleBool(value bool, target []byte) int {
+	if value {
+		target[0] = 0x01
+	} else {
+		target[0] = 0x00
+	}
+	return 1
+}
+func PickleBoolLen(value bool) int {
+	return 1
+}
+
+func PickleBytes(value, target []byte) int {
+	return copy(target, value)
+}
+func PickleBytesLen(value []byte) int {
+	return len(value)
+}
+
+func PickleUInt32(value uint32, target []byte) int {
+	res := make([]byte, 4) //4 bytes for int32
+	binary.BigEndian.PutUint32(res, value)
+	return copy(target, res)
+}
+func PickleUInt32Len(value uint32) int {
+	return 4
+}
diff --git a/vendor/maunium.net/go/mautrix/crypto/goolm/libolmpickle/unpickle.go b/vendor/maunium.net/go/mautrix/crypto/goolm/libolmpickle/unpickle.go
new file mode 100644
index 0000000..dbd275a
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/goolm/libolmpickle/unpickle.go
@@ -0,0 +1,53 @@
+package libolmpickle
+
+import (
+	"fmt"
+
+	"maunium.net/go/mautrix/crypto/olm"
+)
+
+func isZeroByteSlice(bytes []byte) bool {
+	b := byte(0)
+	for _, s := range bytes {
+		b |= s
+	}
+	return b == 0
+}
+
+func UnpickleUInt8(value []byte) (uint8, int, error) {
+	if len(value) < 1 {
+		return 0, 0, fmt.Errorf("unpickle uint8: %w", olm.ErrValueTooShort)
+	}
+	return value[0], 1, nil
+}
+
+func UnpickleBool(value []byte) (bool, int, error) {
+	if len(value) < 1 {
+		return false, 0, fmt.Errorf("unpickle bool: %w", olm.ErrValueTooShort)
+	}
+	return value[0] != uint8(0x00), 1, nil
+}
+
+func UnpickleBytes(value []byte, length int) ([]byte, int, error) {
+	if len(value) < length {
+		return nil, 0, fmt.Errorf("unpickle bytes: %w", olm.ErrValueTooShort)
+	}
+	resp := value[:length]
+	if isZeroByteSlice(resp) {
+		return nil, length, nil
+	}
+	return resp, length, nil
+}
+
+func UnpickleUInt32(value []byte) (uint32, int, error) {
+	if len(value) < 4 {
+		return 0, 0, fmt.Errorf("unpickle uint32: %w", olm.ErrValueTooShort)
+	}
+	var res uint32
+	count := 0
+	for i := 3; i >= 0; i-- {
+		res |= uint32(value[count]) << (8 * i)
+		count++
+	}
+	return res, 4, nil
+}