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  }