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  }