...

Source file src/crypto/rand/rand_unix.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	// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris
     6	
     7	// Unix cryptographically secure pseudorandom number
     8	// generator.
     9	
    10	package rand
    11	
    12	import (
    13		"bufio"
    14		"crypto/aes"
    15		"crypto/cipher"
    16		"encoding/binary"
    17		"io"
    18		"os"
    19		"runtime"
    20		"sync"
    21		"sync/atomic"
    22		"time"
    23	)
    24	
    25	const urandomDevice = "/dev/urandom"
    26	
    27	// Easy implementation: read from /dev/urandom.
    28	// This is sufficient on Linux, OS X, and FreeBSD.
    29	
    30	func init() {
    31		if runtime.GOOS == "plan9" {
    32			Reader = newReader(nil)
    33		} else {
    34			Reader = &devReader{name: urandomDevice}
    35		}
    36	}
    37	
    38	// A devReader satisfies reads by reading the file named name.
    39	type devReader struct {
    40		name string
    41		f    io.Reader
    42		mu   sync.Mutex
    43		used int32 // atomic; whether this devReader has been used
    44	}
    45	
    46	// altGetRandom if non-nil specifies an OS-specific function to get
    47	// urandom-style randomness.
    48	var altGetRandom func([]byte) (ok bool)
    49	
    50	func (r *devReader) Read(b []byte) (n int, err error) {
    51		if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
    52			// First use of randomness. Start timer to warn about
    53			// being blocked on entropy not being available.
    54			t := time.AfterFunc(60*time.Second, warnBlocked)
    55			defer t.Stop()
    56		}
    57		if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) {
    58			return len(b), nil
    59		}
    60		r.mu.Lock()
    61		defer r.mu.Unlock()
    62		if r.f == nil {
    63			f, err := os.Open(r.name)
    64			if f == nil {
    65				return 0, err
    66			}
    67			if runtime.GOOS == "plan9" {
    68				r.f = f
    69			} else {
    70				r.f = bufio.NewReader(hideAgainReader{f})
    71			}
    72		}
    73		return r.f.Read(b)
    74	}
    75	
    76	var isEAGAIN func(error) bool // set by eagain.go on unix systems
    77	
    78	// hideAgainReader masks EAGAIN reads from /dev/urandom.
    79	// See golang.org/issue/9205
    80	type hideAgainReader struct {
    81		r io.Reader
    82	}
    83	
    84	func (hr hideAgainReader) Read(p []byte) (n int, err error) {
    85		n, err = hr.r.Read(p)
    86		if err != nil && isEAGAIN != nil && isEAGAIN(err) {
    87			err = nil
    88		}
    89		return
    90	}
    91	
    92	// Alternate pseudo-random implementation for use on
    93	// systems without a reliable /dev/urandom.
    94	
    95	// newReader returns a new pseudorandom generator that
    96	// seeds itself by reading from entropy. If entropy == nil,
    97	// the generator seeds itself by reading from the system's
    98	// random number generator, typically /dev/random.
    99	// The Read method on the returned reader always returns
   100	// the full amount asked for, or else it returns an error.
   101	//
   102	// The generator uses the X9.31 algorithm with AES-128,
   103	// reseeding after every 1 MB of generated data.
   104	func newReader(entropy io.Reader) io.Reader {
   105		if entropy == nil {
   106			entropy = &devReader{name: "/dev/random"}
   107		}
   108		return &reader{entropy: entropy}
   109	}
   110	
   111	type reader struct {
   112		mu                   sync.Mutex
   113		budget               int // number of bytes that can be generated
   114		cipher               cipher.Block
   115		entropy              io.Reader
   116		time, seed, dst, key [aes.BlockSize]byte
   117	}
   118	
   119	func (r *reader) Read(b []byte) (n int, err error) {
   120		r.mu.Lock()
   121		defer r.mu.Unlock()
   122		n = len(b)
   123	
   124		for len(b) > 0 {
   125			if r.budget == 0 {
   126				_, err := io.ReadFull(r.entropy, r.seed[0:])
   127				if err != nil {
   128					return n - len(b), err
   129				}
   130				_, err = io.ReadFull(r.entropy, r.key[0:])
   131				if err != nil {
   132					return n - len(b), err
   133				}
   134				r.cipher, err = aes.NewCipher(r.key[0:])
   135				if err != nil {
   136					return n - len(b), err
   137				}
   138				r.budget = 1 << 20 // reseed after generating 1MB
   139			}
   140			r.budget -= aes.BlockSize
   141	
   142			// ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
   143			//
   144			// single block:
   145			// t = encrypt(time)
   146			// dst = encrypt(t^seed)
   147			// seed = encrypt(t^dst)
   148			ns := time.Now().UnixNano()
   149			binary.BigEndian.PutUint64(r.time[:], uint64(ns))
   150			r.cipher.Encrypt(r.time[0:], r.time[0:])
   151			for i := 0; i < aes.BlockSize; i++ {
   152				r.dst[i] = r.time[i] ^ r.seed[i]
   153			}
   154			r.cipher.Encrypt(r.dst[0:], r.dst[0:])
   155			for i := 0; i < aes.BlockSize; i++ {
   156				r.seed[i] = r.time[i] ^ r.dst[i]
   157			}
   158			r.cipher.Encrypt(r.seed[0:], r.seed[0:])
   159	
   160			m := copy(b, r.dst[0:])
   161			b = b[m:]
   162		}
   163	
   164		return n, nil
   165	}
   166	

View as plain text