summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Lackner2017-11-19 13:30:04 +0100
committerrfjakob2017-11-21 23:37:06 +0100
commitf3c777d5eaa682d878c638192311e52f9c204294 (patch)
treedc3fcf616371479abec93ab93688f9e2937e7d9d
parent1b0426bcb23a1850f3a03619a15413281dc733e3 (diff)
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.
-rw-r--r--Documentation/MANPAGE.md7
-rw-r--r--cli_args.go3
-rw-r--r--init_dir.go2
-rw-r--r--internal/configfile/config_file.go26
-rw-r--r--internal/configfile/config_test.go13
-rw-r--r--tests/cli/cli_test.go5
6 files changed, 49 insertions, 7 deletions
diff --git a/Documentation/MANPAGE.md b/Documentation/MANPAGE.md
index efb8565..d3a6c81 100644
--- a/Documentation/MANPAGE.md
+++ b/Documentation/MANPAGE.md
@@ -51,6 +51,13 @@ be suitable.
#### -d, -debug
Enable debug output
+#### -devrandom
+Use /dev/random for generating the master key instead of the default Go
+implementation. This is especially useful on embedded systems with Go versions
+prior to 1.9, which fall back to weak random data when the getrandom syscall
+is blocking. Using this option can block indefinitely when the kernel cannot
+harvest enough entropy.
+
#### -extpass string
Use an external program (like ssh-askpass) for the password prompt.
The program should return the password on stdout, a trailing newline is
diff --git a/cli_args.go b/cli_args.go
index 71ad6bd..7bde89d 100644
--- a/cli_args.go
+++ b/cli_args.go
@@ -22,7 +22,7 @@ type argContainer struct {
plaintextnames, quiet, nosyslog, wpanic,
longnames, allow_other, ro, reverse, aessiv, nonempty, raw64,
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
- sharedstorage bool
+ sharedstorage, devrandom bool
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
memprofile, ko, passfile, ctlsock, fsname, force_owner, trace string
// Configuration file name override
@@ -132,6 +132,7 @@ func parseCliOpts() (args argContainer) {
flagSet.BoolVar(&args.hh, "hh", false, "Show this long help text")
flagSet.BoolVar(&args.info, "info", false, "Display information about CIPHERDIR")
flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer")
+ flagSet.BoolVar(&args.devrandom, "devrandom", false, "Use /dev/random for generating master key")
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory profile to specified file")
diff --git a/init_dir.go b/init_dir.go
index 20c9fd9..f057bf4 100644
--- a/init_dir.go
+++ b/init_dir.go
@@ -39,7 +39,7 @@ func initDir(args *argContainer) {
password := readpassword.Twice(args.extpass)
readpassword.CheckTrailingGarbage()
creator := tlog.ProgramName + " " + GitVersion
- err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv)
+ err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv, args.devrandom)
if err != nil {
tlog.Fatal.Println(err)
os.Exit(exitcodes.WriteConf)
diff --git a/internal/configfile/config_file.go b/internal/configfile/config_file.go
index fea4a84..67d67f0 100644
--- a/internal/configfile/config_file.go
+++ b/internal/configfile/config_file.go
@@ -5,7 +5,9 @@ package configfile
import (
"encoding/json"
"fmt"
+ "io"
"io/ioutil"
+ "log"
"github.com/rfjakob/gocryptfs/internal/contentenc"
"github.com/rfjakob/gocryptfs/internal/cryptocore"
@@ -47,10 +49,25 @@ type ConfFile struct {
filename string
}
+// randBytesDevRandom gets "n" random bytes from /dev/random or panics
+func randBytesDevRandom(n int) []byte {
+ f, err := os.Open("/dev/random")
+ if err != nil {
+ log.Panic("Failed to open /dev/random: " + err.Error())
+ }
+ defer f.Close()
+ b := make([]byte, n)
+ _, err = io.ReadFull(f, b)
+ if err != nil {
+ log.Panic("Failed to read random bytes: " + err.Error())
+ }
+ return b
+}
+
// CreateConfFile - create a new config with a random key encrypted with
// "password" and write it to "filename".
// Uses scrypt with cost parameter logN.
-func CreateConfFile(filename string, password string, plaintextNames bool, logN int, creator string, aessiv bool) error {
+func CreateConfFile(filename string, password string, plaintextNames bool, logN int, creator string, aessiv bool, devrandom bool) error {
var cf ConfFile
cf.filename = filename
cf.Creator = creator
@@ -72,7 +89,12 @@ func CreateConfFile(filename string, password string, plaintextNames bool, logN
}
// Generate new random master key
- key := cryptocore.RandBytes(cryptocore.KeyLen)
+ var key []byte
+ if devrandom {
+ key = randBytesDevRandom(cryptocore.KeyLen)
+ } else {
+ key = cryptocore.RandBytes(cryptocore.KeyLen)
+ }
// Encrypt it using the password
// This sets ScryptObject and EncryptedKey
diff --git a/internal/configfile/config_test.go b/internal/configfile/config_test.go
index dc796ea..b984a37 100644
--- a/internal/configfile/config_test.go
+++ b/internal/configfile/config_test.go
@@ -60,7 +60,7 @@ func TestLoadV2StrangeFeature(t *testing.T) {
}
func TestCreateConfDefault(t *testing.T) {
- err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false)
+ err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false, false)
if err != nil {
t.Fatal(err)
}
@@ -80,8 +80,15 @@ func TestCreateConfDefault(t *testing.T) {
}
}
+func TestCreateConfDevRandom(t *testing.T) {
+ err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
func TestCreateConfPlaintextnames(t *testing.T) {
- err := CreateConfFile("config_test/tmp.conf", "test", true, 10, "test", false)
+ err := CreateConfFile("config_test/tmp.conf", "test", true, 10, "test", false, false)
if err != nil {
t.Fatal(err)
}
@@ -102,7 +109,7 @@ func TestCreateConfPlaintextnames(t *testing.T) {
// Reverse mode uses AESSIV
func TestCreateConfFileAESSIV(t *testing.T) {
- err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", true)
+ err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", true, false)
if err != nil {
t.Fatal(err)
}
diff --git a/tests/cli/cli_test.go b/tests/cli/cli_test.go
index 97de8da..c7752f2 100644
--- a/tests/cli/cli_test.go
+++ b/tests/cli/cli_test.go
@@ -34,6 +34,11 @@ func TestInit(t *testing.T) {
}
}
+// Test -init with -devrandom flag
+func TestInitDevRandom(t *testing.T) {
+ test_helpers.InitFS(t, "-devrandom")
+}
+
// Test -init with -aessiv
func TestInitAessiv(t *testing.T) {
dir := test_helpers.InitFS(t, "-aessiv")