Add partial XChaCha20-Poly1305 support (mount flag only)
Mount flag only at the moment, not saved to gocryptfs.conf. https://github.com/rfjakob/gocryptfs/issues/452
This commit is contained in:
parent
b02812f8b3
commit
4764a9bde0
@ -30,7 +30,8 @@ type argContainer struct {
|
|||||||
plaintextnames, quiet, nosyslog, wpanic,
|
plaintextnames, quiet, nosyslog, wpanic,
|
||||||
longnames, allow_other, reverse, aessiv, nonempty, raw64,
|
longnames, allow_other, reverse, aessiv, nonempty, raw64,
|
||||||
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
|
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
|
||||||
sharedstorage, devrandom, fsck, one_file_system, deterministic_names bool
|
sharedstorage, devrandom, fsck, one_file_system, deterministic_names,
|
||||||
|
xchacha bool
|
||||||
// Mount options with opposites
|
// Mount options with opposites
|
||||||
dev, nodev, suid, nosuid, exec, noexec, rw, ro, kernel_cache, acl bool
|
dev, nodev, suid, nosuid, exec, noexec, rw, ro, kernel_cache, acl bool
|
||||||
masterkey, mountpoint, cipherdir, cpuprofile,
|
masterkey, mountpoint, cipherdir, cpuprofile,
|
||||||
@ -180,6 +181,7 @@ func parseCliOpts(osArgs []string) (args argContainer) {
|
|||||||
flagSet.BoolVar(&args.fsck, "fsck", false, "Run a filesystem check on CIPHERDIR")
|
flagSet.BoolVar(&args.fsck, "fsck", false, "Run a filesystem check on CIPHERDIR")
|
||||||
flagSet.BoolVar(&args.one_file_system, "one-file-system", false, "Don't cross filesystem boundaries")
|
flagSet.BoolVar(&args.one_file_system, "one-file-system", false, "Don't cross filesystem boundaries")
|
||||||
flagSet.BoolVar(&args.deterministic_names, "deterministic-names", false, "Disable diriv file name randomisation")
|
flagSet.BoolVar(&args.deterministic_names, "deterministic-names", false, "Disable diriv file name randomisation")
|
||||||
|
flagSet.BoolVar(&args.xchacha, "xchacha", false, "Use XChaCha20-Poly1305 file content encryption")
|
||||||
|
|
||||||
// Mount options with opposites
|
// Mount options with opposites
|
||||||
flagSet.BoolVar(&args.dev, "dev", false, "Allow device files")
|
flagSet.BoolVar(&args.dev, "dev", false, "Allow device files")
|
||||||
|
@ -28,6 +28,8 @@ const (
|
|||||||
// FlagFIDO2 means that "-fido2" was used when creating the filesystem.
|
// FlagFIDO2 means that "-fido2" was used when creating the filesystem.
|
||||||
// The masterkey is protected using a FIDO2 token instead of a password.
|
// The masterkey is protected using a FIDO2 token instead of a password.
|
||||||
FlagFIDO2
|
FlagFIDO2
|
||||||
|
// FlagXChaCha20Poly1305 means we use XChaCha20-Poly1305 file content encryption
|
||||||
|
FlagXChaCha20Poly1305
|
||||||
)
|
)
|
||||||
|
|
||||||
// knownFlags stores the known feature flags and their string representation
|
// knownFlags stores the known feature flags and their string representation
|
||||||
@ -41,6 +43,7 @@ var knownFlags = map[flagIota]string{
|
|||||||
FlagRaw64: "Raw64",
|
FlagRaw64: "Raw64",
|
||||||
FlagHKDF: "HKDF",
|
FlagHKDF: "HKDF",
|
||||||
FlagFIDO2: "FIDO2",
|
FlagFIDO2: "FIDO2",
|
||||||
|
FlagXChaCha20Poly1305: "XChaCha20Poly1305",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filesystems that do not have these feature flags set are deprecated.
|
// Filesystems that do not have these feature flags set are deprecated.
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
|
|
||||||
"github.com/rfjakob/eme"
|
"github.com/rfjakob/eme"
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/v2/internal/siv_aead"
|
"github.com/rfjakob/gocryptfs/v2/internal/siv_aead"
|
||||||
@ -29,11 +31,17 @@ type AEADTypeEnum int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// BackendOpenSSL specifies the OpenSSL backend.
|
// BackendOpenSSL specifies the OpenSSL backend.
|
||||||
|
// "AES-GCM-256-OpenSSL" in gocryptfs -speed.
|
||||||
BackendOpenSSL AEADTypeEnum = 3
|
BackendOpenSSL AEADTypeEnum = 3
|
||||||
// BackendGoGCM specifies the Go based GCM backend.
|
// BackendGoGCM specifies the Go based GCM backend.
|
||||||
|
// "AES-GCM-256-Go" in gocryptfs -speed.
|
||||||
BackendGoGCM AEADTypeEnum = 4
|
BackendGoGCM AEADTypeEnum = 4
|
||||||
// BackendAESSIV specifies an AESSIV backend.
|
// BackendAESSIV specifies an AESSIV backend.
|
||||||
|
// "AES-SIV-512-Go" in gocryptfs -speed.
|
||||||
BackendAESSIV AEADTypeEnum = 5
|
BackendAESSIV AEADTypeEnum = 5
|
||||||
|
// BackendXChaCha20Poly1305 specifies XChaCha20-Poly1305-Go.
|
||||||
|
// "XChaCha20-Poly1305-Go" in gocryptfs -speed.
|
||||||
|
BackendXChaCha20Poly1305 AEADTypeEnum = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a AEADTypeEnum) String() string {
|
func (a AEADTypeEnum) String() string {
|
||||||
@ -78,7 +86,7 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec
|
|||||||
if len(key) != KeyLen {
|
if len(key) != KeyLen {
|
||||||
log.Panicf("Unsupported key length of %d bytes", len(key))
|
log.Panicf("Unsupported key length of %d bytes", len(key))
|
||||||
}
|
}
|
||||||
if IVBitLen != 96 && IVBitLen != 128 {
|
if IVBitLen != 96 && IVBitLen != 128 && IVBitLen != chacha20poly1305.NonceSizeX*8 {
|
||||||
log.Panicf("Unsupported IV length of %d bits", IVBitLen)
|
log.Panicf("Unsupported IV length of %d bits", IVBitLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +160,26 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec
|
|||||||
for i := range key64 {
|
for i := range key64 {
|
||||||
key64[i] = 0
|
key64[i] = 0
|
||||||
}
|
}
|
||||||
|
} else if aeadType == BackendXChaCha20Poly1305 {
|
||||||
|
// We don't support legacy modes with XChaCha20-Poly1305
|
||||||
|
if IVBitLen != chacha20poly1305.NonceSizeX*8 {
|
||||||
|
log.Panicf("XChaCha20-Poly1305 must use 192-bit IVs, you wanted %d", IVBitLen)
|
||||||
|
}
|
||||||
|
if !useHKDF {
|
||||||
|
log.Panic("XChaCha20-Poly1305 must use HKDF, but it is disabled")
|
||||||
|
}
|
||||||
|
derivedKey := hkdfDerive(key, hkdfInfoXChaChaPoly1305Content, chacha20poly1305.KeySize)
|
||||||
|
aeadCipher, err = chacha20poly1305.NewX(derivedKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Panic("unknown backend cipher")
|
log.Panicf("unknown cipher backend %q", aeadType.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if aeadCipher.NonceSize()*8 != IVBitLen {
|
||||||
|
log.Panicf("Mismatched aeadCipher.NonceSize*8=%d and IVBitLen=%d bits",
|
||||||
|
aeadCipher.NonceSize()*8, IVBitLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &CryptoCore{
|
return &CryptoCore{
|
||||||
|
@ -13,6 +13,7 @@ const (
|
|||||||
hkdfInfoEMENames = "EME filename encryption"
|
hkdfInfoEMENames = "EME filename encryption"
|
||||||
hkdfInfoGCMContent = "AES-GCM file content encryption"
|
hkdfInfoGCMContent = "AES-GCM file content encryption"
|
||||||
hkdfInfoSIVContent = "AES-SIV file content encryption"
|
hkdfInfoSIVContent = "AES-SIV file content encryption"
|
||||||
|
hkdfInfoXChaChaPoly1305Content = "XChaCha20-Poly1305 file content encryption"
|
||||||
)
|
)
|
||||||
|
|
||||||
// hkdfDerive derives "outLen" bytes from "masterkey" and "info" using
|
// hkdfDerive derives "outLen" bytes from "masterkey" and "info" using
|
||||||
|
22
mount.go
22
mount.go
@ -19,6 +19,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
|
|
||||||
"github.com/hanwen/go-fuse/v2/fs"
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
"github.com/hanwen/go-fuse/v2/fuse"
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
|
|
||||||
@ -249,12 +251,17 @@ func initFuseFrontend(args *argContainer) (rootNode fs.InodeEmbedder, wipeKeys f
|
|||||||
// Reconciliate CLI and config file arguments into a fusefrontend.Args struct
|
// Reconciliate CLI and config file arguments into a fusefrontend.Args struct
|
||||||
// that is passed to the filesystem implementation
|
// that is passed to the filesystem implementation
|
||||||
cryptoBackend := cryptocore.BackendGoGCM
|
cryptoBackend := cryptocore.BackendGoGCM
|
||||||
|
IVBits := contentenc.DefaultIVBits
|
||||||
if args.openssl {
|
if args.openssl {
|
||||||
cryptoBackend = cryptocore.BackendOpenSSL
|
cryptoBackend = cryptocore.BackendOpenSSL
|
||||||
}
|
}
|
||||||
if args.aessiv {
|
if args.aessiv {
|
||||||
cryptoBackend = cryptocore.BackendAESSIV
|
cryptoBackend = cryptocore.BackendAESSIV
|
||||||
}
|
}
|
||||||
|
if args.xchacha {
|
||||||
|
cryptoBackend = cryptocore.BackendXChaCha20Poly1305
|
||||||
|
IVBits = chacha20poly1305.NonceSizeX * 8
|
||||||
|
}
|
||||||
// forceOwner implies allow_other, as documented.
|
// forceOwner implies allow_other, as documented.
|
||||||
// Set this early, so args.allow_other can be relied on below this point.
|
// Set this early, so args.allow_other can be relied on below this point.
|
||||||
if args._forceOwner != nil {
|
if args._forceOwner != nil {
|
||||||
@ -287,10 +294,23 @@ func initFuseFrontend(args *argContainer) (rootNode fs.InodeEmbedder, wipeKeys f
|
|||||||
args.hkdf = confFile.IsFeatureFlagSet(configfile.FlagHKDF)
|
args.hkdf = confFile.IsFeatureFlagSet(configfile.FlagHKDF)
|
||||||
if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) {
|
if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) {
|
||||||
cryptoBackend = cryptocore.BackendAESSIV
|
cryptoBackend = cryptocore.BackendAESSIV
|
||||||
|
IVBits = contentenc.DefaultIVBits
|
||||||
} else if args.reverse {
|
} else if args.reverse {
|
||||||
tlog.Fatal.Printf("AES-SIV is required by reverse mode, but not enabled in the config file")
|
tlog.Fatal.Printf("AES-SIV is required by reverse mode, but not enabled in the config file")
|
||||||
os.Exit(exitcodes.Usage)
|
os.Exit(exitcodes.Usage)
|
||||||
}
|
}
|
||||||
|
if confFile.IsFeatureFlagSet(configfile.FlagXChaCha20Poly1305) {
|
||||||
|
cryptoBackend = cryptocore.BackendXChaCha20Poly1305
|
||||||
|
IVBits = chacha20poly1305.NonceSizeX * 8
|
||||||
|
}
|
||||||
|
// If neither AES-SIV nor XChaCha are selected, we must be using AES-GCM
|
||||||
|
if !confFile.IsFeatureFlagSet(configfile.FlagAESSIV) && !confFile.IsFeatureFlagSet(configfile.FlagXChaCha20Poly1305) {
|
||||||
|
cryptoBackend = cryptocore.BackendGoGCM
|
||||||
|
if args.openssl {
|
||||||
|
cryptoBackend = cryptocore.BackendOpenSSL
|
||||||
|
}
|
||||||
|
IVBits = contentenc.DefaultIVBits
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// If allow_other is set and we run as root, try to give newly created files to
|
// If allow_other is set and we run as root, try to give newly created files to
|
||||||
// the right user.
|
// the right user.
|
||||||
@ -299,7 +319,7 @@ func initFuseFrontend(args *argContainer) (rootNode fs.InodeEmbedder, wipeKeys f
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init crypto backend
|
// Init crypto backend
|
||||||
cCore := cryptocore.New(masterkey, cryptoBackend, contentenc.DefaultIVBits, args.hkdf, args.forcedecode)
|
cCore := cryptocore.New(masterkey, cryptoBackend, IVBits, args.hkdf, args.forcedecode)
|
||||||
cEnc := contentenc.New(cCore, contentenc.DefaultBS, args.forcedecode)
|
cEnc := contentenc.New(cCore, contentenc.DefaultBS, args.forcedecode)
|
||||||
nameTransform := nametransform.New(cCore.EMECipher, frontendArgs.LongNames,
|
nameTransform := nametransform.New(cCore.EMECipher, frontendArgs.LongNames,
|
||||||
args.raw64, []string(args.badname), frontendArgs.DeterministicNames)
|
args.raw64, []string(args.badname), frontendArgs.DeterministicNames)
|
||||||
|
Loading…
Reference in New Issue
Block a user