From bc1f09086f61995d0227caa68dae29c2e4f6bccd Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Thu, 24 Oct 2024 20:34:53 -0600 Subject: [PATCH] goolm: use constants for pickle lengths when possible Signed-off-by: Sumner Evans --- crypto/goolm/account/account.go | 16 +++---- crypto/goolm/crypto/curve25519.go | 38 +++++---------- crypto/goolm/crypto/curve25519_test.go | 6 +-- crypto/goolm/crypto/ed25519.go | 37 +++++--------- crypto/goolm/crypto/ed25519_test.go | 6 +-- crypto/goolm/crypto/one_time_key.go | 15 ++---- crypto/goolm/libolmpickle/pickle.go | 15 +++--- crypto/goolm/libolmpickle/pickle_test.go | 6 +-- crypto/goolm/megolm/megolm.go | 12 ++--- crypto/goolm/pk/decryption.go | 19 ++++---- crypto/goolm/ratchet/chain.go | 48 +++++++------------ crypto/goolm/ratchet/olm.go | 24 +++++----- crypto/goolm/ratchet/skipped_message.go | 12 ++--- .../goolm/session/megolm_inbound_session.go | 21 ++++---- .../goolm/session/megolm_outbound_session.go | 16 +++---- crypto/goolm/session/olm_session.go | 20 ++++---- 16 files changed, 119 insertions(+), 192 deletions(-) diff --git a/crypto/goolm/account/account.go b/crypto/goolm/account/account.go index 4708fba1..dcb4c9d4 100644 --- a/crypto/goolm/account/account.go +++ b/crypto/goolm/account/account.go @@ -488,14 +488,14 @@ func (a *Account) PickleLibOlm(target []byte) (int, error) { // PickleLen returns the number of bytes the pickled Account will have. func (a *Account) PickleLen() int { - length := libolmpickle.PickleUInt32Len(accountPickleVersionLibOLM) - length += a.IdKeys.Ed25519.PickleLen() - length += a.IdKeys.Curve25519.PickleLen() - length += libolmpickle.PickleUInt32Len(uint32(len(a.OTKeys))) - length += (len(a.OTKeys) * (&crypto.OneTimeKey{}).PickleLen()) - length += libolmpickle.PickleUInt8Len(a.NumFallbackKeys) - length += (int(a.NumFallbackKeys) * (&crypto.OneTimeKey{}).PickleLen()) - length += libolmpickle.PickleUInt32Len(a.NextOneTimeKeyID) + length := libolmpickle.PickleUInt32Length + length += crypto.Ed25519KeyPairPickleLength // IdKeys.Ed25519 + length += crypto.Curve25519KeyPairPickleLength // IdKeys.Curve25519 + length += libolmpickle.PickleUInt32Length + length += (len(a.OTKeys) * crypto.OneTimeKeyPickleLength) + length += libolmpickle.PickleUInt8Length + length += (int(a.NumFallbackKeys) * crypto.OneTimeKeyPickleLength) + length += libolmpickle.PickleUInt32Length return length } diff --git a/crypto/goolm/crypto/curve25519.go b/crypto/goolm/crypto/curve25519.go index 2ae20e0e..01ada7e0 100644 --- a/crypto/goolm/crypto/curve25519.go +++ b/crypto/goolm/crypto/curve25519.go @@ -15,7 +15,7 @@ import ( const ( Curve25519KeyLength = curve25519.ScalarSize //The length of the private key. - curve25519PubKeyLength = 32 + Curve25519PubKeyLength = 32 ) // Curve25519GenerateKey creates a new curve25519 key pair. @@ -51,6 +51,9 @@ type Curve25519KeyPair struct { PublicKey Curve25519PublicKey `json:"public,omitempty"` } +const Curve25519KeyPairPickleLength = Curve25519PubKeyLength + // Public Key + Curve25519KeyLength // Private Key + // B64Encoded returns a base64 encoded string of the public key. func (c Curve25519KeyPair) B64Encoded() id.Curve25519 { return c.PublicKey.B64Encoded() @@ -61,10 +64,11 @@ func (c Curve25519KeyPair) SharedSecret(pubKey Curve25519PublicKey) ([]byte, err 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. +// PickleLibOlm encodes the key pair into target. The target has to have a size +// of at least [Curve25519KeyPairPickleLength] 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() { + if len(target) < Curve25519KeyPairPickleLength { return 0, fmt.Errorf("pickle curve25519 key pair: %w", olm.ErrValueTooShort) } written, err := c.PublicKey.PickleLibOlm(target) @@ -95,18 +99,6 @@ func (c *Curve25519KeyPair) UnpickleLibOlm(value []byte) (int, error) { 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 @@ -141,29 +133,21 @@ func (c Curve25519PublicKey) B64Encoded() id.Curve25519 { // 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() { + if len(target) < Curve25519PubKeyLength { return 0, fmt.Errorf("pickle curve25519 public key: %w", olm.ErrValueTooShort) } - if len(c) != curve25519PubKeyLength { - return libolmpickle.PickleBytes(make([]byte, curve25519PubKeyLength), target), nil + 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) + 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/crypto/goolm/crypto/curve25519_test.go b/crypto/goolm/crypto/curve25519_test.go index b7c86eee..fc8ee54b 100644 --- a/crypto/goolm/crypto/curve25519_test.go +++ b/crypto/goolm/crypto/curve25519_test.go @@ -74,7 +74,7 @@ func TestCurve25519Pickle(t *testing.T) { //create keypair keyPair, err := crypto.Curve25519GenerateKey() assert.NoError(t, err) - target := make([]byte, keyPair.PickleLen()) + target := make([]byte, crypto.Curve25519KeyPairPickleLength) writtenBytes, err := keyPair.PickleLibOlm(target) assert.NoError(t, err) assert.Len(t, target, writtenBytes) @@ -92,7 +92,7 @@ func TestCurve25519PicklePubKeyOnly(t *testing.T) { assert.NoError(t, err) //Remove privateKey keyPair.PrivateKey = nil - target := make([]byte, keyPair.PickleLen()) + target := make([]byte, crypto.Curve25519KeyPairPickleLength) writtenBytes, err := keyPair.PickleLibOlm(target) assert.NoError(t, err) assert.Len(t, target, writtenBytes) @@ -109,7 +109,7 @@ func TestCurve25519PicklePrivKeyOnly(t *testing.T) { assert.NoError(t, err) //Remove public keyPair.PublicKey = nil - target := make([]byte, keyPair.PickleLen()) + target := make([]byte, crypto.Curve25519KeyPairPickleLength) writtenBytes, err := keyPair.PickleLibOlm(target) assert.NoError(t, err) assert.Len(t, target, writtenBytes) diff --git a/crypto/goolm/crypto/ed25519.go b/crypto/goolm/crypto/ed25519.go index ceb3818b..abacb1ee 100644 --- a/crypto/goolm/crypto/ed25519.go +++ b/crypto/goolm/crypto/ed25519.go @@ -46,6 +46,9 @@ type Ed25519KeyPair struct { PublicKey Ed25519PublicKey `json:"public,omitempty"` } +const Ed25519KeyPairPickleLength = ed25519.PublicKeySize + // PublicKey + ed25519.PrivateKeySize // Private Key + // B64Encoded returns a base64 encoded string of the public key. func (c Ed25519KeyPair) B64Encoded() id.Ed25519 { return id.Ed25519(base64.RawStdEncoding.EncodeToString(c.PublicKey)) @@ -61,10 +64,11 @@ 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. +// PickleLibOlm encodes the key pair into target. target has to have a size of +// at least [Ed25519KeyPairPickleLength] 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() { + if len(target) < Ed25519KeyPairPickleLength { return 0, fmt.Errorf("pickle ed25519 key pair: %w", olm.ErrValueTooShort) } written, err := c.PublicKey.PickleLibOlm(target) @@ -96,18 +100,6 @@ func (c *Ed25519KeyPair) UnpickleLibOlm(value []byte) (int, error) { 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 @@ -149,10 +141,11 @@ 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. +// PickleLibOlm encodes the public key into target. target has to have a size +// of at least [ed25519.PublicKeySize] 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() { + if len(target) < ed25519.PublicKeySize { return 0, fmt.Errorf("pickle ed25519 public key: %w", olm.ErrValueTooShort) } if len(c) != ed25519.PublicKeySize { @@ -170,11 +163,3 @@ func (c *Ed25519PublicKey) UnpickleLibOlm(value []byte) (int, error) { *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/crypto/goolm/crypto/ed25519_test.go b/crypto/goolm/crypto/ed25519_test.go index 41fb0977..e5314622 100644 --- a/crypto/goolm/crypto/ed25519_test.go +++ b/crypto/goolm/crypto/ed25519_test.go @@ -38,7 +38,7 @@ func TestEd25519Pickle(t *testing.T) { //create keypair keyPair, err := crypto.Ed25519GenerateKey() assert.NoError(t, err) - target := make([]byte, keyPair.PickleLen()) + target := make([]byte, crypto.Ed25519KeyPairPickleLength) writtenBytes, err := keyPair.PickleLibOlm(target) assert.NoError(t, err) assert.Len(t, target, writtenBytes) @@ -56,7 +56,7 @@ func TestEd25519PicklePubKeyOnly(t *testing.T) { assert.NoError(t, err) //Remove privateKey keyPair.PrivateKey = nil - target := make([]byte, keyPair.PickleLen()) + target := make([]byte, crypto.Ed25519KeyPairPickleLength) writtenBytes, err := keyPair.PickleLibOlm(target) assert.NoError(t, err) assert.Len(t, target, writtenBytes) @@ -74,7 +74,7 @@ func TestEd25519PicklePrivKeyOnly(t *testing.T) { assert.NoError(t, err) //Remove public keyPair.PublicKey = nil - target := make([]byte, keyPair.PickleLen()) + target := make([]byte, crypto.Ed25519KeyPairPickleLength) writtenBytes, err := keyPair.PickleLibOlm(target) assert.NoError(t, err) assert.Len(t, target, writtenBytes) diff --git a/crypto/goolm/crypto/one_time_key.go b/crypto/goolm/crypto/one_time_key.go index aaa253d2..2fbd6366 100644 --- a/crypto/goolm/crypto/one_time_key.go +++ b/crypto/goolm/crypto/one_time_key.go @@ -17,6 +17,10 @@ type OneTimeKey struct { Key Curve25519KeyPair `json:"key,omitempty"` } +const OneTimeKeyPickleLength = libolmpickle.PickleUInt32Length + // ID + libolmpickle.PickleBoolLength + // Published + Curve25519KeyPairPickleLength // Key + // Equal compares the one time key to the given one. func (otk OneTimeKey) Equal(s OneTimeKey) bool { if otk.ID != s.ID { @@ -37,7 +41,7 @@ func (otk OneTimeKey) Equal(s OneTimeKey) bool { // 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() { + if len(target) < OneTimeKeyPickleLength { return 0, fmt.Errorf("pickle one time key: %w", olm.ErrValueTooShort) } written := libolmpickle.PickleUInt32(uint32(c.ID), target) @@ -73,15 +77,6 @@ func (c *OneTimeKey) UnpickleLibOlm(value []byte) (int, error) { 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) diff --git a/crypto/goolm/libolmpickle/pickle.go b/crypto/goolm/libolmpickle/pickle.go index ec125a34..bedeee04 100644 --- a/crypto/goolm/libolmpickle/pickle.go +++ b/crypto/goolm/libolmpickle/pickle.go @@ -4,13 +4,16 @@ import ( "encoding/binary" ) +const ( + PickleBoolLength = 1 + PickleUInt8Length = 1 + PickleUInt32Length = 4 +) + 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 { @@ -20,9 +23,6 @@ func PickleBool(value bool, target []byte) int { } return 1 } -func PickleBoolLen(value bool) int { - return 1 -} func PickleBytes(value, target []byte) int { return copy(target, value) @@ -36,6 +36,3 @@ func PickleUInt32(value uint32, target []byte) int { binary.BigEndian.PutUint32(res, value) return copy(target, res) } -func PickleUInt32Len(value uint32) int { - return 4 -} diff --git a/crypto/goolm/libolmpickle/pickle_test.go b/crypto/goolm/libolmpickle/pickle_test.go index 27f083a0..d5596b2a 100644 --- a/crypto/goolm/libolmpickle/pickle_test.go +++ b/crypto/goolm/libolmpickle/pickle_test.go @@ -24,7 +24,7 @@ func TestPickleUInt32(t *testing.T) { for curIndex := range values { response := make([]byte, 4) resPLen := libolmpickle.PickleUInt32(values[curIndex], response) - assert.Equal(t, libolmpickle.PickleUInt32Len(values[curIndex]), resPLen) + assert.Equal(t, libolmpickle.PickleUInt32Length, resPLen) assert.Equal(t, expected[curIndex], response) } } @@ -41,7 +41,7 @@ func TestPickleBool(t *testing.T) { for curIndex := range values { response := make([]byte, 1) resPLen := libolmpickle.PickleBool(values[curIndex], response) - assert.Equal(t, libolmpickle.PickleBoolLen(values[curIndex]), resPLen) + assert.Equal(t, libolmpickle.PickleBoolLength, resPLen) assert.Equal(t, expected[curIndex], response) } } @@ -58,7 +58,7 @@ func TestPickleUInt8(t *testing.T) { for curIndex := range values { response := make([]byte, 1) resPLen := libolmpickle.PickleUInt8(values[curIndex], response) - assert.Equal(t, libolmpickle.PickleUInt8Len(values[curIndex]), resPLen) + assert.Equal(t, libolmpickle.PickleUInt8Length, resPLen) assert.Equal(t, expected[curIndex], response) } } diff --git a/crypto/goolm/megolm/megolm.go b/crypto/goolm/megolm/megolm.go index c88583ee..47e24077 100644 --- a/crypto/goolm/megolm/megolm.go +++ b/crypto/goolm/megolm/megolm.go @@ -22,6 +22,9 @@ const ( protocolVersion = 3 RatchetParts = 4 // number of ratchet parts RatchetPartLength = 256 / 8 // length of each ratchet part in bytes + + RatchetPickleLength = (RatchetParts * RatchetPartLength) + //Data + libolmpickle.PickleUInt32Length // Counter ) var RatchetCipher = cipher.NewAESSHA256([]byte("MEGOLM_KEYS")) @@ -219,17 +222,10 @@ func (r *Ratchet) UnpickleLibOlm(unpickled []byte) (int, error) { // PickleLibOlm encodes the ratchet 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 (r Ratchet) PickleLibOlm(target []byte) (int, error) { - if len(target) < r.PickleLen() { + if len(target) < RatchetPickleLength { return 0, fmt.Errorf("pickle account: %w", olm.ErrValueTooShort) } written := libolmpickle.PickleBytes(r.Data[:], target) written += libolmpickle.PickleUInt32(r.Counter, target[written:]) return written, nil } - -// PickleLen returns the number of bytes the pickled ratchet will have. -func (r Ratchet) PickleLen() int { - length := libolmpickle.PickleBytesLen(r.Data[:]) - length += libolmpickle.PickleUInt32Len(r.Counter) - return length -} diff --git a/crypto/goolm/pk/decryption.go b/crypto/goolm/pk/decryption.go index 76dfa0da..fb537eaf 100644 --- a/crypto/goolm/pk/decryption.go +++ b/crypto/goolm/pk/decryption.go @@ -17,6 +17,9 @@ import ( const ( decryptionPickleVersionJSON uint8 = 1 decryptionPickleVersionLibOlm uint32 = 1 + + DecryptionPickleLength = libolmpickle.PickleUInt32Length + // Version + crypto.Curve25519KeyPairPickleLength // KeyPair ) // Decryption is used to decrypt pk messages @@ -124,7 +127,7 @@ func (a *Decryption) UnpickleLibOlm(value []byte) (int, error) { // Pickle returns a base64 encoded and with key encrypted pickled Decryption using PickleLibOlm(). func (a Decryption) Pickle(key []byte) ([]byte, error) { - pickeledBytes := make([]byte, a.PickleLen()) + pickeledBytes := make([]byte, DecryptionPickleLength) written, err := a.PickleLibOlm(pickeledBytes) if err != nil { return nil, err @@ -135,10 +138,11 @@ func (a Decryption) Pickle(key []byte) ([]byte, error) { return cipher.Pickle(key, pickeledBytes) } -// PickleLibOlm encodes the Decryption 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. +// PickleLibOlm encodes the Decryption into target. target has to have a size +// of at least [DecryptionPickleLength] and is written to from index 0. It +// returns the number of bytes written. func (a Decryption) PickleLibOlm(target []byte) (int, error) { - if len(target) < a.PickleLen() { + if len(target) < DecryptionPickleLength { return 0, fmt.Errorf("pickle Decryption: %w", olm.ErrValueTooShort) } written := libolmpickle.PickleUInt32(decryptionPickleVersionLibOlm, target) @@ -149,10 +153,3 @@ func (a Decryption) PickleLibOlm(target []byte) (int, error) { written += writtenKey return written, nil } - -// PickleLen returns the number of bytes the pickled Decryption will have. -func (a Decryption) PickleLen() int { - length := libolmpickle.PickleUInt32Len(decryptionPickleVersionLibOlm) - length += a.KeyPair.PickleLen() - return length -} diff --git a/crypto/goolm/ratchet/chain.go b/crypto/goolm/ratchet/chain.go index 2c2789b7..ea0400e8 100644 --- a/crypto/goolm/ratchet/chain.go +++ b/crypto/goolm/ratchet/chain.go @@ -19,6 +19,9 @@ type chainKey struct { Key crypto.Curve25519PublicKey `json:"key"` } +const chainKeyPickleLength = crypto.Curve25519PubKeyLength + // Key + libolmpickle.PickleUInt32Length // Index + // advance advances the chain func (c *chainKey) advance() { c.Key = crypto.HMACSHA256(c.Key, []byte{chainKeySeed}) @@ -44,7 +47,7 @@ func (r *chainKey) UnpickleLibOlm(value []byte) (int, error) { // PickleLibOlm encodes the chain 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 (r chainKey) PickleLibOlm(target []byte) (int, error) { - if len(target) < r.PickleLen() { + if len(target) < chainKeyPickleLength { return 0, fmt.Errorf("pickle chain key: %w", olm.ErrValueTooShort) } written, err := r.Key.PickleLibOlm(target) @@ -55,13 +58,6 @@ func (r chainKey) PickleLibOlm(target []byte) (int, error) { return written, nil } -// PickleLen returns the number of bytes the pickled chain key will have. -func (r chainKey) PickleLen() int { - length := r.Key.PickleLen() - length += libolmpickle.PickleUInt32Len(r.Index) - return length -} - // senderChain is a chain for sending messages type senderChain struct { RKey crypto.Curve25519KeyPair `json:"ratchet_key"` @@ -69,6 +65,9 @@ type senderChain struct { IsSet bool `json:"set"` } +const senderChainPickleLength = chainKeyPickleLength + // RKey + chainKeyPickleLength // CKey + // newSenderChain returns a sender chain initialized with chainKey and ratchet key pair. func newSenderChain(key crypto.Curve25519PublicKey, ratchet crypto.Curve25519KeyPair) *senderChain { return &senderChain{ @@ -115,7 +114,7 @@ func (r *senderChain) UnpickleLibOlm(value []byte) (int, error) { // PickleLibOlm encodes the chain 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 (r senderChain) PickleLibOlm(target []byte) (int, error) { - if len(target) < r.PickleLen() { + if len(target) < senderChainPickleLength { return 0, fmt.Errorf("pickle sender chain: %w", olm.ErrValueTooShort) } written, err := r.RKey.PickleLibOlm(target) @@ -130,19 +129,15 @@ func (r senderChain) PickleLibOlm(target []byte) (int, error) { return written, nil } -// PickleLen returns the number of bytes the pickled chain will have. -func (r senderChain) PickleLen() int { - length := r.RKey.PickleLen() - length += r.CKey.PickleLen() - return length -} - // senderChain is a chain for receiving messages type receiverChain struct { RKey crypto.Curve25519PublicKey `json:"ratchet_key"` CKey chainKey `json:"chain_key"` } +const receiverChainPickleLength = crypto.Curve25519PubKeyLength + // Ratchet Key + chainKeyPickleLength // CKey + // newReceiverChain returns a receiver chain initialized with chainKey and ratchet public key. func newReceiverChain(chain crypto.Curve25519PublicKey, ratchet crypto.Curve25519PublicKey) *receiverChain { return &receiverChain{ @@ -188,7 +183,7 @@ func (r *receiverChain) UnpickleLibOlm(value []byte) (int, error) { // PickleLibOlm encodes the chain 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 (r receiverChain) PickleLibOlm(target []byte) (int, error) { - if len(target) < r.PickleLen() { + if len(target) < receiverChainPickleLength { return 0, fmt.Errorf("pickle sender chain: %w", olm.ErrValueTooShort) } written, err := r.RKey.PickleLibOlm(target) @@ -203,19 +198,15 @@ func (r receiverChain) PickleLibOlm(target []byte) (int, error) { return written, nil } -// PickleLen returns the number of bytes the pickled chain will have. -func (r receiverChain) PickleLen() int { - length := r.RKey.PickleLen() - length += r.CKey.PickleLen() - return length -} - // messageKey wraps the index and the key of a message type messageKey struct { Index uint32 `json:"index"` Key []byte `json:"key"` } +const messageKeyPickleLength = messageKeyLength + // Key + libolmpickle.PickleUInt32Length // Index + // UnpickleLibOlm decodes the unencryted value and populates the message key accordingly. It returns the number of bytes read. func (m *messageKey) UnpickleLibOlm(value []byte) (int, error) { curPos := 0 @@ -237,7 +228,7 @@ func (m *messageKey) UnpickleLibOlm(value []byte) (int, error) { // PickleLibOlm encodes the message 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 (m messageKey) PickleLibOlm(target []byte) (int, error) { - if len(target) < m.PickleLen() { + if len(target) < messageKeyPickleLength { return 0, fmt.Errorf("pickle message key: %w", olm.ErrValueTooShort) } written := 0 @@ -249,10 +240,3 @@ func (m messageKey) PickleLibOlm(target []byte) (int, error) { written += libolmpickle.PickleUInt32(m.Index, target[written:]) return written, nil } - -// PickleLen returns the number of bytes the pickled message key will have. -func (r messageKey) PickleLen() int { - length := libolmpickle.PickleBytesLen(make([]byte, messageKeyLength)) - length += libolmpickle.PickleUInt32Len(r.Index) - return length -} diff --git a/crypto/goolm/ratchet/olm.go b/crypto/goolm/ratchet/olm.go index 879f6cfe..8e0944d4 100644 --- a/crypto/goolm/ratchet/olm.go +++ b/crypto/goolm/ratchet/olm.go @@ -388,25 +388,25 @@ func (r Ratchet) PickleLibOlm(target []byte) (int, error) { // PickleLen returns the actual number of bytes the pickled ratchet will have. func (r Ratchet) PickleLen() int { - length := r.RootKey.PickleLen() + length := crypto.Curve25519PubKeyLength // Root Key if r.SenderChains.IsSet { - length += libolmpickle.PickleUInt32Len(1) - length += r.SenderChains.PickleLen() + length += libolmpickle.PickleUInt32Length // 1 + length += senderChainPickleLength // SenderChains } else { - length += libolmpickle.PickleUInt32Len(0) + length += libolmpickle.PickleUInt32Length // 0 } - length += libolmpickle.PickleUInt32Len(uint32(len(r.ReceiverChains))) - length += len(r.ReceiverChains) * receiverChain{}.PickleLen() - length += libolmpickle.PickleUInt32Len(uint32(len(r.SkippedMessageKeys))) - length += len(r.SkippedMessageKeys) * skippedMessageKey{}.PickleLen() + length += libolmpickle.PickleUInt32Length // ReceiverChains length + length += len(r.ReceiverChains) * receiverChainPickleLength + length += libolmpickle.PickleUInt32Length // SkippedMessageKeys length + length += len(r.SkippedMessageKeys) * skippedMessageKeyPickleLen return length } // PickleLen returns the minimum number of bytes the pickled ratchet must have. func (r Ratchet) PickleLenMin() int { - length := r.RootKey.PickleLen() - length += libolmpickle.PickleUInt32Len(0) - length += libolmpickle.PickleUInt32Len(0) - length += libolmpickle.PickleUInt32Len(0) + length := crypto.Curve25519PubKeyLength // Root Key + length += libolmpickle.PickleUInt32Length + length += libolmpickle.PickleUInt32Length + length += libolmpickle.PickleUInt32Length return length } diff --git a/crypto/goolm/ratchet/skipped_message.go b/crypto/goolm/ratchet/skipped_message.go index 79927480..b577edbe 100644 --- a/crypto/goolm/ratchet/skipped_message.go +++ b/crypto/goolm/ratchet/skipped_message.go @@ -13,6 +13,9 @@ type skippedMessageKey struct { MKey messageKey `json:"message_key"` } +const skippedMessageKeyPickleLen = crypto.Curve25519PubKeyLength + // RKey + messageKeyPickleLength // MKey + // UnpickleLibOlm decodes the unencryted value and populates the chain accordingly. It returns the number of bytes read. func (r *skippedMessageKey) UnpickleLibOlm(value []byte) (int, error) { curPos := 0 @@ -32,7 +35,7 @@ func (r *skippedMessageKey) UnpickleLibOlm(value []byte) (int, error) { // PickleLibOlm encodes the chain 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 (r skippedMessageKey) PickleLibOlm(target []byte) (int, error) { - if len(target) < r.PickleLen() { + if len(target) < skippedMessageKeyPickleLen { return 0, fmt.Errorf("pickle sender chain: %w", olm.ErrValueTooShort) } written, err := r.RKey.PickleLibOlm(target) @@ -46,10 +49,3 @@ func (r skippedMessageKey) PickleLibOlm(target []byte) (int, error) { written += writtenChain return written, nil } - -// PickleLen returns the number of bytes the pickled chain will have. -func (r skippedMessageKey) PickleLen() int { - length := r.RKey.PickleLen() - length += r.MKey.PickleLen() - return length -} diff --git a/crypto/goolm/session/megolm_inbound_session.go b/crypto/goolm/session/megolm_inbound_session.go index bfb24322..50ca4d97 100644 --- a/crypto/goolm/session/megolm_inbound_session.go +++ b/crypto/goolm/session/megolm_inbound_session.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "maunium.net/go/mautrix/crypto/ed25519" "maunium.net/go/mautrix/crypto/goolm/cipher" "maunium.net/go/mautrix/crypto/goolm/crypto" "maunium.net/go/mautrix/crypto/goolm/goolmbase64" @@ -19,6 +20,12 @@ import ( const ( megolmInboundSessionPickleVersionJSON byte = 1 megolmInboundSessionPickleVersionLibOlm uint32 = 2 + + megolmInboundSessionPickleLength = libolmpickle.PickleUInt32Length + // Version + megolm.RatchetPickleLength + // InitialRatchet + megolm.RatchetPickleLength + // Ratchet + ed25519.PublicKeySize + // SigningKey + libolmpickle.PickleBoolLength // Verified ) // MegolmInboundSession stores information about the sessions of receive. @@ -246,7 +253,7 @@ func (o *MegolmInboundSession) Pickle(key []byte) ([]byte, error) { if len(key) == 0 { return nil, olm.ErrNoKeyProvided } - pickeledBytes := make([]byte, o.PickleLen()) + pickeledBytes := make([]byte, megolmInboundSessionPickleLength) written, err := o.PickleLibOlm(pickeledBytes) if err != nil { return nil, err @@ -260,7 +267,7 @@ func (o *MegolmInboundSession) Pickle(key []byte) ([]byte, error) { // PickleLibOlm encodes the session 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 (o *MegolmInboundSession) PickleLibOlm(target []byte) (int, error) { - if len(target) < o.PickleLen() { + if len(target) < megolmInboundSessionPickleLength { return 0, fmt.Errorf("pickle MegolmInboundSession: %w", olm.ErrValueTooShort) } written := libolmpickle.PickleUInt32(megolmInboundSessionPickleVersionLibOlm, target) @@ -283,16 +290,6 @@ func (o *MegolmInboundSession) PickleLibOlm(target []byte) (int, error) { return written, nil } -// PickleLen returns the number of bytes the pickled session will have. -func (o *MegolmInboundSession) PickleLen() int { - length := libolmpickle.PickleUInt32Len(megolmInboundSessionPickleVersionLibOlm) - length += o.InitialRatchet.PickleLen() - length += o.Ratchet.PickleLen() - length += o.SigningKey.PickleLen() - length += libolmpickle.PickleBoolLen(o.SigningKeyVerified) - return length -} - // FirstKnownIndex returns the first message index we know how to decrypt. func (s *MegolmInboundSession) FirstKnownIndex() uint32 { return s.InitialRatchet.Counter diff --git a/crypto/goolm/session/megolm_outbound_session.go b/crypto/goolm/session/megolm_outbound_session.go index e85a5c12..d58650ce 100644 --- a/crypto/goolm/session/megolm_outbound_session.go +++ b/crypto/goolm/session/megolm_outbound_session.go @@ -21,6 +21,10 @@ import ( const ( megolmOutboundSessionPickleVersion byte = 1 megolmOutboundSessionPickleVersionLibOlm uint32 = 1 + + MegolmOutboundSessionPickleLength = libolmpickle.PickleUInt32Length + // Version + megolm.RatchetPickleLength + // Ratchet + crypto.Ed25519KeyPairPickleLength // SigningKey ) // MegolmOutboundSession stores information about the sessions to send. @@ -130,7 +134,7 @@ func (o *MegolmOutboundSession) Pickle(key []byte) ([]byte, error) { if len(key) == 0 { return nil, olm.ErrNoKeyProvided } - pickeledBytes := make([]byte, o.PickleLen()) + pickeledBytes := make([]byte, MegolmOutboundSessionPickleLength) written, err := o.PickleLibOlm(pickeledBytes) if err != nil { return nil, err @@ -144,7 +148,7 @@ func (o *MegolmOutboundSession) Pickle(key []byte) ([]byte, error) { // PickleLibOlm encodes the session 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 (o *MegolmOutboundSession) PickleLibOlm(target []byte) (int, error) { - if len(target) < o.PickleLen() { + if len(target) < MegolmOutboundSessionPickleLength { return 0, fmt.Errorf("pickle MegolmOutboundSession: %w", olm.ErrValueTooShort) } written := libolmpickle.PickleUInt32(megolmOutboundSessionPickleVersionLibOlm, target) @@ -161,14 +165,6 @@ func (o *MegolmOutboundSession) PickleLibOlm(target []byte) (int, error) { return written, nil } -// PickleLen returns the number of bytes the pickled session will have. -func (o *MegolmOutboundSession) PickleLen() int { - length := libolmpickle.PickleUInt32Len(megolmOutboundSessionPickleVersionLibOlm) - length += o.Ratchet.PickleLen() - length += o.SigningKey.PickleLen() - return length -} - func (o *MegolmOutboundSession) SessionSharingMessage() ([]byte, error) { return o.Ratchet.SessionSharingMessage(o.SigningKey) } diff --git a/crypto/goolm/session/olm_session.go b/crypto/goolm/session/olm_session.go index f58edf87..2c9585b3 100644 --- a/crypto/goolm/session/olm_session.go +++ b/crypto/goolm/session/olm_session.go @@ -458,22 +458,22 @@ func (o *OlmSession) PickleLibOlm(target []byte) (int, error) { // PickleLen returns the actual number of bytes the pickled session will have. func (o *OlmSession) PickleLen() int { - length := libolmpickle.PickleUInt32Len(olmSessionPickleVersionLibOlm) - length += libolmpickle.PickleBoolLen(o.ReceivedMessage) - length += o.AliceIdentityKey.PickleLen() - length += o.AliceBaseKey.PickleLen() - length += o.BobOneTimeKey.PickleLen() + length := libolmpickle.PickleUInt32Length + length += libolmpickle.PickleBoolLength + length += crypto.Curve25519PubKeyLength // AliceIdentityKey + length += crypto.Curve25519PubKeyLength // AliceBaseKey + length += crypto.Curve25519PubKeyLength // BobOneTimeKey length += o.Ratchet.PickleLen() return length } // PickleLenMin returns the minimum number of bytes the pickled session must have. func (o *OlmSession) PickleLenMin() int { - length := libolmpickle.PickleUInt32Len(olmSessionPickleVersionLibOlm) - length += libolmpickle.PickleBoolLen(o.ReceivedMessage) - length += o.AliceIdentityKey.PickleLen() - length += o.AliceBaseKey.PickleLen() - length += o.BobOneTimeKey.PickleLen() + length := libolmpickle.PickleUInt32Length + length += libolmpickle.PickleBoolLength + length += crypto.Curve25519PubKeyLength // AliceIdentityKey + length += crypto.Curve25519PubKeyLength // AliceBaseKey + length += crypto.Curve25519PubKeyLength // BobOneTimeKey length += o.Ratchet.PickleLenMin() return length }