...

Source file src/crypto/rand/rand_windows.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	// Windows cryptographically secure pseudorandom number
     6	// generator.
     7	
     8	package rand
     9	
    10	import (
    11		"os"
    12		"sync"
    13		"sync/atomic"
    14		"syscall"
    15		"time"
    16	)
    17	
    18	// Implemented by using Windows CryptoAPI 2.0.
    19	
    20	func init() { Reader = &rngReader{} }
    21	
    22	// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
    23	type rngReader struct {
    24		used int32 // atomic; whether this rngReader has been used
    25		prov syscall.Handle
    26		mu   sync.Mutex
    27	}
    28	
    29	func (r *rngReader) Read(b []byte) (n int, err error) {
    30		if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
    31			// First use of randomness. Start timer to warn about
    32			// being blocked on entropy not being available.
    33			t := time.AfterFunc(60*time.Second, warnBlocked)
    34			defer t.Stop()
    35		}
    36		r.mu.Lock()
    37		if r.prov == 0 {
    38			const provType = syscall.PROV_RSA_FULL
    39			const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
    40			err := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
    41			if err != nil {
    42				r.mu.Unlock()
    43				return 0, os.NewSyscallError("CryptAcquireContext", err)
    44			}
    45		}
    46		r.mu.Unlock()
    47	
    48		if len(b) == 0 {
    49			return 0, nil
    50		}
    51		err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
    52		if err != nil {
    53			return 0, os.NewSyscallError("CryptGenRandom", err)
    54		}
    55		return len(b), nil
    56	}
    57	

View as plain text