1 | package entropychecker |
||
2 | |||
3 | import ( |
||
4 | "errors" |
||
5 | "io/ioutil" |
||
6 | "runtime" |
||
7 | "strconv" |
||
8 | "strings" |
||
9 | "time" |
||
10 | ) |
||
11 | |||
12 | // MinimumEntropy is the minimum amount of entropy that will be considered safe. |
||
13 | // Set this to what you consider to be a 'safe' minimum entropy amount (in bits) |
||
14 | var MinimumEntropy = 128 |
||
15 | |||
16 | // Timeout sets the maximum amount of time to wait for entropy. |
||
17 | // Waiting for entropy will time out after this amount of time. Setting to zero will never time out. |
||
18 | var Timeout = time.Second * 10 |
||
19 | |||
20 | // The only supported OS is linux at this time. |
||
21 | var supportedOS = "linux" |
||
22 | |||
23 | // ErrTimeout is for when the system waits too long and gives up |
||
24 | var ErrTimeout = errors.New("entropychecker: Timed out waiting for sufficient entropy") |
||
25 | |||
26 | // ErrUnsupportedOS is for for an invalid OS that does not provide entropy estimates |
||
27 | var ErrUnsupportedOS = errors.New("entropychecker: Unsupported OS. Only Linux is supported") |
||
28 | |||
29 | // GetEntropy gets the entropy estimate. Returns the estimated entropy in bits |
||
30 | func GetEntropy() (int, error) { |
||
31 | 1 | if runtime.GOOS != supportedOS { |
|
32 | 1 | return 0, ErrUnsupportedOS |
|
33 | } |
||
34 | |||
35 | 1 | text, err := ioutil.ReadFile("/proc/sys/kernel/random/entropy_avail") |
|
36 | 1 | if err != nil { |
|
37 | return 0, err |
||
38 | } |
||
39 | 1 | return strconv.Atoi(strings.TrimSuffix(string(text), "\n")) |
|
40 | } |
||
41 | |||
42 | // WaitForEntropy blocks until sufficient entropy is available |
||
43 | func WaitForEntropy() error { |
||
44 | 1 | if runtime.GOOS != supportedOS { |
|
45 | 1 | return ErrUnsupportedOS |
|
46 | } |
||
47 | |||
48 | // set up the timeout |
||
49 | 1 | timeout := make(chan bool, 1) |
|
50 | 1 | if Timeout != 0 { |
|
51 | 1 | go func(timeoutDuration time.Duration) { |
|
52 | 1 | time.Sleep(timeoutDuration) |
|
53 | 1 | timeout <- true |
|
54 | }(Timeout) |
||
55 | } |
||
56 | |||
57 | 1 | for { |
|
58 | 1 | entropy, err := GetEntropy() |
|
59 | |||
60 | 1 | switch { |
|
61 | case err != nil: |
||
62 | return err |
||
63 | case entropy > MinimumEntropy: |
||
64 | 1 | return nil |
|
65 | default: |
||
66 | 1 | select { |
|
67 | case <-timeout: |
||
68 | 1 | return ErrTimeout |
|
69 | default: |
||
70 | 1 | time.Sleep(50 * time.Millisecond) |
|
71 | } |
||
72 | } |
||
73 | } |
||
74 | } |
||
75 |