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.

103 lines
2.4 KiB

8 years ago
  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/tmlibs/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. // CRandHex returns a hex encoded string that's floor(numDigits/2) * 2 long.
  40. //
  41. // Note: CRandHex(24) gives 96 bits of randomness that
  42. // are usually strong enough for most purposes.
  43. func CRandHex(numDigits int) string {
  44. return hex.EncodeToString(CRandBytes(numDigits / 2))
  45. }
  46. // Returns a crand.Reader mixed with user-supplied entropy
  47. func CReader() io.Reader {
  48. return gRandInfo
  49. }
  50. //--------------------------------------------------------------------------------
  51. type randInfo struct {
  52. mtx sync.Mutex
  53. seedBytes [32]byte
  54. cipherAES256 cipher.Block
  55. streamAES256 cipher.Stream
  56. reader io.Reader
  57. }
  58. // You can call this as many times as you'd like.
  59. // XXX TODO review
  60. func (ri *randInfo) MixEntropy(seedBytes []byte) {
  61. ri.mtx.Lock()
  62. defer ri.mtx.Unlock()
  63. // Make new ri.seedBytes
  64. hashBytes := Sha256(seedBytes)
  65. hashBytes32 := [32]byte{}
  66. copy(hashBytes32[:], hashBytes)
  67. ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
  68. // Create new cipher.Block
  69. var err error
  70. ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
  71. if err != nil {
  72. PanicSanity("Error creating AES256 cipher: " + err.Error())
  73. }
  74. // Create new stream
  75. ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
  76. // Create new reader
  77. ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
  78. }
  79. func (ri *randInfo) Read(b []byte) (n int, err error) {
  80. ri.mtx.Lock()
  81. defer ri.mtx.Unlock()
  82. return ri.reader.Read(b)
  83. }
  84. func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
  85. for i, b := range bytesA {
  86. res[i] = b ^ bytesB[i]
  87. }
  88. return res
  89. }