1
0

securesource.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package rand
  7. import (
  8. "bufio"
  9. "crypto/rand"
  10. "encoding/binary"
  11. "io"
  12. "sync"
  13. )
  14. // The secureSource is a math/rand.Source that reads bytes from
  15. // crypto/rand.Reader. It means we can use the convenience functions
  16. // provided by math/rand.Rand on top of a secure source of numbers. It is
  17. // concurrency safe for ease of use.
  18. type secureSource struct {
  19. rd io.Reader
  20. mut sync.Mutex
  21. }
  22. func newSecureSource() *secureSource {
  23. return &secureSource{
  24. // Using buffering on top of the rand.Reader increases our
  25. // performance by about 20%, even though it means we must use
  26. // locking.
  27. rd: bufio.NewReader(rand.Reader),
  28. }
  29. }
  30. func (s *secureSource) Seed(int64) {
  31. panic("SecureSource is not seedable")
  32. }
  33. func (s *secureSource) Int63() int64 {
  34. return int64(s.Uint64() & (1<<63 - 1))
  35. }
  36. func (s *secureSource) Uint64() uint64 {
  37. var buf [8]byte
  38. // Read eight bytes of entropy from the buffered, secure random number
  39. // generator. The buffered reader isn't concurrency safe, so we lock
  40. // around that.
  41. s.mut.Lock()
  42. _, err := io.ReadFull(s.rd, buf[:])
  43. s.mut.Unlock()
  44. if err != nil {
  45. panic("randomness failure: " + err.Error())
  46. }
  47. // Grab those bytes as an uint64
  48. return binary.BigEndian.Uint64(buf[:])
  49. }