lib/rand: Break out random functions into separate package

The intention for this package is to provide a combination of the
security of crypto/rand and the convenience of math/rand. It should be
the first choice of random data unless ultimate performance is required
and the usage is provably irrelevant from a security standpoint.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3186
This commit is contained in:
Jakob Borg 2016-05-26 07:02:56 +00:00 committed by Audrius Butkevicius
parent 410d700ae3
commit e6b78e5d56
10 changed files with 42 additions and 31 deletions

View File

@ -35,11 +35,11 @@ import (
"github.com/syncthing/syncthing/lib/model"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/stats"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/util"
"github.com/vitrun/qart/qr"
"golang.org/x/crypto/bcrypt"
)
@ -750,7 +750,7 @@ func (s *apiService) postSystemConfig(w http.ResponseWriter, r *http.Request) {
if curAcc := s.cfg.Options().URAccepted; to.Options.URAccepted > curAcc {
// UR was enabled
to.Options.URAccepted = usageReportVersion
to.Options.URUniqueID = util.RandomString(8)
to.Options.URUniqueID = rand.String(8)
} else if to.Options.URAccepted < curAcc {
// UR was disabled
to.Options.URAccepted = -1

View File

@ -9,15 +9,14 @@ package main
import (
"bytes"
"encoding/base64"
"math/rand"
"net/http"
"strings"
"time"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/util"
"golang.org/x/crypto/bcrypt"
)
@ -114,7 +113,7 @@ func basicAuthAndSessionMiddleware(cookieName string, cfg config.GUIConfiguratio
return
passwordOK:
sessionid := util.RandomString(32)
sessionid := rand.String(32)
sessionsMut.Lock()
sessions[sessionid] = true
sessionsMut.Unlock()

View File

@ -15,8 +15,8 @@ import (
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/util"
)
// csrfTokens is a list of valid tokens. It is sorted so that the most
@ -87,7 +87,7 @@ func validCsrfToken(token string) bool {
}
func newCsrfToken() string {
token := util.RandomString(32)
token := rand.String(32)
csrfMut.Lock()
csrfTokens = append([]string{token}, csrfTokens...)

View File

@ -39,10 +39,10 @@ import (
"github.com/syncthing/syncthing/lib/model"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/symlinks"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/util"
"github.com/thejerf/suture"
)
@ -761,7 +761,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
if opts.URUniqueID == "" {
// Previously the ID was generated from the node ID. We now need
// to generate a new one.
opts.URUniqueID = util.RandomString(8)
opts.URUniqueID = rand.String(8)
cfg.SetOptions(opts)
cfg.Save()
}
@ -947,7 +947,7 @@ func defaultConfig(myName string) config.Configuration {
if !noDefaultFolder {
l.Infoln("Default folder created and/or linked to new config")
folderID := util.RandomString(5) + "-" + util.RandomString(5)
folderID := rand.String(5) + "-" + rand.String(5)
defaultFolder = config.NewFolderConfiguration(folderID, locations[locDefFolder])
defaultFolder.Label = "Default Folder (" + folderID + ")"
defaultFolder.RescanIntervalS = 60

View File

@ -19,6 +19,7 @@ import (
"strings"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/util"
)
@ -254,7 +255,7 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) {
}
if cfg.GUI.APIKey == "" {
cfg.GUI.APIKey = util.RandomString(32)
cfg.GUI.APIKey = rand.String(32)
}
}

View File

@ -4,7 +4,9 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package util
// Package rand implements functions similar to math/rand in the standard
// library, but on top of a secure random number generator.
package rand
import (
"crypto/md5"
@ -14,6 +16,9 @@ import (
mathRand "math/rand"
)
// Reader is the standard crypto/rand.Reader, re-exported for convenience
var Reader = cryptoRand.Reader
// randomCharset contains the characters that can make up a randomString().
const randomCharset = "2345679abcdefghijkmnopqrstuvwxyzACDEFGHJKLMNPQRSTUVWXYZ"
@ -26,15 +31,10 @@ var (
defaultSecureRand = mathRand.New(defaltSecureSource)
)
func init() {
// The default RNG should be seeded with something good.
mathRand.Seed(RandomInt64())
}
// RandomString returns a strongly random string of characters (taken from
// String returns a strongly random string of characters (taken from
// randomCharset) of the specified length. The returned string contains ~5.8
// bits of entropy per character, due to the character set used.
func RandomString(l int) string {
func String(l int) string {
bs := make([]byte, l)
for i := range bs {
bs[i] = randomCharset[defaultSecureRand.Intn(len(randomCharset))]
@ -42,14 +42,25 @@ func RandomString(l int) string {
return string(bs)
}
// RandomInt64 returns a strongly random int64, slowly
func RandomInt64() int64 {
// Int63 returns a strongly random int63
func Int63() int64 {
return defaltSecureSource.Int63()
}
// Int64 returns a strongly random int64
func Int64() int64 {
var bs [8]byte
_, err := io.ReadFull(cryptoRand.Reader, bs[:])
if err != nil {
panic("randomness failure: " + err.Error())
}
return SeedFromBytes(bs[:])
return int64(binary.BigEndian.Uint64(bs[:]))
}
// Intn returns, as an int, a non-negative strongly random number in [0,n).
// It panics if n <= 0.
func Intn(n int) int {
return defaultSecureRand.Intn(n)
}
// SeedFromBytes calculates a weak 64 bit hash from the given byte slice,

View File

@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package util
package rand
import "testing"
@ -27,7 +27,7 @@ func TestSeedFromBytes(t *testing.T) {
func TestRandomString(t *testing.T) {
for _, l := range []int{0, 1, 2, 3, 4, 8, 42} {
s := RandomString(l)
s := String(l)
if len(s) != l {
t.Errorf("Incorrect length %d != %d", len(s), l)
}
@ -35,7 +35,7 @@ func TestRandomString(t *testing.T) {
strings := make([]string, 1000)
for i := range strings {
strings[i] = RandomString(8)
strings[i] = String(8)
for j := range strings {
if i == j {
continue
@ -50,7 +50,7 @@ func TestRandomString(t *testing.T) {
func TestRandomInt64(t *testing.T) {
ints := make([]int64, 1000)
for i := range ints {
ints[i] = RandomInt64()
ints[i] = Int64()
for j := range ints {
if i == j {
continue

View File

@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package util
package rand
import (
"bufio"

View File

@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package util
package rand
import "testing"

View File

@ -10,7 +10,6 @@ import (
"bufio"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
@ -19,10 +18,11 @@ import (
"fmt"
"io"
"math/big"
mr "math/rand"
"net"
"os"
"time"
"github.com/syncthing/syncthing/lib/rand"
)
var (
@ -48,7 +48,7 @@ func NewCertificate(certFile, keyFile, tlsDefaultCommonName string, tlsRSABits i
notAfter := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
template := x509.Certificate{
SerialNumber: new(big.Int).SetInt64(mr.Int63()),
SerialNumber: new(big.Int).SetInt64(rand.Int63()),
Subject: pkix.Name{
CommonName: tlsDefaultCommonName,
},