crypto: always read from crypto/rand

Signed-off-by: Sumner Evans <sumner.evans@automattic.com>
This commit is contained in:
Sumner Evans 2024-10-25 01:58:22 -06:00
commit 7cc46f1ff3
No known key found for this signature in database
19 changed files with 86 additions and 108 deletions

View file

@ -27,7 +27,7 @@ type OlmAccount struct {
}
func NewOlmAccount() *OlmAccount {
account, err := olm.NewAccount(nil)
account, err := olm.NewAccount()
if err != nil {
panic(err)
}
@ -105,7 +105,7 @@ func (account *OlmAccount) getInitialKeys(userID id.UserID, deviceID id.DeviceID
func (account *OlmAccount) getOneTimeKeys(userID id.UserID, deviceID id.DeviceID, currentOTKCount int) map[id.KeyID]mautrix.OneTimeKey {
newCount := int(account.Internal.MaxNumberOfOneTimeKeys()/2) - currentOTKCount
if newCount > 0 {
account.Internal.GenOneTimeKeys(nil, uint(newCount))
account.Internal.GenOneTimeKeys(uint(newCount))
}
oneTimeKeys := make(map[id.KeyID]mautrix.OneTimeKey)
internalKeys, err := account.Internal.OneTimeKeys()

View file

@ -6,7 +6,6 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"maunium.net/go/mautrix/id"
@ -68,15 +67,15 @@ func AccountFromPickled(pickled, key []byte) (*Account, error) {
return a, nil
}
// NewAccount creates a new Account. If reader is nil, crypto/rand is used for the key creation.
func NewAccount(reader io.Reader) (*Account, error) {
// NewAccount creates a new Account.
func NewAccount() (*Account, error) {
a := &Account{}
kPEd25519, err := crypto.Ed25519GenerateKey(reader)
kPEd25519, err := crypto.Ed25519GenerateKey()
if err != nil {
return nil, err
}
a.IdKeys.Ed25519 = kPEd25519
kPCurve25519, err := crypto.Curve25519GenerateKey(reader)
kPCurve25519, err := crypto.Curve25519GenerateKey()
if err != nil {
return nil, err
}
@ -151,14 +150,14 @@ func (a *Account) MarkKeysAsPublished() {
// GenOneTimeKeys generates a number of new one time keys. If the total number
// of keys stored by this Account exceeds MaxOneTimeKeys then the older
// keys are discarded. If reader is nil, crypto/rand is used for the key creation.
func (a *Account) GenOneTimeKeys(reader io.Reader, num uint) error {
// keys are discarded.
func (a *Account) GenOneTimeKeys(num uint) error {
for i := uint(0); i < num; i++ {
key := crypto.OneTimeKey{
Published: false,
ID: a.NextOneTimeKeyID,
}
newKP, err := crypto.Curve25519GenerateKey(reader)
newKP, err := crypto.Curve25519GenerateKey()
if err != nil {
return err
}
@ -247,14 +246,15 @@ func (a *Account) RemoveOneTimeKeys(s olm.Session) error {
//if the key is a fallback or prevFallback, don't remove it
}
// GenFallbackKey generates a new fallback key. The old fallback key is stored in a.PrevFallbackKey overwriting any previous PrevFallbackKey. If reader is nil, crypto/rand is used for the key creation.
func (a *Account) GenFallbackKey(reader io.Reader) error {
// GenFallbackKey generates a new fallback key. The old fallback key is stored
// in a.PrevFallbackKey overwriting any previous PrevFallbackKey.
func (a *Account) GenFallbackKey() error {
a.PrevFallbackKey = a.CurrentFallbackKey
key := crypto.OneTimeKey{
Published: false,
ID: a.NextOneTimeKeyID,
}
newKP, err := crypto.Curve25519GenerateKey(reader)
newKP, err := crypto.Curve25519GenerateKey()
if err != nil {
return err
}

View file

@ -17,15 +17,15 @@ import (
)
func TestAccount(t *testing.T) {
firstAccount, err := account.NewAccount(nil)
firstAccount, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
err = firstAccount.GenFallbackKey(nil)
err = firstAccount.GenFallbackKey()
if err != nil {
t.Fatal(err)
}
err = firstAccount.GenOneTimeKeys(nil, 2)
err = firstAccount.GenOneTimeKeys(2)
if err != nil {
t.Fatal(err)
}
@ -118,19 +118,19 @@ func TestAccountPickleJSON(t *testing.T) {
}
func TestSessions(t *testing.T) {
aliceAccount, err := account.NewAccount(nil)
aliceAccount, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
err = aliceAccount.GenOneTimeKeys(nil, 5)
err = aliceAccount.GenOneTimeKeys(5)
if err != nil {
t.Fatal(err)
}
bobAccount, err := account.NewAccount(nil)
bobAccount, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
err = bobAccount.GenOneTimeKeys(nil, 5)
err = bobAccount.GenOneTimeKeys(5)
if err != nil {
t.Fatal(err)
}
@ -217,7 +217,7 @@ func TestOldAccountPickle(t *testing.T) {
"K/A/8TOu9iK2hDFszy6xETiousHnHgh2ZGbRUh4pQx+YMm8ZdNZeRnwFGLnrWyf9" +
"O5TmXua1FcU")
pickleKey := []byte("")
account, err := account.NewAccount(nil)
account, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
@ -232,16 +232,16 @@ func TestOldAccountPickle(t *testing.T) {
}
func TestLoopback(t *testing.T) {
accountA, err := account.NewAccount(nil)
accountA, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
accountB, err := account.NewAccount(nil)
accountB, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
err = accountB.GenOneTimeKeys(nil, 42)
err = accountB.GenOneTimeKeys(42)
if err != nil {
t.Fatal(err)
}
@ -328,16 +328,16 @@ func TestLoopback(t *testing.T) {
}
func TestMoreMessages(t *testing.T) {
accountA, err := account.NewAccount(nil)
accountA, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
accountB, err := account.NewAccount(nil)
accountB, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
err = accountB.GenOneTimeKeys(nil, 42)
err = accountB.GenOneTimeKeys(42)
if err != nil {
t.Fatal(err)
}
@ -411,16 +411,16 @@ func TestMoreMessages(t *testing.T) {
}
func TestFallbackKey(t *testing.T) {
accountA, err := account.NewAccount(nil)
accountA, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
accountB, err := account.NewAccount(nil)
accountB, err := account.NewAccount()
if err != nil {
t.Fatal(err)
}
err = accountB.GenFallbackKey(nil)
err = accountB.GenFallbackKey()
if err != nil {
t.Fatal(err)
}
@ -483,7 +483,7 @@ func TestFallbackKey(t *testing.T) {
}
// create a new fallback key for B (the old fallback should still be usable)
err = accountB.GenFallbackKey(nil)
err = accountB.GenFallbackKey()
if err != nil {
t.Fatal(err)
}
@ -602,7 +602,7 @@ func TestOldV3AccountPickle(t *testing.T) {
}
func TestAccountSign(t *testing.T) {
accountA, err := account.NewAccount(nil)
accountA, err := account.NewAccount()
require.NoError(t, err)
plainText := []byte("Hello, World")
signatureB64, err := accountA.Sign(plainText)

View file

@ -7,14 +7,12 @@
package account
import (
"io"
"maunium.net/go/mautrix/crypto/olm"
)
func init() {
olm.InitNewAccount = func(r io.Reader) (olm.Account, error) {
return NewAccount(r)
olm.InitNewAccount = func() (olm.Account, error) {
return NewAccount()
}
olm.InitBlankAccount = func() olm.Account {
return &Account{}

View file

@ -5,7 +5,6 @@ import (
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"golang.org/x/crypto/curve25519"
@ -19,19 +18,11 @@ const (
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) {
// Curve25519GenerateKey creates a new curve25519 key pair.
func Curve25519GenerateKey() (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
}
if _, err := rand.Read(privateKeyByte); err != nil {
return Curve25519KeyPair{}, err
}
privateKey := Curve25519PrivateKey(privateKeyByte)

View file

@ -8,11 +8,11 @@ import (
)
func TestCurve25519(t *testing.T) {
firstKeypair, err := crypto.Curve25519GenerateKey(nil)
firstKeypair, err := crypto.Curve25519GenerateKey()
if err != nil {
t.Fatal(err)
}
secondKeypair, err := crypto.Curve25519GenerateKey(nil)
secondKeypair, err := crypto.Curve25519GenerateKey()
if err != nil {
t.Fatal(err)
}
@ -93,7 +93,7 @@ func TestCurve25519Case1(t *testing.T) {
func TestCurve25519Pickle(t *testing.T) {
//create keypair
keyPair, err := crypto.Curve25519GenerateKey(nil)
keyPair, err := crypto.Curve25519GenerateKey()
if err != nil {
t.Fatal(err)
}
@ -124,7 +124,7 @@ func TestCurve25519Pickle(t *testing.T) {
func TestCurve25519PicklePubKeyOnly(t *testing.T) {
//create keypair
keyPair, err := crypto.Curve25519GenerateKey(nil)
keyPair, err := crypto.Curve25519GenerateKey()
if err != nil {
t.Fatal(err)
}
@ -156,7 +156,7 @@ func TestCurve25519PicklePubKeyOnly(t *testing.T) {
func TestCurve25519PicklePrivKeyOnly(t *testing.T) {
//create keypair
keyPair, err := crypto.Curve25519GenerateKey(nil)
keyPair, err := crypto.Curve25519GenerateKey()
if err != nil {
t.Fatal(err)
}

View file

@ -3,7 +3,6 @@ package crypto
import (
"encoding/base64"
"fmt"
"io"
"maunium.net/go/mautrix/crypto/ed25519"
"maunium.net/go/mautrix/crypto/goolm/libolmpickle"
@ -15,9 +14,9 @@ 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)
// Ed25519GenerateKey creates a new ed25519 key pair.
func Ed25519GenerateKey() (Ed25519KeyPair, error) {
publicKey, privateKey, err := ed25519.GenerateKey(nil)
if err != nil {
return Ed25519KeyPair{}, err
}

View file

@ -8,7 +8,7 @@ import (
)
func TestEd25519(t *testing.T) {
keypair, err := crypto.Ed25519GenerateKey(nil)
keypair, err := crypto.Ed25519GenerateKey()
if err != nil {
t.Fatal(err)
}
@ -21,7 +21,7 @@ func TestEd25519(t *testing.T) {
func TestEd25519Case1(t *testing.T) {
//64 bytes for ed25519 package
keyPair, err := crypto.Ed25519GenerateKey(nil)
keyPair, err := crypto.Ed25519GenerateKey()
if err != nil {
t.Fatal(err)
}
@ -46,7 +46,7 @@ func TestEd25519Case1(t *testing.T) {
func TestEd25519Pickle(t *testing.T) {
//create keypair
keyPair, err := crypto.Ed25519GenerateKey(nil)
keyPair, err := crypto.Ed25519GenerateKey()
if err != nil {
t.Fatal(err)
}
@ -77,7 +77,7 @@ func TestEd25519Pickle(t *testing.T) {
func TestEd25519PicklePubKeyOnly(t *testing.T) {
//create keypair
keyPair, err := crypto.Ed25519GenerateKey(nil)
keyPair, err := crypto.Ed25519GenerateKey()
if err != nil {
t.Fatal(err)
}
@ -109,7 +109,7 @@ func TestEd25519PicklePubKeyOnly(t *testing.T) {
func TestEd25519PicklePrivKeyOnly(t *testing.T) {
//create keypair
keyPair, err := crypto.Ed25519GenerateKey(nil)
keyPair, err := crypto.Ed25519GenerateKey()
if err != nil {
t.Fatal(err)
}

View file

@ -26,7 +26,7 @@ type Decryption struct {
// NewDecryption returns a new Decryption with a new generated key pair.
func NewDecryption() (*Decryption, error) {
keyPair, err := crypto.Curve25519GenerateKey(nil)
keyPair, err := crypto.Curve25519GenerateKey()
if err != nil {
return nil, err
}

View file

@ -94,11 +94,11 @@ func (r *Ratchet) InitializeAsAlice(sharedSecret []byte, ourRatchetKey crypto.Cu
return nil
}
// Encrypt encrypts the message in a message.Message with MAC. If reader is nil, crypto/rand is used for key generations.
// Encrypt encrypts the message in a message.Message with MAC.
func (r *Ratchet) Encrypt(plaintext []byte) ([]byte, error) {
var err error
if !r.SenderChains.IsSet {
newRatchetKey, err := crypto.Curve25519GenerateKey(nil)
newRatchetKey, err := crypto.Curve25519GenerateKey()
if err != nil {
return nil, err
}
@ -132,7 +132,7 @@ func (r *Ratchet) Encrypt(plaintext []byte) ([]byte, error) {
return output, nil
}
// Decrypt decrypts the ciphertext and verifies the MAC. If reader is nil, crypto/rand is used for key generations.
// Decrypt decrypts the ciphertext and verifies the MAC.
func (r *Ratchet) Decrypt(input []byte) ([]byte, error) {
message := &message.Message{}
//The mac is not verified here, as we do not know the key yet

View file

@ -26,7 +26,7 @@ func initializeRatchets() (*ratchet.Ratchet, *ratchet.Ratchet, error) {
aliceRatchet := ratchet.New()
bobRatchet := ratchet.New()
aliceKey, err := crypto.Curve25519GenerateKey(nil)
aliceKey, err := crypto.Curve25519GenerateKey()
if err != nil {
return nil, nil, err
}

View file

@ -35,7 +35,7 @@ var _ olm.OutboundGroupSession = (*MegolmOutboundSession)(nil)
func NewMegolmOutboundSession() (*MegolmOutboundSession, error) {
o := &MegolmOutboundSession{}
var err error
o.SigningKey, err = crypto.Ed25519GenerateKey(nil)
o.SigningKey, err = crypto.Ed25519GenerateKey()
if err != nil {
return nil, err
}

View file

@ -18,7 +18,7 @@ func TestOutboundPickleJSON(t *testing.T) {
if err != nil {
t.Fatal(err)
}
kp, err := crypto.Ed25519GenerateKey(nil)
kp, err := crypto.Ed25519GenerateKey()
if err != nil {
t.Fatal(err)
}
@ -50,7 +50,7 @@ func TestOutboundPickleJSON(t *testing.T) {
func TestInboundPickleJSON(t *testing.T) {
pickleKey := []byte("secretKey")
sess := session.MegolmInboundSession{}
kp, err := crypto.Ed25519GenerateKey(nil)
kp, err := crypto.Ed25519GenerateKey()
if err != nil {
t.Fatal(err)
}

View file

@ -80,12 +80,12 @@ func NewOlmSession() *OlmSession {
func NewOutboundOlmSession(identityKeyAlice crypto.Curve25519KeyPair, identityKeyBob crypto.Curve25519PublicKey, oneTimeKeyBob crypto.Curve25519PublicKey) (*OlmSession, error) {
s := NewOlmSession()
//generate E_A
baseKey, err := crypto.Curve25519GenerateKey(nil)
baseKey, err := crypto.Curve25519GenerateKey()
if err != nil {
return nil, err
}
//generate T_0
ratchetKey, err := crypto.Curve25519GenerateKey(nil)
ratchetKey, err := crypto.Curve25519GenerateKey()
if err != nil {
return nil, err
}

View file

@ -14,15 +14,15 @@ import (
func TestOlmSession(t *testing.T) {
pickleKey := []byte("secretKey")
aliceKeyPair, err := crypto.Curve25519GenerateKey(nil)
aliceKeyPair, err := crypto.Curve25519GenerateKey()
if err != nil {
t.Fatal(err)
}
bobKeyPair, err := crypto.Curve25519GenerateKey(nil)
bobKeyPair, err := crypto.Curve25519GenerateKey()
if err != nil {
t.Fatal(err)
}
bobOneTimeKey, err := crypto.Curve25519GenerateKey(nil)
bobOneTimeKey, err := crypto.Curve25519GenerateKey()
if err != nil {
t.Fatal(err)
}

View file

@ -8,7 +8,6 @@ import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"io"
"unsafe"
"github.com/tidwall/gjson"
@ -24,8 +23,8 @@ type Account struct {
}
func init() {
olm.InitNewAccount = func(r io.Reader) (olm.Account, error) {
return NewAccount(r)
olm.InitNewAccount = func() (olm.Account, error) {
return NewAccount()
}
olm.InitBlankAccount = func() olm.Account {
return NewBlankAccount()
@ -60,13 +59,10 @@ func NewBlankAccount() *Account {
}
// NewAccount creates a new [Account].
func NewAccount(r io.Reader) (*Account, error) {
func NewAccount() (*Account, error) {
a := NewBlankAccount()
random := make([]byte, a.createRandomLen()+1)
if r == nil {
r = rand.Reader
}
_, err := r.Read(random)
_, err := rand.Read(random)
if err != nil {
panic(olm.NotEnoughGoRandom)
}
@ -307,12 +303,9 @@ func (a *Account) MaxNumberOfOneTimeKeys() uint {
// GenOneTimeKeys generates a number of new one time keys. If the total number
// of keys stored by this Account exceeds MaxNumberOfOneTimeKeys then the old
// keys are discarded.
func (a *Account) GenOneTimeKeys(reader io.Reader, num uint) error {
func (a *Account) GenOneTimeKeys(num uint) error {
random := make([]byte, a.genOneTimeKeysRandomLen(num)+1)
if reader == nil {
reader = rand.Reader
}
_, err := reader.Read(random)
_, err := rand.Read(random)
if err != nil {
return olm.NotEnoughGoRandom
}

View file

@ -7,8 +7,6 @@
package olm
import (
"io"
"maunium.net/go/mautrix/id"
)
@ -57,9 +55,8 @@ type Account interface {
// GenOneTimeKeys generates a number of new one time keys. If the total
// number of keys stored by this Account exceeds MaxNumberOfOneTimeKeys
// then the old keys are discarded. Reads random data from the given
// reader, or if nil is passed, defaults to crypto/rand.
GenOneTimeKeys(reader io.Reader, num uint) error
// then the old keys are discarded.
GenOneTimeKeys(num uint) error
// NewOutboundSession creates a new out-bound session for sending messages to a
// given curve25519 identityKey and oneTimeKey. Returns error on failure. If the
@ -91,12 +88,12 @@ type Account interface {
}
var InitBlankAccount func() Account
var InitNewAccount func(io.Reader) (Account, error)
var InitNewAccount func() (Account, error)
var InitNewAccountFromPickled func(pickled, key []byte) (Account, error)
// NewAccount creates a new Account.
func NewAccount(r io.Reader) (Account, error) {
return InitNewAccount(r)
func NewAccount() (Account, error) {
return InitNewAccount()
}
func NewBlankAccount() Account {

View file

@ -49,10 +49,10 @@ func ensureAccountsEqual(t *testing.T, a, b olm.Account) {
// TestAccount_UnpickleLibolmToGoolm tests creating an account from libolm,
// pickling it, and importing it into goolm.
func TestAccount_UnpickleLibolmToGoolm(t *testing.T) {
libolmAccount, err := libolm.NewAccount(nil)
libolmAccount, err := libolm.NewAccount()
require.NoError(t, err)
require.NoError(t, libolmAccount.GenOneTimeKeys(nil, 50))
require.NoError(t, libolmAccount.GenOneTimeKeys(50))
libolmPickled, err := libolmAccount.Pickle([]byte("test"))
require.NoError(t, err)
@ -70,10 +70,10 @@ func TestAccount_UnpickleLibolmToGoolm(t *testing.T) {
// TestAccount_UnpickleGoolmToLibolm tests creating an account from goolm,
// pickling it, and importing it into libolm.
func TestAccount_UnpickleGoolmToLibolm(t *testing.T) {
goolmAccount, err := account.NewAccount(nil)
goolmAccount, err := account.NewAccount()
require.NoError(t, err)
require.NoError(t, goolmAccount.GenOneTimeKeys(nil, 50))
require.NoError(t, goolmAccount.GenOneTimeKeys(50))
goolmPickled, err := goolmAccount.Pickle([]byte("test"))
require.NoError(t, err)
@ -91,7 +91,7 @@ func TestAccount_UnpickleGoolmToLibolm(t *testing.T) {
func FuzzAccount_Sign(f *testing.F) {
f.Add([]byte("anything"))
libolmAccount := exerrors.Must(libolm.NewAccount(nil))
libolmAccount := exerrors.Must(libolm.NewAccount())
goolmAccount := exerrors.Must(account.AccountFromPickled(exerrors.Must(libolmAccount.Pickle([]byte("test"))), []byte("test")))
f.Fuzz(func(t *testing.T, message []byte) {

View file

@ -60,16 +60,16 @@ func TestSessionPickle(t *testing.T) {
func TestSession_EncryptDecrypt(t *testing.T) {
combos := [][2]olm.Account{
{exerrors.Must(libolm.NewAccount(nil)), exerrors.Must(libolm.NewAccount(nil))},
{exerrors.Must(account.NewAccount(nil)), exerrors.Must(account.NewAccount(nil))},
{exerrors.Must(libolm.NewAccount(nil)), exerrors.Must(account.NewAccount(nil))},
{exerrors.Must(account.NewAccount(nil)), exerrors.Must(libolm.NewAccount(nil))},
{exerrors.Must(libolm.NewAccount()), exerrors.Must(libolm.NewAccount())},
{exerrors.Must(account.NewAccount()), exerrors.Must(account.NewAccount())},
{exerrors.Must(libolm.NewAccount()), exerrors.Must(account.NewAccount())},
{exerrors.Must(account.NewAccount()), exerrors.Must(libolm.NewAccount())},
}
for _, combo := range combos {
receiver, sender := combo[0], combo[1]
require.NoError(t, receiver.GenOneTimeKeys(nil, 50))
require.NoError(t, sender.GenOneTimeKeys(nil, 50))
require.NoError(t, receiver.GenOneTimeKeys(50))
require.NoError(t, sender.GenOneTimeKeys(50))
_, receiverCurve25519, err := receiver.IdentityKeys()
require.NoError(t, err)