diff options
Diffstat (limited to 'vendor/maunium.net/go/mautrix/crypto/goolm')
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 +} |