aboutsummaryrefslogtreecommitdiff
path: root/cryptfs
diff options
context:
space:
mode:
authorJakob Unterwurzacher2016-02-06 19:20:54 +0100
committerJakob Unterwurzacher2016-02-06 19:22:35 +0100
commit2b8cbd944149afe51fadddbd67ee4499d1d86250 (patch)
tree76361984cc4394bbb9b19ae987aeaff71fb6073b /cryptfs
parentadcfbd79a8b8bb85cbee25996ab622a05de0dbc1 (diff)
Major refactoring: Split up "cryptfs" into several internal packages
"git status" for reference: deleted: cryptfs/cryptfs.go deleted: cryptfs/names_core.go modified: integration_tests/cli_test.go modified: integration_tests/helpers.go renamed: cryptfs/config_file.go -> internal/configfile/config_file.go renamed: cryptfs/config_test.go -> internal/configfile/config_test.go renamed: cryptfs/config_test/.gitignore -> internal/configfile/config_test/.gitignore renamed: cryptfs/config_test/PlaintextNames.conf -> internal/configfile/config_test/PlaintextNames.conf renamed: cryptfs/config_test/StrangeFeature.conf -> internal/configfile/config_test/StrangeFeature.conf renamed: cryptfs/config_test/v1.conf -> internal/configfile/config_test/v1.conf renamed: cryptfs/config_test/v2.conf -> internal/configfile/config_test/v2.conf renamed: cryptfs/kdf.go -> internal/configfile/kdf.go renamed: cryptfs/kdf_test.go -> internal/configfile/kdf_test.go renamed: cryptfs/cryptfs_content.go -> internal/contentenc/content.go new file: internal/contentenc/content_api.go renamed: cryptfs/content_test.go -> internal/contentenc/content_test.go renamed: cryptfs/file_header.go -> internal/contentenc/file_header.go renamed: cryptfs/intrablock.go -> internal/contentenc/intrablock.go renamed: cryptfs/address_translation.go -> internal/contentenc/offsets.go new file: internal/cryptocore/crypto_api.go renamed: cryptfs/gcm_go1.4.go -> internal/cryptocore/gcm_go1.4.go renamed: cryptfs/gcm_go1.5.go -> internal/cryptocore/gcm_go1.5.go renamed: cryptfs/nonce.go -> internal/cryptocore/nonce.go renamed: cryptfs/openssl_aead.go -> internal/cryptocore/openssl_aead.go renamed: cryptfs/openssl_benchmark.bash -> internal/cryptocore/openssl_benchmark.bash renamed: cryptfs/openssl_test.go -> internal/cryptocore/openssl_test.go new file: internal/nametransform/name_api.go new file: internal/nametransform/names_core.go renamed: cryptfs/names_diriv.go -> internal/nametransform/names_diriv.go renamed: cryptfs/names_noiv.go -> internal/nametransform/names_noiv.go renamed: cryptfs/names_test.go -> internal/nametransform/names_test.go new file: internal/nametransform/pad16.go renamed: cryptfs/log.go -> internal/toggledlog/log.go renamed: cryptfs/log_go1.4.go -> internal/toggledlog/log_go1.4.go renamed: cryptfs/log_go1.5.go -> internal/toggledlog/log_go1.5.go modified: main.go modified: masterkey.go modified: pathfs_frontend/file.go modified: pathfs_frontend/file_holes.go modified: pathfs_frontend/fs.go modified: pathfs_frontend/fs_dir.go modified: pathfs_frontend/names.go modified: test.bash
Diffstat (limited to 'cryptfs')
-rw-r--r--cryptfs/address_translation.go89
-rw-r--r--cryptfs/config_file.go188
-rw-r--r--cryptfs/config_test.go83
-rw-r--r--cryptfs/config_test/.gitignore1
-rw-r--r--cryptfs/config_test/PlaintextNames.conf14
-rw-r--r--cryptfs/config_test/StrangeFeature.conf14
-rw-r--r--cryptfs/config_test/v1.conf11
-rw-r--r--cryptfs/config_test/v2.conf11
-rw-r--r--cryptfs/content_test.go91
-rw-r--r--cryptfs/cryptfs.go83
-rw-r--r--cryptfs/cryptfs_content.go129
-rw-r--r--cryptfs/file_header.go56
-rw-r--r--cryptfs/gcm_go1.4.go22
-rw-r--r--cryptfs/gcm_go1.5.go16
-rw-r--r--cryptfs/intrablock.go51
-rw-r--r--cryptfs/kdf.go54
-rw-r--r--cryptfs/kdf_test.go60
-rw-r--r--cryptfs/log.go61
-rw-r--r--cryptfs/log_go1.4.go12
-rw-r--r--cryptfs/log_go1.5.go17
-rw-r--r--cryptfs/names_core.go134
-rw-r--r--cryptfs/names_diriv.go140
-rw-r--r--cryptfs/names_noiv.go63
-rw-r--r--cryptfs/names_test.go58
-rw-r--r--cryptfs/nonce.go42
-rw-r--r--cryptfs/openssl_aead.go100
-rwxr-xr-xcryptfs/openssl_benchmark.bash3
-rw-r--r--cryptfs/openssl_test.go75
28 files changed, 0 insertions, 1678 deletions
diff --git a/cryptfs/address_translation.go b/cryptfs/address_translation.go
deleted file mode 100644
index b21cfc7..0000000
--- a/cryptfs/address_translation.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package cryptfs
-
-// CryptFS methods that translate offsets between ciphertext and plaintext
-
-// get the block number at plain-text offset
-func (be *CryptFS) PlainOffToBlockNo(plainOffset uint64) uint64 {
- return plainOffset / be.plainBS
-}
-
-// get the block number at ciphter-text offset
-func (be *CryptFS) CipherOffToBlockNo(cipherOffset uint64) uint64 {
- return (cipherOffset - HEADER_LEN) / be.cipherBS
-}
-
-// get ciphertext offset of block "blockNo"
-func (be *CryptFS) BlockNoToCipherOff(blockNo uint64) uint64 {
- return HEADER_LEN + blockNo*be.cipherBS
-}
-
-// get plaintext offset of block "blockNo"
-func (be *CryptFS) BlockNoToPlainOff(blockNo uint64) uint64 {
- return blockNo * be.plainBS
-}
-
-// PlainSize - calculate plaintext size from ciphertext size
-func (be *CryptFS) CipherSizeToPlainSize(cipherSize uint64) uint64 {
-
- // Zero sized files stay zero-sized
- if cipherSize == 0 {
- return 0
- }
-
- if cipherSize == HEADER_LEN {
- Warn.Printf("cipherSize %d == header size: interrupted write?\n", cipherSize)
- return 0
- }
-
- if cipherSize < HEADER_LEN {
- Warn.Printf("cipherSize %d < header size: corrupt file\n", cipherSize)
- return 0
- }
-
- // Block number at last byte
- blockNo := be.CipherOffToBlockNo(cipherSize - 1)
- blockCount := blockNo + 1
-
- overhead := be.BlockOverhead()*blockCount + HEADER_LEN
-
- return cipherSize - overhead
-}
-
-// CipherSize - calculate ciphertext size from plaintext size
-func (be *CryptFS) PlainSizeToCipherSize(plainSize uint64) uint64 {
-
- // Block number at last byte
- blockNo := be.PlainOffToBlockNo(plainSize - 1)
- blockCount := blockNo + 1
-
- overhead := be.BlockOverhead()*blockCount + HEADER_LEN
-
- return plainSize + overhead
-}
-
-// Split a plaintext byte range into (possibly partial) blocks
-func (be *CryptFS) ExplodePlainRange(offset uint64, length uint64) []intraBlock {
- var blocks []intraBlock
- var nextBlock intraBlock
- nextBlock.fs = be
-
- for length > 0 {
- nextBlock.BlockNo = be.PlainOffToBlockNo(offset)
- nextBlock.Skip = offset - be.BlockNoToPlainOff(nextBlock.BlockNo)
-
- // Minimum of remaining data and remaining space in the block
- nextBlock.Length = MinUint64(length, be.plainBS-nextBlock.Skip)
-
- blocks = append(blocks, nextBlock)
- offset += nextBlock.Length
- length -= nextBlock.Length
- }
- return blocks
-}
-
-func MinUint64(x uint64, y uint64) uint64 {
- if x < y {
- return x
- }
- return y
-}
diff --git a/cryptfs/config_file.go b/cryptfs/config_file.go
deleted file mode 100644
index 013b82d..0000000
--- a/cryptfs/config_file.go
+++ /dev/null
@@ -1,188 +0,0 @@
-package cryptfs
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "log"
-)
-import "os"
-
-const (
- // The dot "." is not used in base64url (RFC4648), hence
- // we can never clash with an encrypted file.
- ConfDefaultName = "gocryptfs.conf"
-)
-
-type ConfFile struct {
- // File the config is saved to. Not exported to JSON.
- filename string
- // Encrypted AES key, unlocked using a password hashed with scrypt
- EncryptedKey []byte
- // Stores parameters for scrypt hashing (key derivation)
- ScryptObject scryptKdf
- // The On-Disk-Format version this filesystem uses
- Version uint16
- // List of feature flags this filesystem has enabled.
- // If gocryptfs encounters a feature flag it does not support, it will refuse
- // mounting. This mechanism is analogous to the ext4 feature flags that are
- // stored in the superblock.
- FeatureFlags []string
-}
-
-// CreateConfFile - create a new config with a random key encrypted with
-// "password" and write it to "filename".
-// Uses scrypt with cost parameter logN.
-func CreateConfFile(filename string, password string, plaintextNames bool, logN int) error {
- var cf ConfFile
- cf.filename = filename
- cf.Version = HEADER_CURRENT_VERSION
-
- // Generate new random master key
- key := RandBytes(KEY_LEN)
-
- // Encrypt it using the password
- // This sets ScryptObject and EncryptedKey
- cf.EncryptKey(key, password, logN)
-
- // Set feature flags
- cf.FeatureFlags = append(cf.FeatureFlags, FlagGCMIV128)
- if plaintextNames {
- cf.FeatureFlags = append(cf.FeatureFlags, FlagPlaintextNames)
- } else {
- cf.FeatureFlags = append(cf.FeatureFlags, FlagDirIV)
- cf.FeatureFlags = append(cf.FeatureFlags, FlagEMENames)
- }
-
- // Write file to disk
- return cf.WriteFile()
-}
-
-// LoadConfFile - read config file from disk and decrypt the
-// contained key using password.
-//
-// Returns the decrypted key and the ConfFile object
-func LoadConfFile(filename string, password string) ([]byte, *ConfFile, error) {
- var cf ConfFile
- cf.filename = filename
-
- // Read from disk
- js, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, nil, err
- }
-
- // Unmarshal
- err = json.Unmarshal(js, &cf)
- if err != nil {
- Warn.Printf("Failed to unmarshal config file")
- return nil, nil, err
- }
-
- if cf.Version != HEADER_CURRENT_VERSION {
- return nil, nil, fmt.Errorf("Unsupported on-disk format %d", cf.Version)
- }
-
- for _, flag := range cf.FeatureFlags {
- if cf.isFeatureFlagKnown(flag) == false {
- return nil, nil, fmt.Errorf("Unsupported feature flag %s", flag)
- }
- }
-
- // Generate derived key from password
- scryptHash := cf.ScryptObject.DeriveKey(password)
-
- // Unlock master key using password-based key
- // We use stock go GCM instead of OpenSSL here as speed is not important
- // and we get better error messages
- cfs := NewCryptFS(scryptHash, false, false, false)
- key, err := cfs.DecryptBlock(cf.EncryptedKey, 0, nil)
- if err != nil {
- Warn.Printf("failed to unlock master key: %s", err.Error())
- Warn.Printf("Password incorrect.")
- return nil, nil, err
- }
-
- return key, &cf, nil
-}
-
-// EncryptKey - encrypt "key" using an scrypt hash generated from "password"
-// and store it in cf.EncryptedKey.
-// Uses scrypt with cost parameter logN and stores the scrypt parameters in
-// cf.ScryptObject.
-func (cf *ConfFile) EncryptKey(key []byte, password string, logN int) {
- // Generate derived key from password
- cf.ScryptObject = NewScryptKdf(logN)
- scryptHash := cf.ScryptObject.DeriveKey(password)
-
- // Lock master key using password-based key
- cfs := NewCryptFS(scryptHash, false, false, false)
- cf.EncryptedKey = cfs.EncryptBlock(key, 0, nil)
-}
-
-// WriteFile - write out config in JSON format to file "filename.tmp"
-// then rename over "filename".
-// This way a password change atomically replaces the file.
-func (cf *ConfFile) WriteFile() error {
- tmp := cf.filename + ".tmp"
- // 0400 permissions: gocryptfs.conf should be kept secret and never be written to.
- fd, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0400)
- if err != nil {
- return err
- }
- js, err := json.MarshalIndent(cf, "", "\t")
- if err != nil {
- return err
- }
- _, err = fd.Write(js)
- if err != nil {
- return err
- }
- err = fd.Sync()
- if err != nil {
- return err
- }
- err = fd.Close()
- if err != nil {
- return err
- }
- err = os.Rename(tmp, cf.filename)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-const (
- // Understood Feature Flags.
- // Also teach isFeatureFlagKnown() about any additions and
- // add it to CreateConfFile() if you want to have it enabled by default.
- FlagPlaintextNames = "PlaintextNames"
- FlagDirIV = "DirIV"
- FlagEMENames = "EMENames"
- FlagGCMIV128 = "GCMIV128"
-)
-
-// Verify that we understand a feature flag
-func (cf *ConfFile) isFeatureFlagKnown(flag string) bool {
- switch flag {
- case FlagPlaintextNames, FlagDirIV, FlagEMENames, FlagGCMIV128:
- return true
- default:
- return false
- }
-}
-
-// isFeatureFlagSet - is the feature flag "flagWant" enabled?
-func (cf *ConfFile) IsFeatureFlagSet(flagWant string) bool {
- if !cf.isFeatureFlagKnown(flagWant) {
- log.Panicf("BUG: Tried to use unsupported feature flag %s", flagWant)
- }
- for _, flag := range cf.FeatureFlags {
- if flag == flagWant {
- return true
- }
- }
- return false
-}
diff --git a/cryptfs/config_test.go b/cryptfs/config_test.go
deleted file mode 100644
index 11599c0..0000000
--- a/cryptfs/config_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package cryptfs
-
-import (
- "fmt"
- "testing"
- "time"
-)
-
-func TestLoadV1(t *testing.T) {
- _, _, err := LoadConfFile("config_test/v1.conf", "test")
- if err == nil {
- t.Errorf("Outdated v1 config file must fail to load but it didn't")
- } else if testing.Verbose() {
- fmt.Print(err)
- }
-}
-
-// Load a known-good config file and verify that it takes at least 100ms
-// (brute-force protection)
-func TestLoadV2(t *testing.T) {
- t1 := time.Now()
-
- _, _, err := LoadConfFile("config_test/v2.conf", "foo")
- if err != nil {
- t.Errorf("Could not load v2 config file: %v", err)
- }
-
- elapsed := time.Since(t1)
- if elapsed < 100*time.Millisecond {
- t.Errorf("scrypt calculation runs too fast: %d ms", elapsed/time.Millisecond)
- }
-}
-
-func TestLoadV2PwdError(t *testing.T) {
- if !testing.Verbose() {
- Warn.Enabled = false
- }
- _, _, err := LoadConfFile("config_test/v2.conf", "wrongpassword")
- if err == nil {
- t.Errorf("Loading with wrong password must fail but it didn't")
- }
-}
-
-func TestLoadV2Feature(t *testing.T) {
- _, _, err := LoadConfFile("config_test/PlaintextNames.conf", "test")
- if err != nil {
- t.Errorf("Could not load v2 PlaintextNames config file: %v", err)
- }
-}
-
-func TestLoadV2StrangeFeature(t *testing.T) {
- _, _, err := LoadConfFile("config_test/StrangeFeature.conf", "test")
- if err == nil {
- t.Errorf("Loading unknown feature must fail but it didn't")
- } else if testing.Verbose() {
- fmt.Print(err)
- }
-}
-
-func TestCreateConfFile(t *testing.T) {
- err := CreateConfFile("config_test/tmp.conf", "test", false, 10)
- if err != nil {
- t.Fatal(err)
- }
- _, _, err = LoadConfFile("config_test/tmp.conf", "test")
- if err != nil {
- t.Fatal(err)
- }
-
-}
-
-func TestIsFeatureFlagKnown(t *testing.T) {
- var cf ConfFile
- if !cf.isFeatureFlagKnown(FlagDirIV) {
- t.Errorf("This flag should be known")
- }
- if !cf.isFeatureFlagKnown(FlagPlaintextNames) {
- t.Errorf("This flag should be known")
- }
- if cf.isFeatureFlagKnown("StrangeFeatureFlag") {
- t.Errorf("This flag should be NOT known")
- }
-}
diff --git a/cryptfs/config_test/.gitignore b/cryptfs/config_test/.gitignore
deleted file mode 100644
index 0720169..0000000
--- a/cryptfs/config_test/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-tmp.conf
diff --git a/cryptfs/config_test/PlaintextNames.conf b/cryptfs/config_test/PlaintextNames.conf
deleted file mode 100644
index c1ff8cc..0000000
--- a/cryptfs/config_test/PlaintextNames.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "EncryptedKey": "rG4u0argMq02V5G9Fa+gAaaHtNrj3wn7OZjP44hWOzO4yBFtn+Qn3PW4V6LMuKmGLEhyktCyWOI3K8lj",
- "ScryptObject": {
- "Salt": "bRjq1V63u5ML3FoTWx/GBXUhUVpTunOX3DPxS+yPjg0=",
- "N": 65536,
- "R": 8,
- "P": 1,
- "KeyLen": 32
- },
- "Version": 2,
- "FeatureFlags": [
- "PlaintextNames"
- ]
-}
diff --git a/cryptfs/config_test/StrangeFeature.conf b/cryptfs/config_test/StrangeFeature.conf
deleted file mode 100644
index 6a97781..0000000
--- a/cryptfs/config_test/StrangeFeature.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "EncryptedKey": "rG4u0argMq02V5G9Fa+gAaaHtNrj3wn7OZjP44hWOzO4yBFtn+Qn3PW4V6LMuKmGLEhyktCyWOI3K8lj",
- "ScryptObject": {
- "Salt": "bRjq1V63u5ML3FoTWx/GBXUhUVpTunOX3DPxS+yPjg0=",
- "N": 65536,
- "R": 8,
- "P": 1,
- "KeyLen": 32
- },
- "Version": 2,
- "FeatureFlags": [
- "StrangeFeatureFlag"
- ]
-}
diff --git a/cryptfs/config_test/v1.conf b/cryptfs/config_test/v1.conf
deleted file mode 100644
index 588a25a..0000000
--- a/cryptfs/config_test/v1.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "EncryptedKey": "t6YAvFQJvbv46c93bHQ5IZnvNz80DA9cohGoSPL/2M257LuIigow6jbr8b9HhnbDqHTCcz7aKkMDzneF",
- "ScryptObject": {
- "Salt": "yT4yQmmRmVNx2P0tJrUswk5SQzZaL6Z8kUteAoNJkXM=",
- "N": 65536,
- "R": 8,
- "P": 1,
- "KeyLen": 32
- },
- "Version": 1
-}
diff --git a/cryptfs/config_test/v2.conf b/cryptfs/config_test/v2.conf
deleted file mode 100644
index 8ef3dcf..0000000
--- a/cryptfs/config_test/v2.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "EncryptedKey": "RvxJnZWKTBSU21+7xbl08xlZyNyUCkpIqlK8Z51TUrRiBhqqNPxbdk1WXMvmOf/YzZ85Xbyz+DGM+SDf",
- "ScryptObject": {
- "Salt": "2OrFRfdW/5SanbMXM3TMINmfMO6oYU9awG+NZ77V8E8=",
- "N": 65536,
- "R": 8,
- "P": 1,
- "KeyLen": 32
- },
- "Version": 2
-}
diff --git a/cryptfs/content_test.go b/cryptfs/content_test.go
deleted file mode 100644
index 3efa959..0000000
--- a/cryptfs/content_test.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package cryptfs
-
-import (
- "testing"
-)
-
-type testRange struct {
- offset uint64
- length uint64
-}
-
-func TestSplitRange(t *testing.T) {
- var ranges []testRange
-
- ranges = append(ranges, testRange{0, 70000},
- testRange{0, 10},
- testRange{234, 6511},
- testRange{65444, 54},
- testRange{0, 1024 * 1024},
- testRange{0, 65536},
- testRange{6654, 8945})
-
- key := make([]byte, KEY_LEN)
- f := NewCryptFS(key, true, false, true)
-
- for _, r := range ranges {
- parts := f.ExplodePlainRange(r.offset, r.length)
- var lastBlockNo uint64 = 1 << 63
- for _, p := range parts {
- if p.BlockNo == lastBlockNo {
- t.Errorf("Duplicate block number %d", p.BlockNo)
- }
- lastBlockNo = p.BlockNo
- if p.Length > DEFAULT_PLAINBS || p.Skip >= DEFAULT_PLAINBS {
- t.Errorf("Test fail: n=%d, length=%d, offset=%d\n", p.BlockNo, p.Length, p.Skip)
- }
- }
- }
-}
-
-func TestCiphertextRange(t *testing.T) {
- var ranges []testRange
-
- ranges = append(ranges, testRange{0, 70000},
- testRange{0, 10},
- testRange{234, 6511},
- testRange{65444, 54},
- testRange{6654, 8945})
-
- key := make([]byte, KEY_LEN)
- f := NewCryptFS(key, true, false, true)
-
- for _, r := range ranges {
-
- blocks := f.ExplodePlainRange(r.offset, r.length)
- alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks)
- skipBytes := blocks[0].Skip
-
- if alignedLength < r.length {
- t.Errorf("alignedLength=%d is smaller than length=%d", alignedLength, r.length)
- }
- if (alignedOffset-HEADER_LEN)%f.cipherBS != 0 {
- t.Errorf("alignedOffset=%d is not aligned", alignedOffset)
- }
- if r.offset%f.plainBS != 0 && skipBytes == 0 {
- t.Errorf("skipBytes=0")
- }
- }
-}
-
-func TestBlockNo(t *testing.T) {
- key := make([]byte, KEY_LEN)
- f := NewCryptFS(key, true, false, true)
-
- b := f.CipherOffToBlockNo(788)
- if b != 0 {
- t.Errorf("actual: %d", b)
- }
- b = f.CipherOffToBlockNo(HEADER_LEN + f.cipherBS)
- if b != 1 {
- t.Errorf("actual: %d", b)
- }
- b = f.PlainOffToBlockNo(788)
- if b != 0 {
- t.Errorf("actual: %d", b)
- }
- b = f.PlainOffToBlockNo(f.plainBS)
- if b != 1 {
- t.Errorf("actual: %d", b)
- }
-}
diff --git a/cryptfs/cryptfs.go b/cryptfs/cryptfs.go
deleted file mode 100644
index 3a40e29..0000000
--- a/cryptfs/cryptfs.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package cryptfs
-
-// CryptFS is the crypto backend of GoCryptFS
-
-import (
- "crypto/aes"
- "crypto/cipher"
- "fmt"
-)
-
-const (
- PROGRAM_NAME = "gocryptfs"
-
- DEFAULT_PLAINBS = 4096
- KEY_LEN = 32 // AES-256
- AUTH_TAG_LEN = 16
- DIRIV_LEN = 16 // identical to AES block size
- DIRIV_FILENAME = "gocryptfs.diriv"
-)
-
-type CryptFS struct {
- blockCipher cipher.Block
- gcm cipher.AEAD
- gcmIVLen int
- gcmIVGen nonceGenerator
- plainBS uint64
- cipherBS uint64
- // Stores an all-zero block of size cipherBS
- allZeroBlock []byte
- // DirIV cache for filename encryption
- DirIVCache dirIVCache
-}
-
-func NewCryptFS(key []byte, useOpenssl bool, plaintextNames bool, GCMIV128 bool) *CryptFS {
-
- if len(key) != KEY_LEN {
- panic(fmt.Sprintf("Unsupported key length %d", len(key)))
- }
-
- b, err := aes.NewCipher(key)
- if err != nil {
- panic(err)
- }
-
- // We want the IV size in bytes
- gcmIV := 96 / 8
- if GCMIV128 {
- gcmIV = 128 / 8
- }
-
- var gcm cipher.AEAD
- if useOpenssl {
- gcm = opensslGCM{key}
- } else {
- gcm, err = goGCMWrapper(b, gcmIV)
- if err != nil {
- panic(err)
- }
- }
-
- plainBS := DEFAULT_PLAINBS
- cipherBS := plainBS + gcmIV + AUTH_TAG_LEN
-
- return &CryptFS{
- blockCipher: b,
- gcm: gcm,
- gcmIVLen: gcmIV,
- gcmIVGen: nonceGenerator{nonceLen: gcmIV},
- plainBS: uint64(plainBS),
- cipherBS: uint64(cipherBS),
- allZeroBlock: make([]byte, cipherBS),
- }
-}
-
-// Get plaintext block size
-func (be *CryptFS) PlainBS() uint64 {
- return be.plainBS
-}
-
-// Per-block storage overhead
-func (be *CryptFS) BlockOverhead() uint64 {
- return be.cipherBS - be.plainBS
-}
diff --git a/cryptfs/cryptfs_content.go b/cryptfs/cryptfs_content.go
deleted file mode 100644
index 2036e58..0000000
--- a/cryptfs/cryptfs_content.go
+++ /dev/null
@@ -1,129 +0,0 @@
-package cryptfs
-
-// File content encryption / decryption
-
-import (
- "bytes"
- "crypto/cipher"
- "crypto/md5"
- "encoding/binary"
- "encoding/hex"
- "errors"
- "os"
-)
-
-// md5sum - debug helper, return md5 hex string
-func md5sum(buf []byte) string {
- rawHash := md5.Sum(buf)
- hash := hex.EncodeToString(rawHash[:])
- return hash
-}
-
-type CryptFile struct {
- file *os.File
- gcm cipher.AEAD
-}
-
-// DecryptBlocks - Decrypt a number of blocks
-func (be *CryptFS) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, fileId []byte) ([]byte, error) {
- cBuf := bytes.NewBuffer(ciphertext)
- var err error
- var pBuf bytes.Buffer
- for cBuf.Len() > 0 {
- cBlock := cBuf.Next(int(be.cipherBS))
- var pBlock []byte
- pBlock, err = be.DecryptBlock(cBlock, firstBlockNo, fileId)
- if err != nil {
- break
- }
- pBuf.Write(pBlock)
- firstBlockNo++
- }
- return pBuf.Bytes(), err
-}
-
-// DecryptBlock - Verify and decrypt GCM block
-//
-// Corner case: A full-sized block of all-zero ciphertext bytes is translated
-// to an all-zero plaintext block, i.e. file hole passtrough.
-func (be *CryptFS) DecryptBlock(ciphertext []byte, blockNo uint64, fileId []byte) ([]byte, error) {
-
- // Empty block?
- if len(ciphertext) == 0 {
- return ciphertext, nil
- }
-
- // All-zero block?
- if bytes.Equal(ciphertext, be.allZeroBlock) {
- Debug.Printf("DecryptBlock: file hole encountered")
- return make([]byte, be.plainBS), nil
- }
-
- if len(ciphertext) < be.gcmIVLen {
- Warn.Printf("DecryptBlock: Block is too short: %d bytes", len(ciphertext))
- return nil, errors.New("Block is too short")
- }
-
- // Extract nonce
- nonce := ciphertext[:be.gcmIVLen]
- ciphertextOrig := ciphertext
- ciphertext = ciphertext[be.gcmIVLen:]
-
- // Decrypt
- var plaintext []byte
- aData := make([]byte, 8)
- aData = append(aData, fileId...)
- binary.BigEndian.PutUint64(aData, blockNo)
- plaintext, err := be.gcm.Open(plaintext, nonce, ciphertext, aData)
-
- if err != nil {
- Warn.Printf("DecryptBlock: %s, len=%d, md5=%s", err.Error(), len(ciphertextOrig), md5sum(ciphertextOrig))
- Debug.Println(hex.Dump(ciphertextOrig))
- return nil, err
- }
-
- return plaintext, nil
-}
-
-// encryptBlock - Encrypt and add IV and MAC
-func (be *CryptFS) EncryptBlock(plaintext []byte, blockNo uint64, fileID []byte) []byte {
-
- // Empty block?
- if len(plaintext) == 0 {
- return plaintext
- }
-
- // Get fresh nonce
- nonce := be.gcmIVGen.Get()
-
- // Authenticate block with block number and file ID
- aData := make([]byte, 8)
- binary.BigEndian.PutUint64(aData, blockNo)
- aData = append(aData, fileID...)
-
- // Encrypt plaintext and append to nonce
- ciphertext := be.gcm.Seal(nonce, nonce, plaintext, aData)
-
- return ciphertext
-}
-
-// MergeBlocks - Merge newData into oldData at offset
-// New block may be bigger than both newData and oldData
-func (be *CryptFS) MergeBlocks(oldData []byte, newData []byte, offset int) []byte {
-
- // Make block of maximum size
- out := make([]byte, be.plainBS)
-
- // Copy old and new data into it
- copy(out, oldData)
- l := len(newData)
- copy(out[offset:offset+l], newData)
-
- // Crop to length
- outLen := len(oldData)
- newLen := offset + len(newData)
- if outLen < newLen {
- outLen = newLen
- }
- return out[0:outLen]
-}
diff --git a/cryptfs/file_header.go b/cryptfs/file_header.go
deleted file mode 100644
index fe4ac56..0000000
--- a/cryptfs/file_header.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package cryptfs
-
-// Per-file header
-//
-// Format: [ "Version" uint16 big endian ] [ "Id" 16 random bytes ]
-
-import (
- "encoding/binary"
- "fmt"
-)
-
-const (
- HEADER_CURRENT_VERSION = 2 // Current on-disk-format version
- HEADER_VERSION_LEN = 2 // uint16
- HEADER_ID_LEN = 16 // 128 bit random file id
- HEADER_LEN = HEADER_VERSION_LEN + HEADER_ID_LEN // Total header length
-)
-
-type FileHeader struct {
- Version uint16
- Id []byte
-}
-
-// Pack - serialize fileHeader object
-func (h *FileHeader) Pack() []byte {
- if len(h.Id) != HEADER_ID_LEN || h.Version != HEADER_CURRENT_VERSION {
- panic("FileHeader object not properly initialized")
- }
- buf := make([]byte, HEADER_LEN)
- binary.BigEndian.PutUint16(buf[0:HEADER_VERSION_LEN], h.Version)
- copy(buf[HEADER_VERSION_LEN:], h.Id)
- return buf
-
-}
-
-// ParseHeader - parse "buf" into fileHeader object
-func ParseHeader(buf []byte) (*FileHeader, error) {
- if len(buf) != HEADER_LEN {
- return nil, fmt.Errorf("ParseHeader: invalid length: got %d, want %d", len(buf), HEADER_LEN)
- }
- var h FileHeader
- h.Version = binary.BigEndian.Uint16(buf[0:HEADER_VERSION_LEN])
- if h.Version != HEADER_CURRENT_VERSION {
- return nil, fmt.Errorf("ParseHeader: invalid version: got %d, want %d", h.Version, HEADER_CURRENT_VERSION)
- }
- h.Id = buf[HEADER_VERSION_LEN:]
- return &h, nil
-}
-
-// RandomHeader - create new fileHeader object with random Id
-func RandomHeader() *FileHeader {
- var h FileHeader
- h.Version = HEADER_CURRENT_VERSION
- h.Id = RandBytes(HEADER_ID_LEN)
- return &h
-}
diff --git a/cryptfs/gcm_go1.4.go b/cryptfs/gcm_go1.4.go
deleted file mode 100644
index 0a2ff49..0000000
--- a/cryptfs/gcm_go1.4.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// +build !go1.5
-// = go 1.4 or lower
-
-package cryptfs
-
-import (
- "crypto/cipher"
- "fmt"
-)
-
-// goGCMWrapper - This wrapper makes sure gocryptfs can be compiled on Go
-// versions 1.4 and lower that lack NewGCMWithNonceSize().
-// 128 bit GCM IVs will not work when using built-in Go crypto, obviously, when
-// compiled on 1.4.
-func goGCMWrapper(bc cipher.Block, nonceSize int) (cipher.AEAD, error) {
- if nonceSize != 12 {
- Warn.Printf("128 bit GCM IVs are not supported by Go 1.4 and lower.")
- Warn.Printf("Please use openssl crypto or recompile using a newer Go runtime.")
- return nil, fmt.Errorf("128 bit GCM IVs are not supported by Go 1.4 and lower")
- }
- return cipher.NewGCM(bc)
-}
diff --git a/cryptfs/gcm_go1.5.go b/cryptfs/gcm_go1.5.go
deleted file mode 100644
index c469357..0000000
--- a/cryptfs/gcm_go1.5.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// +build go1.5
-// = go 1.5 or higher
-
-package cryptfs
-
-import (
- "crypto/cipher"
-)
-
-// goGCMWrapper - This wrapper makes sure gocryptfs can be compiled on Go
-// versions 1.4 and lower that lack NewGCMWithNonceSize().
-// 128 bit GCM IVs will not work when using built-in Go crypto, obviously, when
-// compiled on 1.4.
-func goGCMWrapper(bc cipher.Block, nonceSize int) (cipher.AEAD, error) {
- return cipher.NewGCMWithNonceSize(bc, nonceSize)
-}
diff --git a/cryptfs/intrablock.go b/cryptfs/intrablock.go
deleted file mode 100644
index faff471..0000000
--- a/cryptfs/intrablock.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package cryptfs
-
-// intraBlock identifies a part of a file block
-type intraBlock struct {
- BlockNo uint64 // Block number in file
- Skip uint64 // Offset into block plaintext
- Length uint64 // Length of data from this block
- fs *CryptFS
-}
-
-// isPartial - is the block partial? This means we have to do read-modify-write.
-func (ib *intraBlock) IsPartial() bool {
- if ib.Skip > 0 || ib.Length < ib.fs.plainBS {
- return true
- }
- return false
-}
-
-// CiphertextRange - get byte range in ciphertext file corresponding to BlockNo
-// (complete block)
-func (ib *intraBlock) CiphertextRange() (offset uint64, length uint64) {
- return ib.fs.BlockNoToCipherOff(ib.BlockNo), ib.fs.cipherBS
-}
-
-// PlaintextRange - get byte range in plaintext corresponding to BlockNo
-// (complete block)
-func (ib *intraBlock) PlaintextRange() (offset uint64, length uint64) {
- return ib.fs.BlockNoToPlainOff(ib.BlockNo), ib.fs.plainBS
-}
-
-// CropBlock - crop a potentially larger plaintext block down to the relevant part
-func (ib *intraBlock) CropBlock(d []byte) []byte {
- lenHave := len(d)
- lenWant := int(ib.Skip + ib.Length)
- if lenHave < lenWant {
- return d[ib.Skip:lenHave]
- }
- return d[ib.Skip:lenWant]
-}
-
-// Ciphertext range corresponding to the sum of all "blocks" (complete blocks)
-func (ib *intraBlock) JointCiphertextRange(blocks []intraBlock) (offset uint64, length uint64) {
- firstBlock := blocks[0]
- lastBlock := blocks[len(blocks)-1]
-
- offset = ib.fs.BlockNoToCipherOff(firstBlock.BlockNo)
- offsetLast := ib.fs.BlockNoToCipherOff(lastBlock.BlockNo)
- length = offsetLast + ib.fs.cipherBS - offset
-
- return offset, length
-}
diff --git a/cryptfs/kdf.go b/cryptfs/kdf.go
deleted file mode 100644
index e958413..0000000
--- a/cryptfs/kdf.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package cryptfs
-
-import (
- "fmt"
- "golang.org/x/crypto/scrypt"
- "math"
- "os"
-)
-
-const (
- // 1 << 16 uses 64MB of memory,
- // takes 4 seconds on my Atom Z3735F netbook
- SCRYPT_DEFAULT_LOGN = 16
-)
-
-type scryptKdf struct {
- Salt []byte
- N int
- R int
- P int
- KeyLen int
-}
-
-func NewScryptKdf(logN int) scryptKdf {
- var s scryptKdf
- s.Salt = RandBytes(KEY_LEN)
- if logN <= 0 {
- s.N = 1 << SCRYPT_DEFAULT_LOGN
- } else {
- if logN < 10 {
- fmt.Println("Error: scryptn below 10 is too low to make sense. Aborting.")
- os.Exit(1)
- }
- s.N = 1 << uint32(logN)
- }
- s.R = 8 // Always 8
- s.P = 1 // Always 1
- s.KeyLen = KEY_LEN
- return s
-}
-
-func (s *scryptKdf) DeriveKey(pw string) []byte {
- k, err := scrypt.Key([]byte(pw), s.Salt, s.N, s.R, s.P, s.KeyLen)
- if err != nil {
- panic(fmt.Sprintf("DeriveKey failed: %s", err.Error()))
- }
- return k
-}
-
-// LogN - N is saved as 2^LogN, but LogN is much easier to work with.
-// This function gives you LogN = Log2(N).
-func (s *scryptKdf) LogN() int {
- return int(math.Log2(float64(s.N)) + 0.5)
-}
diff --git a/cryptfs/kdf_test.go b/cryptfs/kdf_test.go
deleted file mode 100644
index 4d909ea..0000000
--- a/cryptfs/kdf_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package cryptfs
-
-import (
- "testing"
-)
-
-/*
-Results on a 2.7GHz Pentium G630:
-
-gocryptfs/cryptfs$ go test -bench=.
-PASS
-BenchmarkScrypt10-2 300 6021435 ns/op ... 6ms
-BenchmarkScrypt11-2 100 11861460 ns/op
-BenchmarkScrypt12-2 100 23420822 ns/op
-BenchmarkScrypt13-2 30 47666518 ns/op
-BenchmarkScrypt14-2 20 92561590 ns/op ... 92ms
-BenchmarkScrypt15-2 10 183971593 ns/op
-BenchmarkScrypt16-2 3 368506365 ns/op
-BenchmarkScrypt17-2 2 755502608 ns/op ... 755ms
-ok github.com/rfjakob/gocryptfs/cryptfs 18.772s
-*/
-
-func benchmarkScryptN(n int, b *testing.B) {
- kdf := NewScryptKdf(n)
- for i := 0; i < b.N; i++ {
- kdf.DeriveKey("test")
- }
-}
-
-func BenchmarkScrypt10(b *testing.B) {
- benchmarkScryptN(10, b)
-}
-
-func BenchmarkScrypt11(b *testing.B) {
- benchmarkScryptN(11, b)
-}
-
-func BenchmarkScrypt12(b *testing.B) {
- benchmarkScryptN(12, b)
-}
-
-func BenchmarkScrypt13(b *testing.B) {
- benchmarkScryptN(13, b)
-}
-
-func BenchmarkScrypt14(b *testing.B) {
- benchmarkScryptN(14, b)
-}
-
-func BenchmarkScrypt15(b *testing.B) {
- benchmarkScryptN(15, b)
-}
-
-func BenchmarkScrypt16(b *testing.B) {
- benchmarkScryptN(16, b)
-}
-
-func BenchmarkScrypt17(b *testing.B) {
- benchmarkScryptN(17, b)
-}
diff --git a/cryptfs/log.go b/cryptfs/log.go
deleted file mode 100644
index 19d8b51..0000000
--- a/cryptfs/log.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package cryptfs
-
-import (
- "encoding/json"
- "fmt"
- "log"
- "os"
-)
-
-func JSONDump(obj interface{}) string {
- b, err := json.MarshalIndent(obj, "", "\t")
- if err != nil {
- return err.Error()
- } else {
- return string(b)
- }
-}
-
-// toggledLogger - a Logger than can be enabled and disabled
-type toggledLogger struct {
- // Enable or disable output
- Enabled bool
- // Panic after logging a message, useful in regression tests
- PanicAfter bool
- *log.Logger
-}
-
-func (l *toggledLogger) Printf(format string, v ...interface{}) {
- if !l.Enabled {
- return
- }
- l.Logger.Printf(format, v...)
- if l.PanicAfter {
- panic("PanicAfter: " + fmt.Sprintf(format, v...))
- }
-}
-func (l *toggledLogger) Println(v ...interface{}) {
- if !l.Enabled {
- return
- }
- l.Logger.Println(v...)
- if l.PanicAfter {
- panic("PanicAfter: " + fmt.Sprintln(v...))
- }
-}
-
-// As defined by http://elinux.org/Debugging_by_printing#Log_Levels
-// Debug messages
-var Debug *toggledLogger
-
-// Informational message e.g. startup information
-var Info *toggledLogger
-
-// A warning, meaning nothing serious by itself but might indicate problems
-var Warn *toggledLogger
-
-func init() {
- Debug = &toggledLogger{false, false, log.New(os.Stdout, "", 0)}
- Info = &toggledLogger{true, false, log.New(os.Stdout, "", 0)}
- Warn = &toggledLogger{true, false, log.New(os.Stderr, "", 0)}
-}
diff --git a/cryptfs/log_go1.4.go b/cryptfs/log_go1.4.go
deleted file mode 100644
index 4b91bad..0000000
--- a/cryptfs/log_go1.4.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build !go1.5
-// = go 1.4 or lower
-
-package cryptfs
-
-import (
- "log/syslog"
-)
-
-func (l *toggledLogger) SwitchToSyslog(p syslog.Priority) {
- Debug.Printf("Cannot switch to syslog - need Go 1.5 or higher")
-}
diff --git a/cryptfs/log_go1.5.go b/cryptfs/log_go1.5.go
deleted file mode 100644
index 8daae9c..0000000
--- a/cryptfs/log_go1.5.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// +build go1.5
-// = go 1.5 or higher
-
-package cryptfs
-
-import (
- "log/syslog"
-)
-
-func (l *toggledLogger) SwitchToSyslog(p syslog.Priority) {
- w, err := syslog.New(p, PROGRAM_NAME)
- if err != nil {
- Warn.Printf("Cannot switch 0x%02x to syslog: %v", p, err)
- } else {
- l.SetOutput(w)
- }
-}
diff --git a/cryptfs/names_core.go b/cryptfs/names_core.go
deleted file mode 100644
index 0f2e5b3..0000000
--- a/cryptfs/names_core.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package cryptfs
-
-// Filename encryption / decryption functions
-
-import (
- "crypto/aes"
- "crypto/cipher"
- "encoding/base64"
- "errors"
- "fmt"
-
- "github.com/rfjakob/eme"
-)
-
-// DecryptName - decrypt base64-encoded encrypted filename "cipherName"
-// The used encryption is either CBC or EME, depending on the "EMENames" argument.
-//
-// This function is exported because it allows for a very efficient readdir
-// implementation (read IV once, decrypt all names using this function).
-func (be *CryptFS) DecryptName(cipherName string, iv []byte, EMENames bool) (string, error) {
- return be.decryptName(cipherName, iv, EMENames)
-}
-
-// decryptName - decrypt base64-encoded encrypted filename "cipherName".
-// The used encryption is either CBC or EME, depending on the "EMENames" argument.
-func (be *CryptFS) decryptName(cipherName string, iv []byte, EMENames bool) (string, error) {
-
- // Make sure relative symlinks still work after encryption
- // by passing these through unchanged
- if cipherName == "." || cipherName == ".." {
- return cipherName, nil
- }
-
- bin, err := base64.URLEncoding.DecodeString(cipherName)
- if err != nil {
- return "", err
- }
-
- if len(bin)%aes.BlockSize != 0 {
- return "", fmt.Errorf("Decoded length %d is not a multiple of the AES block size", len(bin))
- }
-
- if EMENames {
- bin = eme.Transform(be.blockCipher, iv, bin, eme.DirectionDecrypt)
- } else {
- cbc := cipher.NewCBCDecrypter(be.blockCipher, iv)
- cbc.CryptBlocks(bin, bin)
- }
-
- bin, err = be.unPad16(bin)
- if err != nil {
- return "", err
- }
-
- plain := string(bin)
- return plain, err
-}
-
-// encryptName - encrypt "plainName", return base64-encoded "cipherName64"
-// The used encryption is either CBC or EME, depending on the "EMENames" argument.
-func (be *CryptFS) encryptName(plainName string, iv []byte, EMENames bool) (cipherName64 string) {
-
- // Make sure relative symlinks still work after encryption
- // by passing these trough unchanged
- if plainName == "." || plainName == ".." {
- return plainName
- }
-
- bin := []byte(plainName)
- bin = be.pad16(bin)
-
- if EMENames {
- bin = eme.Transform(be.blockCipher, iv, bin, eme.DirectionEncrypt)
- } else {
- cbc := cipher.NewCBCEncrypter(be.blockCipher, iv)
- cbc.CryptBlocks(bin, bin)
- }
-
- cipherName64 = base64.URLEncoding.EncodeToString(bin)
- return cipherName64
-}
-
-// pad16 - pad filename to 16 byte blocks using standard PKCS#7 padding
-// https://tools.ietf.org/html/rfc5652#section-6.3
-func (be *CryptFS) pad16(orig []byte) (padded []byte) {
- oldLen := len(orig)
- if oldLen == 0 {
- panic("Padding zero-length string makes no sense")
- }
- padLen := aes.BlockSize - oldLen%aes.BlockSize
- if padLen == 0 {
- padLen = aes.BlockSize
- }
- newLen := oldLen + padLen
- padded = make([]byte, newLen)
- copy(padded, orig)
- padByte := byte(padLen)
- for i := oldLen; i < newLen; i++ {
- padded[i] = padByte
- }
- return padded
-}
-
-// unPad16 - remove padding
-func (be *CryptFS) unPad16(orig []byte) ([]byte, error) {
- oldLen := len(orig)
- if oldLen%aes.BlockSize != 0 {
- return nil, errors.New("Unaligned size")
- }
- // The last byte is always a padding byte
- padByte := orig[oldLen-1]
- // The padding byte's value is the padding length
- padLen := int(padByte)
- // Padding must be at least 1 byte
- if padLen <= 0 {
- return nil, errors.New("Padding cannot be zero-length")
- }
- // Larger paddings make no sense
- if padLen > aes.BlockSize {
- return nil, errors.New("Padding cannot be larger than 16")
- }
- // All padding bytes must be identical
- for i := oldLen - padLen; i < oldLen; i++ {
- if orig[i] != padByte {
- return nil, errors.New(fmt.Sprintf("Padding byte at i=%d is invalid", i))
- }
- }
- newLen := oldLen - padLen
- // Padding an empty string makes no sense
- if newLen == 0 {
- return nil, errors.New("Unpadded length is zero")
- }
- return orig[0:newLen], nil
-}
diff --git a/cryptfs/names_diriv.go b/cryptfs/names_diriv.go
deleted file mode 100644
index 276316c..0000000
--- a/cryptfs/names_diriv.go
+++ /dev/null
@@ -1,140 +0,0 @@
-package cryptfs
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
- "sync"
-)
-
-// A simple one-entry DirIV cache
-type dirIVCache struct {
- // Invalidated?
- cleared bool
- // The DirIV
- iv []byte
- // Directory the DirIV belongs to
- dir string
- // Ecrypted version of "dir"
- translatedDir string
- // Synchronisation
- lock sync.RWMutex
-}
-
-// lookup - fetch entry for "dir" from the cache
-func (c *dirIVCache) lookup(dir string) (bool, []byte, string) {
- c.lock.RLock()
- defer c.lock.RUnlock()
- if !c.cleared && c.dir == dir {
- return true, c.iv, c.translatedDir
- }
- return false, nil, ""
-}
-
-// store - write entry for "dir" into the caches
-func (c *dirIVCache) store(dir string, iv []byte, translatedDir string) {
- c.lock.Lock()
- defer c.lock.Unlock()
- c.cleared = false
- c.iv = iv
- c.dir = dir
- c.translatedDir = translatedDir
-}
-
-func (c *dirIVCache) Clear() {
- c.lock.Lock()
- defer c.lock.Unlock()
- c.cleared = true
-}
-
-// readDirIV - read the "gocryptfs.diriv" file from "dir" (absolute ciphertext path)
-func (be *CryptFS) ReadDirIV(dir string) (iv []byte, readErr error) {
- ivfile := filepath.Join(dir, DIRIV_FILENAME)
- Debug.Printf("ReadDirIV: reading %s\n", ivfile)
- iv, readErr = ioutil.ReadFile(ivfile)
- if readErr != nil {
- // The directory may have been concurrently deleted or moved. Failure to
- // read the diriv is not an error in that case.
- _, statErr := os.Stat(dir)
- if os.IsNotExist(statErr) {
- Debug.Printf("ReadDirIV: Dir %s was deleted under our feet", dir)
- } else {
- // This should not happen
- Warn.Printf("ReadDirIV: Dir exists but diriv does not: %v\n", readErr)
- }
- return nil, readErr
- }
- if len(iv) != DIRIV_LEN {
- return nil, fmt.Errorf("ReadDirIV: Invalid length %d\n", len(iv))
- }
- return iv, nil
-}
-
-// WriteDirIV - create diriv file inside "dir" (absolute ciphertext path)
-// This function is exported because it is used from pathfs_frontend, main,
-// and also the automated tests.
-func WriteDirIV(dir string) error {
- iv := RandBytes(DIRIV_LEN)
- file := filepath.Join(dir, DIRIV_FILENAME)
- // 0444 permissions: the file is not secret but should not be written to
- return ioutil.WriteFile(file, iv, 0444)
-}
-
-// EncryptPathDirIV - encrypt path using EME with DirIV
-func (be *CryptFS) EncryptPathDirIV(plainPath string, rootDir string, eme bool) (cipherPath string, err error) {
- // Empty string means root directory
- if plainPath == "" {
- return plainPath, nil
- }
- // Check if the DirIV is cached
- parentDir := filepath.Dir(plainPath)
- found, iv, cParentDir := be.DirIVCache.lookup(parentDir)
- if found {
- //fmt.Print("h")
- baseName := filepath.Base(plainPath)
- cBaseName := be.encryptName(baseName, iv, eme)
- cipherPath = cParentDir + "/" + cBaseName
- return cipherPath, nil
- }
- // Walk the directory tree
- var wd = rootDir
- var encryptedNames []string
- plainNames := strings.Split(plainPath, "/")
- for _, plainName := range plainNames {
- iv, err = be.ReadDirIV(wd)
- if err != nil {
- return "", err
- }
- encryptedName := be.encryptName(plainName, iv, eme)
- encryptedNames = append(encryptedNames, encryptedName)
- wd = filepath.Join(wd, encryptedName)
- }
- // Cache the final DirIV
- cipherPath = strings.Join(encryptedNames, "/")
- cParentDir = filepath.Dir(cipherPath)
- be.DirIVCache.store(parentDir, iv, cParentDir)
- return cipherPath, nil
-}
-
-// DecryptPathDirIV - decrypt path using EME with DirIV
-func (be *CryptFS) DecryptPathDirIV(encryptedPath string, rootDir string, eme bool) (string, error) {
- var wd = rootDir
- var plainNames []string
- encryptedNames := strings.Split(encryptedPath, "/")
- Debug.Printf("DecryptPathDirIV: decrypting %v\n", encryptedNames)
- for _, encryptedName := range encryptedNames {
- iv, err := be.ReadDirIV(wd)
- if err != nil {
- return "", err
- }
- plainName, err := be.decryptName(encryptedName, iv, eme)
- if err != nil {
- return "", err
- }
- plainNames = append(plainNames, plainName)
- wd = filepath.Join(wd, encryptedName)
- }
- return filepath.Join(plainNames...), nil
-}
diff --git a/cryptfs/names_noiv.go b/cryptfs/names_noiv.go
deleted file mode 100644
index 7eed4b8..0000000
--- a/cryptfs/names_noiv.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package cryptfs
-
-import (
- "strings"
-)
-
-const (
- OpEncrypt = iota
- OpDecrypt
-)
-
-// DecryptPathNoIV - decrypt path using CBC without any IV.
-// This function is deprecated by the the more secure DirIV variant and only retained
-// for compatability with old filesystems.
-func (be *CryptFS) DecryptPathNoIV(cipherPath string) (plainPath string, err error) {
- plainPath, err = be.translatePathNoIV(cipherPath, OpDecrypt)
- return plainPath, err
-}
-
-// EncryptPathNoIV - decrypt path using CBC without any IV.
-// This function is deprecated by the the more secure DirIV variant and only retained
-// for compatability with old filesystems.
-func (be *CryptFS) EncryptPathNoIV(plainPath string) (cipherPath string) {
- cipherPath, _ = be.translatePathNoIV(plainPath, OpEncrypt)
- return cipherPath
-}
-
-// translatePathZeroIV - encrypt or decrypt path using CBC with an all-zero IV.
-// Just splits the string on "/" and hands the parts to encryptName() / decryptName()
-func (be *CryptFS) translatePathNoIV(path string, op int) (string, error) {
- var err error
-
- // Empty string means root directory
- if path == "" {
- return path, err
- }
-
- zeroIV := make([]byte, DIRIV_LEN)
-
- // Run operation on each path component
- var translatedParts []string
- parts := strings.Split(path, "/")
- for _, part := range parts {
- if part == "" {
- // This happens on "/foo/bar/" on the front and on the end.
- // Don't panic.
- translatedParts = append(translatedParts, "")
- continue
- }
- var newPart string
- if op == OpEncrypt {
- newPart = be.encryptName(part, zeroIV, false)
- } else {
- newPart, err = be.decryptName(part, zeroIV, false)
- if err != nil {
- return "", err
- }
- }
- translatedParts = append(translatedParts, newPart)
- }
-
- return strings.Join(translatedParts, "/"), err
-}
diff --git a/cryptfs/names_test.go b/cryptfs/names_test.go
deleted file mode 100644
index 0207f0a..0000000
--- a/cryptfs/names_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package cryptfs
-
-import (
- "bytes"
- "testing"
-)
-
-func TestEncryptPathNoIV(t *testing.T) {
- var s []string
- s = append(s, "foo")
- s = append(s, "foo12312312312312312313123123123")
- s = append(s, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890")
-
- key := make([]byte, KEY_LEN)
- fs := NewCryptFS(key, true, false, true)
-
- for _, n := range s {
- c := fs.EncryptPathNoIV(n)
- d, err := fs.DecryptPathNoIV(c)
- if err != nil {
- t.Errorf("Got error from DecryptPathNoIV: %s", err)
- }
- if d != n {
- t.Errorf("Content mismatch, n != d: n=%s c=%s d=%s", n, c, d)
- }
- }
-}
-
-func TestPad16(t *testing.T) {
- var s [][]byte
- s = append(s, []byte("foo"))
- s = append(s, []byte("12345678901234567"))
- s = append(s, []byte("12345678901234567abcdefg"))
-
- key := make([]byte, KEY_LEN)
- fs := NewCryptFS(key, true, false, true)
-
- for i := range s {
- orig := s[i]
- padded := fs.pad16(orig)
- if len(padded) <= len(orig) {
- t.Errorf("Padded length not bigger than orig: %d", len(padded))
- }
- if len(padded)%16 != 0 {
- t.Errorf("Length is not aligend: %d", len(padded))
- }
- unpadded, err := fs.unPad16(padded)
- if err != nil {
- t.Error("unPad16 returned error:", err)
- }
- if len(unpadded) != len(orig) {
- t.Errorf("Size mismatch: orig=%d unpadded=%d", len(s[i]), len(unpadded))
- }
- if !bytes.Equal(orig, unpadded) {
- t.Error("Content mismatch orig vs unpadded")
- }
- }
-}
diff --git a/cryptfs/nonce.go b/cryptfs/nonce.go
deleted file mode 100644
index be777fc..0000000
--- a/cryptfs/nonce.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package cryptfs
-
-import (
- "bytes"
- "crypto/rand"
- "encoding/binary"
- "encoding/hex"
- "fmt"
-)
-
-// Get "n" random bytes from /dev/urandom or panic
-func RandBytes(n int) []byte {
- b := make([]byte, n)
- _, err := rand.Read(b)
- if err != nil {
- panic("Failed to read random bytes: " + err.Error())
- }
- return b
-}
-
-// Return a secure random uint64
-func RandUint64() uint64 {
- b := RandBytes(8)
- return binary.BigEndian.Uint64(b)
-}
-
-type nonceGenerator struct {
- lastNonce []byte
- nonceLen int // bytes
-}
-
-// Get a random 96 bit nonce
-func (n *nonceGenerator) Get() []byte {
- nonce := RandBytes(n.nonceLen)
- Debug.Printf("nonceGenerator.Get(): %s\n", hex.EncodeToString(nonce))
- if bytes.Equal(nonce, n.lastNonce) {
- m := fmt.Sprintf("Got the same nonce twice: %s. This should never happen!", hex.EncodeToString(nonce))
- panic(m)
- }
- n.lastNonce = nonce
- return nonce
-}
diff --git a/cryptfs/openssl_aead.go b/cryptfs/openssl_aead.go
deleted file mode 100644
index 5d38d38..0000000
--- a/cryptfs/openssl_aead.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package cryptfs
-
-// Implements cipher.AEAD with OpenSSL backend
-
-import (
- "bytes"
- "github.com/spacemonkeygo/openssl"
-)
-
-// Supports all nonce sizes
-type opensslGCM struct {
- key []byte
-}
-
-func (be opensslGCM) Overhead() int {
- return AUTH_TAG_LEN
-}
-
-func (be opensslGCM) NonceSize() int {
- // We support any nonce size
- return -1
-}
-
-// Seal encrypts and authenticates plaintext, authenticates the
-// additional data and appends the result to dst, returning the updated
-// slice. opensslGCM supports any nonce size.
-func (be opensslGCM) Seal(dst, nonce, plaintext, data []byte) []byte {
-
- // Preallocate output buffer
- var cipherBuf bytes.Buffer
- cipherBuf.Grow(len(dst) + len(plaintext) + AUTH_TAG_LEN)
- // Output will be appended to dst
- cipherBuf.Write(dst)
-
- ectx, err := openssl.NewGCMEncryptionCipherCtx(KEY_LEN*8, nil, be.key, nonce)
- if err != nil {
- panic(err)
- }
- err = ectx.ExtraData(data)
- if err != nil {
- panic(err)
- }
- part, err := ectx.EncryptUpdate(plaintext)
- if err != nil {
- panic(err)
- }
- cipherBuf.Write(part)
- part, err = ectx.EncryptFinal()
- if err != nil {
- panic(err)
- }
- cipherBuf.Write(part)
- part, err = ectx.GetTag()
- if err != nil {
- panic(err)
- }
- cipherBuf.Write(part)
-
- return cipherBuf.Bytes()
-}
-
-// Open decrypts and authenticates ciphertext, authenticates the
-// additional data and, if successful, appends the resulting plaintext
-// to dst, returning the updated slice. The nonce must be NonceSize()
-// bytes long and both it and the additional data must match the
-// value passed to Seal.
-//
-// The ciphertext and dst may alias exactly or not at all.
-func (be opensslGCM) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
-
- l := len(ciphertext)
- tag := ciphertext[l-AUTH_TAG_LEN : l]
- ciphertext = ciphertext[0 : l-AUTH_TAG_LEN]
- plainBuf := bytes.NewBuffer(dst)
-
- dctx, err := openssl.NewGCMDecryptionCipherCtx(KEY_LEN*8, nil, be.key, nonce)
- if err != nil {
- return nil, err
- }
- err = dctx.ExtraData(data)
- if err != nil {
- return nil, err
- }
- part, err := dctx.DecryptUpdate(ciphertext)
- if err != nil {
- return nil, err
- }
- plainBuf.Write(part)
- err = dctx.SetTag(tag)
- if err != nil {
- return nil, err
- }
- part, err = dctx.DecryptFinal()
- if err != nil {
- return nil, err
- }
- plainBuf.Write(part)
-
- return plainBuf.Bytes(), nil
-}
diff --git a/cryptfs/openssl_benchmark.bash b/cryptfs/openssl_benchmark.bash
deleted file mode 100755
index df29628..0000000
--- a/cryptfs/openssl_benchmark.bash
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-go test -run NONE -bench BenchmarkEnc
diff --git a/cryptfs/openssl_test.go b/cryptfs/openssl_test.go
deleted file mode 100644
index aecee94..0000000
--- a/cryptfs/openssl_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package cryptfs
-
-// Benchmark go built-int GCM against spacemonkey openssl bindings
-//
-// Note: The benchmarks in this file supersede the ones in the openssl_benchmark
-// directory as they use the same code paths that gocryptfs actually uses.
-//
-// Run benchmark:
-// go test -bench Enc
-
-import (
- "crypto/aes"
- "testing"
-)
-
-func benchmarkGoEnc(b *testing.B, plaintext []byte, key []byte, nonce []byte) (ciphertext []byte) {
- b.SetBytes(int64(len(plaintext)))
- aes, err := aes.NewCipher(key[:])
- if err != nil {
- b.Fatal(err)
- }
- aesgcm, err := goGCMWrapper(aes, len(nonce))
- if err != nil {
- b.Fatal(err)
- }
- // This would be fileID + blockNo
- aData := make([]byte, 24)
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- // Encrypt plaintext and append to nonce
- ciphertext = aesgcm.Seal(nonce, nonce, plaintext, aData)
- }
- return ciphertext
-}
-
-func benchmarkOpensslEnc(b *testing.B, plaintext []byte, key []byte, nonce []byte) (ciphertext []byte) {
- b.SetBytes(int64(len(plaintext)))
- var aesgcm opensslGCM
- aesgcm.key = key
- // This would be fileID + blockNo
- aData := make([]byte, 24)
- for i := 0; i < b.N; i++ {
- // Encrypt plaintext and append to nonce
- ciphertext = aesgcm.Seal(nonce, nonce, plaintext, aData)
- }
- return ciphertext
-}
-
-func BenchmarkEnc_Go_4k_AES256_nonce96(b *testing.B) {
- plaintext := make([]byte, 4048)
- key := make([]byte, 256/8)
- nonce := make([]byte, 96/8)
- benchmarkGoEnc(b, plaintext, key, nonce)
-}
-
-func BenchmarkEnc_Go_4k_AES256_nonce128(b *testing.B) {
- plaintext := make([]byte, 4048)
- key := make([]byte, 256/8)
- nonce := make([]byte, 128/8)
- benchmarkGoEnc(b, plaintext, key, nonce)
-}
-
-func BenchmarkEnc_OpenSSL_4k_AES256_nonce96(b *testing.B) {
- plaintext := make([]byte, 4048)
- key := make([]byte, 256/8)
- nonce := make([]byte, 96/8)
- benchmarkOpensslEnc(b, plaintext, key, nonce)
-}
-
-func BenchmarkEnc_OpenSSL_4k_AES256_nonce128(b *testing.B) {
- plaintext := make([]byte, 4048)
- key := make([]byte, 256/8)
- nonce := make([]byte, 96/8)
- benchmarkOpensslEnc(b, plaintext, key, nonce)
-}