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.
This commit is contained in:
parent
1b0426bcb2
commit
f3c777d5ea
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user