diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/configfile/config_file.go | 4 | ||||
| -rw-r--r-- | internal/contentenc/content.go | 16 | ||||
| -rw-r--r-- | internal/contentenc/content_test.go | 12 | ||||
| -rw-r--r-- | internal/cryptocore/cryptocore.go | 4 | ||||
| -rw-r--r-- | internal/cryptocore/cryptocore_test.go | 8 | ||||
| -rw-r--r-- | internal/fusefrontend/args.go | 2 | ||||
| -rw-r--r-- | internal/fusefrontend/file.go | 4 | ||||
| -rw-r--r-- | internal/fusefrontend/fs.go | 4 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/rfs.go | 4 | ||||
| -rw-r--r-- | internal/speed/speed.go | 2 | ||||
| -rw-r--r-- | internal/stupidgcm/stupidgcm.go | 18 | ||||
| -rw-r--r-- | internal/stupidgcm/stupidgcm_test.go | 4 | ||||
| -rw-r--r-- | internal/stupidgcm/without_openssl.go | 5 | 
13 files changed, 57 insertions, 30 deletions
| diff --git a/internal/configfile/config_file.go b/internal/configfile/config_file.go index bf56f8b..5605e1d 100644 --- a/internal/configfile/config_file.go +++ b/internal/configfile/config_file.go @@ -225,7 +225,7 @@ func getKeyEncrypter(scryptHash []byte, useHKDF bool) *contentenc.ContentEnc {  	if useHKDF {  		IVLen = contentenc.DefaultIVBits  	} -	cc := cryptocore.New(scryptHash, cryptocore.BackendGoGCM, IVLen, useHKDF) -	ce := contentenc.New(cc, 4096) +	cc := cryptocore.New(scryptHash, cryptocore.BackendGoGCM, IVLen, useHKDF, false) +	ce := contentenc.New(cc, 4096, false)  	return ce  } diff --git a/internal/contentenc/content.go b/internal/contentenc/content.go index a2a263c..9998c06 100644 --- a/internal/contentenc/content.go +++ b/internal/contentenc/content.go @@ -9,6 +9,7 @@ import (  	"log"  	"github.com/rfjakob/gocryptfs/internal/cryptocore" +	"github.com/rfjakob/gocryptfs/internal/stupidgcm"  	"github.com/rfjakob/gocryptfs/internal/tlog"  ) @@ -46,10 +47,12 @@ type ContentEnc struct {  	allZeroBlock []byte  	// All-zero block of size IVBitLen/8, for fast compares  	allZeroNonce []byte +	// Force decode even if integrity check fails (openSSL only) +	forceDecode bool  }  // New returns an initialized ContentEnc instance. -func New(cc *cryptocore.CryptoCore, plainBS uint64) *ContentEnc { +func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEnc {  	cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen  	return &ContentEnc{ @@ -58,6 +61,7 @@ func New(cc *cryptocore.CryptoCore, plainBS uint64) *ContentEnc {  		cipherBS:     cipherBS,  		allZeroBlock: make([]byte, cipherBS),  		allZeroNonce: make([]byte, cc.IVLen), +		forceDecode:  forceDecode,  	}  } @@ -82,7 +86,9 @@ func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, file  		var pBlock []byte  		pBlock, err = be.DecryptBlock(cBlock, firstBlockNo, fileID)  		if err != nil { -			break +			if be.forceDecode == false || (be.forceDecode == true && stupidgcm.AuthError != err) { +				break +			}  		}  		pBuf.Write(pBlock)  		firstBlockNo++ @@ -133,7 +139,11 @@ func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileID []b  	if err != nil {  		tlog.Warn.Printf("DecryptBlock: %s, len=%d", err.Error(), len(ciphertextOrig))  		tlog.Debug.Println(hex.Dump(ciphertextOrig)) -		return nil, err +		if be.forceDecode == true { +			return plaintext, err +		} else { +			return nil, err +		}  	}  	return plaintext, nil diff --git a/internal/contentenc/content_test.go b/internal/contentenc/content_test.go index 8ce496d..e4d4a3e 100644 --- a/internal/contentenc/content_test.go +++ b/internal/contentenc/content_test.go @@ -23,8 +23,8 @@ func TestSplitRange(t *testing.T) {  		testRange{6654, 8945})  	key := make([]byte, cryptocore.KeyLen) -	cc := cryptocore.New(key, cryptocore.BackendOpenSSL, DefaultIVBits, true) -	f := New(cc, DefaultBS) +	cc := cryptocore.New(key, cryptocore.BackendOpenSSL, DefaultIVBits, true, false) +	f := New(cc, DefaultBS, false)  	for _, r := range ranges {  		parts := f.ExplodePlainRange(r.offset, r.length) @@ -51,8 +51,8 @@ func TestCiphertextRange(t *testing.T) {  		testRange{6654, 8945})  	key := make([]byte, cryptocore.KeyLen) -	cc := cryptocore.New(key, cryptocore.BackendOpenSSL, DefaultIVBits, true) -	f := New(cc, DefaultBS) +	cc := cryptocore.New(key, cryptocore.BackendOpenSSL, DefaultIVBits, true, false) +	f := New(cc, DefaultBS, false)  	for _, r := range ranges { @@ -74,8 +74,8 @@ func TestCiphertextRange(t *testing.T) {  func TestBlockNo(t *testing.T) {  	key := make([]byte, cryptocore.KeyLen) -	cc := cryptocore.New(key, cryptocore.BackendOpenSSL, DefaultIVBits, true) -	f := New(cc, DefaultBS) +	cc := cryptocore.New(key, cryptocore.BackendOpenSSL, DefaultIVBits, true, false) +	f := New(cc, DefaultBS, false)  	b := f.CipherOffToBlockNo(788)  	if b != 0 { diff --git a/internal/cryptocore/cryptocore.go b/internal/cryptocore/cryptocore.go index 5244104..2c352c2 100644 --- a/internal/cryptocore/cryptocore.go +++ b/internal/cryptocore/cryptocore.go @@ -51,7 +51,7 @@ type CryptoCore struct {  // Even though the "GCMIV128" feature flag is now mandatory, we must still  // support 96-bit IVs here because they were used for encrypting the master  // key in gocryptfs.conf up to gocryptfs v1.2. v1.3 switched to 128 bits. -func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool) *CryptoCore { +func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDecode bool) *CryptoCore {  	if len(key) != KeyLen {  		log.Panic(fmt.Sprintf("Unsupported key length %d", len(key)))  	} @@ -86,7 +86,7 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool) *CryptoC  			if IVLen != 16 {  				log.Panic("stupidgcm only supports 128-bit IVs")  			} -			aeadCipher = stupidgcm.New(gcmKey) +			aeadCipher = stupidgcm.New(gcmKey, forceDecode)  		case BackendGoGCM:  			goGcmBlockCipher, err := aes.NewCipher(gcmKey)  			if err != nil { diff --git a/internal/cryptocore/cryptocore_test.go b/internal/cryptocore/cryptocore_test.go index 25f6572..4c34652 100644 --- a/internal/cryptocore/cryptocore_test.go +++ b/internal/cryptocore/cryptocore_test.go @@ -8,15 +8,15 @@ import (  func TestCryptoCoreNew(t *testing.T) {  	key := make([]byte, 32)  	for _, useHKDF := range []bool{true, false} { -		c := New(key, BackendOpenSSL, 128, useHKDF) +		c := New(key, BackendOpenSSL, 128, useHKDF, false)  		if c.IVLen != 16 {  			t.Fail()  		} -		c = New(key, BackendGoGCM, 96, useHKDF) +		c = New(key, BackendGoGCM, 96, useHKDF, false)  		if c.IVLen != 12 {  			t.Fail()  		} -		c = New(key, BackendGoGCM, 128, useHKDF) +		c = New(key, BackendGoGCM, 128, useHKDF, false)  		if c.IVLen != 16 {  			t.Fail()  		} @@ -32,5 +32,5 @@ func TestNewPanic(t *testing.T) {  	}()  	key := make([]byte, 16) -	New(key, BackendOpenSSL, 128, true) +	New(key, BackendOpenSSL, 128, true, false)  } diff --git a/internal/fusefrontend/args.go b/internal/fusefrontend/args.go index ddfb9dc..5781db8 100644 --- a/internal/fusefrontend/args.go +++ b/internal/fusefrontend/args.go @@ -31,4 +31,6 @@ type Args struct {  	HKDF bool  	// Try to serialize read operations, "-serialize_reads"  	SerializeReads bool +	// Force decode even if integrity check fails (openSSL only) +	ForceDecode bool  } diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index 84ce058..4d75d64 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -202,7 +202,9 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {  	if err != nil {  		curruptBlockNo := firstBlockNo + f.contentEnc.PlainOffToBlockNo(uint64(len(plaintext)))  		tlog.Warn.Printf("ino%d: doRead: corrupt block #%d: %v", f.devIno.ino, curruptBlockNo, err) -		return nil, fuse.EIO +		if (f.fs.args.ForceDecode == false) { +			return nil, fuse.EIO +		}  	}  	// Crop down to the relevant part diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go index 28c43b6..4aa4ffd 100644 --- a/internal/fusefrontend/fs.go +++ b/internal/fusefrontend/fs.go @@ -40,8 +40,8 @@ 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) -	contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS) +	cryptoCore := cryptocore.New(args.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)  	if args.SerializeReads { diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go index a94f448..3c52244 100644 --- a/internal/fusefrontend_reverse/rfs.go +++ b/internal/fusefrontend_reverse/rfs.go @@ -44,8 +44,8 @@ func NewFS(args fusefrontend.Args) *ReverseFS {  		log.Panic("reverse mode must use AES-SIV, everything else is insecure")  	}  	initLongnameCache() -	cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF) -	contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS) +	cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, false) +	contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS, false)  	nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64)  	return &ReverseFS{ diff --git a/internal/speed/speed.go b/internal/speed/speed.go index f9bf93c..8732576 100644 --- a/internal/speed/speed.go +++ b/internal/speed/speed.go @@ -72,7 +72,7 @@ func bStupidGCM(b *testing.B) {  	in := make([]byte, blockSize)  	b.SetBytes(int64(len(in))) -	sGCM := stupidgcm.New(key) +	sGCM := stupidgcm.New(key, false)  	b.ResetTimer()  	for i := 0; i < b.N; i++ { diff --git a/internal/stupidgcm/stupidgcm.go b/internal/stupidgcm/stupidgcm.go index a1a5a14..133ee1a 100644 --- a/internal/stupidgcm/stupidgcm.go +++ b/internal/stupidgcm/stupidgcm.go @@ -26,17 +26,21 @@ const (  // stupidGCM implements the cipher.AEAD interface  type stupidGCM struct { -	key []byte +	key         []byte +	forceDecode bool  } +//authentication error +var AuthError error = fmt.Errorf("stupidgcm: message authentication failed") +  var _ cipher.AEAD = &stupidGCM{}  // New returns a new cipher.AEAD implementation.. -func New(key []byte) cipher.AEAD { +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} +	return stupidGCM{key: key, forceDecode: forceDecode}  }  func (g stupidGCM) NonceSize() int { @@ -186,7 +190,13 @@ func (g stupidGCM) Open(dst, iv, in, authData []byte) ([]byte, error) {  	C.EVP_CIPHER_CTX_free(ctx)  	if res != 1 { -		return nil, fmt.Errorf("stupidgcm: message authentication failed") +		// The error code must always be checked by the calling function, because the decrypted buffer +		// may contain corrupted data that we are returning in case the user forced reads +		if g.forceDecode == true { +			return append(dst, buf...), AuthError +		} else { +			return nil, AuthError +		}  	}  	return append(dst, buf...), nil diff --git a/internal/stupidgcm/stupidgcm_test.go b/internal/stupidgcm/stupidgcm_test.go index 3081085..eb322f2 100644 --- a/internal/stupidgcm/stupidgcm_test.go +++ b/internal/stupidgcm/stupidgcm_test.go @@ -27,7 +27,7 @@ func randBytes(n int) []byte {  // GCM implemenatation and verifies that the results are identical.  func TestEncryptDecrypt(t *testing.T) {  	key := randBytes(32) -	sGCM := New(key) +	sGCM := New(key, false)  	authData := randBytes(24)  	iv := randBytes(16)  	dst := make([]byte, 71) // 71 = random length @@ -77,7 +77,7 @@ func TestEncryptDecrypt(t *testing.T) {  // error  func TestCorruption(t *testing.T) {  	key := randBytes(32) -	sGCM := New(key) +	sGCM := New(key, false)  	authData := randBytes(24)  	iv := randBytes(16) diff --git a/internal/stupidgcm/without_openssl.go b/internal/stupidgcm/without_openssl.go index 18c5ddc..52d8fa0 100644 --- a/internal/stupidgcm/without_openssl.go +++ b/internal/stupidgcm/without_openssl.go @@ -14,12 +14,15 @@ const (  	BuiltWithoutOpenssl = true  ) +//authentication error - needed to compile as same varaible is exported when openssl is enable via stupidgcm.go +var AuthError error = fmt.Errorf("stupidgcm: message authentication failed with openssl disabled!") +  func errExit() {  	fmt.Fprintln(os.Stderr, "gocryptfs has been compiled without openssl support but you are still trying to use openssl")  	os.Exit(2)  } -func New(_ []byte) stupidGCM { +func New(_ []byte, _ bool) stupidGCM {  	errExit()  	// Never reached  	return stupidGCM{} | 
