package rand import ( crand "crypto/rand" "encoding/binary" "fmt" mrand "math/rand" ) const ( strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters ) func init() { Reseed() } // NewRand returns a prng, that is seeded with OS randomness. // The OS randomness is obtained from crypto/rand, however, like with any math/rand.Rand // object none of the provided methods are suitable for cryptographic usage. // // Note that the returned instance of math/rand's Rand is not // suitable for concurrent use by multiple goroutines. // // For concurrent use, call Reseed to reseed math/rand's default source and // use math/rand's top-level convenience functions instead. func NewRand() *mrand.Rand { seed := crandSeed() // nolint:gosec // G404: Use of weak random number generator return mrand.New(mrand.NewSource(seed)) } // Reseed conveniently re-seeds the default Source of math/rand with // randomness obtained from crypto/rand. // // Note that this does not make math/rand suitable for cryptographic usage. // // Use math/rand's top-level convenience functions remain suitable // for concurrent use by multiple goroutines. func Reseed() { seed := crandSeed() mrand.Seed(seed) } // Str constructs a random alphanumeric string of given length // from math/rand's global default Source. func Str(length int) string { if length <= 0 { return "" } chars := make([]byte, 0, length) for { // nolint:gosec // G404: Use of weak random number generator val := mrand.Int63() for i := 0; i < 10; i++ { v := int(val & 0x3f) // rightmost 6 bits if v >= 62 { // only 62 characters in strChars val >>= 6 continue } else { chars = append(chars, strChars[v]) if len(chars) == length { return string(chars) } val >>= 6 } } } } // Bytes returns n random bytes generated from math/rand's global default Source. func Bytes(n int) []byte { bs := make([]byte, n) for i := 0; i < len(bs); i++ { // nolint:gosec // G404: Use of weak random number generator bs[i] = byte(mrand.Int() & 0xFF) } return bs } func crandSeed() int64 { var seed int64 err := binary.Read(crand.Reader, binary.BigEndian, &seed) if err != nil { panic(fmt.Sprintf("could nor read random seed from crypto/rand: %v", err)) } return seed }