libgocryptfs: update to gocryptfs v2.3

This commit is contained in:
Matéo Duparc 2022-09-18 15:05:28 +02:00
commit 27232cbdb7
Signed by: hardcoresushi
GPG Key ID: AFE384344A45E13A
17 changed files with 119 additions and 46 deletions

11
go.mod
View File

@ -1,14 +1,17 @@
module libgocryptfs/v2
go 1.16
go 1.19
require (
github.com/jacobsa/crypto v0.0.0-20190317225127-9f44e2d11115
github.com/rfjakob/eme v1.1.2
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41
)
require (
github.com/jacobsa/oglematchers v0.0.0-20150720000706-141901ea67cd // indirect
github.com/jacobsa/oglemock v0.0.0-20150831005832-e94d794d06ff // indirect
github.com/jacobsa/ogletest v0.0.0-20170503003838-80d50a735a11 // indirect
github.com/jacobsa/reqtrace v0.0.0-20150505043853-245c9e0234cb // indirect
github.com/rfjakob/eme v1.1.2
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
)

15
go.sum
View File

@ -10,15 +10,8 @@ github.com/jacobsa/reqtrace v0.0.0-20150505043853-245c9e0234cb h1:uSWBjJdMf47kQl
github.com/jacobsa/reqtrace v0.0.0-20150505043853-245c9e0234cb/go.mod h1:ivcmUvxXWjb27NsPEaiYK7AidlZXS7oQ5PowUS9z3I4=
github.com/rfjakob/eme v1.1.2 h1:SxziR8msSOElPayZNFfQw4Tjx/Sbaeeh3eRvrHVMUs4=
github.com/rfjakob/eme v1.1.2/go.mod h1:cVvpasglm/G3ngEfcfT/Wt0GwhkuO32pf/poW6Nyk1k=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -54,6 +54,8 @@ type ConfFile struct {
FeatureFlags []string
// FIDO2 parameters
FIDO2 *FIDO2Params `json:",omitempty"`
// LongNameMax corresponds to the -longnamemax flag
LongNameMax uint8 `json:",omitempty"`
// Filename is the name of the config file. Not exported to JSON.
filename string
}
@ -68,6 +70,7 @@ type CreateArgs struct {
AESSIV bool
DeterministicNames bool
XChaCha20Poly1305 bool
LongNameMax uint8
}
// Create - create a new config with a random key encrypted with
@ -94,6 +97,12 @@ func Create(args *CreateArgs, returnedScryptHashBuff []byte) error {
if !args.DeterministicNames {
cf.setFeatureFlag(FlagDirIV)
}
// 0 means to *use* the default (which means we don't have to save it), and
// 255 *is* the default, which means we don't have to save it either.
if args.LongNameMax != 0 && args.LongNameMax != 255 {
cf.LongNameMax = args.LongNameMax
cf.setFeatureFlag(FlagLongNameMax)
}
cf.setFeatureFlag(FlagEMENames)
cf.setFeatureFlag(FlagLongNames)
cf.setFeatureFlag(FlagRaw64)

View File

@ -14,8 +14,11 @@ const (
// This flag is mandatory since gocryptfs v1.0,
// except when XChaCha20Poly1305 is used.
FlagGCMIV128
// FlagLongNames allows file names longer than 176 bytes.
// FlagLongNames allows file names longer than 175 bytes.
FlagLongNames
// FlagLongNameMax sets a custom name length limit, names longer than that
// will be hashed.
FlagLongNameMax
// FlagAESSIV selects an AES-SIV based crypto backend.
FlagAESSIV
// FlagRaw64 enables raw (unpadded) base64 encoding for file names
@ -40,6 +43,7 @@ var knownFlags = map[flagIota]string{
FlagEMENames: "EMENames",
FlagGCMIV128: "GCMIV128",
FlagLongNames: "LongNames",
FlagLongNameMax: "LongNameMax",
FlagAESSIV: "AESSIV",
FlagRaw64: "Raw64",
FlagHKDF: "HKDF",

View File

@ -23,22 +23,23 @@ func (cf *ConfFile) Validate() error {
}
// File content encryption
{
switch {
case cf.IsFeatureFlagSet(FlagXChaCha20Poly1305) && cf.IsFeatureFlagSet(FlagAESSIV):
if cf.IsFeatureFlagSet(FlagXChaCha20Poly1305) && cf.IsFeatureFlagSet(FlagAESSIV) {
return fmt.Errorf("Can't have both XChaCha20Poly1305 and AESSIV feature flags")
case cf.IsFeatureFlagSet(FlagAESSIV):
if !cf.IsFeatureFlagSet(FlagGCMIV128) {
return fmt.Errorf("AESSIV requires GCMIV128 feature flag")
}
case cf.IsFeatureFlagSet(FlagXChaCha20Poly1305):
}
if cf.IsFeatureFlagSet(FlagAESSIV) && !cf.IsFeatureFlagSet(FlagGCMIV128) {
return fmt.Errorf("AESSIV requires GCMIV128 feature flag")
}
if cf.IsFeatureFlagSet(FlagXChaCha20Poly1305) {
if cf.IsFeatureFlagSet(FlagGCMIV128) {
return fmt.Errorf("XChaCha20Poly1305 conflicts with GCMIV128 feature flag")
}
if !cf.IsFeatureFlagSet(FlagHKDF) {
return fmt.Errorf("XChaCha20Poly1305 requires HKDF feature flag")
}
}
// The absence of other flags means AES-GCM (oldest algorithm)
case !cf.IsFeatureFlagSet(FlagXChaCha20Poly1305) && !cf.IsFeatureFlagSet(FlagAESSIV):
if !cf.IsFeatureFlagSet(FlagXChaCha20Poly1305) && !cf.IsFeatureFlagSet(FlagAESSIV) {
if !cf.IsFeatureFlagSet(FlagGCMIV128) {
return fmt.Errorf("AES-GCM requires GCMIV128 feature flag")
}
@ -46,10 +47,10 @@ func (cf *ConfFile) Validate() error {
}
// Filename encryption
{
switch {
case cf.IsFeatureFlagSet(FlagPlaintextNames) && cf.IsFeatureFlagSet(FlagEMENames):
return fmt.Errorf("Can't have both PlaintextNames and EMENames feature flags")
case cf.IsFeatureFlagSet(FlagPlaintextNames):
if cf.IsFeatureFlagSet(FlagPlaintextNames) {
if cf.IsFeatureFlagSet(FlagEMENames) {
return fmt.Errorf("PlaintextNames conflicts with EMENames feature flag")
}
if cf.IsFeatureFlagSet(FlagDirIV) {
return fmt.Errorf("PlaintextNames conflicts with DirIV feature flag")
}
@ -59,9 +60,19 @@ func (cf *ConfFile) Validate() error {
if cf.IsFeatureFlagSet(FlagRaw64) {
return fmt.Errorf("PlaintextNames conflicts with Raw64 feature flag")
}
case cf.IsFeatureFlagSet(FlagEMENames):
if cf.IsFeatureFlagSet(FlagLongNameMax) {
return fmt.Errorf("PlaintextNames conflicts with LongNameMax feature flag")
}
}
if cf.IsFeatureFlagSet(FlagEMENames) {
// All combinations of DirIV, LongNames, Raw64 allowed
}
if cf.LongNameMax != 0 && !cf.IsFeatureFlagSet(FlagLongNameMax) {
return fmt.Errorf("LongNameMax=%d but the LongNameMax feature flag is NOT set", cf.LongNameMax)
}
if cf.LongNameMax == 0 && cf.IsFeatureFlagSet(FlagLongNameMax) {
return fmt.Errorf("LongNameMax=0 but the LongNameMax feature flag IS set")
}
}
return nil
}

View File

@ -34,7 +34,7 @@ func (be *NameTransform) EncryptAndHashBadName(name string, iv []byte, dirfd int
//file found, return result
return lastFoundName, nil
}
//BadName Mode: check if the name was tranformed without change (badname suffix and undecryptable cipher name)
//BadName Mode: check if the name was transformed without change (badname suffix and undecryptable cipher name)
err = syscallcompat.Fstatat(dirfd, name[:len(name)-len(BadnameSuffix)], &st, unix.AT_SYMLINK_NOFOLLOW)
if err == nil {
filesFound++
@ -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)]

View File

@ -4,6 +4,7 @@ package nametransform
import (
"crypto/aes"
"encoding/base64"
"math"
"path/filepath"
"syscall"
@ -18,7 +19,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
@ -28,14 +31,26 @@ type NameTransform struct {
}
// New returns a new NameTransform instance.
func New(e *eme.EMECipher, longNames bool, raw64 bool, badname []string, deterministicNames bool) *NameTransform {
//
// 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 {
b64 := base64.URLEncoding
if raw64 {
b64 = base64.RawURLEncoding
}
var effectiveLongNameMax int = math.MaxInt32
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,
@ -47,7 +62,13 @@ func New(e *eme.EMECipher, longNames bool, raw64 bool, badname []string, determi
func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error) {
res, err := n.decryptName(cipherName, iv)
if err != nil && n.HaveBadnamePatterns() {
return n.decryptBadname(cipherName, iv)
res, err = n.decryptBadname(cipherName, iv)
}
if err != nil {
return "", err
}
if err := IsValidName(res); err != nil {
return "", syscall.EBADMSG
}
return res, err
}
@ -71,26 +92,34 @@ func (n *NameTransform) decryptName(cipherName string, iv []byte) (string, error
return "", syscall.EBADMSG
}
plain := string(bin)
if err := IsValidName(plain); err != nil {
return "", syscall.EBADMSG
}
return plain, err
}
// EncryptName encrypts "plainName", returns a base64-encoded "cipherName64",
// EncryptName encrypts a file name "plainName" and returns a base64-encoded "cipherName64",
// encrypted using EME (https://github.com/rfjakob/eme).
//
// plainName is checked for null bytes, slashes etc. and such names are rejected
// with an error.
//
// This function is exported because in some cases, fusefrontend needs access
// to the full (not hashed) name if longname is used.
func (n *NameTransform) EncryptName(plainName string, iv []byte) (cipherName64 string, err error) {
if err := IsValidName(plainName); err != nil {
return "", syscall.EBADMSG
}
return n.encryptName(plainName, iv), nil
}
// encryptName encrypts "plainName" and returns a base64-encoded "cipherName64",
// encrypted using EME (https://github.com/rfjakob/eme).
//
// No checks for null bytes etc are performed against plainName.
func (n *NameTransform) encryptName(plainName string, iv []byte) (cipherName64 string) {
bin := []byte(plainName)
bin = pad16(bin)
bin = n.emeCipher.Encrypt(iv, bin)
cipherName64 = n.B64.EncodeToString(bin)
return cipherName64, nil
return cipherName64
}
// EncryptAndHashName encrypts "name" and hashes it to a longname if it is
@ -105,7 +134,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
@ -129,3 +158,9 @@ func Dir(path string) string {
}
return d
}
// GetLongNameMax will return curent `longNameMax`. File name longer than
// this should be hashed.
func (n *NameTransform) GetLongNameMax() int {
return n.longNameMax
}

View File

@ -1,3 +1,4 @@
//go:build !without_openssl
// +build !without_openssl
package stupidgcm

View File

@ -1,3 +1,4 @@
//go:build !without_openssl
// +build !without_openssl
package stupidgcm

View File

@ -1,3 +1,4 @@
//go:build !without_openssl
// +build !without_openssl
package stupidgcm

View File

@ -1,3 +1,4 @@
//go:build !without_openssl
// +build !without_openssl
package stupidgcm

View File

@ -1,3 +1,4 @@
//go:build !without_openssl
// +build !without_openssl
package stupidgcm
@ -117,7 +118,7 @@ func slicePointerOrNull(s []byte) (ptr *C.uchar) {
}
// This functions exists to benchmark the C call overhead from Go.
// See BenchmarkCCall for resuts.
// See BenchmarkCCall for results.
func noopCFunction() {
C.noop_c_function()
}

View File

@ -40,7 +40,7 @@ func PreferOpenSSLXchacha20poly1305() bool {
if runtime.GOARCH == "amd64" {
return false
}
// On arm64 and arm, OpenSSL is faster. Probably everwhere else too.
// On arm64 and arm, OpenSSL is faster. Probably everywhere else too.
return true
}

View File

@ -1,3 +1,4 @@
//go:build !without_openssl
// +build !without_openssl
// Copyright 2018 The Go Authors. All rights reserved.

View File

@ -1,3 +1,4 @@
//go:build linux
// +build linux
package syscallcompat

View File

@ -17,8 +17,10 @@ const (
// O_PATH is only defined on Linux
O_PATH = unix.O_PATH
// RENAME_NOREPLACE is only defined on Linux
// Only defined on Linux
RENAME_NOREPLACE = unix.RENAME_NOREPLACE
RENAME_WHITEOUT = unix.RENAME_WHITEOUT
RENAME_EXCHANGE = unix.RENAME_EXCHANGE
)
// EnospcPrealloc preallocates ciphertext space without changing the file

View File

@ -9,6 +9,7 @@ import (
"sync"
"syscall"
"path/filepath"
"runtime/debug"
"libgocryptfs/v2/internal/configfile"
"libgocryptfs/v2/internal/contentenc"
@ -81,6 +82,7 @@ func registerNewVolume(rootCipherDir string, masterkey []byte, cf *configfile.Co
newVolume.nameTransform = nametransform.New(
newVolume.cryptoCore.EMECipher,
true,
cf.LongNameMax,
cf.IsFeatureFlagSet(configfile.FlagRaw64),
badname,
!cf.IsFeatureFlagSet(configfile.FlagDirIV),
@ -116,6 +118,8 @@ func gcf_init(rootCipherDir string, password, givenScryptHash, returnedScryptHas
cf, err := configfile.Load(filepath.Join(rootCipherDir, configfile.ConfDefaultName))
if err == nil {
masterkey := cf.GetMasterkey(password, givenScryptHash, returnedScryptHashBuff)
wipe(password)
debug.FreeOSMemory()
if masterkey != nil {
volumeID = registerNewVolume(rootCipherDir, masterkey, cf)
wipe(masterkey)
@ -152,14 +156,14 @@ func gcf_is_closed(volumeID int) bool {
}
//export gcf_change_password
func gcf_change_password(rootCipherDir string, oldPassword, givenScryptHash, new_password, returnedScryptHashBuff []byte) bool {
func gcf_change_password(rootCipherDir string, oldPassword, givenScryptHash, newPassword, returnedScryptHashBuff []byte) bool {
success := false
cf, err := configfile.Load(filepath.Join(rootCipherDir, configfile.ConfDefaultName))
if err == nil {
masterkey := cf.GetMasterkey(oldPassword, givenScryptHash, nil)
if masterkey != nil {
logN := cf.ScryptObject.LogN()
scryptHash := cf.EncryptKey(masterkey, new_password, logN, len(returnedScryptHashBuff) > 0)
scryptHash := cf.EncryptKey(masterkey, newPassword, logN, len(returnedScryptHashBuff) > 0)
wipe(masterkey)
for i := range scryptHash {
returnedScryptHashBuff[i] = scryptHash[i]
@ -168,6 +172,9 @@ func gcf_change_password(rootCipherDir string, oldPassword, givenScryptHash, new
success = errToBool(cf.WriteFile())
}
}
wipe(newPassword)
wipe(oldPassword)
wipe(givenScryptHash)
return success
}
@ -191,7 +198,9 @@ func gcf_create_volume(rootCipherDir string, password []byte, plaintextNames boo
AESSIV: false,
DeterministicNames: false,
XChaCha20Poly1305: useXChaCha,
LongNameMax: 255,
}, returnedScryptHashBuff)
wipe(password)
if err == nil {
if plaintextNames {
return true