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
|
#### -d, -debug
|
||||||
Enable debug output
|
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
|
#### -extpass string
|
||||||
Use an external program (like ssh-askpass) for the password prompt.
|
Use an external program (like ssh-askpass) for the password prompt.
|
||||||
The program should return the password on stdout, a trailing newline is
|
The program should return the password on stdout, a trailing newline is
|
||||||
|
@ -22,7 +22,7 @@ type argContainer struct {
|
|||||||
plaintextnames, quiet, nosyslog, wpanic,
|
plaintextnames, quiet, nosyslog, wpanic,
|
||||||
longnames, allow_other, ro, reverse, aessiv, nonempty, raw64,
|
longnames, allow_other, ro, reverse, aessiv, nonempty, raw64,
|
||||||
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
|
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
|
||||||
sharedstorage bool
|
sharedstorage, devrandom bool
|
||||||
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
|
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
|
||||||
memprofile, ko, passfile, ctlsock, fsname, force_owner, trace string
|
memprofile, ko, passfile, ctlsock, fsname, force_owner, trace string
|
||||||
// Configuration file name override
|
// 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.hh, "hh", false, "Show this long help text")
|
||||||
flagSet.BoolVar(&args.info, "info", false, "Display information about CIPHERDIR")
|
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.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.masterkey, "masterkey", "", "Mount with explicit master key")
|
||||||
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
|
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
|
||||||
flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory 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)
|
password := readpassword.Twice(args.extpass)
|
||||||
readpassword.CheckTrailingGarbage()
|
readpassword.CheckTrailingGarbage()
|
||||||
creator := tlog.ProgramName + " " + GitVersion
|
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 {
|
if err != nil {
|
||||||
tlog.Fatal.Println(err)
|
tlog.Fatal.Println(err)
|
||||||
os.Exit(exitcodes.WriteConf)
|
os.Exit(exitcodes.WriteConf)
|
||||||
|
@ -5,7 +5,9 @@ package configfile
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
||||||
"github.com/rfjakob/gocryptfs/internal/cryptocore"
|
"github.com/rfjakob/gocryptfs/internal/cryptocore"
|
||||||
@ -47,10 +49,25 @@ type ConfFile struct {
|
|||||||
filename string
|
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
|
// CreateConfFile - create a new config with a random key encrypted with
|
||||||
// "password" and write it to "filename".
|
// "password" and write it to "filename".
|
||||||
// Uses scrypt with cost parameter logN.
|
// 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
|
var cf ConfFile
|
||||||
cf.filename = filename
|
cf.filename = filename
|
||||||
cf.Creator = creator
|
cf.Creator = creator
|
||||||
@ -72,7 +89,12 @@ func CreateConfFile(filename string, password string, plaintextNames bool, logN
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate new random master key
|
// 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
|
// Encrypt it using the password
|
||||||
// This sets ScryptObject and EncryptedKey
|
// This sets ScryptObject and EncryptedKey
|
||||||
|
@ -60,7 +60,7 @@ func TestLoadV2StrangeFeature(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateConfDefault(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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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) {
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -102,7 +109,7 @@ func TestCreateConfPlaintextnames(t *testing.T) {
|
|||||||
|
|
||||||
// Reverse mode uses AESSIV
|
// Reverse mode uses AESSIV
|
||||||
func TestCreateConfFileAESSIV(t *testing.T) {
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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
|
// Test -init with -aessiv
|
||||||
func TestInitAessiv(t *testing.T) {
|
func TestInitAessiv(t *testing.T) {
|
||||||
dir := test_helpers.InitFS(t, "-aessiv")
|
dir := test_helpers.InitFS(t, "-aessiv")
|
||||||
|
Loading…
Reference in New Issue
Block a user