securesource.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  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. }
  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) Read(p []byte) (int, error) {
  37. s.mut.Lock()
  38. defer s.mut.Unlock()
  39. return s.rd.Read(p)
  40. }
  41. func (s *secureSource) Uint64() uint64 {
  42. var buf [8]byte
  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. _, err := io.ReadFull(s.rd, buf[:])
  48. s.mut.Unlock()
  49. if err != nil {
  50. panic("randomness failure: " + err.Error())
  51. }
  52. // Grab those bytes as an uint64
  53. return binary.BigEndian.Uint64(buf[:])
  54. }