github.com/annchain/OG@v0.0.9/deprecated/ogcrypto/random.go (about)

     1  // Copyright 2017 Baptist-Publication Information Technology Services Co.,Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ogcrypto
    16  
    17  import (
    18  	"crypto/aes"
    19  	"crypto/cipher"
    20  	crand "crypto/rand"
    21  	"encoding/hex"
    22  	"github.com/annchain/OG/deprecated"
    23  	"io"
    24  	"sync"
    25  )
    26  
    27  var gRandInfo *randInfo
    28  
    29  func init() {
    30  	gRandInfo = &randInfo{}
    31  	gRandInfo.MixEntropy(randBytes(32)) // init
    32  }
    33  
    34  // Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
    35  // It is OK to call it multiple times.  It does not diminish security.
    36  func MixEntropy(seedBytes []byte) {
    37  	gRandInfo.MixEntropy(seedBytes)
    38  }
    39  
    40  // This only uses the OS's randomness
    41  func randBytes(numBytes int) []byte {
    42  	b := make([]byte, numBytes)
    43  	_, err := crand.Read(b)
    44  	if err != nil {
    45  		panic(err)
    46  	}
    47  	return b
    48  }
    49  
    50  // This uses the OS and the Seed(s).
    51  func CRandBytes(numBytes int) []byte {
    52  	b := make([]byte, numBytes)
    53  	_, err := gRandInfo.Read(b)
    54  	if err != nil {
    55  		panic(err)
    56  	}
    57  	return b
    58  }
    59  
    60  // RandHex(24) gives 96 bits of randomness, strong enough for most purposes.
    61  func CRandHex(numDigits int) string {
    62  	return hex.EncodeToString(CRandBytes(numDigits / 2))
    63  }
    64  
    65  // Returns a crand.Reader mixed with user-supplied entropy
    66  func CReader() io.Reader {
    67  	return gRandInfo
    68  }
    69  
    70  //--------------------------------------------------------------------------------
    71  
    72  type randInfo struct {
    73  	mtx          sync.Mutex
    74  	seedBytes    [32]byte
    75  	cipherAES256 cipher.Block
    76  	streamAES256 cipher.Stream
    77  	reader       io.Reader
    78  }
    79  
    80  // You can call this as many times as you'd like.
    81  // XXX TODO review
    82  func (ri *randInfo) MixEntropy(seedBytes []byte) {
    83  	ri.mtx.Lock()
    84  	defer ri.mtx.Unlock()
    85  	// Make new ri.seedBytes
    86  	hashBytes := deprecated.Sha256(seedBytes)
    87  	hashBytes32 := [32]byte{}
    88  	copy(hashBytes32[:], hashBytes)
    89  	ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
    90  	// Create new cipher.Block
    91  	var err error
    92  	ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
    93  	if err != nil {
    94  		panic("Error creating AES256 cipher: " + err.Error())
    95  	}
    96  	// Create new stream
    97  	ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
    98  	// Create new reader
    99  	ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
   100  }
   101  
   102  func (ri *randInfo) Read(b []byte) (n int, err error) {
   103  	ri.mtx.Lock()
   104  	defer ri.mtx.Unlock()
   105  	return ri.reader.Read(b)
   106  }
   107  
   108  func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
   109  	for i, b := range bytesA {
   110  		res[i] = b ^ bytesB[i]
   111  	}
   112  	return res
   113  }