From 18f6c6106c66ba1fe6e7b48aaa5dd444ba0f9b09 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 18 Feb 2018 11:33:47 +0100 Subject: main: try to wipe cryptocore's secret keys on unmount Raise the bar for recovering keys from memory. https://github.com/rfjakob/gocryptfs/issues/211 --- internal/cryptocore/cryptocore.go | 24 ++++++++++++++++++++++++ internal/stupidgcm/stupidgcm.go | 20 ++++++++++---------- internal/stupidgcm/without_openssl.go | 18 +++++++++++------- 3 files changed, 45 insertions(+), 17 deletions(-) (limited to 'internal') diff --git a/internal/cryptocore/cryptocore.go b/internal/cryptocore/cryptocore.go index 9e25bfa..a355342 100644 --- a/internal/cryptocore/cryptocore.go +++ b/internal/cryptocore/cryptocore.go @@ -8,11 +8,13 @@ import ( "crypto/sha512" "fmt" "log" + "runtime" "github.com/rfjakob/eme" "github.com/rfjakob/gocryptfs/internal/siv_aead" "github.com/rfjakob/gocryptfs/internal/stupidgcm" + "github.com/rfjakob/gocryptfs/internal/tlog" ) // AEADTypeEnum indicates the type of AEAD backend in use. @@ -129,3 +131,25 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec IVLen: IVLen, } } + +// Wipe tries to wipe secret keys from memory by overwriting them with zeros +// and/or setting references to nil. +// +// This is not bulletproof due to possible GC copies, but +// still raises to bar for extracting the key. +func (c *CryptoCore) Wipe() { + if c.AEADBackend == BackendOpenSSL { + tlog.Debug.Print("CryptoCore.Wipe: Wiping stupidgcm key") + // We don't use "x, ok :=" because we *want* to crash loudly if the + // type assertion fails (it should never fail). + sgcm := c.AEADCipher.(*stupidgcm.StupidGCM) + sgcm.Wipe() + } else { + tlog.Debug.Print("CryptoCore.Wipe: niling stdlib refs") + } + // We have no access to the keys (or key-equivalents) stored inside the + // Go stdlib. Best we can is to nil the references and force a GC. + c.AEADCipher = nil + c.EMECipher = nil + runtime.GC() +} diff --git a/internal/stupidgcm/stupidgcm.go b/internal/stupidgcm/stupidgcm.go index 9fa730f..77d6770 100644 --- a/internal/stupidgcm/stupidgcm.go +++ b/internal/stupidgcm/stupidgcm.go @@ -24,32 +24,32 @@ const ( ) // stupidGCM implements the cipher.AEAD interface -type stupidGCM struct { +type StupidGCM struct { key []byte forceDecode bool } // Verify that we satisfy the cipher.AEAD interface -var _ cipher.AEAD = &stupidGCM{} +var _ cipher.AEAD = &StupidGCM{} // New returns a new cipher.AEAD implementation.. func New(key []byte, forceDecode bool) cipher.AEAD { if len(key) != keyLen { log.Panicf("Only %d-byte keys are supported", keyLen) } - return &stupidGCM{key: key, forceDecode: forceDecode} + return &StupidGCM{key: key, forceDecode: forceDecode} } -func (g *stupidGCM) NonceSize() int { +func (g *StupidGCM) NonceSize() int { return ivLen } -func (g *stupidGCM) Overhead() int { +func (g *StupidGCM) Overhead() int { return tagLen } // Seal encrypts "in" using "iv" and "authData" and append the result to "dst" -func (g *stupidGCM) Seal(dst, iv, in, authData []byte) []byte { +func (g *StupidGCM) Seal(dst, iv, in, authData []byte) []byte { if len(iv) != ivLen { log.Panicf("Only %d-byte IVs are supported", ivLen) } @@ -136,7 +136,7 @@ func (g *stupidGCM) Seal(dst, iv, in, authData []byte) []byte { } // Open decrypts "in" using "iv" and "authData" and append the result to "dst" -func (g *stupidGCM) Open(dst, iv, in, authData []byte) ([]byte, error) { +func (g *StupidGCM) Open(dst, iv, in, authData []byte) ([]byte, error) { if len(iv) != ivLen { log.Panicf("Only %d-byte IVs are supported", ivLen) } @@ -231,12 +231,12 @@ func (g *stupidGCM) Open(dst, iv, in, authData []byte) ([]byte, error) { return append(dst, buf...), nil } -// Wipe wipes the AES key from memory by overwriting it with zeros and -// setting the reference to nil. +// Wipe tries to wipe the AES key from memory by overwriting it with zeros +// and setting the reference to nil. // // This is not bulletproof due to possible GC copies, but // still raises to bar for extracting the key. -func (g *stupidGCM) Wipe() { +func (g *StupidGCM) Wipe() { for i := range g.key { g.key[i] = 0 } diff --git a/internal/stupidgcm/without_openssl.go b/internal/stupidgcm/without_openssl.go index 0c1c149..deac342 100644 --- a/internal/stupidgcm/without_openssl.go +++ b/internal/stupidgcm/without_openssl.go @@ -9,7 +9,7 @@ import ( "github.com/rfjakob/gocryptfs/internal/exitcodes" ) -type stupidGCM struct{} +type StupidGCM struct{} const ( // BuiltWithoutOpenssl indicates if openssl been disabled at compile-time @@ -21,28 +21,32 @@ func errExit() { os.Exit(exitcodes.OpenSSL) } -func New(_ []byte, _ bool) *stupidGCM { +func New(_ []byte, _ bool) *StupidGCM { errExit() // Never reached - return &stupidGCM{} + return &StupidGCM{} } -func (g *stupidGCM) NonceSize() int { +func (g *StupidGCM) NonceSize() int { errExit() return -1 } -func (g *stupidGCM) Overhead() int { +func (g *StupidGCM) Overhead() int { errExit() return -1 } -func (g *stupidGCM) Seal(_, _, _, _ []byte) []byte { +func (g *StupidGCM) Seal(_, _, _, _ []byte) []byte { errExit() return nil } -func (g *stupidGCM) Open(_, _, _, _ []byte) ([]byte, error) { +func (g *StupidGCM) Open(_, _, _, _ []byte) ([]byte, error) { errExit() return nil, nil } + +func (g *StupidGCM) Wipe() { + errExit() +} -- cgit v1.2.3