aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go.mod1
-rw-r--r--go.sum2
-rw-r--r--internal/nametransform/names.go38
3 files changed, 34 insertions, 7 deletions
diff --git a/go.mod b/go.mod
index c608e6f..986f329 100644
--- a/go.mod
+++ b/go.mod
@@ -13,4 +13,5 @@ require (
golang.org/x/crypto v0.45.0
golang.org/x/sys v0.38.0
golang.org/x/term v0.37.0
+ golang.org/x/text v0.31.0
)
diff --git a/go.sum b/go.sum
index f0e7ea7..29d991f 100644
--- a/go.sum
+++ b/go.sum
@@ -38,6 +38,8 @@ golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
+golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
+golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/nametransform/names.go b/internal/nametransform/names.go
index 3313a7c..d007592 100644
--- a/internal/nametransform/names.go
+++ b/internal/nametransform/names.go
@@ -7,9 +7,12 @@ import (
"errors"
"math"
"path/filepath"
+ "runtime"
"strings"
"syscall"
+ "golang.org/x/text/unicode/norm"
+
"github.com/rfjakob/eme"
"github.com/rfjakob/gocryptfs/v2/internal/tlog"
@@ -32,6 +35,10 @@ type NameTransform struct {
// Patterns to bypass decryption
badnamePatterns []string
deterministicNames bool
+ // Convert filenames to NFC before encrypting,
+ // and to NFD when decrypting.
+ // For MacOS compatibility.
+ nfd2nfc bool
}
// New returns a new NameTransform instance.
@@ -55,34 +62,44 @@ func New(e *eme.EMECipher, longNames bool, longNameMax uint8, raw64 bool, badnam
effectiveLongNameMax = int(longNameMax)
}
}
+ nfd2nfc := runtime.GOOS == "darwin"
+ if nfd2nfc {
+ tlog.Info.Printf("Running on MacOS, enabling Unicode normalization")
+ }
return &NameTransform{
emeCipher: e,
longNameMax: effectiveLongNameMax,
B64: b64,
badnamePatterns: badname,
deterministicNames: deterministicNames,
+ nfd2nfc: nfd2nfc,
}
}
// DecryptName calls decryptName to try and decrypt a base64-encoded encrypted
// filename "cipherName", and failing that checks if it can be bypassed
-func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error) {
- res, err := n.decryptName(cipherName, iv)
+func (n *NameTransform) DecryptName(cipherName string, iv []byte) (plainName string, err error) {
+ plainName, err = n.decryptName(cipherName, iv)
if err != nil && n.HaveBadnamePatterns() {
- res, err = n.decryptBadname(cipherName, iv)
+ plainName, err = n.decryptBadname(cipherName, iv)
}
if err != nil {
return "", err
}
- if err := IsValidName(res); err != nil {
+ if err := IsValidName(plainName); err != nil {
tlog.Warn.Printf("DecryptName %q: invalid name after decryption: %v", cipherName, err)
return "", syscall.EBADMSG
}
- return res, err
+ if n.nfd2nfc {
+ // MacOS expects file names in NFD form. Present them as NFD.
+ // They are converted back to NFC in EncryptName.
+ plainName = norm.NFD.String(plainName)
+ }
+ return plainName, err
}
-// decryptName decrypts a base64-encoded encrypted filename "cipherName" using the
-// initialization vector "iv".
+// decryptName decrypts a base64-encoded encrypted file- or xattr-name "cipherName"
+// using the initialization vector "iv".
func (n *NameTransform) decryptName(cipherName string, iv []byte) (string, error) {
// From https://pkg.go.dev/encoding/base64#Encoding.Strict :
// > Note that the input is still malleable, as new line characters
@@ -126,6 +143,13 @@ func (n *NameTransform) EncryptName(plainName string, iv []byte) (cipherName64 s
tlog.Warn.Printf("EncryptName %q: invalid plainName: %v", plainName, err)
return "", syscall.EBADMSG
}
+ if n.nfd2nfc {
+ // MacOS GUI apps expect Unicode in NFD form.
+ // But MacOS CLI apps, Linux and Windows use NFC form.
+ // To prevent trouble when decrypting MacOS-created gocryptfs filesystems
+ // on other OS, we convert to NFC form.
+ plainName = norm.NFC.String(plainName)
+ }
return n.encryptName(plainName, iv), nil
}