gitee.com/mirrors_u-root/u-root@v7.0.0+incompatible/pkg/rng/entropy.go (about) 1 // Copyright 2017-2019 the u-root Authors. 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 rng 6 7 import ( 8 "errors" 9 "io/ioutil" 10 "os" 11 "strconv" 12 "strings" 13 "time" 14 15 "github.com/u-root/u-root/pkg/recovery" 16 ) 17 18 // The concept 19 // 20 // Most systems in real world application do not provide enough entropy at boot 21 // time. Therefore we will seed /dev/random with /dev/hwrng if a HW random 22 // number generator is available. Entropy is important for cryptographic 23 // protocols running in network stacks. Also disk encryption can be a problem 24 // if bad or no entropy is available. It can either block provisioning or makes 25 // a symmetric key easy to re-calculate. 26 27 var ( 28 // HwRandomCurrentFile shows/sets the current 29 // HW random number generator 30 HwRandomCurrentFile = "/sys/class/misc/hw_random/rng_current" 31 // HwRandomAvailableFile shows the current available 32 // HW random number generator 33 HwRandomAvailableFile = "/sys/class/misc/hw_random/rng_available" 34 // RandomEntropyAvailableFile shows how much of the entropy poolsize is used 35 RandomEntropyAvailableFile = "/proc/sys/kernel/random/entropy_avail" 36 // EntropyFeedTime sets the loop time for seeding /dev/random by /dev/hwrng 37 // in seconds 38 EntropyFeedTime = 2 * time.Second 39 // EntropyBlockSize sets the bytes to read per Read function call 40 EntropyBlockSize = 128 41 // EntropyThreshold is used to stop seeding at specific entropy level 42 EntropyThreshold uint64 = 3000 43 // RandomDevice is the linux random device 44 RandomDevice = "/dev/random" 45 // HwRandomDevice is the linux hw random device 46 HwRandomDevice = "/dev/hwrng" 47 ) 48 49 // trngList is a list of hw random number generator 50 // names used by the Linux kernel. 51 // Can be extended but keep in mind to priorize 52 // more secure random sources like hw random over 53 // timer, jitter based mechanisms. At the top of the array 54 // is the highest priority. 55 // <rng-name> 56 var trngList = []string{ 57 "tpm-rng", 58 "intel-rng", 59 "amd-rng", 60 "timeriomem-rng", 61 } 62 63 // setAvailableTRNG searches for available True Random Number Generator 64 // inside the kernel api and sets the most secure on if 65 // available which seeds /dev/hwrng 66 func setAvailableTRNG() error { 67 var ( 68 currentRNG string 69 availableRNGs []string 70 selectedRNG string 71 ) 72 73 availableFileData, err := ioutil.ReadFile(HwRandomAvailableFile) 74 if err != nil { 75 return err 76 } 77 availableRNGs = strings.Split(string(availableFileData), " ") 78 79 for _, trng := range trngList { 80 for _, rng := range availableRNGs { 81 if trng == rng { 82 selectedRNG = trng 83 break 84 } 85 } 86 } 87 88 if selectedRNG == "" { 89 return errors.New("no TRNG found on platform") 90 } 91 92 if err = ioutil.WriteFile(HwRandomCurrentFile, []byte(selectedRNG), 0644); err != nil { 93 return err 94 } 95 96 // Check if the correct TRNG was successful written 97 currentFileData, err := ioutil.ReadFile(HwRandomCurrentFile) 98 if err != nil { 99 return err 100 } 101 currentRNG = string(currentFileData) 102 103 if currentRNG != selectedRNG { 104 return errors.New("Couldn't select TRNG: " + currentRNG) 105 } 106 107 return nil 108 } 109 110 // UpdateLinuxRandomness seeds random data from 111 // /dev/hwrng into /dev/random based on a timer and 112 // the entropy pool size 113 func UpdateLinuxRandomness(recoverer recovery.Recoverer) error { 114 if err := setAvailableTRNG(); err != nil { 115 return err 116 } 117 118 hwRng, err := os.OpenFile(HwRandomDevice, os.O_RDONLY, os.ModeDevice) 119 if err != nil { 120 return err 121 } 122 123 rng, err := os.OpenFile(RandomDevice, os.O_APPEND|os.O_WRONLY, os.ModeDevice) 124 if err != nil { 125 return err 126 } 127 128 go func() { 129 defer hwRng.Close() 130 defer rng.Close() 131 132 for { 133 time.Sleep(EntropyFeedTime) 134 135 randomEntropyAvailableData, err := ioutil.ReadFile(RandomEntropyAvailableFile) 136 if err != nil { 137 recoverer.Recover("Can't read entropy pool size") 138 } 139 140 formatted := strings.TrimSuffix(string(randomEntropyAvailableData), "\n") 141 randomEntropyAvailable, err := strconv.ParseUint(formatted, 10, 32) 142 if err != nil { 143 recoverer.Recover("Can't parse entropy pool size") 144 } 145 146 if randomEntropyAvailable >= EntropyThreshold { 147 continue 148 } 149 150 var random = make([]byte, EntropyBlockSize) 151 length, err := hwRng.Read(random) 152 if err != nil { 153 recoverer.Recover("Can't open the hardware random device") 154 } 155 _, err = rng.Write(random[:length]) 156 if err != nil { 157 recoverer.Recover("Can't open the random device") 158 } 159 } 160 }() 161 162 return nil 163 }