lib/util: Add secure random numbers source (fixes #3178)

The math/rand package contains lots of convenient functions, for example
to get an integer in a specified range without running into issues
caused by just truncating a number from a different distribution and so
on. But it's insecure, and we use if for things that benefit from being
more secure like session IDs, CSRF tokens and API keys.

This implements a math/rand.Source that reads from crypto/rand.Reader,
this bridging the gap between them. It also updates our RandomString to
use the new source, thus giving us secure session IDs and CSRF tokens.

Some future work remains:

 - Fix API keys by making the generation in the UI use this code as well

 - Refactor out these things into an actual random package, and audit
   our use of randomness everywhere

I'll leave both of those for the future in order to not muddy the waters
on this diff...

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3180
This commit is contained in:
Jakob Borg
2016-05-25 06:38:38 +00:00
committed by Audrius Butkevicius
parent ebce5d07ac
commit 31b5156191
3 changed files with 166 additions and 3 deletions

View File

@@ -17,17 +17,27 @@ import (
// randomCharset contains the characters that can make up a randomString().
const randomCharset = "2345679abcdefghijkmnopqrstuvwxyzACDEFGHJKLMNPQRSTUVWXYZ"
var (
// defaultSecureSource is a concurrency safe math/rand.Source with a
// cryptographically sound base.
defaltSecureSource = newSecureSource()
// defaultSecureRand is a math/rand.Rand based on the secure source.
defaultSecureRand = mathRand.New(defaltSecureSource)
)
func init() {
// The default RNG should be seeded with something good.
mathRand.Seed(RandomInt64())
}
// RandomString returns a string of random characters (taken from
// randomCharset) of the specified length.
// RandomString 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 {
bs := make([]byte, l)
for i := range bs {
bs[i] = randomCharset[mathRand.Intn(len(randomCharset))]
bs[i] = randomCharset[defaultSecureRand.Intn(len(randomCharset))]
}
return string(bs)
}