github.com/karalabe/go-ethereum@v0.8.5/crypto/randentropy/rand_entropy.go (about) 1 package randentropy 2 3 import ( 4 crand "crypto/rand" 5 "encoding/binary" 6 "github.com/ethereum/go-ethereum/crypto/sha3" 7 "io" 8 "os" 9 "strings" 10 "time" 11 ) 12 13 var Reader io.Reader = &randEntropy{} 14 15 type randEntropy struct { 16 } 17 18 func (*randEntropy) Read(bytes []byte) (n int, err error) { 19 readBytes := GetEntropyMixed(len(bytes)) 20 copy(bytes, readBytes) 21 return len(bytes), nil 22 } 23 24 // TODO: copied from crypto.go , move to sha3 package? 25 func Sha3(data []byte) []byte { 26 d := sha3.NewKeccak256() 27 d.Write(data) 28 29 return d.Sum(nil) 30 } 31 32 // TODO: verify. this needs to be audited 33 // we start with crypt/rand, then XOR in additional entropy from OS 34 func GetEntropyMixed(n int) []byte { 35 startTime := time.Now().UnixNano() 36 // for each source, we take SHA3 of the source and use it as seed to math/rand 37 // then read bytes from it and XOR them onto the bytes read from crypto/rand 38 mainBuff := GetEntropyCSPRNG(n) 39 // 1. OS entropy sources 40 startTimeBytes := make([]byte, 32) 41 binary.PutVarint(startTimeBytes, startTime) 42 startTimeHash := Sha3(startTimeBytes) 43 mixBytes(mainBuff, startTimeHash) 44 45 pid := os.Getpid() 46 pidBytes := make([]byte, 32) 47 binary.PutUvarint(pidBytes, uint64(pid)) 48 pidHash := Sha3(pidBytes) 49 mixBytes(mainBuff, pidHash) 50 51 osEnv := os.Environ() 52 osEnvBytes := []byte(strings.Join(osEnv, "")) 53 osEnvHash := Sha3(osEnvBytes) 54 mixBytes(mainBuff, osEnvHash) 55 56 // not all OS have hostname in env variables 57 osHostName, err := os.Hostname() 58 if err != nil { 59 osHostNameBytes := []byte(osHostName) 60 osHostNameHash := Sha3(osHostNameBytes) 61 mixBytes(mainBuff, osHostNameHash) 62 } 63 return mainBuff 64 } 65 66 func GetEntropyCSPRNG(n int) []byte { 67 mainBuff := make([]byte, n) 68 _, err := io.ReadFull(crand.Reader, mainBuff) 69 if err != nil { 70 panic("reading from crypto/rand failed: " + err.Error()) 71 } 72 return mainBuff 73 } 74 75 func mixBytes(buff []byte, mixBuff []byte) []byte { 76 bytesToMix := len(buff) 77 if bytesToMix > 32 { 78 bytesToMix = 32 79 } 80 for i := 0; i < bytesToMix; i++ { 81 buff[i] ^= mixBuff[i] 82 } 83 return buff 84 }