Skip to content

Commit d023cd6

Browse files
committed
cli: drop -forcedecode flag
The rewritten openssl backend does not support this flag anymore, and it was inherently dangerour. Drop it (ignored for compatibility)
1 parent c974116 commit d023cd6

File tree

17 files changed

+37
-104
lines changed

17 files changed

+37
-104
lines changed

Documentation/MANPAGE.md

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -256,21 +256,8 @@ of a case where this may be useful is a situation where content is stored on a
256256
filesystem that doesn't properly support UNIX ownership and permissions.
257257

258258
#### -forcedecode
259-
Force decode of encrypted files even if the integrity check fails, instead of
260-
failing with an IO error. Warning messages are still printed to syslog if corrupted
261-
files are encountered.
262-
It can be useful to recover files from disks with bad sectors or other corrupted
263-
media. It shall not be used if the origin of corruption is unknown, specially
264-
if you want to run executable files.
265259

266-
For corrupted media, note that you probably want to use dd_rescue(1)
267-
instead, which will recover all but the corrupted 4kB block.
268-
269-
This option makes no sense in reverse mode. It requires gocryptfs to be compiled with openssl
270-
support and implies -openssl true. Because of this, it is not compatible with -aessiv,
271-
that uses built-in Go crypto.
272-
273-
Setting this option forces the filesystem to read-only and noexec.
260+
Obsolete and ignored on gocryptfs v2.2 and later.
274261

275262
#### -fsname string
276263
Override the filesystem name (first column in df -T). Can also be

cli_args.go

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type argContainer struct {
2929
debug, init, zerokey, fusedebug, openssl, passwd, fg, version,
3030
plaintextnames, quiet, nosyslog, wpanic,
3131
longnames, allow_other, reverse, aessiv, nonempty, raw64,
32-
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
32+
noprealloc, speed, hkdf, serialize_reads, hh, info,
3333
sharedstorage, fsck, one_file_system, deterministic_names,
3434
xchacha bool
3535
// Mount options with opposites
@@ -172,8 +172,6 @@ func parseCliOpts(osArgs []string) (args argContainer) {
172172
flagSet.BoolVar(&args.speed, "speed", false, "Run crypto speed test")
173173
flagSet.BoolVar(&args.hkdf, "hkdf", true, "Use HKDF as an additional key derivation step")
174174
flagSet.BoolVar(&args.serialize_reads, "serialize_reads", false, "Try to serialize read operations")
175-
flagSet.BoolVar(&args.forcedecode, "forcedecode", false, "Force decode of files even if integrity check fails."+
176-
" Requires gocryptfs to be compiled with openssl support and implies -openssl true")
177175
flagSet.BoolVar(&args.hh, "hh", false, "Show this long help text")
178176
flagSet.BoolVar(&args.info, "info", false, "Display information about CIPHERDIR")
179177
flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer")
@@ -234,7 +232,8 @@ func parseCliOpts(osArgs []string) (args argContainer) {
234232
{
235233
var tmp bool
236234
flagSet.BoolVar(&tmp, "nofail", false, "Ignored for /etc/fstab compatibility")
237-
flagSet.BoolVar(&tmp, "devrandom", false, "Deprecated (ignored for compatibility)")
235+
flagSet.BoolVar(&tmp, "devrandom", false, "Obsolete, ignored for compatibility")
236+
flagSet.BoolVar(&tmp, "forcedecode", false, "Obsolete, ignored for compatibility")
238237
}
239238

240239
// Actual parsing
@@ -265,32 +264,6 @@ func parseCliOpts(osArgs []string) (args argContainer) {
265264
os.Exit(exitcodes.Usage)
266265
}
267266
}
268-
// "-forcedecode" only works with openssl. Check compilation and command line parameters
269-
if args.forcedecode {
270-
if stupidgcm.BuiltWithoutOpenssl {
271-
tlog.Fatal.Printf("The -forcedecode flag requires openssl support, but gocryptfs was compiled without it!")
272-
os.Exit(exitcodes.Usage)
273-
}
274-
if args.aessiv {
275-
tlog.Fatal.Printf("The -forcedecode and -aessiv flags are incompatible because they use different crypto libs (openssl vs native Go)")
276-
os.Exit(exitcodes.Usage)
277-
}
278-
if args.reverse {
279-
tlog.Fatal.Printf("The reverse mode and the -forcedecode option are not compatible")
280-
os.Exit(exitcodes.Usage)
281-
}
282-
// Has the user explicitly disabled openssl using "-openssl=false/0"?
283-
if !args.openssl && opensslAuto != "auto" {
284-
tlog.Fatal.Printf("-forcedecode requires openssl, but is disabled via command-line option")
285-
os.Exit(exitcodes.Usage)
286-
}
287-
args.openssl = true
288-
289-
// Try to make it harder for the user to shoot himself in the foot.
290-
args.ro = true
291-
args.allow_other = false
292-
args.ko = "noexec"
293-
}
294267
if len(args.extpass) > 0 && len(args.passfile) != 0 {
295268
tlog.Fatal.Printf("The options -extpass and -passfile cannot be used at the same time")
296269
os.Exit(exitcodes.Usage)

internal/configfile/config_file.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ func getKeyEncrypter(scryptHash []byte, useHKDF bool) *contentenc.ContentEnc {
298298
if useHKDF {
299299
IVLen = contentenc.DefaultIVBits
300300
}
301-
cc := cryptocore.New(scryptHash, cryptocore.BackendGoGCM, IVLen, useHKDF, false)
302-
ce := contentenc.New(cc, 4096, false)
301+
cc := cryptocore.New(scryptHash, cryptocore.BackendGoGCM, IVLen, useHKDF)
302+
ce := contentenc.New(cc, 4096)
303303
return ce
304304
}
305305

internal/contentenc/content.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/hanwen/go-fuse/v2/fuse"
1414

1515
"github.com/rfjakob/gocryptfs/v2/internal/cryptocore"
16-
"github.com/rfjakob/gocryptfs/v2/internal/stupidgcm"
1716
"github.com/rfjakob/gocryptfs/v2/internal/tlog"
1817
)
1918

@@ -41,8 +40,6 @@ type ContentEnc struct {
4140
allZeroBlock []byte
4241
// All-zero block of size IVBitLen/8, for fast compares
4342
allZeroNonce []byte
44-
// Force decode even if integrity check fails (openSSL only)
45-
forceDecode bool
4643

4744
// Ciphertext block "sync.Pool" pool. Always returns cipherBS-sized byte
4845
// slices (usually 4128 bytes).
@@ -60,9 +57,8 @@ type ContentEnc struct {
6057
}
6158

6259
// New returns an initialized ContentEnc instance.
63-
func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEnc {
64-
tlog.Debug.Printf("contentenc.New: plainBS=%d, forceDecode=%v",
65-
plainBS, forceDecode)
60+
func New(cc *cryptocore.CryptoCore, plainBS uint64) *ContentEnc {
61+
tlog.Debug.Printf("contentenc.New: plainBS=%d", plainBS)
6662

6763
if fuse.MAX_KERNEL_WRITE%plainBS != 0 {
6864
log.Panicf("unaligned MAX_KERNEL_WRITE=%d", fuse.MAX_KERNEL_WRITE)
@@ -81,7 +77,6 @@ func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEn
8177
cipherBS: cipherBS,
8278
allZeroBlock: make([]byte, cipherBS),
8379
allZeroNonce: make([]byte, cc.IVLen),
84-
forceDecode: forceDecode,
8580
cBlockPool: newBPool(int(cipherBS)),
8681
CReqPool: newBPool(cReqSize),
8782
pBlockPool: newBPool(int(plainBS)),
@@ -111,11 +106,7 @@ func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, file
111106
var pBlock []byte
112107
pBlock, err = be.DecryptBlock(cBlock, blockNo, fileID)
113108
if err != nil {
114-
if be.forceDecode && err == stupidgcm.ErrAuth {
115-
tlog.Warn.Printf("DecryptBlocks: authentication failure in block #%d, overridden by forcedecode", firstBlockNo)
116-
} else {
117-
break
118-
}
109+
break
119110
}
120111
pBuf.Write(pBlock)
121112
be.pBlockPool.Put(pBlock)
@@ -183,9 +174,6 @@ func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileID []b
183174
if err != nil {
184175
tlog.Debug.Printf("DecryptBlock: %s, len=%d", err.Error(), len(ciphertextOrig))
185176
tlog.Debug.Println(hex.Dump(ciphertextOrig))
186-
if be.forceDecode && err == stupidgcm.ErrAuth {
187-
return plaintext, err
188-
}
189177
return nil, err
190178
}
191179

internal/contentenc/content_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ func TestSplitRange(t *testing.T) {
2323
testRange{6654, 8945})
2424

2525
key := make([]byte, cryptocore.KeyLen)
26-
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true, false)
27-
f := New(cc, DefaultBS, false)
26+
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
27+
f := New(cc, DefaultBS)
2828

2929
for _, r := range ranges {
3030
parts := f.ExplodePlainRange(r.offset, r.length)
@@ -51,8 +51,8 @@ func TestCiphertextRange(t *testing.T) {
5151
testRange{6654, 8945})
5252

5353
key := make([]byte, cryptocore.KeyLen)
54-
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true, false)
55-
f := New(cc, DefaultBS, false)
54+
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
55+
f := New(cc, DefaultBS)
5656

5757
for _, r := range ranges {
5858

@@ -74,8 +74,8 @@ func TestCiphertextRange(t *testing.T) {
7474

7575
func TestBlockNo(t *testing.T) {
7676
key := make([]byte, cryptocore.KeyLen)
77-
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true, false)
78-
f := New(cc, DefaultBS, false)
77+
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
78+
f := New(cc, DefaultBS)
7979

8080
b := f.CipherOffToBlockNo(788)
8181
if b != 0 {

internal/contentenc/offsets_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
// TestSizeToSize tests CipherSizeToPlainSize and PlainSizeToCipherSize
1111
func TestSizeToSize(t *testing.T) {
1212
key := make([]byte, cryptocore.KeyLen)
13-
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true, false)
14-
ce := New(cc, DefaultBS, false)
13+
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
14+
ce := New(cc, DefaultBS)
1515

1616
const rangeMax = 10000
1717

internal/cryptocore/cryptocore.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ type CryptoCore struct {
7373
//
7474
// Note: "key" is either the scrypt hash of the password (when decrypting
7575
// a config file) or the masterkey (when finally mounting the filesystem).
76-
func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDecode bool) *CryptoCore {
77-
tlog.Debug.Printf("cryptocore.New: key=%d bytes, aeadType=%v, IVBitLen=%d, useHKDF=%v, forceDecode=%v",
78-
len(key), aeadType, IVBitLen, useHKDF, forceDecode)
76+
func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool) *CryptoCore {
77+
tlog.Debug.Printf("cryptocore.New: key=%d bytes, aeadType=%v, IVBitLen=%d, useHKDF=%v",
78+
len(key), aeadType, IVBitLen, useHKDF)
7979

8080
if len(key) != KeyLen {
8181
log.Panicf("Unsupported key length of %d bytes", len(key))
@@ -120,7 +120,7 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec
120120
if IVBitLen != 128 {
121121
log.Panicf("stupidgcm only supports 128-bit IVs, you wanted %d", IVBitLen)
122122
}
123-
aeadCipher = stupidgcm.NewAES256GCM(gcmKey, forceDecode)
123+
aeadCipher = stupidgcm.NewAES256GCM(gcmKey)
124124
case BackendGoGCM:
125125
goGcmBlockCipher, err := aes.NewCipher(gcmKey)
126126
if err != nil {

internal/cryptocore/cryptocore_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ import (
1010
func TestCryptoCoreNew(t *testing.T) {
1111
key := make([]byte, 32)
1212
for _, useHKDF := range []bool{true, false} {
13-
c := New(key, BackendGoGCM, 96, useHKDF, false)
13+
c := New(key, BackendGoGCM, 96, useHKDF)
1414
if c.IVLen != 12 {
1515
t.Fail()
1616
}
17-
c = New(key, BackendGoGCM, 128, useHKDF, false)
17+
c = New(key, BackendGoGCM, 128, useHKDF)
1818
if c.IVLen != 16 {
1919
t.Fail()
2020
}
2121
if stupidgcm.BuiltWithoutOpenssl {
2222
continue
2323
}
24-
c = New(key, BackendOpenSSL, 128, useHKDF, false)
24+
c = New(key, BackendOpenSSL, 128, useHKDF)
2525
if c.IVLen != 16 {
2626
t.Fail()
2727
}
@@ -37,5 +37,5 @@ func TestNewPanic(t *testing.T) {
3737
}()
3838

3939
key := make([]byte, 16)
40-
New(key, BackendOpenSSL, 128, true, false)
40+
New(key, BackendOpenSSL, 128, true)
4141
}

internal/fusefrontend/args.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ type Args struct {
2626
ConfigCustom bool
2727
// NoPrealloc disables automatic preallocation before writing
2828
NoPrealloc bool
29-
// Force decode even if integrity check fails (openSSL only)
30-
ForceDecode bool
3129
// Exclude is a list of paths to make inaccessible, starting match at
3230
// the filesystem root
3331
Exclude []string

internal/fusefrontend/file.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"github.com/rfjakob/gocryptfs/v2/internal/contentenc"
2121
"github.com/rfjakob/gocryptfs/v2/internal/inomap"
2222
"github.com/rfjakob/gocryptfs/v2/internal/openfiletable"
23-
"github.com/rfjakob/gocryptfs/v2/internal/stupidgcm"
2423
"github.com/rfjakob/gocryptfs/v2/internal/syscallcompat"
2524
"github.com/rfjakob/gocryptfs/v2/internal/tlog"
2625
)
@@ -208,16 +207,9 @@ func (f *File) doRead(dst []byte, off uint64, length uint64) ([]byte, syscall.Er
208207
plaintext, err := f.contentEnc.DecryptBlocks(ciphertext, firstBlockNo, fileID)
209208
f.rootNode.contentEnc.CReqPool.Put(ciphertext)
210209
if err != nil {
211-
if f.rootNode.args.ForceDecode && err == stupidgcm.ErrAuth {
212-
// We do not have the information which block was corrupt here anymore,
213-
// but DecryptBlocks() has already logged it anyway.
214-
tlog.Warn.Printf("doRead %d: off=%d len=%d: returning corrupt data due to forcedecode",
215-
f.qIno.Ino, off, length)
216-
} else {
217-
curruptBlockNo := firstBlockNo + f.contentEnc.PlainOffToBlockNo(uint64(len(plaintext)))
218-
tlog.Warn.Printf("doRead %d: corrupt block #%d: %v", f.qIno.Ino, curruptBlockNo, err)
219-
return nil, syscall.EIO
220-
}
210+
curruptBlockNo := firstBlockNo + f.contentEnc.PlainOffToBlockNo(uint64(len(plaintext)))
211+
tlog.Warn.Printf("doRead %d: corrupt block #%d: %v", f.qIno.Ino, curruptBlockNo, err)
212+
return nil, syscall.EIO
221213
}
222214

223215
// Crop down to the relevant part

0 commit comments

Comments
 (0)