main: purge masterkey from memory as soon as possible
Remove the "Masterkey" field from fusefrontend.Args because it should not be stored longer than neccessary. Instead pass the masterkey as a separate argument to the filesystem initializers. Then overwrite it with zeros immediately so we don't have to wait for garbage collection. Note that the crypto implementation still stores at least a masterkey-derived value, so this change makes it harder, but not impossible, to extract the encryption keys from memory. Suggested at https://github.com/rfjakob/gocryptfs/issues/137
This commit is contained in:
parent
f59479736b
commit
0c520845f3
@ -72,7 +72,7 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec
|
|||||||
emeCipher = eme.New(emeBlockCipher)
|
emeCipher = eme.New(emeBlockCipher)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initilize an AEAD cipher for file content encryption.
|
// Initialize an AEAD cipher for file content encryption.
|
||||||
var aeadCipher cipher.AEAD
|
var aeadCipher cipher.AEAD
|
||||||
if aeadType == BackendOpenSSL || aeadType == BackendGoGCM {
|
if aeadType == BackendOpenSSL || aeadType == BackendGoGCM {
|
||||||
gcmKey := key
|
gcmKey := key
|
||||||
@ -84,7 +84,13 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec
|
|||||||
if IVLen != 16 {
|
if IVLen != 16 {
|
||||||
log.Panic("stupidgcm only supports 128-bit IVs")
|
log.Panic("stupidgcm only supports 128-bit IVs")
|
||||||
}
|
}
|
||||||
aeadCipher = stupidgcm.New(gcmKey, forceDecode)
|
// stupidgcm does not create a private copy of the key, so things
|
||||||
|
// break when initFuseFrontend() overwrites it with zeros. Create
|
||||||
|
// a copy here. This is unneccessary when useHKDF == true, but
|
||||||
|
// does no harm.
|
||||||
|
var stupidgcmKey []byte
|
||||||
|
stupidgcmKey = append(stupidgcmKey, gcmKey...)
|
||||||
|
aeadCipher = stupidgcm.New(stupidgcmKey, forceDecode)
|
||||||
case BackendGoGCM:
|
case BackendGoGCM:
|
||||||
goGcmBlockCipher, err := aes.NewCipher(gcmKey)
|
goGcmBlockCipher, err := aes.NewCipher(gcmKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
// Args is a container for arguments that are passed from main() to fusefrontend
|
// Args is a container for arguments that are passed from main() to fusefrontend
|
||||||
type Args struct {
|
type Args struct {
|
||||||
Masterkey []byte
|
|
||||||
// Cipherdir is the backing storage directory (absolute path).
|
// Cipherdir is the backing storage directory (absolute path).
|
||||||
// For reverse mode, Cipherdir actually contains *plaintext* files.
|
// For reverse mode, Cipherdir actually contains *plaintext* files.
|
||||||
Cipherdir string
|
Cipherdir string
|
||||||
|
@ -42,8 +42,8 @@ type FS struct {
|
|||||||
var _ pathfs.FileSystem = &FS{} // Verify that interface is implemented.
|
var _ pathfs.FileSystem = &FS{} // Verify that interface is implemented.
|
||||||
|
|
||||||
// NewFS returns a new encrypted FUSE overlay filesystem.
|
// NewFS returns a new encrypted FUSE overlay filesystem.
|
||||||
func NewFS(args Args) *FS {
|
func NewFS(masterkey []byte, args Args) *FS {
|
||||||
cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, args.ForceDecode)
|
cryptoCore := cryptocore.New(masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, args.ForceDecode)
|
||||||
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS, args.ForceDecode)
|
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS, args.ForceDecode)
|
||||||
nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64)
|
nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64)
|
||||||
|
|
||||||
|
@ -40,12 +40,12 @@ var _ pathfs.FileSystem = &ReverseFS{}
|
|||||||
// NewFS returns an encrypted FUSE overlay filesystem.
|
// NewFS returns an encrypted FUSE overlay filesystem.
|
||||||
// In this case (reverse mode) the backing directory is plain-text and
|
// In this case (reverse mode) the backing directory is plain-text and
|
||||||
// ReverseFS provides an encrypted view.
|
// ReverseFS provides an encrypted view.
|
||||||
func NewFS(args fusefrontend.Args) *ReverseFS {
|
func NewFS(masterkey []byte, args fusefrontend.Args) *ReverseFS {
|
||||||
if args.CryptoBackend != cryptocore.BackendAESSIV {
|
if args.CryptoBackend != cryptocore.BackendAESSIV {
|
||||||
log.Panic("reverse mode must use AES-SIV, everything else is insecure")
|
log.Panic("reverse mode must use AES-SIV, everything else is insecure")
|
||||||
}
|
}
|
||||||
initLongnameCache()
|
initLongnameCache()
|
||||||
cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, false)
|
cryptoCore := cryptocore.New(masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, false)
|
||||||
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS, false)
|
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS, false)
|
||||||
nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64)
|
nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64)
|
||||||
|
|
||||||
|
12
mount.go
12
mount.go
@ -170,7 +170,7 @@ func setOpenFileLimit() {
|
|||||||
|
|
||||||
// initFuseFrontend - initialize gocryptfs/fusefrontend
|
// initFuseFrontend - initialize gocryptfs/fusefrontend
|
||||||
// Calls os.Exit on errors
|
// Calls os.Exit on errors
|
||||||
func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfFile) *fuse.Server {
|
func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile.ConfFile) *fuse.Server {
|
||||||
// Reconciliate CLI and config file arguments into a fusefrontend.Args struct
|
// Reconciliate CLI and config file arguments into a fusefrontend.Args struct
|
||||||
// that is passed to the filesystem implementation
|
// that is passed to the filesystem implementation
|
||||||
cryptoBackend := cryptocore.BackendGoGCM
|
cryptoBackend := cryptocore.BackendGoGCM
|
||||||
@ -187,7 +187,6 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF
|
|||||||
}
|
}
|
||||||
frontendArgs := fusefrontend.Args{
|
frontendArgs := fusefrontend.Args{
|
||||||
Cipherdir: args.cipherdir,
|
Cipherdir: args.cipherdir,
|
||||||
Masterkey: key,
|
|
||||||
PlaintextNames: args.plaintextnames,
|
PlaintextNames: args.plaintextnames,
|
||||||
LongNames: args.longnames,
|
LongNames: args.longnames,
|
||||||
CryptoBackend: cryptoBackend,
|
CryptoBackend: cryptoBackend,
|
||||||
@ -222,14 +221,19 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF
|
|||||||
var finalFs pathfs.FileSystem
|
var finalFs pathfs.FileSystem
|
||||||
var ctlSockBackend ctlsock.Interface
|
var ctlSockBackend ctlsock.Interface
|
||||||
if args.reverse {
|
if args.reverse {
|
||||||
fs := fusefrontend_reverse.NewFS(frontendArgs)
|
fs := fusefrontend_reverse.NewFS(masterkey, frontendArgs)
|
||||||
finalFs = fs
|
finalFs = fs
|
||||||
ctlSockBackend = fs
|
ctlSockBackend = fs
|
||||||
} else {
|
} else {
|
||||||
fs := fusefrontend.NewFS(frontendArgs)
|
fs := fusefrontend.NewFS(masterkey, frontendArgs)
|
||||||
finalFs = fs
|
finalFs = fs
|
||||||
ctlSockBackend = fs
|
ctlSockBackend = fs
|
||||||
}
|
}
|
||||||
|
// fusefrontend / fusefrontend_reverse have initialized their crypto with
|
||||||
|
// derived keys (HKDF), we can purge the master key from memory.
|
||||||
|
for i := range masterkey {
|
||||||
|
masterkey[i] = 0
|
||||||
|
}
|
||||||
// We have opened the socket early so that we cannot fail here after
|
// We have opened the socket early so that we cannot fail here after
|
||||||
// asking the user for the password
|
// asking the user for the password
|
||||||
if args._ctlsockFd != nil {
|
if args._ctlsockFd != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user