Add support for unpadded base64 filenames, "-raw64"
Through base64.RawURLEncoding. New command-line parameter "-raw64".
This commit is contained in:
parent
964e0e6b36
commit
2b991c9743
@ -16,7 +16,7 @@ import (
|
|||||||
type argContainer struct {
|
type argContainer struct {
|
||||||
debug, init, zerokey, fusedebug, openssl, passwd, foreground, version,
|
debug, init, zerokey, fusedebug, openssl, passwd, foreground, version,
|
||||||
plaintextnames, quiet, nosyslog, wpanic,
|
plaintextnames, quiet, nosyslog, wpanic,
|
||||||
longnames, allow_other, ro, reverse, aessiv, nonempty bool
|
longnames, allow_other, ro, reverse, aessiv, nonempty, raw64 bool
|
||||||
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
|
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
|
||||||
memprofile, ko, passfile string
|
memprofile, ko, passfile string
|
||||||
// Configuration file name override
|
// Configuration file name override
|
||||||
@ -103,6 +103,7 @@ func parseCliOpts() (args argContainer) {
|
|||||||
flagSet.BoolVar(&args.reverse, "reverse", false, "Reverse mode")
|
flagSet.BoolVar(&args.reverse, "reverse", false, "Reverse mode")
|
||||||
flagSet.BoolVar(&args.aessiv, "aessiv", false, "AES-SIV encryption")
|
flagSet.BoolVar(&args.aessiv, "aessiv", false, "AES-SIV encryption")
|
||||||
flagSet.BoolVar(&args.nonempty, "nonempty", false, "Allow mounting over non-empty directories")
|
flagSet.BoolVar(&args.nonempty, "nonempty", false, "Allow mounting over non-empty directories")
|
||||||
|
flagSet.BoolVar(&args.raw64, "raw64", false, "Use unpadded base64 for file names")
|
||||||
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
|
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
|
||||||
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
|
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
|
||||||
flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory profile to specified file")
|
flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory profile to specified file")
|
||||||
|
@ -37,7 +37,7 @@ func initDir(args *argContainer) {
|
|||||||
}
|
}
|
||||||
password := readpassword.Twice(args.extpass)
|
password := readpassword.Twice(args.extpass)
|
||||||
creator := tlog.ProgramName + " " + GitVersion
|
creator := tlog.ProgramName + " " + GitVersion
|
||||||
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv)
|
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv, args.raw64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Fatal.Println(err)
|
tlog.Fatal.Println(err)
|
||||||
os.Exit(ErrExitInit)
|
os.Exit(ErrExitInit)
|
||||||
|
@ -49,7 +49,7 @@ type ConfFile struct {
|
|||||||
// CreateConfFile - create a new config with a random key encrypted with
|
// CreateConfFile - create a new config with a random key encrypted with
|
||||||
// "password" and write it to "filename".
|
// "password" and write it to "filename".
|
||||||
// Uses scrypt with cost parameter logN.
|
// Uses scrypt with cost parameter logN.
|
||||||
func CreateConfFile(filename string, password string, plaintextNames bool, logN int, creator string, aessiv bool) error {
|
func CreateConfFile(filename string, password string, plaintextNames bool, logN int, creator string, aessiv bool, raw64 bool) error {
|
||||||
var cf ConfFile
|
var cf ConfFile
|
||||||
cf.filename = filename
|
cf.filename = filename
|
||||||
cf.Creator = creator
|
cf.Creator = creator
|
||||||
@ -70,6 +70,9 @@ func CreateConfFile(filename string, password string, plaintextNames bool, logN
|
|||||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagDirIV])
|
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagDirIV])
|
||||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagEMENames])
|
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagEMENames])
|
||||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagLongNames])
|
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagLongNames])
|
||||||
|
if raw64 {
|
||||||
|
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagRaw64])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if aessiv {
|
if aessiv {
|
||||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagAESSIV])
|
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagAESSIV])
|
||||||
|
@ -60,7 +60,7 @@ func TestLoadV2StrangeFeature(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateConfFile(t *testing.T) {
|
func TestCreateConfFile(t *testing.T) {
|
||||||
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false)
|
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -68,11 +68,10 @@ func TestCreateConfFile(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateConfFileAESSIV(t *testing.T) {
|
func TestCreateConfFileAESSIV(t *testing.T) {
|
||||||
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", true)
|
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -85,6 +84,20 @@ func TestCreateConfFileAESSIV(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateConfFileRaw64(t *testing.T) {
|
||||||
|
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", false, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, c, err := LoadConfFile("config_test/tmp.conf", "test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !c.IsFeatureFlagSet(FlagRaw64) {
|
||||||
|
t.Error("FlagRaw64 flag should be set but is not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsFeatureFlagKnown(t *testing.T) {
|
func TestIsFeatureFlagKnown(t *testing.T) {
|
||||||
// Test a few hardcoded values
|
// Test a few hardcoded values
|
||||||
testKnownFlags := []string{"DirIV", "PlaintextNames", "EMENames", "GCMIV128", "LongNames", "AESSIV"}
|
testKnownFlags := []string{"DirIV", "PlaintextNames", "EMENames", "GCMIV128", "LongNames", "AESSIV"}
|
||||||
|
@ -17,6 +17,8 @@ const (
|
|||||||
FlagLongNames
|
FlagLongNames
|
||||||
// FlagAESSIV selects an AES-SIV based crypto backend.
|
// FlagAESSIV selects an AES-SIV based crypto backend.
|
||||||
FlagAESSIV
|
FlagAESSIV
|
||||||
|
// FlagRaw64 enables raw (unpadded) base64 encoding for file names
|
||||||
|
FlagRaw64
|
||||||
)
|
)
|
||||||
|
|
||||||
// knownFlags stores the known feature flags and their string representation
|
// knownFlags stores the known feature flags and their string representation
|
||||||
@ -27,6 +29,7 @@ var knownFlags = map[flagIota]string{
|
|||||||
FlagGCMIV128: "GCMIV128",
|
FlagGCMIV128: "GCMIV128",
|
||||||
FlagLongNames: "LongNames",
|
FlagLongNames: "LongNames",
|
||||||
FlagAESSIV: "AESSIV",
|
FlagAESSIV: "AESSIV",
|
||||||
|
FlagRaw64: "Raw64",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filesystems that do not have these feature flags set are deprecated.
|
// Filesystems that do not have these feature flags set are deprecated.
|
||||||
|
@ -18,4 +18,7 @@ type Args struct {
|
|||||||
// location. If it is false, reverse mode maps ".gocryptfs.reverse.conf"
|
// location. If it is false, reverse mode maps ".gocryptfs.reverse.conf"
|
||||||
// to "gocryptfs.conf" in the plaintext dir.
|
// to "gocryptfs.conf" in the plaintext dir.
|
||||||
ConfigCustom bool
|
ConfigCustom bool
|
||||||
|
// Raw64 is true when RawURLEncoding (without padding) should be used for
|
||||||
|
// file names
|
||||||
|
Raw64 bool
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ var _ pathfs.FileSystem = &FS{} // Verify that interface is implemented.
|
|||||||
func NewFS(args Args) *FS {
|
func NewFS(args Args) *FS {
|
||||||
cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits)
|
cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits)
|
||||||
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS)
|
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS)
|
||||||
nameTransform := nametransform.New(cryptoCore, args.LongNames)
|
nameTransform := nametransform.New(cryptoCore, args.LongNames, args.Raw64)
|
||||||
|
|
||||||
return &FS{
|
return &FS{
|
||||||
FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),
|
FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),
|
||||||
|
@ -56,7 +56,7 @@ func NewFS(args fusefrontend.Args) pathfs.FileSystem {
|
|||||||
initLongnameCache()
|
initLongnameCache()
|
||||||
cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits)
|
cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits)
|
||||||
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS)
|
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS)
|
||||||
nameTransform := nametransform.New(cryptoCore, args.LongNames)
|
nameTransform := nametransform.New(cryptoCore, args.LongNames, args.Raw64)
|
||||||
|
|
||||||
return &reverseFS{
|
return &reverseFS{
|
||||||
// pathfs.defaultFileSystem returns ENOSYS for all operations
|
// pathfs.defaultFileSystem returns ENOSYS for all operations
|
||||||
|
@ -17,13 +17,20 @@ type NameTransform struct {
|
|||||||
cryptoCore *cryptocore.CryptoCore
|
cryptoCore *cryptocore.CryptoCore
|
||||||
longNames bool
|
longNames bool
|
||||||
DirIVCache dirIVCache
|
DirIVCache dirIVCache
|
||||||
|
// b64 = either base64.URLEncoding or base64.RawURLEncoding
|
||||||
|
b64 *base64.Encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new NameTransform instance.
|
// New returns a new NameTransform instance.
|
||||||
func New(c *cryptocore.CryptoCore, longNames bool) *NameTransform {
|
func New(c *cryptocore.CryptoCore, longNames bool, raw64 bool) *NameTransform {
|
||||||
|
b64 := base64.URLEncoding
|
||||||
|
if raw64 {
|
||||||
|
b64 = base64.RawURLEncoding
|
||||||
|
}
|
||||||
return &NameTransform{
|
return &NameTransform{
|
||||||
cryptoCore: c,
|
cryptoCore: c,
|
||||||
longNames: longNames,
|
longNames: longNames,
|
||||||
|
b64: b64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +39,7 @@ func New(c *cryptocore.CryptoCore, longNames bool) *NameTransform {
|
|||||||
// This function is exported because it allows for a very efficient readdir
|
// This function is exported because it allows for a very efficient readdir
|
||||||
// implementation (read IV once, decrypt all names using this function).
|
// implementation (read IV once, decrypt all names using this function).
|
||||||
func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error) {
|
func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error) {
|
||||||
bin, err := base64.URLEncoding.DecodeString(cipherName)
|
bin, err := n.b64.DecodeString(cipherName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -63,6 +70,6 @@ func (n *NameTransform) EncryptName(plainName string, iv []byte) (cipherName64 s
|
|||||||
bin := []byte(plainName)
|
bin := []byte(plainName)
|
||||||
bin = pad16(bin)
|
bin = pad16(bin)
|
||||||
bin = eme.Transform(n.cryptoCore.BlockCipher, iv, bin, eme.DirectionEncrypt)
|
bin = eme.Transform(n.cryptoCore.BlockCipher, iv, bin, eme.DirectionEncrypt)
|
||||||
cipherName64 = base64.URLEncoding.EncodeToString(bin)
|
cipherName64 = n.b64.EncodeToString(bin)
|
||||||
return cipherName64
|
return cipherName64
|
||||||
}
|
}
|
||||||
|
2
mount.go
2
mount.go
@ -143,11 +143,13 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF
|
|||||||
LongNames: args.longnames,
|
LongNames: args.longnames,
|
||||||
CryptoBackend: cryptoBackend,
|
CryptoBackend: cryptoBackend,
|
||||||
ConfigCustom: args._configCustom,
|
ConfigCustom: args._configCustom,
|
||||||
|
Raw64: args.raw64,
|
||||||
}
|
}
|
||||||
// confFile is nil when "-zerokey" or "-masterkey" was used
|
// confFile is nil when "-zerokey" or "-masterkey" was used
|
||||||
if confFile != nil {
|
if confFile != nil {
|
||||||
// Settings from the config file override command line args
|
// Settings from the config file override command line args
|
||||||
frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(configfile.FlagPlaintextNames)
|
frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(configfile.FlagPlaintextNames)
|
||||||
|
frontendArgs.Raw64 = confFile.IsFeatureFlagSet(configfile.FlagRaw64)
|
||||||
if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) {
|
if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) {
|
||||||
frontendArgs.CryptoBackend = cryptocore.BackendAESSIV
|
frontendArgs.CryptoBackend = cryptocore.BackendAESSIV
|
||||||
} else if args.reverse {
|
} else if args.reverse {
|
||||||
|
Loading…
Reference in New Issue
Block a user