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

View as plain text