Increase GCM IV size from 96 to 128 bits
This pushes back the birthday bound for collisions to make it virtually irrelevant.
This commit is contained in:
parent
88826dc51d
commit
1caa925868
@ -57,6 +57,11 @@ to mount the gocryptfs filesytem without user interaction.
|
|||||||
**-fusedebug**
|
**-fusedebug**
|
||||||
: Enable fuse library debug output
|
: Enable fuse library debug output
|
||||||
|
|
||||||
|
**-gcmiv128**
|
||||||
|
: Use an 128-bit IV for GCM encryption instead of Go's default of
|
||||||
|
96 bits (default true). This pushes back the birthday bound for IV
|
||||||
|
collisions far enough to make it irrelevant.
|
||||||
|
|
||||||
**-init**
|
**-init**
|
||||||
: Initialize encrypted directory
|
: Initialize encrypted directory
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ File Contents
|
|||||||
All file contents are encrypted using AES-256-GCM (Galois/Counter Mode).
|
All file contents are encrypted using AES-256-GCM (Galois/Counter Mode).
|
||||||
|
|
||||||
Files are segmented into 4KB blocks. Each block gets a fresh random
|
Files are segmented into 4KB blocks. Each block gets a fresh random
|
||||||
96 bit IV each time it is modified. A 128-bit authentication tag (GHASH)
|
128 bit IV each time it is modified. A 128-bit authentication tag (GHASH)
|
||||||
protects each block from modifications.
|
protects each block from modifications.
|
||||||
|
|
||||||
Each file has a header containing a random 128-bit file ID. The
|
Each file has a header containing a random 128-bit file ID. The
|
||||||
|
32
Documentation/file-format.md
Normal file
32
Documentation/file-format.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
File Format
|
||||||
|
===========
|
||||||
|
|
||||||
|
Header
|
||||||
|
|
||||||
|
2 bytes header version (big endian uint16, currently 2)
|
||||||
|
16 bytes file id
|
||||||
|
|
||||||
|
Data block
|
||||||
|
|
||||||
|
16 bytes GCM IV (nonce)
|
||||||
|
1-4096 bytes encrypted data
|
||||||
|
16 bytes GHASH
|
||||||
|
|
||||||
|
|
||||||
|
Example: 1-byte file
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Header 18 bytes
|
||||||
|
Data block 33 bytes
|
||||||
|
|
||||||
|
Total: 51 bytes
|
||||||
|
|
||||||
|
|
||||||
|
Example: 5000-byte file
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Header 18 bytes
|
||||||
|
Data block 4128 bytes
|
||||||
|
Data block 936 bytes
|
||||||
|
|
||||||
|
Total: 5082 bytes
|
@ -44,7 +44,7 @@ func (be *CryptFS) CipherSizeToPlainSize(cipherSize uint64) uint64 {
|
|||||||
blockNo := be.CipherOffToBlockNo(cipherSize - 1)
|
blockNo := be.CipherOffToBlockNo(cipherSize - 1)
|
||||||
blockCount := blockNo + 1
|
blockCount := blockNo + 1
|
||||||
|
|
||||||
overhead := BLOCK_OVERHEAD*blockCount + HEADER_LEN
|
overhead := be.BlockOverhead()*blockCount + HEADER_LEN
|
||||||
|
|
||||||
return cipherSize - overhead
|
return cipherSize - overhead
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ func (be *CryptFS) PlainSizeToCipherSize(plainSize uint64) uint64 {
|
|||||||
blockNo := be.PlainOffToBlockNo(plainSize - 1)
|
blockNo := be.PlainOffToBlockNo(plainSize - 1)
|
||||||
blockCount := blockNo + 1
|
blockCount := blockNo + 1
|
||||||
|
|
||||||
overhead := BLOCK_OVERHEAD*blockCount + HEADER_LEN
|
overhead := be.BlockOverhead()*blockCount + HEADER_LEN
|
||||||
|
|
||||||
return plainSize + overhead
|
return plainSize + overhead
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ func CreateConfFile(filename string, password string, plaintextNames bool, logN
|
|||||||
cf.EncryptKey(key, password, logN)
|
cf.EncryptKey(key, password, logN)
|
||||||
|
|
||||||
// Set feature flags
|
// Set feature flags
|
||||||
|
cf.FeatureFlags = append(cf.FeatureFlags, FlagGCMIV128)
|
||||||
if plaintextNames {
|
if plaintextNames {
|
||||||
cf.FeatureFlags = append(cf.FeatureFlags, FlagPlaintextNames)
|
cf.FeatureFlags = append(cf.FeatureFlags, FlagPlaintextNames)
|
||||||
} else {
|
} else {
|
||||||
@ -94,7 +95,7 @@ func LoadConfFile(filename string, password string) ([]byte, *ConfFile, error) {
|
|||||||
// Unlock master key using password-based key
|
// Unlock master key using password-based key
|
||||||
// We use stock go GCM instead of OpenSSL here as speed is not important
|
// We use stock go GCM instead of OpenSSL here as speed is not important
|
||||||
// and we get better error messages
|
// and we get better error messages
|
||||||
cfs := NewCryptFS(scryptHash, false, false)
|
cfs := NewCryptFS(scryptHash, false, false, false)
|
||||||
key, err := cfs.DecryptBlock(cf.EncryptedKey, 0, nil)
|
key, err := cfs.DecryptBlock(cf.EncryptedKey, 0, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Warn.Printf("failed to unlock master key: %s\n", err.Error())
|
Warn.Printf("failed to unlock master key: %s\n", err.Error())
|
||||||
@ -115,7 +116,7 @@ func (cf *ConfFile) EncryptKey(key []byte, password string, logN int) {
|
|||||||
scryptHash := cf.ScryptObject.DeriveKey(password)
|
scryptHash := cf.ScryptObject.DeriveKey(password)
|
||||||
|
|
||||||
// Lock master key using password-based key
|
// Lock master key using password-based key
|
||||||
cfs := NewCryptFS(scryptHash, false, false)
|
cfs := NewCryptFS(scryptHash, false, false, false)
|
||||||
cf.EncryptedKey = cfs.EncryptBlock(key, 0, nil)
|
cf.EncryptedKey = cfs.EncryptBlock(key, 0, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,16 +156,18 @@ func (cf *ConfFile) WriteFile() error {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Understood Feature Flags.
|
// Understood Feature Flags.
|
||||||
// Also teach isFeatureFlagKnown() about any additions
|
// Also teach isFeatureFlagKnown() about any additions and
|
||||||
|
// add it to CreateConfFile() if you want to have it enabled by default.
|
||||||
FlagPlaintextNames = "PlaintextNames"
|
FlagPlaintextNames = "PlaintextNames"
|
||||||
FlagDirIV = "DirIV"
|
FlagDirIV = "DirIV"
|
||||||
FlagEMENames = "EMENames"
|
FlagEMENames = "EMENames"
|
||||||
|
FlagGCMIV128 = "GCMIV128"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Verify that we understand a feature flag
|
// Verify that we understand a feature flag
|
||||||
func (cf *ConfFile) isFeatureFlagKnown(flag string) bool {
|
func (cf *ConfFile) isFeatureFlagKnown(flag string) bool {
|
||||||
switch flag {
|
switch flag {
|
||||||
case FlagPlaintextNames, FlagDirIV, FlagEMENames:
|
case FlagPlaintextNames, FlagDirIV, FlagEMENames, FlagGCMIV128:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@ -21,7 +21,7 @@ func TestSplitRange(t *testing.T) {
|
|||||||
testRange{6654, 8945})
|
testRange{6654, 8945})
|
||||||
|
|
||||||
key := make([]byte, KEY_LEN)
|
key := make([]byte, KEY_LEN)
|
||||||
f := NewCryptFS(key, true, false)
|
f := NewCryptFS(key, true, false, true)
|
||||||
|
|
||||||
for _, r := range ranges {
|
for _, r := range ranges {
|
||||||
parts := f.ExplodePlainRange(r.offset, r.length)
|
parts := f.ExplodePlainRange(r.offset, r.length)
|
||||||
@ -48,7 +48,7 @@ func TestCiphertextRange(t *testing.T) {
|
|||||||
testRange{6654, 8945})
|
testRange{6654, 8945})
|
||||||
|
|
||||||
key := make([]byte, KEY_LEN)
|
key := make([]byte, KEY_LEN)
|
||||||
f := NewCryptFS(key, true, false)
|
f := NewCryptFS(key, true, false, true)
|
||||||
|
|
||||||
for _, r := range ranges {
|
for _, r := range ranges {
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ func TestCiphertextRange(t *testing.T) {
|
|||||||
|
|
||||||
func TestBlockNo(t *testing.T) {
|
func TestBlockNo(t *testing.T) {
|
||||||
key := make([]byte, KEY_LEN)
|
key := make([]byte, KEY_LEN)
|
||||||
f := NewCryptFS(key, true, false)
|
f := NewCryptFS(key, true, false, true)
|
||||||
|
|
||||||
b := f.CipherOffToBlockNo(788)
|
b := f.CipherOffToBlockNo(788)
|
||||||
if b != 0 {
|
if b != 0 {
|
||||||
|
@ -11,9 +11,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
DEFAULT_PLAINBS = 4096
|
DEFAULT_PLAINBS = 4096
|
||||||
KEY_LEN = 32 // AES-256
|
KEY_LEN = 32 // AES-256
|
||||||
NONCE_LEN = 12
|
|
||||||
AUTH_TAG_LEN = 16
|
AUTH_TAG_LEN = 16
|
||||||
BLOCK_OVERHEAD = NONCE_LEN + AUTH_TAG_LEN
|
|
||||||
DIRIV_LEN = 16 // identical to AES block size
|
DIRIV_LEN = 16 // identical to AES block size
|
||||||
DIRIV_FILENAME = "gocryptfs.diriv"
|
DIRIV_FILENAME = "gocryptfs.diriv"
|
||||||
)
|
)
|
||||||
@ -21,6 +19,8 @@ const (
|
|||||||
type CryptFS struct {
|
type CryptFS struct {
|
||||||
blockCipher cipher.Block
|
blockCipher cipher.Block
|
||||||
gcm cipher.AEAD
|
gcm cipher.AEAD
|
||||||
|
gcmIVLen int
|
||||||
|
gcmIVGen nonceGenerator
|
||||||
plainBS uint64
|
plainBS uint64
|
||||||
cipherBS uint64
|
cipherBS uint64
|
||||||
// Stores an all-zero block of size cipherBS
|
// Stores an all-zero block of size cipherBS
|
||||||
@ -29,7 +29,7 @@ type CryptFS struct {
|
|||||||
DirIVCacheEnc DirIVCache
|
DirIVCacheEnc DirIVCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCryptFS(key []byte, useOpenssl bool, plaintextNames bool) *CryptFS {
|
func NewCryptFS(key []byte, useOpenssl bool, plaintextNames bool, GCMIV128 bool) *CryptFS {
|
||||||
|
|
||||||
if len(key) != KEY_LEN {
|
if len(key) != KEY_LEN {
|
||||||
panic(fmt.Sprintf("Unsupported key length %d", len(key)))
|
panic(fmt.Sprintf("Unsupported key length %d", len(key)))
|
||||||
@ -40,22 +40,31 @@ func NewCryptFS(key []byte, useOpenssl bool, plaintextNames bool) *CryptFS {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We want the IV size in bytes
|
||||||
|
gcmIV := 96 / 8
|
||||||
|
if GCMIV128 {
|
||||||
|
gcmIV = 128 / 8
|
||||||
|
}
|
||||||
|
|
||||||
var gcm cipher.AEAD
|
var gcm cipher.AEAD
|
||||||
if useOpenssl {
|
if useOpenssl {
|
||||||
gcm = opensslGCM{key}
|
gcm = opensslGCM{key}
|
||||||
} else {
|
} else {
|
||||||
gcm, err = cipher.NewGCM(b)
|
gcm, err = cipher.NewGCMWithNonceSize(b, gcmIV)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cipherBS := DEFAULT_PLAINBS + NONCE_LEN + AUTH_TAG_LEN
|
plainBS := DEFAULT_PLAINBS
|
||||||
|
cipherBS := plainBS + gcmIV + AUTH_TAG_LEN
|
||||||
|
|
||||||
return &CryptFS{
|
return &CryptFS{
|
||||||
blockCipher: b,
|
blockCipher: b,
|
||||||
gcm: gcm,
|
gcm: gcm,
|
||||||
plainBS: DEFAULT_PLAINBS,
|
gcmIVLen: gcmIV,
|
||||||
|
gcmIVGen: nonceGenerator{nonceLen: gcmIV},
|
||||||
|
plainBS: uint64(plainBS),
|
||||||
cipherBS: uint64(cipherBS),
|
cipherBS: uint64(cipherBS),
|
||||||
allZeroBlock: make([]byte, cipherBS),
|
allZeroBlock: make([]byte, cipherBS),
|
||||||
}
|
}
|
||||||
@ -65,3 +74,8 @@ func NewCryptFS(key []byte, useOpenssl bool, plaintextNames bool) *CryptFS {
|
|||||||
func (be *CryptFS) PlainBS() uint64 {
|
func (be *CryptFS) PlainBS() uint64 {
|
||||||
return be.plainBS
|
return be.plainBS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Per-block storage overhead
|
||||||
|
func (be *CryptFS) BlockOverhead() uint64 {
|
||||||
|
return be.cipherBS - be.plainBS
|
||||||
|
}
|
||||||
|
@ -59,15 +59,15 @@ func (be *CryptFS) DecryptBlock(ciphertext []byte, blockNo uint64, fileId []byte
|
|||||||
return make([]byte, be.plainBS), nil
|
return make([]byte, be.plainBS), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ciphertext) < NONCE_LEN {
|
if len(ciphertext) < be.gcmIVLen {
|
||||||
Warn.Printf("DecryptBlock: Block is too short: %d bytes\n", len(ciphertext))
|
Warn.Printf("DecryptBlock: Block is too short: %d bytes\n", len(ciphertext))
|
||||||
return nil, errors.New("Block is too short")
|
return nil, errors.New("Block is too short")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract nonce
|
// Extract nonce
|
||||||
nonce := ciphertext[:NONCE_LEN]
|
nonce := ciphertext[:be.gcmIVLen]
|
||||||
ciphertextOrig := ciphertext
|
ciphertextOrig := ciphertext
|
||||||
ciphertext = ciphertext[NONCE_LEN:]
|
ciphertext = ciphertext[be.gcmIVLen:]
|
||||||
|
|
||||||
// Decrypt
|
// Decrypt
|
||||||
var plaintext []byte
|
var plaintext []byte
|
||||||
@ -94,7 +94,7 @@ func (be *CryptFS) EncryptBlock(plaintext []byte, blockNo uint64, fileID []byte)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get fresh nonce
|
// Get fresh nonce
|
||||||
nonce := gcmNonce.Get()
|
nonce := be.gcmIVGen.Get()
|
||||||
|
|
||||||
// Authenticate block with block number and file ID
|
// Authenticate block with block number and file ID
|
||||||
aData := make([]byte, 8)
|
aData := make([]byte, 8)
|
||||||
|
@ -12,7 +12,7 @@ func TestEncryptPathNoIV(t *testing.T) {
|
|||||||
s = append(s, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890")
|
s = append(s, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890")
|
||||||
|
|
||||||
key := make([]byte, KEY_LEN)
|
key := make([]byte, KEY_LEN)
|
||||||
fs := NewCryptFS(key, true, false)
|
fs := NewCryptFS(key, true, false, true)
|
||||||
|
|
||||||
for _, n := range s {
|
for _, n := range s {
|
||||||
c := fs.EncryptPathNoIV(n)
|
c := fs.EncryptPathNoIV(n)
|
||||||
@ -33,7 +33,7 @@ func TestPad16(t *testing.T) {
|
|||||||
s = append(s, []byte("12345678901234567abcdefg"))
|
s = append(s, []byte("12345678901234567abcdefg"))
|
||||||
|
|
||||||
key := make([]byte, KEY_LEN)
|
key := make([]byte, KEY_LEN)
|
||||||
fs := NewCryptFS(key, true, false)
|
fs := NewCryptFS(key, true, false, true)
|
||||||
|
|
||||||
for i := range s {
|
for i := range s {
|
||||||
orig := s[i]
|
orig := s[i]
|
||||||
|
@ -24,16 +24,15 @@ func RandUint64() uint64 {
|
|||||||
return binary.BigEndian.Uint64(b)
|
return binary.BigEndian.Uint64(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
var gcmNonce nonce96
|
type nonceGenerator struct {
|
||||||
|
|
||||||
type nonce96 struct {
|
|
||||||
lastNonce []byte
|
lastNonce []byte
|
||||||
|
nonceLen int // bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a random 96 bit nonce
|
// Get a random 96 bit nonce
|
||||||
func (n *nonce96) Get() []byte {
|
func (n *nonceGenerator) Get() []byte {
|
||||||
nonce := RandBytes(12)
|
nonce := RandBytes(n.nonceLen)
|
||||||
Debug.Printf("nonce96.Get(): %s\n", hex.EncodeToString(nonce))
|
Debug.Printf("nonceGenerator.Get(): %s\n", hex.EncodeToString(nonce))
|
||||||
if bytes.Equal(nonce, n.lastNonce) {
|
if bytes.Equal(nonce, n.lastNonce) {
|
||||||
m := fmt.Sprintf("Got the same nonce twice: %s. This should never happen!", hex.EncodeToString(nonce))
|
m := fmt.Sprintf("Got the same nonce twice: %s. This should never happen!", hex.EncodeToString(nonce))
|
||||||
panic(m)
|
panic(m)
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/spacemonkeygo/openssl"
|
"github.com/spacemonkeygo/openssl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Supports all nonce sizes
|
||||||
type opensslGCM struct {
|
type opensslGCM struct {
|
||||||
key []byte
|
key []byte
|
||||||
}
|
}
|
||||||
@ -16,13 +17,13 @@ func (be opensslGCM) Overhead() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (be opensslGCM) NonceSize() int {
|
func (be opensslGCM) NonceSize() int {
|
||||||
return NONCE_LEN
|
// We support any nonce size
|
||||||
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seal encrypts and authenticates plaintext, authenticates the
|
// Seal encrypts and authenticates plaintext, authenticates the
|
||||||
// additional data and appends the result to dst, returning the updated
|
// additional data and appends the result to dst, returning the updated
|
||||||
// slice. The nonce must be NonceSize() bytes long and unique for all
|
// slice. opensslGCM supports any nonce size.
|
||||||
// time, for a given key.
|
|
||||||
func (be opensslGCM) Seal(dst, nonce, plaintext, data []byte) []byte {
|
func (be opensslGCM) Seal(dst, nonce, plaintext, data []byte) []byte {
|
||||||
|
|
||||||
// Preallocate output buffer
|
// Preallocate output buffer
|
||||||
|
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
cHxK1r_WYNd43oz_foCmzgt5jWrSvpiD-Ngy94L8LndrP9Kic-xlEg==
|
@ -0,0 +1 @@
|
|||||||
|
cdrpE7F_WZBEDSu1DI2k880I-9dsPjhD8AU8faPjh4omHmDcdcHlyimF
|
16
integration_tests/example_filesystems/v0.7/gocryptfs.conf
Normal file
16
integration_tests/example_filesystems/v0.7/gocryptfs.conf
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"EncryptedKey": "rjkwSNwi3nCUKMLaDttlYweHSDgyhbDx5sWv/a+h+cG1co5IXoXF9ZQSxXl1Qwm/XhY/dvTvnGZRREde",
|
||||||
|
"ScryptObject": {
|
||||||
|
"Salt": "mX6madEb9nbE+xgo840s9d2ro88f/5GuEiimQ+C7Z1I=",
|
||||||
|
"N": 65536,
|
||||||
|
"R": 8,
|
||||||
|
"P": 1,
|
||||||
|
"KeyLen": 32
|
||||||
|
},
|
||||||
|
"Version": 2,
|
||||||
|
"FeatureFlags": [
|
||||||
|
"GCMIV128",
|
||||||
|
"DirIV",
|
||||||
|
"EMENames"
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
¤7vßØFT5ÌÖË£<C38B>N×
|
@ -60,7 +60,7 @@ func TestExampleFSv04(t *testing.T) {
|
|||||||
checkExampleFS(t, pDir)
|
checkExampleFS(t, pDir)
|
||||||
unmount(pDir)
|
unmount(pDir)
|
||||||
mount(cDir, pDir, "-masterkey", "74676e34-0b47c145-00dac61a-17a92316-"+
|
mount(cDir, pDir, "-masterkey", "74676e34-0b47c145-00dac61a-17a92316-"+
|
||||||
"bb57044c-e205b71f-65f4fdca-7cabd4b3", "-diriv=false", "-emenames=false")
|
"bb57044c-e205b71f-65f4fdca-7cabd4b3", "-diriv=false", "-emenames=false", "-gcmiv128=false")
|
||||||
checkExampleFS(t, pDir)
|
checkExampleFS(t, pDir)
|
||||||
unmount(pDir)
|
unmount(pDir)
|
||||||
err = os.Remove(pDir)
|
err = os.Remove(pDir)
|
||||||
@ -82,7 +82,7 @@ func TestExampleFSv05(t *testing.T) {
|
|||||||
checkExampleFS(t, pDir)
|
checkExampleFS(t, pDir)
|
||||||
unmount(pDir)
|
unmount(pDir)
|
||||||
mount(cDir, pDir, "-masterkey", "199eae55-36bff4af-83b9a3a2-4fa16f65-"+
|
mount(cDir, pDir, "-masterkey", "199eae55-36bff4af-83b9a3a2-4fa16f65-"+
|
||||||
"1549ccdb-2d08d1f0-b1b26965-1b61f896", "-emenames=false")
|
"1549ccdb-2d08d1f0-b1b26965-1b61f896", "-emenames=false", "-gcmiv128=false")
|
||||||
checkExampleFS(t, pDir)
|
checkExampleFS(t, pDir)
|
||||||
unmount(pDir)
|
unmount(pDir)
|
||||||
err = os.Remove(pDir)
|
err = os.Remove(pDir)
|
||||||
@ -104,7 +104,7 @@ func TestExampleFSv06(t *testing.T) {
|
|||||||
checkExampleFS(t, pDir)
|
checkExampleFS(t, pDir)
|
||||||
unmount(pDir)
|
unmount(pDir)
|
||||||
mount(cDir, pDir, "-masterkey", "7bc8deb0-5fc894ef-a093da43-61561a81-"+
|
mount(cDir, pDir, "-masterkey", "7bc8deb0-5fc894ef-a093da43-61561a81-"+
|
||||||
"0e8dee83-fdc056a4-937c37dd-9df5c520")
|
"0e8dee83-fdc056a4-937c37dd-9df5c520", "-gcmiv128=false")
|
||||||
checkExampleFS(t, pDir)
|
checkExampleFS(t, pDir)
|
||||||
unmount(pDir)
|
unmount(pDir)
|
||||||
err = os.Remove(pDir)
|
err = os.Remove(pDir)
|
||||||
@ -113,8 +113,10 @@ func TestExampleFSv06(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test example_filesystems/v0.6
|
// Test example_filesystems/v0.6-plaintextnames
|
||||||
// with password mount and -masterkey mount
|
// with password mount and -masterkey mount
|
||||||
|
// v0.6 changed the file name handling a lot, hence the explicit test case for
|
||||||
|
// plaintextnames.
|
||||||
func TestExampleFSv06PlaintextNames(t *testing.T) {
|
func TestExampleFSv06PlaintextNames(t *testing.T) {
|
||||||
pDir := tmpDir + "TestExampleFsV06PlaintextNames/"
|
pDir := tmpDir + "TestExampleFsV06PlaintextNames/"
|
||||||
cDir := "example_filesystems/v0.6-plaintextnames"
|
cDir := "example_filesystems/v0.6-plaintextnames"
|
||||||
@ -126,7 +128,30 @@ func TestExampleFSv06PlaintextNames(t *testing.T) {
|
|||||||
checkExampleFS(t, pDir)
|
checkExampleFS(t, pDir)
|
||||||
unmount(pDir)
|
unmount(pDir)
|
||||||
mount(cDir, pDir, "-masterkey", "f4690202-595e4593-64c4f7e0-4dddd7d1-"+
|
mount(cDir, pDir, "-masterkey", "f4690202-595e4593-64c4f7e0-4dddd7d1-"+
|
||||||
"303147f9-0ca8aea2-966341a7-52ea8ae9", "-plaintextnames")
|
"303147f9-0ca8aea2-966341a7-52ea8ae9", "-plaintextnames", "-gcmiv128=false")
|
||||||
|
checkExampleFS(t, pDir)
|
||||||
|
unmount(pDir)
|
||||||
|
err = os.Remove(pDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test example_filesystems/v0.7
|
||||||
|
// with password mount and -masterkey mount
|
||||||
|
// v0.7 adds 128 bit GCM IVs
|
||||||
|
func TestExampleFSv07(t *testing.T) {
|
||||||
|
pDir := tmpDir + "TestExampleFsV07/"
|
||||||
|
cDir := "example_filesystems/v0.7"
|
||||||
|
err := os.Mkdir(pDir, 0777)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
mount(cDir, pDir, "-extpass", "echo test")
|
||||||
|
checkExampleFS(t, pDir)
|
||||||
|
unmount(pDir)
|
||||||
|
mount(cDir, pDir, "-masterkey", "bee8d0c5-74ec49ff-24b8793d-91d488a9-"+
|
||||||
|
"6117c58b-357eafaa-162ce3cf-8a061a28")
|
||||||
checkExampleFS(t, pDir)
|
checkExampleFS(t, pDir)
|
||||||
unmount(pDir)
|
unmount(pDir)
|
||||||
err = os.Remove(pDir)
|
err = os.Remove(pDir)
|
||||||
|
5
main.go
5
main.go
@ -35,7 +35,7 @@ const (
|
|||||||
|
|
||||||
type argContainer struct {
|
type argContainer struct {
|
||||||
debug, init, zerokey, fusedebug, openssl, passwd, foreground, version,
|
debug, init, zerokey, fusedebug, openssl, passwd, foreground, version,
|
||||||
plaintextnames, quiet, diriv, emenames bool
|
plaintextnames, quiet, diriv, emenames, gcmiv128 bool
|
||||||
masterkey, mountpoint, cipherdir, cpuprofile, config, extpass string
|
masterkey, mountpoint, cipherdir, cpuprofile, config, extpass string
|
||||||
notifypid, scryptn int
|
notifypid, scryptn int
|
||||||
}
|
}
|
||||||
@ -149,6 +149,7 @@ func main() {
|
|||||||
flagSet.BoolVar(&args.quiet, "q", false, "Quiet - silence informational messages")
|
flagSet.BoolVar(&args.quiet, "q", false, "Quiet - silence informational messages")
|
||||||
flagSet.BoolVar(&args.diriv, "diriv", true, "Use per-directory file name IV")
|
flagSet.BoolVar(&args.diriv, "diriv", true, "Use per-directory file name IV")
|
||||||
flagSet.BoolVar(&args.emenames, "emenames", true, "Use EME filename encryption. This option implies diriv.")
|
flagSet.BoolVar(&args.emenames, "emenames", true, "Use EME filename encryption. This option implies diriv.")
|
||||||
|
flagSet.BoolVar(&args.gcmiv128, "gcmiv128", true, "Use an 128-bit IV for GCM encryption instead of Go's default of 96 bits")
|
||||||
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.config, "config", "", "Use specified config file instead of CIPHERDIR/gocryptfs.conf")
|
flagSet.StringVar(&args.config, "config", "", "Use specified config file instead of CIPHERDIR/gocryptfs.conf")
|
||||||
@ -293,6 +294,7 @@ func pathfsFrontend(key []byte, args argContainer, confFile *cryptfs.ConfFile) *
|
|||||||
PlaintextNames: args.plaintextnames,
|
PlaintextNames: args.plaintextnames,
|
||||||
DirIV: args.diriv,
|
DirIV: args.diriv,
|
||||||
EMENames: args.emenames,
|
EMENames: args.emenames,
|
||||||
|
GCMIV128: args.gcmiv128,
|
||||||
}
|
}
|
||||||
// confFile is nil when "-zerokey" or "-masterkey" was used
|
// confFile is nil when "-zerokey" or "-masterkey" was used
|
||||||
if confFile != nil {
|
if confFile != nil {
|
||||||
@ -300,6 +302,7 @@ func pathfsFrontend(key []byte, args argContainer, confFile *cryptfs.ConfFile) *
|
|||||||
frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(cryptfs.FlagPlaintextNames)
|
frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(cryptfs.FlagPlaintextNames)
|
||||||
frontendArgs.DirIV = confFile.IsFeatureFlagSet(cryptfs.FlagDirIV)
|
frontendArgs.DirIV = confFile.IsFeatureFlagSet(cryptfs.FlagDirIV)
|
||||||
frontendArgs.EMENames = confFile.IsFeatureFlagSet(cryptfs.FlagEMENames)
|
frontendArgs.EMENames = confFile.IsFeatureFlagSet(cryptfs.FlagEMENames)
|
||||||
|
frontendArgs.GCMIV128 = confFile.IsFeatureFlagSet(cryptfs.FlagGCMIV128)
|
||||||
}
|
}
|
||||||
// EMENames implies DirIV, both on the command line and in the config file.
|
// EMENames implies DirIV, both on the command line and in the config file.
|
||||||
if frontendArgs.EMENames {
|
if frontendArgs.EMENames {
|
||||||
|
@ -8,4 +8,5 @@ type Args struct {
|
|||||||
PlaintextNames bool
|
PlaintextNames bool
|
||||||
DirIV bool
|
DirIV bool
|
||||||
EMENames bool
|
EMENames bool
|
||||||
|
GCMIV128 bool
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
|
|||||||
blockOffset, blockLen := b.CiphertextRange()
|
blockOffset, blockLen := b.CiphertextRange()
|
||||||
blockData = f.cfs.EncryptBlock(blockData, b.BlockNo, f.header.Id)
|
blockData = f.cfs.EncryptBlock(blockData, b.BlockNo, f.header.Id)
|
||||||
cryptfs.Debug.Printf("ino%d: Writing %d bytes to block #%d, md5=%s\n",
|
cryptfs.Debug.Printf("ino%d: Writing %d bytes to block #%d, md5=%s\n",
|
||||||
f.ino, len(blockData)-cryptfs.BLOCK_OVERHEAD, b.BlockNo, cryptfs.Debug.Md5sum(blockData))
|
f.ino, uint64(len(blockData))-f.cfs.BlockOverhead(), b.BlockNo, cryptfs.Debug.Md5sum(blockData))
|
||||||
|
|
||||||
// Prevent partially written (=corrupt) blocks by preallocating the space beforehand
|
// Prevent partially written (=corrupt) blocks by preallocating the space beforehand
|
||||||
f.fdLock.Lock()
|
f.fdLock.Lock()
|
||||||
|
@ -29,7 +29,7 @@ type FS struct {
|
|||||||
// Encrypted FUSE overlay filesystem
|
// Encrypted FUSE overlay filesystem
|
||||||
func NewFS(args Args) *FS {
|
func NewFS(args Args) *FS {
|
||||||
return &FS{
|
return &FS{
|
||||||
CryptFS: cryptfs.NewCryptFS(args.Masterkey, args.OpenSSL, args.PlaintextNames),
|
CryptFS: cryptfs.NewCryptFS(args.Masterkey, args.OpenSSL, args.PlaintextNames, args.GCMIV128),
|
||||||
FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),
|
FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),
|
||||||
args: args,
|
args: args,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user