You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.3 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package rand
  2. import (
  3. crand "crypto/rand"
  4. "encoding/binary"
  5. "fmt"
  6. mrand "math/rand"
  7. )
  8. const (
  9. strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters
  10. )
  11. func init() {
  12. Reseed()
  13. }
  14. // NewRand returns a prng, that is seeded with OS randomness.
  15. // The OS randomness is obtained from crypto/rand, however, like with any math/rand.Rand
  16. // object none of the provided methods are suitable for cryptographic usage.
  17. //
  18. // Note that the returned instance of math/rand's Rand is not
  19. // suitable for concurrent use by multiple goroutines.
  20. //
  21. // For concurrent use, call Reseed to reseed math/rand's default source and
  22. // use math/rand's top-level convenience functions instead.
  23. func NewRand() *mrand.Rand {
  24. seed := crandSeed()
  25. // nolint:gosec // G404: Use of weak random number generator
  26. return mrand.New(mrand.NewSource(seed))
  27. }
  28. // Reseed conveniently re-seeds the default Source of math/rand with
  29. // randomness obtained from crypto/rand.
  30. //
  31. // Note that this does not make math/rand suitable for cryptographic usage.
  32. //
  33. // Use math/rand's top-level convenience functions remain suitable
  34. // for concurrent use by multiple goroutines.
  35. func Reseed() {
  36. seed := crandSeed()
  37. mrand.Seed(seed)
  38. }
  39. // Str constructs a random alphanumeric string of given length
  40. // from math/rand's global default Source.
  41. func Str(length int) string {
  42. if length <= 0 {
  43. return ""
  44. }
  45. chars := make([]byte, 0, length)
  46. for {
  47. // nolint:gosec // G404: Use of weak random number generator
  48. val := mrand.Int63()
  49. for i := 0; i < 10; i++ {
  50. v := int(val & 0x3f) // rightmost 6 bits
  51. if v >= 62 { // only 62 characters in strChars
  52. val >>= 6
  53. continue
  54. } else {
  55. chars = append(chars, strChars[v])
  56. if len(chars) == length {
  57. return string(chars)
  58. }
  59. val >>= 6
  60. }
  61. }
  62. }
  63. }
  64. // Bytes returns n random bytes generated from math/rand's global default Source.
  65. func Bytes(n int) []byte {
  66. bs := make([]byte, n)
  67. for i := 0; i < len(bs); i++ {
  68. // nolint:gosec // G404: Use of weak random number generator
  69. bs[i] = byte(mrand.Int() & 0xFF)
  70. }
  71. return bs
  72. }
  73. func crandSeed() int64 {
  74. var seed int64
  75. err := binary.Read(crand.Reader, binary.BigEndian, &seed)
  76. if err != nil {
  77. panic(fmt.Sprintf("could nor read random seed from crypto/rand: %v", err))
  78. }
  79. return seed
  80. }