forked from TrueCloudLab/rclone
crypt: Added option to encrypt directory names or leave them intact - #1240
This commit is contained in:
parent
72072d7d6b
commit
dfaee55ef3
4 changed files with 140 additions and 64 deletions
|
@ -139,13 +139,15 @@ type cipher struct {
|
||||||
mode NameEncryptionMode
|
mode NameEncryptionMode
|
||||||
buffers sync.Pool // encrypt/decrypt buffers
|
buffers sync.Pool // encrypt/decrypt buffers
|
||||||
cryptoRand io.Reader // read crypto random numbers from here
|
cryptoRand io.Reader // read crypto random numbers from here
|
||||||
|
dirNameEncrypt bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// newCipher initialises the cipher. If salt is "" then it uses a built in salt val
|
// newCipher initialises the cipher. If salt is "" then it uses a built in salt val
|
||||||
func newCipher(mode NameEncryptionMode, password, salt string) (*cipher, error) {
|
func newCipher(mode NameEncryptionMode, password, salt string, dirNameEncrypt bool) (*cipher, error) {
|
||||||
c := &cipher{
|
c := &cipher{
|
||||||
mode: mode,
|
mode: mode,
|
||||||
cryptoRand: rand.Reader,
|
cryptoRand: rand.Reader,
|
||||||
|
dirNameEncrypt: dirNameEncrypt,
|
||||||
}
|
}
|
||||||
c.buffers.New = func() interface{} {
|
c.buffers.New = func() interface{} {
|
||||||
return make([]byte, blockSize)
|
return make([]byte, blockSize)
|
||||||
|
@ -469,6 +471,11 @@ func (c *cipher) deobfuscateSegment(ciphertext string) (string, error) {
|
||||||
func (c *cipher) encryptFileName(in string) string {
|
func (c *cipher) encryptFileName(in string) string {
|
||||||
segments := strings.Split(in, "/")
|
segments := strings.Split(in, "/")
|
||||||
for i := range segments {
|
for i := range segments {
|
||||||
|
// Skip directory name encryption if the user chose to
|
||||||
|
// leave them intact
|
||||||
|
if !c.dirNameEncrypt && i != (len(segments)-1) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if c.mode == NameEncryptionStandard {
|
if c.mode == NameEncryptionStandard {
|
||||||
segments[i] = c.encryptSegment(segments[i])
|
segments[i] = c.encryptSegment(segments[i])
|
||||||
} else {
|
} else {
|
||||||
|
@ -488,7 +495,7 @@ func (c *cipher) EncryptFileName(in string) string {
|
||||||
|
|
||||||
// EncryptDirName encrypts a directory path
|
// EncryptDirName encrypts a directory path
|
||||||
func (c *cipher) EncryptDirName(in string) string {
|
func (c *cipher) EncryptDirName(in string) string {
|
||||||
if c.mode == NameEncryptionOff {
|
if c.mode == NameEncryptionOff || !c.dirNameEncrypt {
|
||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
return c.encryptFileName(in)
|
return c.encryptFileName(in)
|
||||||
|
@ -499,6 +506,11 @@ func (c *cipher) decryptFileName(in string) (string, error) {
|
||||||
segments := strings.Split(in, "/")
|
segments := strings.Split(in, "/")
|
||||||
for i := range segments {
|
for i := range segments {
|
||||||
var err error
|
var err error
|
||||||
|
// Skip directory name decryption if the user chose to
|
||||||
|
// leave them intact
|
||||||
|
if !c.dirNameEncrypt && i != (len(segments)-1) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if c.mode == NameEncryptionStandard {
|
if c.mode == NameEncryptionStandard {
|
||||||
segments[i], err = c.decryptSegment(segments[i])
|
segments[i], err = c.decryptSegment(segments[i])
|
||||||
} else {
|
} else {
|
||||||
|
@ -526,7 +538,7 @@ func (c *cipher) DecryptFileName(in string) (string, error) {
|
||||||
|
|
||||||
// DecryptDirName decrypts a directory path
|
// DecryptDirName decrypts a directory path
|
||||||
func (c *cipher) DecryptDirName(in string) (string, error) {
|
func (c *cipher) DecryptDirName(in string) (string, error) {
|
||||||
if c.mode == NameEncryptionOff {
|
if c.mode == NameEncryptionOff || !c.dirNameEncrypt {
|
||||||
return in, nil
|
return in, nil
|
||||||
}
|
}
|
||||||
return c.decryptFileName(in)
|
return c.decryptFileName(in)
|
||||||
|
|
|
@ -157,7 +157,7 @@ func TestDecodeFileName(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncryptSegment(t *testing.T) {
|
func TestEncryptSegment(t *testing.T) {
|
||||||
c, _ := newCipher(NameEncryptionStandard, "", "")
|
c, _ := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
in string
|
in string
|
||||||
expected string
|
expected string
|
||||||
|
@ -194,7 +194,7 @@ func TestEncryptSegment(t *testing.T) {
|
||||||
|
|
||||||
func TestDecryptSegment(t *testing.T) {
|
func TestDecryptSegment(t *testing.T) {
|
||||||
// We've tested the forwards above, now concentrate on the errors
|
// We've tested the forwards above, now concentrate on the errors
|
||||||
c, _ := newCipher(NameEncryptionStandard, "", "")
|
c, _ := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
in string
|
in string
|
||||||
expectedErr error
|
expectedErr error
|
||||||
|
@ -214,41 +214,54 @@ func TestDecryptSegment(t *testing.T) {
|
||||||
|
|
||||||
func TestEncryptFileName(t *testing.T) {
|
func TestEncryptFileName(t *testing.T) {
|
||||||
// First standard mode
|
// First standard mode
|
||||||
c, _ := newCipher(NameEncryptionStandard, "", "")
|
c, _ := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s", c.EncryptFileName("1"))
|
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s", c.EncryptFileName("1"))
|
||||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", c.EncryptFileName("1/12"))
|
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", c.EncryptFileName("1/12"))
|
||||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", c.EncryptFileName("1/12/123"))
|
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", c.EncryptFileName("1/12/123"))
|
||||||
|
// Standard mode with directory name encryption off
|
||||||
|
c, _ = newCipher(NameEncryptionStandard, "", "", false)
|
||||||
|
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s", c.EncryptFileName("1"))
|
||||||
|
assert.Equal(t, "1/l42g6771hnv3an9cgc8cr2n1ng", c.EncryptFileName("1/12"))
|
||||||
|
assert.Equal(t, "1/12/qgm4avr35m5loi1th53ato71v0", c.EncryptFileName("1/12/123"))
|
||||||
// Now off mode
|
// Now off mode
|
||||||
c, _ = newCipher(NameEncryptionOff, "", "")
|
c, _ = newCipher(NameEncryptionOff, "", "", true)
|
||||||
assert.Equal(t, "1/12/123.bin", c.EncryptFileName("1/12/123"))
|
assert.Equal(t, "1/12/123.bin", c.EncryptFileName("1/12/123"))
|
||||||
// Obfuscation mode
|
// Obfuscation mode
|
||||||
c, _ = newCipher(NameEncryptionObfuscated, "", "")
|
c, _ = newCipher(NameEncryptionObfuscated, "", "", true)
|
||||||
assert.Equal(t, "49.6/99.23/150.890/53.!!lipps", c.EncryptFileName("1/12/123/!hello"))
|
assert.Equal(t, "49.6/99.23/150.890/53.!!lipps", c.EncryptFileName("1/12/123/!hello"))
|
||||||
assert.Equal(t, "161.\u00e4", c.EncryptFileName("\u00a1"))
|
assert.Equal(t, "161.\u00e4", c.EncryptFileName("\u00a1"))
|
||||||
assert.Equal(t, "160.\u03c2", c.EncryptFileName("\u03a0"))
|
assert.Equal(t, "160.\u03c2", c.EncryptFileName("\u03a0"))
|
||||||
|
// Obfuscation mode with directory name encryption off
|
||||||
|
c, _ = newCipher(NameEncryptionObfuscated, "", "", false)
|
||||||
|
assert.Equal(t, "1/12/123/53.!!lipps", c.EncryptFileName("1/12/123/!hello"))
|
||||||
|
assert.Equal(t, "161.\u00e4", c.EncryptFileName("\u00a1"))
|
||||||
|
assert.Equal(t, "160.\u03c2", c.EncryptFileName("\u03a0"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecryptFileName(t *testing.T) {
|
func TestDecryptFileName(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mode NameEncryptionMode
|
mode NameEncryptionMode
|
||||||
|
dirNameEncrypt bool
|
||||||
in string
|
in string
|
||||||
expected string
|
expected string
|
||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{NameEncryptionStandard, "p0e52nreeaj0a5ea7s64m4j72s", "1", nil},
|
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s", "1", nil},
|
||||||
{NameEncryptionStandard, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", "1/12", nil},
|
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", "1/12", nil},
|
||||||
{NameEncryptionStandard, "p0e52nreeAJ0A5EA7S64M4J72S/L42G6771HNv3an9cgc8cr2n1ng", "1/12", nil},
|
{NameEncryptionStandard, true, "p0e52nreeAJ0A5EA7S64M4J72S/L42G6771HNv3an9cgc8cr2n1ng", "1/12", nil},
|
||||||
{NameEncryptionStandard, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", "1/12/123", nil},
|
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", "1/12/123", nil},
|
||||||
{NameEncryptionStandard, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1/qgm4avr35m5loi1th53ato71v0", "", ErrorNotAMultipleOfBlocksize},
|
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1/qgm4avr35m5loi1th53ato71v0", "", ErrorNotAMultipleOfBlocksize},
|
||||||
{NameEncryptionOff, "1/12/123.bin", "1/12/123", nil},
|
{NameEncryptionStandard, false, "1/12/qgm4avr35m5loi1th53ato71v0", "1/12/123", nil},
|
||||||
{NameEncryptionOff, "1/12/123.bix", "", ErrorNotAnEncryptedFile},
|
{NameEncryptionOff, true, "1/12/123.bin", "1/12/123", nil},
|
||||||
{NameEncryptionOff, ".bin", "", ErrorNotAnEncryptedFile},
|
{NameEncryptionOff, true, "1/12/123.bix", "", ErrorNotAnEncryptedFile},
|
||||||
{NameEncryptionObfuscated, "!.hello", "hello", nil},
|
{NameEncryptionOff, true, ".bin", "", ErrorNotAnEncryptedFile},
|
||||||
{NameEncryptionObfuscated, "hello", "", ErrorNotAnEncryptedFile},
|
{NameEncryptionObfuscated, true, "!.hello", "hello", nil},
|
||||||
{NameEncryptionObfuscated, "161.\u00e4", "\u00a1", nil},
|
{NameEncryptionObfuscated, true, "hello", "", ErrorNotAnEncryptedFile},
|
||||||
{NameEncryptionObfuscated, "160.\u03c2", "\u03a0", nil},
|
{NameEncryptionObfuscated, true, "161.\u00e4", "\u00a1", nil},
|
||||||
|
{NameEncryptionObfuscated, true, "160.\u03c2", "\u03a0", nil},
|
||||||
|
{NameEncryptionObfuscated, false, "1/12/123/53.!!lipps", "1/12/123/!hello", nil},
|
||||||
} {
|
} {
|
||||||
c, _ := newCipher(test.mode, "", "")
|
c, _ := newCipher(test.mode, "", "", test.dirNameEncrypt)
|
||||||
actual, actualErr := c.DecryptFileName(test.in)
|
actual, actualErr := c.DecryptFileName(test.in)
|
||||||
what := fmt.Sprintf("Testing %q (mode=%v)", test.in, test.mode)
|
what := fmt.Sprintf("Testing %q (mode=%v)", test.in, test.mode)
|
||||||
assert.Equal(t, test.expected, actual, what)
|
assert.Equal(t, test.expected, actual, what)
|
||||||
|
@ -266,7 +279,7 @@ func TestEncDecMatches(t *testing.T) {
|
||||||
{NameEncryptionObfuscated, "1/2/3/4/!hello\u03a0"},
|
{NameEncryptionObfuscated, "1/2/3/4/!hello\u03a0"},
|
||||||
{NameEncryptionObfuscated, "Avatar The Last Airbender"},
|
{NameEncryptionObfuscated, "Avatar The Last Airbender"},
|
||||||
} {
|
} {
|
||||||
c, _ := newCipher(test.mode, "", "")
|
c, _ := newCipher(test.mode, "", "", true)
|
||||||
out, err := c.DecryptFileName(c.EncryptFileName(test.in))
|
out, err := c.DecryptFileName(c.EncryptFileName(test.in))
|
||||||
what := fmt.Sprintf("Testing %q (mode=%v)", test.in, test.mode)
|
what := fmt.Sprintf("Testing %q (mode=%v)", test.in, test.mode)
|
||||||
assert.Equal(t, out, test.in, what)
|
assert.Equal(t, out, test.in, what)
|
||||||
|
@ -276,32 +289,39 @@ func TestEncDecMatches(t *testing.T) {
|
||||||
|
|
||||||
func TestEncryptDirName(t *testing.T) {
|
func TestEncryptDirName(t *testing.T) {
|
||||||
// First standard mode
|
// First standard mode
|
||||||
c, _ := newCipher(NameEncryptionStandard, "", "")
|
c, _ := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s", c.EncryptDirName("1"))
|
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s", c.EncryptDirName("1"))
|
||||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", c.EncryptDirName("1/12"))
|
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", c.EncryptDirName("1/12"))
|
||||||
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", c.EncryptDirName("1/12/123"))
|
assert.Equal(t, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", c.EncryptDirName("1/12/123"))
|
||||||
|
// Standard mode with dir name encryption off
|
||||||
|
c, _ = newCipher(NameEncryptionStandard, "", "", false)
|
||||||
|
assert.Equal(t, "1/12", c.EncryptDirName("1/12"))
|
||||||
|
assert.Equal(t, "1/12/123", c.EncryptDirName("1/12/123"))
|
||||||
// Now off mode
|
// Now off mode
|
||||||
c, _ = newCipher(NameEncryptionOff, "", "")
|
c, _ = newCipher(NameEncryptionOff, "", "", true)
|
||||||
assert.Equal(t, "1/12/123", c.EncryptDirName("1/12/123"))
|
assert.Equal(t, "1/12/123", c.EncryptDirName("1/12/123"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecryptDirName(t *testing.T) {
|
func TestDecryptDirName(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
mode NameEncryptionMode
|
mode NameEncryptionMode
|
||||||
|
dirNameEncrypt bool
|
||||||
in string
|
in string
|
||||||
expected string
|
expected string
|
||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{NameEncryptionStandard, "p0e52nreeaj0a5ea7s64m4j72s", "1", nil},
|
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s", "1", nil},
|
||||||
{NameEncryptionStandard, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", "1/12", nil},
|
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", "1/12", nil},
|
||||||
{NameEncryptionStandard, "p0e52nreeAJ0A5EA7S64M4J72S/L42G6771HNv3an9cgc8cr2n1ng", "1/12", nil},
|
{NameEncryptionStandard, true, "p0e52nreeAJ0A5EA7S64M4J72S/L42G6771HNv3an9cgc8cr2n1ng", "1/12", nil},
|
||||||
{NameEncryptionStandard, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", "1/12/123", nil},
|
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0", "1/12/123", nil},
|
||||||
{NameEncryptionStandard, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1/qgm4avr35m5loi1th53ato71v0", "", ErrorNotAMultipleOfBlocksize},
|
{NameEncryptionStandard, true, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1/qgm4avr35m5loi1th53ato71v0", "", ErrorNotAMultipleOfBlocksize},
|
||||||
{NameEncryptionOff, "1/12/123.bin", "1/12/123.bin", nil},
|
{NameEncryptionStandard, false, "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", "p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng", nil},
|
||||||
{NameEncryptionOff, "1/12/123", "1/12/123", nil},
|
{NameEncryptionStandard, false, "1/12/123", "1/12/123", nil},
|
||||||
{NameEncryptionOff, ".bin", ".bin", nil},
|
{NameEncryptionOff, true, "1/12/123.bin", "1/12/123.bin", nil},
|
||||||
|
{NameEncryptionOff, true, "1/12/123", "1/12/123", nil},
|
||||||
|
{NameEncryptionOff, true, ".bin", ".bin", nil},
|
||||||
} {
|
} {
|
||||||
c, _ := newCipher(test.mode, "", "")
|
c, _ := newCipher(test.mode, "", "", test.dirNameEncrypt)
|
||||||
actual, actualErr := c.DecryptDirName(test.in)
|
actual, actualErr := c.DecryptDirName(test.in)
|
||||||
what := fmt.Sprintf("Testing %q (mode=%v)", test.in, test.mode)
|
what := fmt.Sprintf("Testing %q (mode=%v)", test.in, test.mode)
|
||||||
assert.Equal(t, test.expected, actual, what)
|
assert.Equal(t, test.expected, actual, what)
|
||||||
|
@ -310,7 +330,7 @@ func TestDecryptDirName(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncryptedSize(t *testing.T) {
|
func TestEncryptedSize(t *testing.T) {
|
||||||
c, _ := newCipher(NameEncryptionStandard, "", "")
|
c, _ := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
in int64
|
in int64
|
||||||
expected int64
|
expected int64
|
||||||
|
@ -334,7 +354,7 @@ func TestEncryptedSize(t *testing.T) {
|
||||||
|
|
||||||
func TestDecryptedSize(t *testing.T) {
|
func TestDecryptedSize(t *testing.T) {
|
||||||
// Test the errors since we tested the reverse above
|
// Test the errors since we tested the reverse above
|
||||||
c, _ := newCipher(NameEncryptionStandard, "", "")
|
c, _ := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
in int64
|
in int64
|
||||||
expectedErr error
|
expectedErr error
|
||||||
|
@ -705,7 +725,7 @@ func (z *zeroes) Read(p []byte) (n int, err error) {
|
||||||
|
|
||||||
// Test encrypt decrypt with different buffer sizes
|
// Test encrypt decrypt with different buffer sizes
|
||||||
func testEncryptDecrypt(t *testing.T, bufSize int, copySize int64) {
|
func testEncryptDecrypt(t *testing.T, bufSize int, copySize int64) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
c.cryptoRand = &zeroes{} // zero out the nonce
|
c.cryptoRand = &zeroes{} // zero out the nonce
|
||||||
buf := make([]byte, bufSize)
|
buf := make([]byte, bufSize)
|
||||||
|
@ -775,7 +795,7 @@ func TestEncryptData(t *testing.T) {
|
||||||
{[]byte{1}, file1},
|
{[]byte{1}, file1},
|
||||||
{[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, file16},
|
{[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, file16},
|
||||||
} {
|
} {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
c.cryptoRand = newRandomSource(1E8) // nodge the crypto rand generator
|
c.cryptoRand = newRandomSource(1E8) // nodge the crypto rand generator
|
||||||
|
|
||||||
|
@ -798,7 +818,7 @@ func TestEncryptData(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewEncrypter(t *testing.T) {
|
func TestNewEncrypter(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
c.cryptoRand = newRandomSource(1E8) // nodge the crypto rand generator
|
c.cryptoRand = newRandomSource(1E8) // nodge the crypto rand generator
|
||||||
|
|
||||||
|
@ -820,7 +840,7 @@ func TestNewEncrypter(t *testing.T) {
|
||||||
// Test the stream returning 0, io.ErrUnexpectedEOF - this used to
|
// Test the stream returning 0, io.ErrUnexpectedEOF - this used to
|
||||||
// cause a fatal loop
|
// cause a fatal loop
|
||||||
func TestNewEncrypterErrUnexpectedEOF(t *testing.T) {
|
func TestNewEncrypterErrUnexpectedEOF(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
in := &errorReader{io.ErrUnexpectedEOF}
|
in := &errorReader{io.ErrUnexpectedEOF}
|
||||||
|
@ -857,7 +877,7 @@ func (c *closeDetector) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDecrypter(t *testing.T) {
|
func TestNewDecrypter(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
c.cryptoRand = newRandomSource(1E8) // nodge the crypto rand generator
|
c.cryptoRand = newRandomSource(1E8) // nodge the crypto rand generator
|
||||||
|
|
||||||
|
@ -900,7 +920,7 @@ func TestNewDecrypter(t *testing.T) {
|
||||||
|
|
||||||
// Test the stream returning 0, io.ErrUnexpectedEOF
|
// Test the stream returning 0, io.ErrUnexpectedEOF
|
||||||
func TestNewDecrypterErrUnexpectedEOF(t *testing.T) {
|
func TestNewDecrypterErrUnexpectedEOF(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
in2 := &errorReader{io.ErrUnexpectedEOF}
|
in2 := &errorReader{io.ErrUnexpectedEOF}
|
||||||
|
@ -916,7 +936,7 @@ func TestNewDecrypterErrUnexpectedEOF(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDecrypterSeek(t *testing.T) {
|
func TestNewDecrypterSeek(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
c.cryptoRand = &zeroes{} // nodge the crypto rand generator
|
c.cryptoRand = &zeroes{} // nodge the crypto rand generator
|
||||||
|
|
||||||
|
@ -976,7 +996,7 @@ func TestNewDecrypterSeek(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecrypterRead(t *testing.T) {
|
func TestDecrypterRead(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Test truncating the file at each possible point
|
// Test truncating the file at each possible point
|
||||||
|
@ -1040,7 +1060,7 @@ func TestDecrypterRead(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecrypterClose(t *testing.T) {
|
func TestDecrypterClose(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
cd := newCloseDetector(bytes.NewBuffer(file16))
|
cd := newCloseDetector(bytes.NewBuffer(file16))
|
||||||
|
@ -1078,7 +1098,7 @@ func TestDecrypterClose(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutGetBlock(t *testing.T) {
|
func TestPutGetBlock(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
block := c.getBlock()
|
block := c.getBlock()
|
||||||
|
@ -1089,7 +1109,7 @@ func TestPutGetBlock(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKey(t *testing.T) {
|
func TestKey(t *testing.T) {
|
||||||
c, err := newCipher(NameEncryptionStandard, "", "")
|
c, err := newCipher(NameEncryptionStandard, "", "", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Check zero keys OK
|
// Check zero keys OK
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ncw/rclone/fs"
|
"github.com/ncw/rclone/fs"
|
||||||
|
@ -41,6 +42,19 @@ func init() {
|
||||||
Help: "Very simple filename obfuscation.",
|
Help: "Very simple filename obfuscation.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
Name: "directory_name_encryption",
|
||||||
|
Help: "Option to either encrypt directory names or leave them intact.",
|
||||||
|
Examples: []fs.OptionExample{
|
||||||
|
{
|
||||||
|
Value: "true",
|
||||||
|
Help: "Encrypt directory names.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "false",
|
||||||
|
Help: "Don't encrypt directory names, leave them intact.",
|
||||||
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Name: "password",
|
Name: "password",
|
||||||
Help: "Password or pass phrase for encryption.",
|
Help: "Password or pass phrase for encryption.",
|
||||||
|
@ -60,6 +74,10 @@ func NewFs(name, rpath string) (fs.Fs, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
dirNameEncrypt, err := strconv.ParseBool(fs.ConfigFileGet(name, "directory_name_encryption", "true"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
password := fs.ConfigFileGet(name, "password", "")
|
password := fs.ConfigFileGet(name, "password", "")
|
||||||
if password == "" {
|
if password == "" {
|
||||||
return nil, errors.New("password not set in config file")
|
return nil, errors.New("password not set in config file")
|
||||||
|
@ -75,7 +93,7 @@ func NewFs(name, rpath string) (fs.Fs, error) {
|
||||||
return nil, errors.Wrap(err, "failed to decrypt password2")
|
return nil, errors.Wrap(err, "failed to decrypt password2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cipher, err := newCipher(mode, password, salt)
|
cipher, err := newCipher(mode, password, salt, dirNameEncrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to make cipher")
|
return nil, errors.Wrap(err, "failed to make cipher")
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,13 @@ Choose a number from below, or type in your own value
|
||||||
3 / Very simple filename obfuscation.
|
3 / Very simple filename obfuscation.
|
||||||
\ "obfuscate"
|
\ "obfuscate"
|
||||||
filename_encryption> 2
|
filename_encryption> 2
|
||||||
|
Option to either encrypt directory names or leave them intact.
|
||||||
|
Choose a number from below, or type in your own value
|
||||||
|
1 / Encrypt directory names.
|
||||||
|
\ "true"
|
||||||
|
2 / Don't encrypt directory names, leave them intact.
|
||||||
|
\ "false"
|
||||||
|
filename_encryption> 1
|
||||||
Password or pass phrase for encryption.
|
Password or pass phrase for encryption.
|
||||||
y) Yes type in my own password
|
y) Yes type in my own password
|
||||||
g) Generate random password
|
g) Generate random password
|
||||||
|
@ -256,6 +263,25 @@ characters in length then you should be OK on all providers.
|
||||||
There may be an even more secure file name encryption mode in the
|
There may be an even more secure file name encryption mode in the
|
||||||
future which will address the long file name problem.
|
future which will address the long file name problem.
|
||||||
|
|
||||||
|
### Directory name encryption ###
|
||||||
|
Crypt offers the option of encrypting dir names or leaving them intact.
|
||||||
|
There are two options:
|
||||||
|
|
||||||
|
True
|
||||||
|
|
||||||
|
Encrypts the whole file path including directory names
|
||||||
|
Example:
|
||||||
|
`1/12/123.txt` is encrypted to
|
||||||
|
`p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0`
|
||||||
|
|
||||||
|
False
|
||||||
|
|
||||||
|
Only encrypts file names, skips directory names
|
||||||
|
Example:
|
||||||
|
`1/12/123/txt` is encrypted to
|
||||||
|
`1/12/qgm4avr35m5loi1th53ato71v0`
|
||||||
|
|
||||||
|
|
||||||
### Modified time and hashes ###
|
### Modified time and hashes ###
|
||||||
|
|
||||||
Crypt stores modification times using the underlying remote so support
|
Crypt stores modification times using the underlying remote so support
|
||||||
|
|
Loading…
Reference in a new issue