securesource.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  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. var buf [8]byte
  35. // Read eight bytes of entropy from the buffered, secure random number
  36. // generator. The buffered reader isn't concurrency safe, so we lock
  37. // around that.
  38. s.mut.Lock()
  39. _, err := io.ReadFull(s.rd, buf[:])
  40. s.mut.Unlock()
  41. if err != nil {
  42. panic("randomness failure: " + err.Error())
  43. }
  44. // Grab those bytes as an uint64
  45. v := binary.BigEndian.Uint64(buf[:])
  46. // Mask of the high bit and return the resulting int63
  47. return int64(v & (1<<63 - 1))
  48. }