diff options
| -rw-r--r-- | internal/fusefrontend/xattr_unit_test.go | 2 | ||||
| -rw-r--r-- | internal/nametransform/badname.go | 2 | ||||
| -rw-r--r-- | internal/nametransform/longnames_test.go | 41 | ||||
| -rw-r--r-- | internal/nametransform/names.go | 28 | ||||
| -rw-r--r-- | mount.go | 2 | 
5 files changed, 65 insertions, 10 deletions
| diff --git a/internal/fusefrontend/xattr_unit_test.go b/internal/fusefrontend/xattr_unit_test.go index 5bffd5e..86c87a7 100644 --- a/internal/fusefrontend/xattr_unit_test.go +++ b/internal/fusefrontend/xattr_unit_test.go @@ -19,7 +19,7 @@ func newTestFS(args Args) *RootNode {  	key := make([]byte, cryptocore.KeyLen)  	cCore := cryptocore.New(key, cryptocore.BackendGoGCM, contentenc.DefaultIVBits, true)  	cEnc := contentenc.New(cCore, contentenc.DefaultBS) -	n := nametransform.New(cCore.EMECipher, true, true, nil, false) +	n := nametransform.New(cCore.EMECipher, true, 0, true, nil, false)  	rn := NewRootNode(args, cEnc, n)  	oneSec := time.Second  	options := &fs.Options{ diff --git a/internal/nametransform/badname.go b/internal/nametransform/badname.go index eed0061..6e77561 100644 --- a/internal/nametransform/badname.go +++ b/internal/nametransform/badname.go @@ -48,7 +48,7 @@ func (be *NameTransform) EncryptAndHashBadName(name string, iv []byte, dirfd int  			//expand suffix on error  			continue  		} -		if be.longNames && len(cName) > NameMax { +		if len(cName) > be.longNameMax {  			cNamePart = be.HashLongName(cName)  		}  		cNameBadReverse := cNamePart + name[charpos:len(name)-len(BadnameSuffix)] diff --git a/internal/nametransform/longnames_test.go b/internal/nametransform/longnames_test.go index 4210492..7a4e915 100644 --- a/internal/nametransform/longnames_test.go +++ b/internal/nametransform/longnames_test.go @@ -1,7 +1,11 @@  package nametransform  import ( +	"strings"  	"testing" + +	"github.com/rfjakob/gocryptfs/v2/internal/contentenc" +	"github.com/rfjakob/gocryptfs/v2/internal/cryptocore"  )  func TestIsLongName(t *testing.T) { @@ -28,3 +32,40 @@ func TestRemoveLongNameSuffix(t *testing.T) {  		t.Error(".name suffix not removed")  	}  } + +func newLognamesTestInstance(longNameMax uint8) *NameTransform { +	key := make([]byte, cryptocore.KeyLen) +	cCore := cryptocore.New(key, cryptocore.BackendGoGCM, contentenc.DefaultIVBits, true) +	return New(cCore.EMECipher, true, longNameMax, true, nil, false) +} + +func TestLongNameMax(t *testing.T) { +	iv := make([]byte, 16) +	for max := 0; max <= NameMax; max++ { +		n := newLognamesTestInstance(uint8(max)) +		if max == 0 { +			// effective value is 255 +			max = NameMax +		} +		for l := 0; l <= NameMax+10; l++ { +			name := strings.Repeat("x", l) +			out, err := n.EncryptAndHashName(name, iv) +			if l == 0 || l > NameMax { +				if err == nil { +					t.Errorf("should have rejected a name of length %d, but did not", l) +				} +				continue +			} +			cName, _ := n.EncryptName(name, iv) +			rawLen := len(cName) +			want := LongNameNone +			if rawLen > max { +				want = LongNameContent +			} +			have := NameType(out) +			if have != want { +				t.Errorf("l=%d max=%d: wanted %v, got %v\nname=%q\nout=%q", l, max, want, have, name, out) +			} +		} +	} +} diff --git a/internal/nametransform/names.go b/internal/nametransform/names.go index d766d2f..939d31e 100644 --- a/internal/nametransform/names.go +++ b/internal/nametransform/names.go @@ -4,6 +4,7 @@ package nametransform  import (  	"crypto/aes"  	"encoding/base64" +	"math"  	"path/filepath"  	"syscall" @@ -20,7 +21,9 @@ const (  // NameTransform is used to transform filenames.  type NameTransform struct {  	emeCipher *eme.EMECipher -	longNames bool +	// Names longer than `longNameMax` are hashed. Set to MaxInt when +	// longnames are disabled. +	longNameMax int  	// B64 = either base64.URLEncoding or base64.RawURLEncoding, depending  	// on the Raw64 feature flag  	B64 *base64.Encoding @@ -30,17 +33,28 @@ type NameTransform struct {  }  // New returns a new NameTransform instance. -func New(e *eme.EMECipher, longNames bool, raw64 bool, badname []string, deterministicNames bool) *NameTransform { -	tlog.Debug.Printf("nametransform.New: longNames=%v, raw64=%v, badname=%q", -		longNames, raw64, badname) - +// +// If `longNames` is set, names longer than `longNameMax` are hashed to +// `gocryptfs.longname.[sha256]`. +// Pass `longNameMax = 0` to use the default value (255). +func New(e *eme.EMECipher, longNames bool, longNameMax uint8, raw64 bool, badname []string, deterministicNames bool) *NameTransform { +	tlog.Debug.Printf("nametransform.New: longNameMax=%v, raw64=%v, badname=%q", +		longNameMax, raw64, badname)  	b64 := base64.URLEncoding  	if raw64 {  		b64 = base64.RawURLEncoding  	} +	var effectiveLongNameMax int = math.MaxInt +	if longNames { +		if longNameMax == 0 { +			effectiveLongNameMax = NameMax +		} else { +			effectiveLongNameMax = int(longNameMax) +		} +	}  	return &NameTransform{  		emeCipher:          e, -		longNames:          longNames, +		longNameMax:        effectiveLongNameMax,  		B64:                b64,  		badnamePatterns:    badname,  		deterministicNames: deterministicNames, @@ -115,7 +129,7 @@ func (be *NameTransform) EncryptAndHashName(name string, iv []byte) (string, err  	if err != nil {  		return "", err  	} -	if be.longNames && len(cName) > NameMax { +	if len(cName) > be.longNameMax {  		return be.HashLongName(cName), nil  	}  	return cName, nil @@ -324,7 +324,7 @@ func initFuseFrontend(args *argContainer) (rootNode fs.InodeEmbedder, wipeKeys f  	// Init crypto backend  	cCore := cryptocore.New(masterkey, cryptoBackend, IVBits, args.hkdf)  	cEnc := contentenc.New(cCore, contentenc.DefaultBS) -	nameTransform := nametransform.New(cCore.EMECipher, frontendArgs.LongNames, +	nameTransform := nametransform.New(cCore.EMECipher, frontendArgs.LongNames, 0,  		args.raw64, []string(args.badname), frontendArgs.DeterministicNames)  	// After the crypto backend is initialized,  	// we can purge the master key from memory. | 
