securesource.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  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 + io.Reader 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. buf [8]byte
  22. }
  23. func newSecureSource() *secureSource {
  24. return &secureSource{
  25. // Using buffering on top of the rand.Reader increases our
  26. // performance by about 20%, even though it means we must use
  27. // locking.
  28. rd: bufio.NewReader(rand.Reader),
  29. }
  30. }
  31. func (*secureSource) Seed(int64) {
  32. panic("SecureSource is not seedable")
  33. }
  34. func (s *secureSource) Int63() int64 {
  35. return int64(s.Uint64() & (1<<63 - 1))
  36. }
  37. func (s *secureSource) Read(p []byte) (int, error) {
  38. s.mut.Lock()
  39. defer s.mut.Unlock()
  40. return s.rd.Read(p)
  41. }
  42. func (s *secureSource) Uint64() uint64 {
  43. // Read eight bytes of entropy from the buffered, secure random number
  44. // generator. The buffered reader isn't concurrency safe, so we lock
  45. // around that.
  46. s.mut.Lock()
  47. defer s.mut.Unlock()
  48. _, err := io.ReadFull(s.rd, s.buf[:])
  49. if err != nil {
  50. panic("randomness failure: " + err.Error())
  51. }
  52. return binary.LittleEndian.Uint64(s.buf[:])
  53. }