Source file src/crypto/rand/rand_plan9.go

     1  // Copyright 2010 The Go 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 rand
     6  
     7  import (
     8  	"crypto/aes"
     9  	"internal/byteorder"
    10  	"io"
    11  	"os"
    12  	"sync"
    13  	"time"
    14  )
    15  
    16  const randomDevice = "/dev/random"
    17  
    18  // This is a pseudorandom generator that seeds itself by reading from
    19  // /dev/random. The read function always returns the full amount asked for, or
    20  // else it returns an error. The generator is a fast key erasure RNG.
    21  
    22  var (
    23  	mu      sync.Mutex
    24  	seeded  sync.Once
    25  	seedErr error
    26  	key     [32]byte
    27  )
    28  
    29  func read(b []byte) error {
    30  	seeded.Do(func() {
    31  		t := time.AfterFunc(time.Minute, func() {
    32  			println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
    33  		})
    34  		defer t.Stop()
    35  		entropy, err := os.Open(randomDevice)
    36  		if err != nil {
    37  			seedErr = err
    38  			return
    39  		}
    40  		defer entropy.Close()
    41  		_, seedErr = io.ReadFull(entropy, key[:])
    42  	})
    43  	if seedErr != nil {
    44  		return seedErr
    45  	}
    46  
    47  	mu.Lock()
    48  	blockCipher, err := aes.NewCipher(key[:])
    49  	if err != nil {
    50  		mu.Unlock()
    51  		return err
    52  	}
    53  	var (
    54  		counter uint64
    55  		block   [aes.BlockSize]byte
    56  	)
    57  	inc := func() {
    58  		counter++
    59  		if counter == 0 {
    60  			panic("crypto/rand counter wrapped")
    61  		}
    62  		byteorder.LePutUint64(block[:], counter)
    63  	}
    64  	blockCipher.Encrypt(key[:aes.BlockSize], block[:])
    65  	inc()
    66  	blockCipher.Encrypt(key[aes.BlockSize:], block[:])
    67  	inc()
    68  	mu.Unlock()
    69  
    70  	for len(b) >= aes.BlockSize {
    71  		blockCipher.Encrypt(b[:aes.BlockSize], block[:])
    72  		inc()
    73  		b = b[aes.BlockSize:]
    74  	}
    75  	if len(b) > 0 {
    76  		blockCipher.Encrypt(block[:], block[:])
    77  		copy(b, block[:])
    78  	}
    79  	return nil
    80  }
    81  

View as plain text