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.

100 lines
2.3 KiB

  1. package crypto
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. crand "crypto/rand"
  6. "encoding/hex"
  7. "io"
  8. "sync"
  9. . "github.com/tendermint/go-common"
  10. )
  11. var gRandInfo *randInfo
  12. func init() {
  13. gRandInfo = &randInfo{}
  14. gRandInfo.MixEntropy(randBytes(32)) // Init
  15. }
  16. // Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
  17. // It is OK to call it multiple times. It does not diminish security.
  18. func MixEntropy(seedBytes []byte) {
  19. gRandInfo.MixEntropy(seedBytes)
  20. }
  21. // This only uses the OS's randomness
  22. func randBytes(numBytes int) []byte {
  23. b := make([]byte, numBytes)
  24. _, err := crand.Read(b)
  25. if err != nil {
  26. PanicCrisis(err)
  27. }
  28. return b
  29. }
  30. // This uses the OS and the Seed(s).
  31. func CRandBytes(numBytes int) []byte {
  32. b := make([]byte, numBytes)
  33. _, err := gRandInfo.Read(b)
  34. if err != nil {
  35. PanicCrisis(err)
  36. }
  37. return b
  38. }
  39. // RandHex(24) gives 96 bits of randomness, strong enough for most purposes.
  40. func CRandHex(numDigits int) string {
  41. return hex.EncodeToString(CRandBytes(numDigits / 2))
  42. }
  43. // Returns a crand.Reader mixed with user-supplied entropy
  44. func CReader() io.Reader {
  45. return gRandInfo
  46. }
  47. //--------------------------------------------------------------------------------
  48. type randInfo struct {
  49. mtx sync.Mutex
  50. seedBytes [32]byte
  51. cipherAES256 cipher.Block
  52. streamAES256 cipher.Stream
  53. reader io.Reader
  54. }
  55. // You can call this as many times as you'd like.
  56. // XXX TODO review
  57. func (ri *randInfo) MixEntropy(seedBytes []byte) {
  58. ri.mtx.Lock()
  59. defer ri.mtx.Unlock()
  60. // Make new ri.seedBytes
  61. hashBytes := Sha256(seedBytes)
  62. hashBytes32 := [32]byte{}
  63. copy(hashBytes32[:], hashBytes)
  64. ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
  65. // Create new cipher.Block
  66. var err error
  67. ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
  68. if err != nil {
  69. PanicSanity("Error creating AES256 cipher: " + err.Error())
  70. }
  71. // Create new stream
  72. ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
  73. // Create new reader
  74. ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
  75. }
  76. func (ri *randInfo) Read(b []byte) (n int, err error) {
  77. ri.mtx.Lock()
  78. defer ri.mtx.Unlock()
  79. return ri.reader.Read(b)
  80. }
  81. func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
  82. for i, b := range bytesA {
  83. res[i] = b ^ bytesB[i]
  84. }
  85. return res
  86. }