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