Skip to content

Commit f3c777d

Browse files
slacknerrfjakob
authored andcommitted
main: Add '-devrandom' commandline option
Allows to use /dev/random for generating the master key instead of the default Go implementation. When the kernel random generator has been properly initialized both are considered equally secure, however: * Versions of Go prior to 1.9 just fall back to /dev/urandom if the getrandom() syscall would be blocking (Go Bug #19274) * Kernel versions prior to 3.17 do not support getrandom(), and there is no check if the random generator has been properly initialized before reading from /dev/urandom This is especially useful for embedded hardware with low-entroy. Please note that generation of the master key might block indefinitely if the kernel cannot harvest enough entropy.
1 parent 1b0426b commit f3c777d

File tree

6 files changed

+49
-7
lines changed

6 files changed

+49
-7
lines changed

Documentation/MANPAGE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ be suitable.
5151
#### -d, -debug
5252
Enable debug output
5353

54+
#### -devrandom
55+
Use /dev/random for generating the master key instead of the default Go
56+
implementation. This is especially useful on embedded systems with Go versions
57+
prior to 1.9, which fall back to weak random data when the getrandom syscall
58+
is blocking. Using this option can block indefinitely when the kernel cannot
59+
harvest enough entropy.
60+
5461
#### -extpass string
5562
Use an external program (like ssh-askpass) for the password prompt.
5663
The program should return the password on stdout, a trailing newline is

cli_args.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type argContainer struct {
2222
plaintextnames, quiet, nosyslog, wpanic,
2323
longnames, allow_other, ro, reverse, aessiv, nonempty, raw64,
2424
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
25-
sharedstorage bool
25+
sharedstorage, devrandom bool
2626
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
2727
memprofile, ko, passfile, ctlsock, fsname, force_owner, trace string
2828
// Configuration file name override
@@ -132,6 +132,7 @@ func parseCliOpts() (args argContainer) {
132132
flagSet.BoolVar(&args.hh, "hh", false, "Show this long help text")
133133
flagSet.BoolVar(&args.info, "info", false, "Display information about CIPHERDIR")
134134
flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer")
135+
flagSet.BoolVar(&args.devrandom, "devrandom", false, "Use /dev/random for generating master key")
135136
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
136137
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
137138
flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory profile to specified file")

init_dir.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func initDir(args *argContainer) {
3939
password := readpassword.Twice(args.extpass)
4040
readpassword.CheckTrailingGarbage()
4141
creator := tlog.ProgramName + " " + GitVersion
42-
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv)
42+
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv, args.devrandom)
4343
if err != nil {
4444
tlog.Fatal.Println(err)
4545
os.Exit(exitcodes.WriteConf)

internal/configfile/config_file.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ package configfile
55
import (
66
"encoding/json"
77
"fmt"
8+
"io"
89
"io/ioutil"
10+
"log"
911

1012
"github.com/rfjakob/gocryptfs/internal/contentenc"
1113
"github.com/rfjakob/gocryptfs/internal/cryptocore"
@@ -47,10 +49,25 @@ type ConfFile struct {
4749
filename string
4850
}
4951

52+
// randBytesDevRandom gets "n" random bytes from /dev/random or panics
53+
func randBytesDevRandom(n int) []byte {
54+
f, err := os.Open("/dev/random")
55+
if err != nil {
56+
log.Panic("Failed to open /dev/random: " + err.Error())
57+
}
58+
defer f.Close()
59+
b := make([]byte, n)
60+
_, err = io.ReadFull(f, b)
61+
if err != nil {
62+
log.Panic("Failed to read random bytes: " + err.Error())
63+
}
64+
return b
65+
}
66+
5067
// CreateConfFile - create a new config with a random key encrypted with
5168
// "password" and write it to "filename".
5269
// Uses scrypt with cost parameter logN.
53-
func CreateConfFile(filename string, password string, plaintextNames bool, logN int, creator string, aessiv bool) error {
70+
func CreateConfFile(filename string, password string, plaintextNames bool, logN int, creator string, aessiv bool, devrandom bool) error {
5471
var cf ConfFile
5572
cf.filename = filename
5673
cf.Creator = creator
@@ -72,7 +89,12 @@ func CreateConfFile(filename string, password string, plaintextNames bool, logN
7289
}
7390

7491
// Generate new random master key
75-
key := cryptocore.RandBytes(cryptocore.KeyLen)
92+
var key []byte
93+
if devrandom {
94+
key = randBytesDevRandom(cryptocore.KeyLen)
95+
} else {
96+
key = cryptocore.RandBytes(cryptocore.KeyLen)
97+
}
7698

7799
// Encrypt it using the password
78100
// This sets ScryptObject and EncryptedKey

internal/configfile/config_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func TestLoadV2StrangeFeature(t *testing.T) {
6060
}
6161

6262
func TestCreateConfDefault(t *testing.T) {
63-
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false)
63+
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false, false)
6464
if err != nil {
6565
t.Fatal(err)
6666
}
@@ -80,8 +80,15 @@ func TestCreateConfDefault(t *testing.T) {
8080
}
8181
}
8282

83+
func TestCreateConfDevRandom(t *testing.T) {
84+
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false, true)
85+
if err != nil {
86+
t.Fatal(err)
87+
}
88+
}
89+
8390
func TestCreateConfPlaintextnames(t *testing.T) {
84-
err := CreateConfFile("config_test/tmp.conf", "test", true, 10, "test", false)
91+
err := CreateConfFile("config_test/tmp.conf", "test", true, 10, "test", false, false)
8592
if err != nil {
8693
t.Fatal(err)
8794
}
@@ -102,7 +109,7 @@ func TestCreateConfPlaintextnames(t *testing.T) {
102109

103110
// Reverse mode uses AESSIV
104111
func TestCreateConfFileAESSIV(t *testing.T) {
105-
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", true)
112+
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", true, false)
106113
if err != nil {
107114
t.Fatal(err)
108115
}

tests/cli/cli_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ func TestInit(t *testing.T) {
3434
}
3535
}
3636

37+
// Test -init with -devrandom flag
38+
func TestInitDevRandom(t *testing.T) {
39+
test_helpers.InitFS(t, "-devrandom")
40+
}
41+
3742
// Test -init with -aessiv
3843
func TestInitAessiv(t *testing.T) {
3944
dir := test_helpers.InitFS(t, "-aessiv")

0 commit comments

Comments
 (0)