diff options
| author | Jakob Unterwurzacher | 2017-08-11 18:42:30 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2017-08-11 19:02:26 +0200 | 
| commit | 0c520845f3623eff28f0277a52e3ccffd928f5c2 (patch) | |
| tree | 82a3e0f8c55ae980d29e33b230954638229089c9 | |
| parent | f59479736bed49411bda3368f419d6605f1faa78 (diff) | |
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
| -rw-r--r-- | internal/cryptocore/cryptocore.go | 10 | ||||
| -rw-r--r-- | internal/fusefrontend/args.go | 1 | ||||
| -rw-r--r-- | internal/fusefrontend/fs.go | 4 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/rfs.go | 4 | ||||
| -rw-r--r-- | mount.go | 12 | 
5 files changed, 20 insertions, 11 deletions
| diff --git a/internal/cryptocore/cryptocore.go b/internal/cryptocore/cryptocore.go index 1ad928d..aafe12b 100644 --- a/internal/cryptocore/cryptocore.go +++ b/internal/cryptocore/cryptocore.go @@ -72,7 +72,7 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec  		emeCipher = eme.New(emeBlockCipher)  	} -	// Initilize an AEAD cipher for file content encryption. +	// Initialize an AEAD cipher for file content encryption.  	var aeadCipher cipher.AEAD  	if aeadType == BackendOpenSSL || aeadType == BackendGoGCM {  		gcmKey := key @@ -84,7 +84,13 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec  			if IVLen != 16 {  				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:  			goGcmBlockCipher, err := aes.NewCipher(gcmKey)  			if err != nil { diff --git a/internal/fusefrontend/args.go b/internal/fusefrontend/args.go index 37f4463..fc9de73 100644 --- a/internal/fusefrontend/args.go +++ b/internal/fusefrontend/args.go @@ -7,7 +7,6 @@ import (  // Args is a container for arguments that are passed from main() to fusefrontend  type Args struct { -	Masterkey []byte  	// Cipherdir is the backing storage directory (absolute path).  	// For reverse mode, Cipherdir actually contains *plaintext* files.  	Cipherdir      string diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go index 7a23710..3c442a5 100644 --- a/internal/fusefrontend/fs.go +++ b/internal/fusefrontend/fs.go @@ -42,8 +42,8 @@ type FS struct {  var _ pathfs.FileSystem = &FS{} // Verify that interface is implemented.  // NewFS returns a new encrypted FUSE overlay filesystem. -func NewFS(args Args) *FS { -	cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, args.ForceDecode) +func NewFS(masterkey []byte, args Args) *FS { +	cryptoCore := cryptocore.New(masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, args.ForceDecode)  	contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS, args.ForceDecode)  	nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64) diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go index 76b1361..53e6d22 100644 --- a/internal/fusefrontend_reverse/rfs.go +++ b/internal/fusefrontend_reverse/rfs.go @@ -40,12 +40,12 @@ var _ pathfs.FileSystem = &ReverseFS{}  // NewFS returns an encrypted FUSE overlay filesystem.  // In this case (reverse mode) the backing directory is plain-text and  // ReverseFS provides an encrypted view. -func NewFS(args fusefrontend.Args) *ReverseFS { +func NewFS(masterkey []byte, args fusefrontend.Args) *ReverseFS {  	if args.CryptoBackend != cryptocore.BackendAESSIV {  		log.Panic("reverse mode must use AES-SIV, everything else is insecure")  	}  	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)  	nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64) @@ -170,7 +170,7 @@ func setOpenFileLimit() {  // initFuseFrontend - initialize gocryptfs/fusefrontend  // 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  	// that is passed to the filesystem implementation  	cryptoBackend := cryptocore.BackendGoGCM @@ -187,7 +187,6 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF  	}  	frontendArgs := fusefrontend.Args{  		Cipherdir:      args.cipherdir, -		Masterkey:      key,  		PlaintextNames: args.plaintextnames,  		LongNames:      args.longnames,  		CryptoBackend:  cryptoBackend, @@ -222,14 +221,19 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF  	var finalFs pathfs.FileSystem  	var ctlSockBackend ctlsock.Interface  	if args.reverse { -		fs := fusefrontend_reverse.NewFS(frontendArgs) +		fs := fusefrontend_reverse.NewFS(masterkey, frontendArgs)  		finalFs = fs  		ctlSockBackend = fs  	} else { -		fs := fusefrontend.NewFS(frontendArgs) +		fs := fusefrontend.NewFS(masterkey, frontendArgs)  		finalFs = 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  	// asking the user for the password  	if args._ctlsockFd != nil { | 
