From ae93d7861554e971f0df253410519e386499ec86 Mon Sep 17 00:00:00 2001 From: Hardcore Sushi Date: Fri, 11 Jun 2021 16:27:08 +0200 Subject: [PATCH] Switch to external libgocryptfs --- .gitmodules | 3 + app/libgocryptfs | 1 + app/libgocryptfs/.gitignore | 4 - app/libgocryptfs/build.sh | 75 -- .../cryptocore/cryptocore.go | 168 --- .../gocryptfs_internal/cryptocore/hkdf.go | 29 - .../gocryptfs_internal/cryptocore/nonce.go | 32 - .../cryptocore/randprefetch.go | 55 - .../gocryptfs_internal/eme/.travis.yml | 11 - .../gocryptfs_internal/eme/LICENSE | 21 - .../gocryptfs_internal/eme/README.md | 111 -- .../gocryptfs_internal/eme/benchmark.bash | 3 - .../gocryptfs_internal/eme/eme.go | 206 ---- .../gocryptfs_internal/eme/paper-eme-fig2.png | Bin 9648 -> 0 bytes .../gocryptfs_internal/exitcodes/exitcodes.go | 97 -- .../jacobsa_crypto/.gitignore | 22 - .../jacobsa_crypto/.travis.yml | 4 - .../gocryptfs_internal/jacobsa_crypto/LICENSE | 202 ---- .../jacobsa_crypto/README.md | 10 - .../jacobsa_crypto/cmac/const.go | 23 - .../jacobsa_crypto/cmac/doc.go | 19 - .../jacobsa_crypto/cmac/hash.go | 170 --- .../jacobsa_crypto/cmac/hash_32bit.go | 47 - .../jacobsa_crypto/cmac/hash_64bit.go | 55 - .../jacobsa_crypto/cmac/subkey.go | 65 -- .../jacobsa_crypto/common/doc.go | 18 - .../jacobsa_crypto/common/msb.go | 26 - .../jacobsa_crypto/common/pad_block.go | 36 - .../jacobsa_crypto/common/shiftleft.go | 37 - .../jacobsa_crypto/common/xor.go | 33 - .../jacobsa_crypto/siv/dbl.go | 48 - .../jacobsa_crypto/siv/decrypt.go | 103 -- .../jacobsa_crypto/siv/doc.go | 21 - .../jacobsa_crypto/siv/encrypt.go | 124 -- .../jacobsa_crypto/siv/s2v.go | 98 -- .../jacobsa_crypto/siv/xorend.go | 44 - .../gocryptfs_internal/nametransform/diriv.go | 119 -- .../nametransform/longnames.go | 153 --- .../gocryptfs_internal/nametransform/names.go | 133 --- .../gocryptfs_internal/nametransform/pad16.go | 64 -- .../siv_aead/benchmark.bash | 7 - .../gocryptfs_internal/siv_aead/siv_aead.go | 97 -- .../gocryptfs_internal/stupidgcm/autherr.go | 8 - .../stupidgcm/benchmark.bash | 3 - .../gocryptfs_internal/stupidgcm/locking.go | 28 - .../gocryptfs_internal/stupidgcm/prefer.go | 28 - .../gocryptfs_internal/stupidgcm/stupidgcm.go | 250 ---- .../stupidgcm/without_openssl.go | 52 - app/libgocryptfs/main.go | 1003 ----------------- .../rewrites/configfile/config_file.go | 325 ------ .../rewrites/configfile/feature_flags.go | 74 -- .../rewrites/configfile/scrypt.go | 101 -- app/libgocryptfs/rewrites/contentenc/bpool.go | 39 - .../rewrites/contentenc/content.go | 335 ------ .../rewrites/contentenc/file_header.go | 77 -- .../rewrites/contentenc/intrablock.go | 71 -- .../rewrites/contentenc/offsets.go | 135 --- .../rewrites/syscallcompat/emulate.go | 29 - .../rewrites/syscallcompat/getdents_linux.go | 151 --- .../rewrites/syscallcompat/getdents_other.go | 1 - .../rewrites/syscallcompat/helpers.go | 21 - .../rewrites/syscallcompat/open_nofollow.go | 44 - .../rewrites/syscallcompat/sys_common.go | 221 ---- .../rewrites/syscallcompat/sys_darwin.go | 215 ---- .../rewrites/syscallcompat/sys_linux.go | 153 --- .../syscallcompat/unix2syscall_darwin.go | 26 - .../syscallcompat/unix2syscall_linux.go | 28 - .../sushi/hardcore/droidfs/CreateActivity.kt | 2 +- .../sushi/hardcore/droidfs/GocryptfsVolume.kt | 16 +- .../file_operations/FileOperationService.kt | 2 +- .../droidfs/file_viewers/TextEditor.kt | 2 +- app/src/main/native/gocryptfs_jni.c | 23 +- .../main/res/layout/activity_image_viewer.xml | 4 +- 73 files changed, 26 insertions(+), 6035 deletions(-) create mode 100644 .gitmodules create mode 160000 app/libgocryptfs delete mode 100644 app/libgocryptfs/.gitignore delete mode 100755 app/libgocryptfs/build.sh delete mode 100644 app/libgocryptfs/gocryptfs_internal/cryptocore/cryptocore.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/cryptocore/hkdf.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/cryptocore/nonce.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/cryptocore/randprefetch.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/eme/.travis.yml delete mode 100644 app/libgocryptfs/gocryptfs_internal/eme/LICENSE delete mode 100644 app/libgocryptfs/gocryptfs_internal/eme/README.md delete mode 100755 app/libgocryptfs/gocryptfs_internal/eme/benchmark.bash delete mode 100644 app/libgocryptfs/gocryptfs_internal/eme/eme.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/eme/paper-eme-fig2.png delete mode 100644 app/libgocryptfs/gocryptfs_internal/exitcodes/exitcodes.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/.gitignore delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/.travis.yml delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/LICENSE delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/README.md delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/const.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/doc.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash_32bit.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash_64bit.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/subkey.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/doc.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/msb.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/pad_block.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/shiftleft.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/xor.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/dbl.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/decrypt.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/doc.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/encrypt.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/s2v.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/xorend.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/nametransform/diriv.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/nametransform/longnames.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/nametransform/names.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/nametransform/pad16.go delete mode 100755 app/libgocryptfs/gocryptfs_internal/siv_aead/benchmark.bash delete mode 100644 app/libgocryptfs/gocryptfs_internal/siv_aead/siv_aead.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/stupidgcm/autherr.go delete mode 100755 app/libgocryptfs/gocryptfs_internal/stupidgcm/benchmark.bash delete mode 100644 app/libgocryptfs/gocryptfs_internal/stupidgcm/locking.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/stupidgcm/prefer.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/stupidgcm/stupidgcm.go delete mode 100644 app/libgocryptfs/gocryptfs_internal/stupidgcm/without_openssl.go delete mode 100644 app/libgocryptfs/main.go delete mode 100644 app/libgocryptfs/rewrites/configfile/config_file.go delete mode 100644 app/libgocryptfs/rewrites/configfile/feature_flags.go delete mode 100644 app/libgocryptfs/rewrites/configfile/scrypt.go delete mode 100644 app/libgocryptfs/rewrites/contentenc/bpool.go delete mode 100644 app/libgocryptfs/rewrites/contentenc/content.go delete mode 100644 app/libgocryptfs/rewrites/contentenc/file_header.go delete mode 100644 app/libgocryptfs/rewrites/contentenc/intrablock.go delete mode 100644 app/libgocryptfs/rewrites/contentenc/offsets.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/emulate.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/getdents_linux.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/getdents_other.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/helpers.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/open_nofollow.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/sys_common.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/sys_darwin.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/sys_linux.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/unix2syscall_darwin.go delete mode 100644 app/libgocryptfs/rewrites/syscallcompat/unix2syscall_linux.go diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..fc49028 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "app/libgocryptfs"] + path = app/libgocryptfs + url = https://forge.chapril.org/hardcoresushi/libgocryptfs.git diff --git a/app/libgocryptfs b/app/libgocryptfs new file mode 160000 index 0000000..847d4fa --- /dev/null +++ b/app/libgocryptfs @@ -0,0 +1 @@ +Subproject commit 847d4fa7817c84fe1b78726f031172ea508dab19 diff --git a/app/libgocryptfs/.gitignore b/app/libgocryptfs/.gitignore deleted file mode 100644 index 7f5d1a7..0000000 --- a/app/libgocryptfs/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -openssl* -lib -include -build diff --git a/app/libgocryptfs/build.sh b/app/libgocryptfs/build.sh deleted file mode 100755 index 9f202a2..0000000 --- a/app/libgocryptfs/build.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -if [ -z ${ANDROID_NDK_HOME+x} ]; then - echo "Error: \$ANDROID_NDK_HOME is not defined." -elif [ -z ${OPENSSL_PATH+x} ]; then - echo "Error: \$OPENSSL_PATH is not defined." -else - NDK_BIN_PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin" - declare -a ABIs=("x86_64" "arm64-v8a" "armeabi-v7a") - - compile_openssl(){ - if [ ! -d "./lib/$1" ]; then - if [ "$1" = "x86_64" ]; then - OPENSSL_ARCH="android-x86_64" - elif [ "$1" = "arm64-v8a" ]; then - OPENSSL_ARCH="android-arm64" - elif [ "$1" = "armeabi-v7a" ]; then - OPENSSL_ARCH="android-arm" - else - echo "Invalid ABI: $1" - exit - fi - - export CFLAGS=-D__ANDROID_API__=21 - export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH - (cd "$OPENSSL_PATH" && if [ -f "Makefile" ]; then make clean; fi && ./Configure $OPENSSL_ARCH -D__ANDROID_API__=21 no-stdio && make build_libs) - mkdir -p "./lib/$1" && cp "$OPENSSL_PATH/libcrypto.a" "$OPENSSL_PATH/libssl.a" "./lib/$1" - mkdir -p "./include/$1" && cp -r "$OPENSSL_PATH"/include/* "./include/$1/" - fi - } - - compile_for_arch(){ - compile_openssl $1 - MAIN_PACKAGE="main.go" - if [ "$1" = "x86_64" ]; then - CFN="x86_64-linux-android21-clang" - elif [ "$1" = "arm64-v8a" ]; then - CFN="aarch64-linux-android21-clang" - export GOARCH=arm64 - export GOARM=7 - elif [ "$1" = "armeabi-v7a" ]; then - CFN="armv7a-linux-androideabi21-clang" - export GOARCH=arm - export GOARM=7 - MAIN_PACKAGE="main32.go" - #patch arch specific code - sed "s/C.malloc(C.ulong/C.malloc(C.uint/g" main.go > $MAIN_PACKAGE - sed -i "s/st.Mtim.Sec/int64(st.Mtim.Sec)/g" $MAIN_PACKAGE - else - echo "Invalid ABI: $1" - exit - fi - - export CC="$NDK_BIN_PATH/$CFN" - export CXX="$NDK_BIN_PATH/$CFN++" - export CGO_ENABLED=1 - export GOOS=android - export CGO_CFLAGS="-I ${PWD}/include/$1" - export CGO_LDFLAGS="-Wl,-soname=libgocryptfs.so -L${PWD}/lib/$1" - go build -o build/$1/libgocryptfs.so -buildmode=c-shared $MAIN_PACKAGE - if [ $MAIN_PACKAGE = "main32.go" ]; then - rm $MAIN_PACKAGE - fi - } - - if [ "$#" -eq 1 ]; then - compile_for_arch $1 - else - for abi in ${ABIs[@]}; do - echo "Compiling for $abi..." - compile_for_arch $abi - done - fi - echo "Done." -fi diff --git a/app/libgocryptfs/gocryptfs_internal/cryptocore/cryptocore.go b/app/libgocryptfs/gocryptfs_internal/cryptocore/cryptocore.go deleted file mode 100644 index 497eca6..0000000 --- a/app/libgocryptfs/gocryptfs_internal/cryptocore/cryptocore.go +++ /dev/null @@ -1,168 +0,0 @@ -// Package cryptocore wraps OpenSSL and Go GCM crypto and provides -// a nonce generator. -package cryptocore - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/sha512" - "fmt" - "log" - "runtime" - - "../eme" - - "../siv_aead" - "../stupidgcm" -) - -const ( - // KeyLen is the cipher key length in bytes. 32 for AES-256. - KeyLen = 32 - // AuthTagLen is the length of a GCM auth tag in bytes. - AuthTagLen = 16 -) - -// AEADTypeEnum indicates the type of AEAD backend in use. -type AEADTypeEnum int - -const ( - // BackendOpenSSL specifies the OpenSSL backend. - BackendOpenSSL AEADTypeEnum = 3 - // BackendGoGCM specifies the Go based GCM backend. - BackendGoGCM AEADTypeEnum = 4 - // BackendAESSIV specifies an AESSIV backend. - BackendAESSIV AEADTypeEnum = 5 -) - -// CryptoCore is the low level crypto implementation. -type CryptoCore struct { - // EME is used for filename encryption. - EMECipher *eme.EMECipher - // GCM or AES-SIV. This is used for content encryption. - AEADCipher cipher.AEAD - // Which backend is behind AEADCipher? - AEADBackend AEADTypeEnum - // GCM needs unique IVs (nonces) - IVGenerator *nonceGenerator - IVLen int -} - -// New returns a new CryptoCore object or panics. -// -// Even though the "GCMIV128" feature flag is now mandatory, we must still -// support 96-bit IVs here because they were used for encrypting the master -// key in gocryptfs.conf up to gocryptfs v1.2. v1.3 switched to 128 bits. -// -// Note: "key" is either the scrypt hash of the password (when decrypting -// a config file) or the masterkey (when finally mounting the filesystem). -func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDecode bool) *CryptoCore { - if len(key) != KeyLen { - log.Panic(fmt.Sprintf("Unsupported key length %d", len(key))) - } - // We want the IV size in bytes - IVLen := IVBitLen / 8 - - // Initialize EME for filename encryption. - var emeCipher *eme.EMECipher - var err error - { - var emeBlockCipher cipher.Block - if useHKDF { - emeKey := HkdfDerive(key, HkdfInfoEMENames, KeyLen) - emeBlockCipher, err = aes.NewCipher(emeKey) - for i := range emeKey { - emeKey[i] = 0 - } - } else { - emeBlockCipher, err = aes.NewCipher(key) - } - if err != nil { - log.Panic(err) - } - emeCipher = eme.New(emeBlockCipher) - } - - // Initialize an AEAD cipher for file content encryption. - var aeadCipher cipher.AEAD - if aeadType == BackendOpenSSL || aeadType == BackendGoGCM { - var gcmKey []byte - if useHKDF { - gcmKey = HkdfDerive(key, hkdfInfoGCMContent, KeyLen) - } else { - gcmKey = append([]byte{}, key...) - } - switch aeadType { - case BackendOpenSSL: - if IVLen != 16 { - log.Panic("stupidgcm only supports 128-bit IVs") - } - aeadCipher = stupidgcm.New(gcmKey, forceDecode) - case BackendGoGCM: - goGcmBlockCipher, err := aes.NewCipher(gcmKey) - if err != nil { - log.Panic(err) - } - aeadCipher, err = cipher.NewGCMWithNonceSize(goGcmBlockCipher, IVLen) - if err != nil { - log.Panic(err) - } - } - for i := range gcmKey { - gcmKey[i] = 0 - } - } else if aeadType == BackendAESSIV { - if IVLen != 16 { - // SIV supports any nonce size, but we only use 16. - log.Panic("AES-SIV must use 16-byte nonces") - } - // AES-SIV uses 1/2 of the key for authentication, 1/2 for - // encryption, so we need a 64-bytes key for AES-256. Derive it from - // the 32-byte master key using HKDF, or, for older filesystems, with - // SHA256. - var key64 []byte - if useHKDF { - key64 = HkdfDerive(key, hkdfInfoSIVContent, siv_aead.KeyLen) - } else { - s := sha512.Sum512(key) - key64 = s[:] - } - aeadCipher = siv_aead.New(key64) - for i := range key64 { - key64[i] = 0 - } - } else { - log.Panic("unknown backend cipher") - } - return &CryptoCore{ - EMECipher: emeCipher, - AEADCipher: aeadCipher, - AEADBackend: aeadType, - IVGenerator: &nonceGenerator{nonceLen: IVLen}, - IVLen: IVLen, - } -} - -type wiper interface { - Wipe() -} - -// Wipe tries to wipe secret keys from memory by overwriting them with zeros -// and/or setting references to nil. -// -// This is not bulletproof due to possible GC copies, but -// still raises to bar for extracting the key. -func (c *CryptoCore) Wipe() { - be := c.AEADBackend - if be == BackendOpenSSL || be == BackendAESSIV { - // We don't use "x, ok :=" because we *want* to crash loudly if the - // type assertion fails. - w := c.AEADCipher.(wiper) - w.Wipe() - } - // We have no access to the keys (or key-equivalents) stored inside the - // Go stdlib. Best we can is to nil the references and force a GC. - c.AEADCipher = nil - c.EMECipher = nil - runtime.GC() -} diff --git a/app/libgocryptfs/gocryptfs_internal/cryptocore/hkdf.go b/app/libgocryptfs/gocryptfs_internal/cryptocore/hkdf.go deleted file mode 100644 index 1c1a144..0000000 --- a/app/libgocryptfs/gocryptfs_internal/cryptocore/hkdf.go +++ /dev/null @@ -1,29 +0,0 @@ -package cryptocore - -import ( - "crypto/sha256" - "log" - - "golang.org/x/crypto/hkdf" -) - -const ( - // "info" data that HKDF mixes into the generated key to make it unique. - // For convenience, we use a readable string. - HkdfInfoEMENames = "EME filename encryption" - hkdfInfoGCMContent = "AES-GCM file content encryption" - hkdfInfoSIVContent = "AES-SIV file content encryption" -) - -// hkdfDerive derives "outLen" bytes from "masterkey" and "info" using -// HKDF-SHA256 (RFC 5869). -// It returns the derived bytes or panics. -func HkdfDerive(masterkey []byte, info string, outLen int) (out []byte) { - h := hkdf.New(sha256.New, masterkey, nil, []byte(info)) - out = make([]byte, outLen) - n, err := h.Read(out) - if n != outLen || err != nil { - log.Panicf("hkdfDerive: hkdf read failed, got %d bytes, error: %v", n, err) - } - return out -} diff --git a/app/libgocryptfs/gocryptfs_internal/cryptocore/nonce.go b/app/libgocryptfs/gocryptfs_internal/cryptocore/nonce.go deleted file mode 100644 index 9df094c..0000000 --- a/app/libgocryptfs/gocryptfs_internal/cryptocore/nonce.go +++ /dev/null @@ -1,32 +0,0 @@ -package cryptocore - -import ( - "crypto/rand" - "encoding/binary" - "log" -) - -// RandBytes gets "n" random bytes from /dev/urandom or panics -func RandBytes(n int) []byte { - b := make([]byte, n) - _, err := rand.Read(b) - if err != nil { - log.Panic("Failed to read random bytes: " + err.Error()) - } - return b -} - -// RandUint64 returns a secure random uint64 -func RandUint64() uint64 { - b := RandBytes(8) - return binary.BigEndian.Uint64(b) -} - -type nonceGenerator struct { - nonceLen int // bytes -} - -// Get a random "nonceLen"-byte nonce -func (n *nonceGenerator) Get() []byte { - return randPrefetcher.read(n.nonceLen) -} diff --git a/app/libgocryptfs/gocryptfs_internal/cryptocore/randprefetch.go b/app/libgocryptfs/gocryptfs_internal/cryptocore/randprefetch.go deleted file mode 100644 index 0cde31d..0000000 --- a/app/libgocryptfs/gocryptfs_internal/cryptocore/randprefetch.go +++ /dev/null @@ -1,55 +0,0 @@ -package cryptocore - -import ( - "bytes" - "log" - "sync" -) - -// Number of bytes to prefetch. -// 512 looks like a good compromise between throughput and latency - see -// randsize_test.go for numbers. -const prefetchN = 512 - -func init() { - randPrefetcher.refill = make(chan []byte) - go randPrefetcher.refillWorker() -} - -type randPrefetcherT struct { - sync.Mutex - buf bytes.Buffer - refill chan []byte -} - -func (r *randPrefetcherT) read(want int) (out []byte) { - out = make([]byte, want) - r.Lock() - // Note: don't use defer, it slows us down! - have, err := r.buf.Read(out) - if have == want && err == nil { - r.Unlock() - return out - } - // Buffer was empty -> re-fill - fresh := <-r.refill - if len(fresh) != prefetchN { - log.Panicf("randPrefetcher: refill: got %d bytes instead of %d", len(fresh), prefetchN) - } - r.buf.Reset() - r.buf.Write(fresh) - have, err = r.buf.Read(out) - if have != want || err != nil { - log.Panicf("randPrefetcher could not satisfy read: have=%d want=%d err=%v", have, want, err) - } - r.Unlock() - return out -} - -func (r *randPrefetcherT) refillWorker() { - for { - r.refill <- RandBytes(prefetchN) - } -} - -var randPrefetcher randPrefetcherT diff --git a/app/libgocryptfs/gocryptfs_internal/eme/.travis.yml b/app/libgocryptfs/gocryptfs_internal/eme/.travis.yml deleted file mode 100644 index 4072611..0000000 --- a/app/libgocryptfs/gocryptfs_internal/eme/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go - -go: - - 1.11.x # Debian 10 "Buster" - - 1.12.x # Ubuntu 19.10 - - 1.13.x # Debian 11 "Bullseye" - - stable - -script: - - go build - - ./test.bash diff --git a/app/libgocryptfs/gocryptfs_internal/eme/LICENSE b/app/libgocryptfs/gocryptfs_internal/eme/LICENSE deleted file mode 100644 index 569ca02..0000000 --- a/app/libgocryptfs/gocryptfs_internal/eme/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Jakob Unterwurzacher - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/app/libgocryptfs/gocryptfs_internal/eme/README.md b/app/libgocryptfs/gocryptfs_internal/eme/README.md deleted file mode 100644 index 22c7eca..0000000 --- a/app/libgocryptfs/gocryptfs_internal/eme/README.md +++ /dev/null @@ -1,111 +0,0 @@ -EME for Go [![Build Status](https://travis-ci.org/rfjakob/eme.svg?branch=master)](https://travis-ci.org/rfjakob/eme) [![GoDoc](https://godoc.org/github.com/rfjakob/eme?status.svg)](https://godoc.org/github.com/rfjakob/eme) ![MIT License](https://img.shields.io/badge/license-MIT-blue.svg) -========== - -**EME** (ECB-Mix-ECB or, clearer, **Encrypt-Mix-Encrypt**) is a wide-block -encryption mode developed by Halevi -and Rogaway in 2003 [[eme]](#eme). - -EME uses multiple invocations of a block cipher to construct a new -cipher of bigger block size (in multiples of 16 bytes, up to 2048 bytes). - -Quoting from the original [[eme]](#eme) paper: - -> We describe a block-cipher mode of operation, EME, that turns an n-bit block cipher into -> a tweakable enciphering scheme that acts on strings of mn bits, where m ∈ [1..n]. The mode is -> parallelizable, but as serial-efficient as the non-parallelizable mode CMC [6]. EME can be used -> to solve the disk-sector encryption problem. The algorithm entails two layers of ECB encryption -> and a “lightweight mixing” in between. We prove EME secure, in the reduction-based sense of -> modern cryptography. - -Figure 2 from the [[eme]](#eme) paper shows an overview of the transformation: - -[![Figure 2 from [eme]](paper-eme-fig2.png)](#) - -This is an implementation of EME in Go, complete with test vectors from IEEE [[p1619-2]](#p1619-2) -and Halevi [[eme-32-testvec]](#eme-32-testvec). - -It has no dependencies outside the standard library. - -Is it patentend? ----------------- - -In 2007, the UC Davis has decided to abandon [[patabandon]](#patabandon) -the patent application [[patappl]](#patappl) for EME. - -Related algorithms ------------------- - -**EME-32** is EME with the cipher set to AES and the length set to 512. -That is, EME-32 [[eme-32-pdf]](#eme-32-pdf) is a subset of EME. - -**EME2**, also known as EME\* [[emestar]](#emestar), is an extended version of EME -that has built-in handling for data that is not a multiple of 16 bytes -long. -EME2 has been selected for standardization in IEEE P1619.2 [[p1619.2]](#p1619.2). - -References ----------- - -#### [eme] -*A Parallelizable Enciphering Mode* -Shai Halevi, Phillip Rogaway, 28 Jul 2003 -https://eprint.iacr.org/2003/147.pdf - -Note: This is the original EME paper. EME is specified for an arbitrary -number of block-cipher blocks. EME-32 is a concrete implementation of -EME with a fixed length of 32 AES blocks. - -#### [eme-32-email] -*Re: EME-32-AES with editorial comments* -Shai Halevi, 07 Jun 2005 -http://grouper.ieee.org/groups/1619/email/msg00310.html - -#### [eme-32-pdf] -*Draft Standard for Tweakable Wide-block Encryption* -Shai Halevi, 02 June 2005 -http://grouper.ieee.org/groups/1619/email/pdf00020.pdf - -Note: This is the latest version of the EME-32 draft that I could find. It -includes test vectors and C source code. - -#### [eme-32-testvec] -*Re: Test vectors for LRW and EME* -Shai Halevi, 16 Nov 2004 -http://grouper.ieee.org/groups/1619/email/msg00218.html - -#### [emestar] -*EME\*: extending EME to handle arbitrary-length messages with associated data* -Shai Halevi, 27 May 2004 -https://eprint.iacr.org/2004/125.pdf - -#### [patabandon] -*Re: [P1619-2] Non-awareness patent statement made by UC Davis* -Mat Ball, 26 Nov 2007 -http://grouper.ieee.org/groups/1619/email-2/msg00005.html - -#### [patappl] -*Block cipher mode of operation for constructing a wide-blocksize block cipher from a conventional block cipher* -US patent application US20040131182 -http://www.google.com/patents/US20040131182 - -#### [p1619-2] -*IEEE P1619.2™/D9 Draft Standard for Wide-Block Encryption for Shared Storage Media* -IEEE, Dec 2008 -http://siswg.net/index2.php?option=com_docman&task=doc_view&gid=156&Itemid=41 - -Note: This is a draft version. The final version is not freely available -and must be bought from IEEE. - -Package Changelog ------------------ - -v1.1.1, 2020-04-13 -* Update `go vet` call in `test.bash` to work on recent Go versions -* No code changes - -v1.1, 2017-03-05 -* Add eme.New() / \*EMECipher convenience wrapper -* Improve panic message and parameter wording - -v1.0, 2015-12-08 -* Stable release diff --git a/app/libgocryptfs/gocryptfs_internal/eme/benchmark.bash b/app/libgocryptfs/gocryptfs_internal/eme/benchmark.bash deleted file mode 100755 index 8045e6a..0000000 --- a/app/libgocryptfs/gocryptfs_internal/eme/benchmark.bash +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -eu - -go test -bench=. diff --git a/app/libgocryptfs/gocryptfs_internal/eme/eme.go b/app/libgocryptfs/gocryptfs_internal/eme/eme.go deleted file mode 100644 index a05a191..0000000 --- a/app/libgocryptfs/gocryptfs_internal/eme/eme.go +++ /dev/null @@ -1,206 +0,0 @@ -// EME (ECB-Mix-ECB or, clearer, Encrypt-Mix-Encrypt) is a wide-block -// encryption mode developed by Halevi and Rogaway. -// -// It was presented in the 2003 paper "A Parallelizable Enciphering Mode" by -// Halevi and Rogaway. -// -// EME uses multiple invocations of a block cipher to construct a new cipher -// of bigger block size (in multiples of 16 bytes, up to 2048 bytes). -package eme - -import ( - "crypto/cipher" - "log" -) - -type directionConst bool - -const ( - // Encrypt "inputData" - DirectionEncrypt = directionConst(true) - // Decrypt "inputData" - DirectionDecrypt = directionConst(false) -) - -// multByTwo - GF multiplication as specified in the EME-32 draft -func multByTwo(out []byte, in []byte) { - if len(in) != 16 { - panic("len must be 16") - } - tmp := make([]byte, 16) - - tmp[0] = 2 * in[0] - if in[15] >= 128 { - tmp[0] = tmp[0] ^ 135 - } - for j := 1; j < 16; j++ { - tmp[j] = 2 * in[j] - if in[j-1] >= 128 { - tmp[j] += 1 - } - } - copy(out, tmp) -} - -func xorBlocks(out []byte, in1 []byte, in2 []byte) { - if len(in1) != len(in2) { - log.Panicf("len(in1)=%d is not equal to len(in2)=%d", len(in1), len(in2)) - } - - for i := range in1 { - out[i] = in1[i] ^ in2[i] - } -} - -// aesTransform - encrypt or decrypt (according to "direction") using block -// cipher "bc" (typically AES) -func aesTransform(dst []byte, src []byte, direction directionConst, bc cipher.Block) { - if direction == DirectionEncrypt { - bc.Encrypt(dst, src) - return - } else if direction == DirectionDecrypt { - bc.Decrypt(dst, src) - return - } -} - -// tabulateL - calculate L_i for messages up to a length of m cipher blocks -func tabulateL(bc cipher.Block, m int) [][]byte { - /* set L0 = 2*AESenc(K; 0) */ - eZero := make([]byte, 16) - Li := make([]byte, 16) - bc.Encrypt(Li, eZero) - - LTable := make([][]byte, m) - // Allocate pool once and slice into m pieces in the loop - pool := make([]byte, m*16) - for i := 0; i < m; i++ { - multByTwo(Li, Li) - LTable[i] = pool[i*16 : (i+1)*16] - copy(LTable[i], Li) - } - return LTable -} - -// Transform - EME-encrypt or EME-decrypt, according to "direction" -// (defined in the constants DirectionEncrypt and DirectionDecrypt). -// The data in "inputData" is en- or decrypted with the block ciper "bc" under -// "tweak" (also known as IV). -// -// The tweak is used to randomize the encryption in the same way as an -// IV. A use of this encryption mode envisioned by the authors of the -// algorithm was to encrypt each sector of a disk, with the tweak -// being the sector number. If you encipher the same data with the -// same tweak you will get the same ciphertext. -// -// The result is returned in a freshly allocated slice of the same -// size as inputData. -// -// Limitations: -// * The block cipher must have block size 16 (usually AES). -// * The size of "tweak" must be 16 -// * "inputData" must be a multiple of 16 bytes long -// If any of these pre-conditions are not met, the function will panic. -// -// Note that you probably don't want to call this function directly and instead -// use eme.New(), which provides conventient wrappers. -func Transform(bc cipher.Block, tweak []byte, inputData []byte, direction directionConst) []byte { - // In the paper, the tweak is just called "T". Call it the same here to - // make following the paper easy. - T := tweak - // In the paper, the plaintext data is called "P" and the ciphertext is - // called "C". Because encryption and decryption are virtually identical, - // we share the code and always call the input data "P" and the output data - // "C", regardless of the direction. - P := inputData - - if bc.BlockSize() != 16 { - log.Panicf("Using a block size other than 16 is not implemented") - } - if len(T) != 16 { - log.Panicf("Tweak must be 16 bytes long, is %d", len(T)) - } - if len(P)%16 != 0 { - log.Panicf("Data P must be a multiple of 16 long, is %d", len(P)) - } - m := len(P) / 16 - if m == 0 || m > 16*8 { - log.Panicf("EME operates on 1 to %d block-cipher blocks, you passed %d", 16*8, m) - } - - C := make([]byte, len(P)) - - LTable := tabulateL(bc, m) - - PPj := make([]byte, 16) - for j := 0; j < m; j++ { - Pj := P[j*16 : (j+1)*16] - /* PPj = 2**(j-1)*L xor Pj */ - xorBlocks(PPj, Pj, LTable[j]) - /* PPPj = AESenc(K; PPj) */ - aesTransform(C[j*16:(j+1)*16], PPj, direction, bc) - } - - /* MP =(xorSum PPPj) xor T */ - MP := make([]byte, 16) - xorBlocks(MP, C[0:16], T) - for j := 1; j < m; j++ { - xorBlocks(MP, MP, C[j*16:(j+1)*16]) - } - - /* MC = AESenc(K; MP) */ - MC := make([]byte, 16) - aesTransform(MC, MP, direction, bc) - - /* M = MP xor MC */ - M := make([]byte, 16) - xorBlocks(M, MP, MC) - CCCj := make([]byte, 16) - for j := 1; j < m; j++ { - multByTwo(M, M) - /* CCCj = 2**(j-1)*M xor PPPj */ - xorBlocks(CCCj, C[j*16:(j+1)*16], M) - copy(C[j*16:(j+1)*16], CCCj) - } - - /* CCC1 = (xorSum CCCj) xor T xor MC */ - CCC1 := make([]byte, 16) - xorBlocks(CCC1, MC, T) - for j := 1; j < m; j++ { - xorBlocks(CCC1, CCC1, C[j*16:(j+1)*16]) - } - copy(C[0:16], CCC1) - - for j := 0; j < m; j++ { - /* CCj = AES-enc(K; CCCj) */ - aesTransform(C[j*16:(j+1)*16], C[j*16:(j+1)*16], direction, bc) - /* Cj = 2**(j-1)*L xor CCj */ - xorBlocks(C[j*16:(j+1)*16], C[j*16:(j+1)*16], LTable[j]) - } - - return C -} - -// EMECipher provides EME-Encryption and -Decryption functions that are more -// convenient than calling Transform directly. -type EMECipher struct { - bc cipher.Block -} - -// New returns a new EMECipher object. "bc" must have a block size of 16, -// or subsequent calls to Encrypt and Decrypt will panic. -func New(bc cipher.Block) *EMECipher { - return &EMECipher{ - bc: bc, - } -} - -// Encrypt is equivalent to calling Transform with direction=DirectionEncrypt. -func (e *EMECipher) Encrypt(tweak []byte, inputData []byte) []byte { - return Transform(e.bc, tweak, inputData, DirectionEncrypt) -} - -// Decrypt is equivalent to calling Transform with direction=DirectionDecrypt. -func (e *EMECipher) Decrypt(tweak []byte, inputData []byte) []byte { - return Transform(e.bc, tweak, inputData, DirectionDecrypt) -} diff --git a/app/libgocryptfs/gocryptfs_internal/eme/paper-eme-fig2.png b/app/libgocryptfs/gocryptfs_internal/eme/paper-eme-fig2.png deleted file mode 100644 index c59c7c10cc5d38b9c6bec8288131384e7f14831c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9648 zcmb`NcQl+|+wY0qqt_s!x9Fk<(Mtp~dhaF1MDLJyJI%0jr+cswpwb+81HZ%soxg}!0IMm7#Kv9e?OQQSvhp~K|F5_ z9TmLQ2RP(hlq@<|JQx_P7#hlo0RM&ETmpY8;OtpZq^$H&C@+2;=Rm0vD><0M)jq&U ziRm5wQ0Z|&U6N)D#u~R>Ozpe6}oO_^r7It!cMHVp@_;jXfwT+Iayw0=9Zb_Pg5 zfX!gO%y@VQly6i}sPR(p$^BUIX;<0I??+Dlci{gjTrG~gIdqG`>^kZ)qZ^BJJ8~l4 z?CZFctG8T*FANHKt><)xuYN>uR@*+~$eWltA)Grpr$ zS(;`wZvzJCOnqlLz1+eNW4Zf8i6~2j9n;f#ZwZ@!HjL#X8waUyB)lAz(H)!kelYd3rvnR`s?Oixw-ZnnO@N+$XjwUeVSCw&lseq){ zyT2%^T6nJ{uU%Si8|j1Tr=Q_xhO!>`V@S1U-%n3l&wsx#{aztNA+jeW%HOGgzFov?$H?!)-gVsa2;rDv;5C0*2}-@4HFy}((Lm21 zao4B3FiHp$eXj#}Zlt$VjEAu0A4mztFP8X_W%kM3D_{r5MBQyFd~s&l{EzK}mYfu9 zfQ5cl@y{&$R<}hPa16kV`8J=N&+EXvCy^CY z@U^J%l;-rg{CVWQSA}aWL;lXKZE}_A9ajQ87?h!r?EZL50Fl-Rn?9j|ORMGdj_{E> zqyV?*m>XIWJD+v*Kt?X2;zRdlNX)s~9AG+?LsN0bUgBrQ9Rljl=L*MLqATP+syQ1i zUc==sU5%=LFGSl^HGbBaWBvk*hhRHdTz`(wn@{{Do?fNVtgKhn5^6zerTi2$Fk zVEM`)Q4x-R+hZ3Mt1z06@)8IFN2V!ER3a)(fVAjC$ch(hldMRx;5M+#SExL=tgBXo zS6vDgs=gy53snSip$&iT)?wxYxCPeC8>uB_#@Q-^hXJshg!<9jU}>7S2%Qa%y)4-& z_Da`lo}F@}kIr|6Tl-7e{Dtn&JtKL7iZO)fOhx;6HTwF3opK}D9%3~3#6-dbhif#@ zlc>Y-{kGemr$XAhB@3WHb)O!)S7j88P8ZZ5UT(>Xk*eEsp&1If9%_$0thJTI$wFp9 zF$Stq>FTCTm$P=OnQS@dKi{C~B)9||(m1%Glow;+P8o)WjYDdv>Tl69iwM(WKC zuNFt6z9IocU$+SM&JAtk3p*AdgSt=s9gBnp%(kc_*B z#6XTaELf8Oq)wf_Xb||8@8@v3q}eUv$pTErBUYY|TKM_M&q~7?9E8mm8pvk}JE;d$ zYWoL8WRi3cy%75^?~IdScKoV+p3@IAKWAtFjnKG-BCwPZI`UyXpTz$AY6dn@8qtdF zcr$!e2f(9DVWkr3FSg43Y9t@%6EXolI3OY3qV0i1a^4wXnkTkWuJ1;SM~Y#5pvMm( zdZs^JffIBIYj_fkpvQEO4=_Ls6Myon8RvnXU%e!%4j<*R`zcKp&$IbczIUp?6q z7T!nplfxKDr07BrJ>`ksdb9`u^ZOQuP)Y!jgtvGgk@p2DjT$Wd7a^!b#ZC4r7(!(? z;h;w#S^ggIPgS|A*bnRJRoo&G*LRzArH5*c*XkwX5NdBdM$g)3`oOfucy4}CrGh`K zfsmt8dx*FsYC49gN<^u0@O|Xmp93R@0YwY4us0ygf6bj64rn7!hbD@V!%JtS`!R}} zekJH}YqWEwv4RH`p`1Qu1PYN#J+4>ZVf zrZiF(W8?%l3YkQ1)sn7?n8@~jBwS0!yTp-{5)Dy`pdC&rCv~VlwkOt+Kn_rLYW~DPDi0TV0;1)>;I)+k#vdM?D&*g5Z(sKz)D%F(4fpdZ-NeE0AWXk=b8*KH4r^ z5F&8e$X7)c6f2k3gp~c`KZdZJK);>H^_F4XHQV4rC(cXDe2_Yx+(fWC zD{FqX4(48hY-y+>#9bmf-aY}xDkZl}u4$_w#7*BwZjis+T>g>ZUUKE+iQmjQD)&b2 zBD?GO8Zmg^X zhYCX6-C)0)-1L54MUY9$&FfRLde^?~JjF4i)CSe}t%bP$t!m7wbNPIC2;f)CdNamh zBw(UUG~ABY-Q`VQ9y*X@hB+#*DcjgqTFTQ?o4=&mSn5JGVkc{WVro#-GdgK7&VhYN z9ejaTPv=R!pzFZrJ}v`dN4)Z&(rQXl6M-1MejogzXLmN2V-Yjtd;FsGQB1@z&6JBG zzuB8R+m=u0x_<9VUB0HZ&A0)WYir!12qWx>nB_Cp=XXq}Yrwxzo z-g$BY-Uzqb@i`vrP00wd@tnnaWGs|?J=mdypZ5qIG~#8jSO#4>X}^Yl3(>?H-^UD$ z%}*t#RFyE`{;tacK6onn{f0>78xi-ui)y1O~zvaEFLFdQjkB7yw zZ0A)hHG)TtiqjKPN+v%ySmIKtLX)qd{bdM9!haZnd>QUK?fjCpbV?i#d(HHL zALS1`UUOz($t2HL;W@$YV^^5BxnJ;{dZKc0U%YH61an#CgZpWF3|hj%kT`dI5=LjQ zkGENV5y{tFsLJh^C_g*JvdSC71B}l;xlfs!x?R3KO{dNHID^rmtCRt$7mi!|0&`p_ zPtq}&S%2a?l6K~%o!pb{lf6II`@VBS=$(?$f`Y06kUU3as2X55(67x`G-FR^UDvy= z6nDHRz-`7gJ>|PCZ<4D&v-OX1Il>5XQkh_Zk;q-|-H48^ zeTA5dlNt}Am8R{>T>*d-o&eBJy5h5beeZ9;TXw+F(S#3byn5_@LmmdXjZM$}IHtui zX4MHn2R`})44YU95bgbeT$N!Qv*X>n-U$G$x>nj>en8pS^1(az%+5!_e@Y+zr-=WL zbF1<>;-oSN{evgUjFOW-&ArF?Vm%hWIfkT{|YXfG97@U4t&=&~)bYDr2?Mxiv+%=YumZ zf<5ow@xlx56>>O))lOU1tu>kP9p?p#?-Tx_OTAf+3pqr}A%9SugSHrVSL>}nv++a0 z?11b=BABvvt2sV697KV)Y}-e^;PF|9#I!52cg1;LBL@+e_n%Vte_Ol+um>IDICGn5 zSoiJurvkl=t6!B5!iMcP_6RMo|R;Kft+3PTNWB=7lg zw-^an+{w@gtvL=D$LIkM5%0Sg?EWmsccqTzt3=^GD_$0G9HBd(CSs63@bYvUDyvMQ|^Zqt2tTRO|hSV%&Dn5bk>NwjgnEX^%4Niu% z=mp6Qleh8)7B&wKCTPdvy=KZKE`Y^K7r;&jUf#VmruwP~QUIh9wnnobKSC^f`F1A{ z!Te8$7*8vvbNqQmRBQNK+ry5bRI#6{S5M=wTJCITbczND#e5liW^b?#tJi-bN?CV;NxR3O zoHJkRp7ZR78Q<$MD>$K`7-6~fp`T;dc0>HS`*Co__OTiZW^je0&{}|mpor)=Pj2@v zJ=v`jY%ANoAFF^AR8#y`lmED~FTl`Y=Ix#hF9QV(m0en@=$1j3Ie%~OL%MSV)gUCn zLDW!J!x_J7sQ9bXmfC{tv=>fiu)^trZ7;_BjAP8R${z~`7B}z{N|^U}Mv?EiUMQNq zg9bSG+TohE%n0#w!2n1{Un6KS8ZTuB6E9g7NE;e1UaK^EBmH*AS{l6|%hB~xz&jN*a!)z-li{EMlQ`%+!kUt2SS(wiSk^(VzfbofHHqdj<-oW7q%k#G>-^o zV#3e=e@p4hLs6zDFH*dY0TE`^np@$Nou-gUEH0&xC3!I0eHy!6*+^l5841u;nsUSd zh+?DUD~$y7YwnRvZ`I^bA#Bt*Soo| zVp6#0; zFZ+=*H^E6e#+9TSCifQrZB znM0?EVeG>+9qTE)=ADdMM>}qkxr!VTW7a&jH-B1l5iKob39t!k8erR|34lzl%nV^+ zX9AFu`CM+fH&&Q+kO5jv_UJEc3iWf~6!qy4F_rB`~`_Fmp>p zddeHKSq#7>U$kc}1Ta-8p}!sdrbYuVr9HK;HKPL7%8@gLA2mh89KV?emw+Hk2n)lI z7gjSLbe#Ivd@v<{Cn>IYYkV^2s}@rJ^I)H!s4DPh4a^2K+ink_0ZL3yN?@>xHefK)c_tDuEFb*FgO#{ibe(cnr?~VgJdOtC>bjO)x zR24`QzcleF?|I0`!}Nwo^ccf$zgm>y$7xL9!~{0HKWQ#nF)CI_7WJp7tuo z)Z8set#?-W=}NeXGB z5NhxS7oz|?o%&x?aHno1TV;jb6tg*FE+e_l|VLohm9cxsSpV=LAq;9QEb1qDwAUKt7t8@ym|q zXU{XW@$RuFMJZ*)`juCWkk4XqC{%k|P4Nx{Rg) zB537lwh=>T9*SjPxtaijou(nl<4NvZB!}Hfr;k}T=eP^zfJmmP_<(X|M>xZ}%)fuqLa-Vu z%9v|3?ovb!xlJ%ZmHDy9CttQkX{B74q{orpa;C>BoX_jlQvFE;-Q#NlpK66?ZzAu{ zBZhzc8_7RD|6k|Ri@%h*@bSNywevp)RqP-2`=70Ah!9SUbw3M0~JBmBV$-=iE=b+Poi9jLPjX<%k%wU-arq? zU@(@RFGtu}pIWkhy{azx$d|7+88kKMswmjSG{$hzmG3{NnVQEZl3zl0K$^}h&VhFB zt^rO`7Tfak7vMSlY_<|CV~=;GCoYt>{HrBstD5tKXA9qc20u$^EyMP1!A zG5Zaa=9Vkr>;cbuddgsa1X*PBF49u9xae`) zGfbuL9dPRtynTl^2ZNP-&&ByE)`pllX29A>zkj3kF3N;OQxEz7v;!uiu;EzR-5^j#qg(aPmA>mcD3H_sw4MN^sW%i z`CZl-SvW*X`(cz;{AbUsOvj(Q&kpSsHz8AoWI=fC?q2)*meS<`^F?@E9pC<}6c=>V z{XEW66A2VMul<>s;~j`!6sG%b(g>%;*4FlyTkz29;3);`u1q0{Vnk4hxRIC5>*x}) z=;5+I%^~U9q(?q3M*XeB@7F>b71{i=VZo^cR>JbG{Hs#V>7&A#Np0coS`qePU@ z1eQ2L^K|?=nDLgwu~p-_s?T4a;V`BfwX3Fv=ATwn%2ebl9X;S~R^0fF)#-qdvWM;z zjl9}YVl62E+wHooqn@JDbF&rrmh{l$jQqtv2_5MLdA@{Hl8Dt4x~V8K4u@3YaZJ3& zr1sF^U8jMVat1T6BtF5>dBeC|5;`nP)~Co6!jbnh)7eSE4+$}34Hrw9KIv33?83{i z$sSB1K;C3lK1Q(N*~vx5YJo}Gsj9}@*CXU5XGHn+B4h$TX9$7Q-*ATymq>G_t!>D@ zK+}9t;;n8$VRb!SKP1hQ2+Vtl?IDK+WQf--8(GW0^pASHnThpC{}E5ULZHeIW}=W+ zmx(fImU%bJA1(C)Ci#1k>T5K-$=sxO%EOV=9oHK#4Yz3!@5iYrvqnTH5dkF%Px09x&g&3hmL%7B7A~3CznyG%ov<3>vg5mp)#e1XMjMV=DDlVo$t ztkiu?x_XHIY8|VS)85^gmXASAa#hY9ayNL{*igm^-xttm_n77o*E^kE_a_UUYtytm z<{n0#%P+ku*W&JiX3l7z_>ZT;=9}=s-SQTuY72+`u=h$!wOE#p*Cg|NFXWc9tzVNz zn4zT8961|Yn&KHPP=SXQxdi5)bSUep6TKv~TPx{#xCcW+Wc}Mlhid)X3|QLgX`_Q+ z7G4K(qC4}}GsjEx2FD{+aa*?a@(qe!RUcY;=f4&HRCSJhX2c1GZhdtX#INJ|%96k1 zX+2yz%-CW*Ab9w=;1lDo&Dt8)O6cHo@|>eFhKMaDeOlcdwIGZ_J=e@7qOUl1Z-Eyv z+lfa`oVbQj3VROF8;6e~(XX_H%eIob&yY2t;`vPpPb`GFQ)gXae4O)^U@Mt1jh8>R z$@aSn-xUAas#hPgSx?Z{ZN%Jt`pzImb1^>l?sVc;%}I!4#;n=LhPy|W={#z@<)0O! z?$-SGtKGPs(X{Xi&M+<7ujE+K=X<^~_<1wBA~bhrl|&LY0XEczg0+6J10VrUo^|c% zPlSKl?q|zxk7~h{h5{*!k&^pl{3;)4X?=n?><#p|w?Yq>xUP@vK9T$bWP)Ky*Crs! zW(&eA>8v&6Atm~Xo9)NDkKBl-sGSe?hn=QTT7fKsLJjfV77u+eFt9KGz6*dCx*2OX z+8mX0Nme7+fCH_4GWdNNPogT5UBE{Ec-39^o65qYP;`S#!!SnPPZ9P{wC~6sak)H^ z_)c0qT(2ylf6slckGmTlnr9*Z!VKg$B67tkmqK*s0o#OqPe>y{^N8;@fiQsLsr%$3 ziOv2WwS!57l}mKy?B`euQ5dF3f(emtuI4FjjNXRk+_<&BBc7sovZ>4%f@5f zREN2zh7q>7xsArqZs-TiuJAbV zE+XBF4bM&1867WI$jQG=P`%U_zp$PT#e)*r=W-J6rM+&-*sHrt!#SJbHGlkRWzc}5 z*&+MWnz+#!&W66^CD?qP!LuY`Wpi^%DrVC!Dt(-vwG@8q))GiMO>lXJ@G5@wZJZQX!-KNUy<=(t_)PlyU+G$ zfq0!X70H(EKJN*k7u%Tq>L5jRd^6_)g)X!526dfx4GJy6E>l?=w5?_XoGkhlR3O4P zQQeE2nxd6EH_$UZqb`x;QWDn^k^luK54ji%>^+`sJ{u-&dMwNAsv@2oRpa4%SSH;< z<4q){2WEMEc<1B{ZnF$(7+}{gLBA<&se#h(w-0t$8XVzjBvnCbO1s zOA}_N-sl}UFU|qodp!;5?(jDv^PDv}&3qYltXHle7X6pWY2S`%bIo-_1;w4kKD6s* zaELowO@c@?Xi!|gg`SZ#;!28*v+HnuAS(nXS$%OSP_P>J1-2&a4P!5DmEjuY>SlNt zW+f3CBTgUCX1z`0Y!al6A(MN+6Ku$nRS@RsuFJUfHK(vPdDslv<0He5n2GxbWR9m{=Ye#9b(iSmiK4R W(7q?91NSdUVQ8qlRE8^ANBkGzO{KK} diff --git a/app/libgocryptfs/gocryptfs_internal/exitcodes/exitcodes.go b/app/libgocryptfs/gocryptfs_internal/exitcodes/exitcodes.go deleted file mode 100644 index b876333..0000000 --- a/app/libgocryptfs/gocryptfs_internal/exitcodes/exitcodes.go +++ /dev/null @@ -1,97 +0,0 @@ -// Package exitcodes contains all well-defined exit codes that gocryptfs -// can return. -package exitcodes - -import ( - "fmt" - "os" -) - -const ( - // Usage - usage error like wrong cli syntax, wrong number of parameters. - Usage = 1 - // 2 is reserved because it is used by Go panic - // 3 is reserved because it was used by earlier gocryptfs version as a generic - // "mount" error. - - // CipherDir means that the CIPHERDIR does not exist, is not empty, or is not - // a directory. - CipherDir = 6 - // Init is an error on filesystem init - Init = 7 - // LoadConf is an error while loading gocryptfs.conf - LoadConf = 8 - // ReadPassword means something went wrong reading the password - ReadPassword = 9 - // MountPoint error means that the mountpoint is invalid (not empty etc). - MountPoint = 10 - // Other error - please inspect the message - Other = 11 - // PasswordIncorrect - the password was incorrect when mounting or when - // changing the password. - PasswordIncorrect = 12 - // ScryptParams means that scrypt was called with invalid parameters - ScryptParams = 13 - // MasterKey means that something went wrong when parsing the "-masterkey" - // command line option - MasterKey = 14 - // SigInt means we got SIGINT - SigInt = 15 - // PanicLogNotEmpty means the panic log was not empty when we were unmounted - PanicLogNotEmpty = 16 - // ForkChild means forking the worker child failed - ForkChild = 17 - // OpenSSL means you tried to enable OpenSSL, but we were compiled without it. - OpenSSL = 18 - // FuseNewServer - this exit code means that the call to fuse.NewServer failed. - // This usually means that there was a problem executing fusermount, or - // fusermount could not attach the mountpoint to the kernel. - FuseNewServer = 19 - // CtlSock - the control socket file could not be created. - CtlSock = 20 - // Downgraded to a warning in gocryptfs v1.4 - //PanicLogCreate = 21 - - // PasswordEmpty - we received an empty password - PasswordEmpty = 22 - // OpenConf - the was an error opening the gocryptfs.conf file for reading - OpenConf = 23 - // WriteConf - could not write the gocryptfs.conf - WriteConf = 24 - // Profiler - error occurred when trying to write cpu or memory profile or - // execution trace - Profiler = 25 - // FsckErrors - the filesystem check found errors - FsckErrors = 26 - // DeprecatedFS - this filesystem is deprecated - DeprecatedFS = 27 - // skip 28 - // ExcludeError - an error occurred while processing "-exclude" - ExcludeError = 29 - // DevNull means that /dev/null could not be opened - DevNull = 30 -) - -// Err wraps an error with an associated numeric exit code -type Err struct { - error - code int -} - -// NewErr returns an error containing "msg" and the exit code "code". -func NewErr(msg string, code int) Err { - return Err{ - error: fmt.Errorf(msg), - code: code, - } -} - -// Exit extracts the numeric exit code from "err" (if available) and exits the -// application. -func Exit(err error) { - err2, ok := err.(Err) - if !ok { - os.Exit(Other) - } - os.Exit(err2.code) -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/.gitignore b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/.gitignore deleted file mode 100644 index 0026861..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/.travis.yml b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/.travis.yml deleted file mode 100644 index b972119..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -# Cf. http://docs.travis-ci.com/user/getting-started/ -# Cf. http://docs.travis-ci.com/user/languages/go/ - -language: go diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/LICENSE b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/LICENSE deleted file mode 100644 index d645695..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/README.md b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/README.md deleted file mode 100644 index 4d0f7bc..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/README.md +++ /dev/null @@ -1,10 +0,0 @@ -This repository contains Go packages related to cryptographic standards that are -not included in the Go standard library. These include: - - * [SIV mode][siv], which provides deterministic encryption with - authentication. - - * [CMAC][cmac], a message authentication system used by SIV mode. - -[siv]: https://godoc.org/github.com/jacobsa/crypto/siv -[cmac]: https://godoc.org/github.com/jacobsa/crypto/cmac diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/const.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/const.go deleted file mode 100644 index a2dac78..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/const.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmac - -import "crypto/aes" - -// The size of an AES-CMAC checksum, in bytes. -const Size = aes.BlockSize - -const blockSize = Size diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/doc.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/doc.go deleted file mode 100644 index 96d45c3..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package cmac implements the CMAC mode for message authentication, as defined -// by NIST Special Publication 800-38B. When a 16-byte key is used, this -// matches the AES-CMAC algorithm defined by RFC 4493. -package cmac diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash.go deleted file mode 100644 index fb80913..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmac - -import ( - "crypto/aes" - "crypto/cipher" - "fmt" - "hash" - "unsafe" - - "../common" -) - -type cmacHash struct { - // An AES cipher configured with the original key. - ciph cipher.Block - - // Generated sub-keys. - k1 []byte - k2 []byte - - // Data that has been seen by Write but not yet incorporated into x, due to - // us not being sure if it is the final block or not. - // - // INVARIANT: len(data) <= blockSize - data []byte - - // The current value of X, as defined in the AES-CMAC algorithm in RFC 4493. - // Initially this is a 128-bit zero, and it is updated with the current block - // when we're sure it's not the last one. - x []byte -} - -func (h *cmacHash) Write(p []byte) (n int, err error) { - n = len(p) - - // First step: consume enough data to expand h.data to a full block, if - // possible. - { - toConsume := blockSize - len(h.data) - if toConsume > len(p) { - toConsume = len(p) - } - - h.data = append(h.data, p[:toConsume]...) - p = p[toConsume:] - } - - // If there's no data left in p, it means h.data might not be a full block. - // Even if it is, we're not sure it's the final block, which we must treat - // specially. So we must stop here. - if len(p) == 0 { - return - } - - // h.data is a full block and is not the last; process it. - h.writeBlocks(h.data) - h.data = h.data[:0] - - // Consume any further full blocks in p that we're sure aren't the last. Note - // that we're sure that len(p) is greater than zero here. - blocksToProcess := (len(p) - 1) / blockSize - bytesToProcess := blocksToProcess * blockSize - - h.writeBlocks(p[:bytesToProcess]) - p = p[bytesToProcess:] - - // Store the rest for later. - h.data = append(h.data, p...) - - return -} - -// Process block-aligned data that we're sure does not contain the final block. -// -// REQUIRES: len(p) % blockSize == 0 -func (h *cmacHash) writeBlocks(p []byte) { - y := make([]byte, blockSize) - - for off := 0; off < len(p); off += blockSize { - block := p[off : off+blockSize] - - xorBlock( - unsafe.Pointer(&y[0]), - unsafe.Pointer(&h.x[0]), - unsafe.Pointer(&block[0])) - - h.ciph.Encrypt(h.x, y) - } - - return -} - -func (h *cmacHash) Sum(b []byte) []byte { - dataLen := len(h.data) - - // We should have at most one block left. - if dataLen > blockSize { - panic(fmt.Sprintf("Unexpected data: %x", h.data)) - } - - // Calculate M_last. - mLast := make([]byte, blockSize) - if dataLen == blockSize { - common.Xor(mLast, h.data, h.k1) - } else { - // TODO(jacobsa): Accept a destination buffer in common.PadBlock and - // simplify this code. - common.Xor(mLast, common.PadBlock(h.data), h.k2) - } - - y := make([]byte, blockSize) - common.Xor(y, mLast, h.x) - - result := make([]byte, blockSize) - h.ciph.Encrypt(result, y) - - b = append(b, result...) - return b -} - -func (h *cmacHash) Reset() { - h.data = h.data[:0] - h.x = make([]byte, blockSize) -} - -func (h *cmacHash) Size() int { - return h.ciph.BlockSize() -} - -func (h *cmacHash) BlockSize() int { - return h.ciph.BlockSize() -} - -// New returns an AES-CMAC hash using the supplied key. The key must be 16, 24, -// or 32 bytes long. -func New(key []byte) (hash.Hash, error) { - switch len(key) { - case 16, 24, 32: - default: - return nil, fmt.Errorf("AES-CMAC requires a 16-, 24-, or 32-byte key.") - } - - // Create a cipher. - ciph, err := aes.NewCipher(key) - if err != nil { - return nil, fmt.Errorf("aes.NewCipher: %v", err) - } - - // Set up the hash object. - h := &cmacHash{ciph: ciph} - h.k1, h.k2 = generateSubkeys(ciph) - h.Reset() - - return h, nil -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash_32bit.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash_32bit.go deleted file mode 100644 index f9d28ee..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash_32bit.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build 386 arm,!arm64 mips mipsle - -package cmac - -import ( - "log" - "unsafe" -) - -// XOR the blockSize bytes starting at a and b, writing the result over dst. -func xorBlock( - dstPtr unsafe.Pointer, - aPtr unsafe.Pointer, - bPtr unsafe.Pointer) { - // Check assumptions. (These are compile-time constants, so this should - // compile out.) - const wordSize = unsafe.Sizeof(uintptr(0)) - if blockSize != 4*wordSize { - log.Panicf("%d %d", blockSize, wordSize) - } - - // Convert. - a := (*[4]uintptr)(aPtr) - b := (*[4]uintptr)(bPtr) - dst := (*[4]uintptr)(dstPtr) - - // Compute. - dst[0] = a[0] ^ b[0] - dst[1] = a[1] ^ b[1] - dst[2] = a[2] ^ b[2] - dst[3] = a[3] ^ b[3] -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash_64bit.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash_64bit.go deleted file mode 100644 index fe31eda..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/hash_64bit.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build amd64 arm64 ppc64 ppc64le s390x mips64 mips64le - -// This code assumes that it's safe to perform unaligned word-sized loads. This is safe on: -// - arm64 per http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01s02.html -// - Section "5.5.8 Alignment Interrupt" of PowerPC Operating Environment Architecture Book III Version 2.02 -// (the first PowerPC ISA version to include 64-bit), available from -// http://www.ibm.com/developerworks/systems/library/es-archguide-v2.html does not permit fixed-point loads -// or stores to generate exceptions on unaligned access -// - IBM mainframe's have allowed unaligned accesses since the System/370 arrived in 1970 -// - On mips unaligned accesses are fixed up by the kernel per https://www.linux-mips.org/wiki/Alignment -// so performance might be quite bad but it will work. - -package cmac - -import ( - "log" - "unsafe" -) - -// XOR the blockSize bytes starting at a and b, writing the result over dst. -func xorBlock( - dstPtr unsafe.Pointer, - aPtr unsafe.Pointer, - bPtr unsafe.Pointer) { - // Check assumptions. (These are compile-time constants, so this should - // compile out.) - const wordSize = unsafe.Sizeof(uintptr(0)) - if blockSize != 2*wordSize { - log.Panicf("%d %d", blockSize, wordSize) - } - - // Convert. - a := (*[2]uintptr)(aPtr) - b := (*[2]uintptr)(bPtr) - dst := (*[2]uintptr)(dstPtr) - - // Compute. - dst[0] = a[0] ^ b[0] - dst[1] = a[1] ^ b[1] -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/subkey.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/subkey.go deleted file mode 100644 index 67ad906..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/cmac/subkey.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmac - -import ( - "bytes" - "crypto/cipher" - - "../common" -) - -var subkeyZero []byte -var subkeyRb []byte - -func init() { - subkeyZero = bytes.Repeat([]byte{0x00}, blockSize) - subkeyRb = append(bytes.Repeat([]byte{0x00}, blockSize-1), 0x87) -} - -// Given the supplied cipher, whose block size must be 16 bytes, return two -// subkeys that can be used in MAC generation. See section 5.3 of NIST SP -// 800-38B. Note that the other NIST-approved block size of 8 bytes is not -// supported by this function. -func generateSubkeys(ciph cipher.Block) (k1 []byte, k2 []byte) { - if ciph.BlockSize() != blockSize { - panic("generateSubkeys requires a cipher with a block size of 16 bytes.") - } - - // Step 1 - l := make([]byte, blockSize) - ciph.Encrypt(l, subkeyZero) - - // Step 2: Derive the first subkey. - if common.Msb(l) == 0 { - // TODO(jacobsa): Accept a destination buffer in ShiftLeft and then hoist - // the allocation in the else branch below. - k1 = common.ShiftLeft(l) - } else { - k1 = make([]byte, blockSize) - common.Xor(k1, common.ShiftLeft(l), subkeyRb) - } - - // Step 3: Derive the second subkey. - if common.Msb(k1) == 0 { - k2 = common.ShiftLeft(k1) - } else { - k2 = make([]byte, blockSize) - common.Xor(k2, common.ShiftLeft(k1), subkeyRb) - } - - return -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/doc.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/doc.go deleted file mode 100644 index e3b9046..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package common contains common implementation details of other packages, and -// should not be used directly. -package common diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/msb.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/msb.go deleted file mode 100644 index 7f8769d..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/msb.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -// Msb returns the most significant bit of the supplied data (which must be -// non-empty). This is the MSB(L) function of RFC 4493. -func Msb(buf []byte) uint8 { - if len(buf) == 0 { - panic("msb requires non-empty buffer.") - } - - return buf[0] >> 7 -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/pad_block.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/pad_block.go deleted file mode 100644 index b4e323e..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/pad_block.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -import ( - "crypto/aes" -) - -// PadBlock pads a string of bytes less than 16 bytes long to a full block size -// by appending a one bit followed by zero bits. This is the padding function -// used in RFCs 4493 and 5297. -func PadBlock(block []byte) []byte { - blockLen := len(block) - if blockLen >= aes.BlockSize { - panic("PadBlock input must be less than 16 bytes.") - } - - result := make([]byte, aes.BlockSize) - copy(result, block) - result[blockLen] = 0x80 - - return result -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/shiftleft.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/shiftleft.go deleted file mode 100644 index 20db6a1..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/shiftleft.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -// ShiftLeft shifts the binary string left by one bit, causing the -// most-signficant bit to disappear and a zero to be introduced at the right. -// This corresponds to the `x << 1` notation of RFC 4493. -func ShiftLeft(b []byte) []byte { - l := len(b) - if l == 0 { - panic("shiftLeft requires a non-empty buffer.") - } - - output := make([]byte, l) - - overflow := byte(0) - for i := int(l - 1); i >= 0; i-- { - output[i] = b[i] << 1 - output[i] |= overflow - overflow = (b[i] & 0x80) >> 7 - } - - return output -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/xor.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/xor.go deleted file mode 100644 index 0979992..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/common/xor.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package common - -import "log" - -// Xor computes `a XOR b`, as defined by RFC 4493. dst, a, and b must all have -// the same length. -func Xor(dst []byte, a []byte, b []byte) { - // TODO(jacobsa): Consider making this a helper function with known sizes - // where it is most hot, then even trying to inline it entirely. - - if len(dst) != len(a) || len(a) != len(b) { - log.Panicf("Bad buffer lengths: %d, %d, %d", len(dst), len(a), len(b)) - } - - for i, _ := range a { - dst[i] = a[i] ^ b[i] - } -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/dbl.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/dbl.go deleted file mode 100644 index cf65633..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/dbl.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package siv - -import ( - "bytes" - "crypto/aes" - - "../common" -) - -var dblRb []byte - -func init() { - dblRb = append(bytes.Repeat([]byte{0x00}, 15), 0x87) -} - -// Given a 128-bit binary string, shift the string left by one bit and XOR the -// result with 0x00...87 if the bit shifted off was one. This is the dbl -// function of RFC 5297. -func dbl(b []byte) []byte { - if len(b) != aes.BlockSize { - panic("dbl requires a 16-byte buffer.") - } - - shiftedOne := common.Msb(b) == 1 - b = common.ShiftLeft(b) - if shiftedOne { - tmp := make([]byte, aes.BlockSize) - common.Xor(tmp, b, dblRb) - b = tmp - } - - return b -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/decrypt.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/decrypt.go deleted file mode 100644 index d54a596..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/decrypt.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package siv - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/subtle" - "fmt" -) - -// *NotAuthenticError is returned by Decrypt if the input is otherwise -// well-formed but the ciphertext doesn't check out as authentic. This could be -// due to an incorrect key, corrupted ciphertext, or incorrect/corrupted -// associated data. -type NotAuthenticError struct { - s string -} - -func (e *NotAuthenticError) Error() string { - return e.s -} - -// Given ciphertext previously generated by Encrypt and the key and associated -// data that were used when generating the ciphertext, return the original -// plaintext given to Encrypt. If the input is well-formed but the key is -// incorrect, return an instance of WrongKeyError. -func Decrypt(key, ciphertext []byte, associated [][]byte) ([]byte, error) { - keyLen := len(key) - associatedLen := len(associated) - - // The first 16 bytes of the ciphertext are the SIV. - if len(ciphertext) < aes.BlockSize { - return nil, fmt.Errorf("Invalid ciphertext; length must be at least 16.") - } - - v := ciphertext[0:aes.BlockSize] - c := ciphertext[aes.BlockSize:] - - // Make sure the key length is legal. - switch keyLen { - case 32, 48, 64: - default: - return nil, fmt.Errorf("SIV requires a 32-, 48-, or 64-byte key.") - } - - // Derive subkeys. - k1 := key[:keyLen/2] - k2 := key[keyLen/2:] - - // Make sure the number of associated data is legal, per RFC 5297 section 7. - if associatedLen > 126 { - return nil, fmt.Errorf("len(associated) may be no more than 126.") - } - - // Create a CTR cipher using a version of v with the 31st and 63rd bits - // zeroed out. - q := dup(v) - q[aes.BlockSize-4] &= 0x7f - q[aes.BlockSize-8] &= 0x7f - - ciph, err := aes.NewCipher(k2) - if err != nil { - return nil, fmt.Errorf("aes.NewCipher: %v", err) - } - - ctrCiph := cipher.NewCTR(ciph, q) - - // Decrypt the ciphertext. - plaintext := make([]byte, len(c)) - ctrCiph.XORKeyStream(plaintext, c) - - // Verify the SIV. - s2vStrings := make([][]byte, associatedLen+1) - copy(s2vStrings, associated) - s2vStrings[associatedLen] = plaintext - - t := s2v(k1, s2vStrings, nil) - if len(t) != aes.BlockSize { - panic(fmt.Sprintf("Unexpected output of S2V: %v", t)) - } - - if subtle.ConstantTimeCompare(t, v) != 1 { - return nil, &NotAuthenticError{ - "Couldn't validate the authenticity of the ciphertext and " + - "associated data."} - } - - return plaintext, nil -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/doc.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/doc.go deleted file mode 100644 index 8c5e057..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package siv implements the SIV (Synthetic Initialization Vector) mode of -// AES, as defined by RFC 5297. -// -// This mode offers the choice of deterministic authenticated encryption or -// nonce-based, misuse-resistant authenticated encryption. -package siv diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/encrypt.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/encrypt.go deleted file mode 100644 index b9aa7f2..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/encrypt.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package siv - -import ( - "crypto/aes" - "crypto/cipher" - "fmt" -) - -func dup(d []byte) []byte { - result := make([]byte, len(d)) - copy(result, d) - return result -} - -// Given a key and plaintext, encrypt the plaintext using the SIV mode of AES, -// as defined by RFC 5297, append the result (including both the synthetic -// initialization vector and the ciphertext) to dst, and return the updated -// slice. The output can later be fed to Decrypt to recover the plaintext. -// -// In addition to confidentiality, this function also offers authenticity. That -// is, without the secret key an attacker is unable to construct a byte string -// that Decrypt will accept. -// -// The supplied key must be 32, 48, or 64 bytes long. -// -// The supplied associated data, up to 126 strings, is also authenticated, -// though it is not included in the ciphertext. The user must supply the same -// associated data to Decrypt in order for the Decrypt call to succeed. If no -// associated data is desired, pass an empty slice. -// -// If the same key, plaintext, and associated data are supplied to this -// function multiple times, the output is guaranteed to be identical. As per -// RFC 5297 section 3, you may use this function for nonce-based authenticated -// encryption by passing a nonce as the last associated data element. -func Encrypt(dst, key, plaintext []byte, associated [][]byte) ([]byte, error) { - keyLen := len(key) - associatedLen := len(associated) - - // The output will consist of the current contents of dst, followed by the IV - // generated by s2v, followed by the ciphertext (which is the same size as - // the plaintext). - // - // Make sure dst is long enough, then carve it up. - var iv []byte - var ciphertext []byte - { - dstSize := len(dst) - dstAndIVSize := dstSize + s2vSize - outputSize := dstAndIVSize + len(plaintext) - - if cap(dst) < outputSize { - tmp := make([]byte, dstSize, outputSize+outputSize/4) - copy(tmp, dst) - dst = tmp - } - - dst = dst[:outputSize] - iv = dst[dstSize:dstAndIVSize] - ciphertext = dst[dstAndIVSize:outputSize] - } - - // Make sure the key length is legal. - switch keyLen { - case 32, 48, 64: - default: - return nil, fmt.Errorf("SIV requires a 32-, 48-, or 64-byte key.") - } - - // Make sure the number of associated data is legal, per RFC 5297 section 7. - if associatedLen > 126 { - return nil, fmt.Errorf("len(associated) may be no more than 126.") - } - - // Derive subkeys. - k1 := key[:keyLen/2] - k2 := key[keyLen/2:] - - // Call S2V to derive the synthetic initialization vector. Use the ciphertext - // output buffer as scratch space, since it's the same length as the final - // string. - s2vStrings := make([][]byte, associatedLen+1) - copy(s2vStrings, associated) - s2vStrings[associatedLen] = plaintext - - v := s2v(k1, s2vStrings, ciphertext) - if len(v) != len(iv) { - panic(fmt.Sprintf("Unexpected vector: %v", v)) - } - - copy(iv, v) - - // Create a CTR cipher using a version of v with the 31st and 63rd bits - // zeroed out. - q := dup(v) - q[aes.BlockSize-4] &= 0x7f - q[aes.BlockSize-8] &= 0x7f - - ciph, err := aes.NewCipher(k2) - if err != nil { - return nil, fmt.Errorf("aes.NewCipher: %v", err) - } - - ctrCiph := cipher.NewCTR(ciph, q) - - // Fill in the ciphertext. - ctrCiph.XORKeyStream(ciphertext, plaintext) - - return dst, nil -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/s2v.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/s2v.go deleted file mode 100644 index 2d198b1..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/s2v.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package siv - -import ( - "bytes" - "crypto/aes" - "fmt" - - "../cmac" - "../common" -) - -var s2vZero []byte - -func init() { - s2vZero = bytes.Repeat([]byte{0x00}, aes.BlockSize) -} - -// The output size of the s2v function. -const s2vSize = cmac.Size - -// Run the S2V "string to vector" function of RFC 5297 using the input key and -// string vector, which must be non-empty. (RFC 5297 defines S2V to handle the -// empty vector case, but it is never used that way by higher-level functions.) -// -// If provided, the supplied scatch space will be used to avoid an allocation. -// It should be (but is not required to be) as large as the last element of -// strings. -// -// The result is guaranteed to be of length s2vSize. -func s2v(key []byte, strings [][]byte, scratch []byte) []byte { - numStrings := len(strings) - if numStrings == 0 { - panic("strings vector must be non-empty.") - } - - // Create a CMAC hash. - h, err := cmac.New(key) - if err != nil { - panic(fmt.Sprintf("cmac.New: %v", err)) - } - - // Initialize. - if _, err := h.Write(s2vZero); err != nil { - panic(fmt.Sprintf("h.Write: %v", err)) - } - - d := h.Sum([]byte{}) - h.Reset() - - // Handle all strings but the last. - for i := 0; i < numStrings-1; i++ { - if _, err := h.Write(strings[i]); err != nil { - panic(fmt.Sprintf("h.Write: %v", err)) - } - - common.Xor(d, dbl(d), h.Sum([]byte{})) - h.Reset() - } - - // Handle the last string. - lastString := strings[numStrings-1] - var t []byte - if len(lastString) >= aes.BlockSize { - // Make an output buffer the length of lastString. - if cap(scratch) >= len(lastString) { - t = scratch[:len(lastString)] - } else { - t = make([]byte, len(lastString)) - } - - // XOR d on the end of lastString. - xorend(t, lastString, d) - } else { - t = make([]byte, aes.BlockSize) - common.Xor(t, dbl(d), common.PadBlock(lastString)) - } - - if _, err := h.Write(t); err != nil { - panic(fmt.Sprintf("h.Write: %v", err)) - } - - return h.Sum([]byte{}) -} diff --git a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/xorend.go b/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/xorend.go deleted file mode 100644 index e5e3ec6..0000000 --- a/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/xorend.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package siv - -import ( - "log" - - "../common" -) - -// The xorend operator of RFC 5297. -// -// Given strings A and B with len(A) >= len(B), let D be len(A) - len(B). Write -// A[:D] followed by xor(A[D:], B) into dst. In other words, xor B over the -// rightmost end of A and write the result into dst. -func xorend(dst, a, b []byte) { - aLen := len(a) - bLen := len(b) - dstLen := len(dst) - - if dstLen < aLen || aLen < bLen { - log.Panicf("Bad buffer lengths: %d, %d, %d", dstLen, aLen, bLen) - } - - // Copy the left part. - difference := aLen - bLen - copy(dst, a[:difference]) - - // XOR in the right part. - common.Xor(dst[difference:difference+bLen], a[difference:], b) -} diff --git a/app/libgocryptfs/gocryptfs_internal/nametransform/diriv.go b/app/libgocryptfs/gocryptfs_internal/nametransform/diriv.go deleted file mode 100644 index 726eff4..0000000 --- a/app/libgocryptfs/gocryptfs_internal/nametransform/diriv.go +++ /dev/null @@ -1,119 +0,0 @@ -package nametransform - -import ( - "bytes" - "fmt" - "io" - "os" - "path/filepath" - "syscall" - - "../cryptocore" - "../../rewrites/syscallcompat" -) - -const ( - // DirIVLen is identical to AES block size - DirIVLen = 16 - // DirIVFilename is the filename used to store directory IV. - // Exported because we have to ignore this name in directory listing. - DirIVFilename = "gocryptfs.diriv" -) - -// ReadDirIVAt reads "gocryptfs.diriv" from the directory that is opened as "dirfd". -// Using the dirfd makes it immune to concurrent renames of the directory. -func ReadDirIVAt(dirfd int) (iv []byte, err error) { - fdRaw, err := syscallcompat.Openat(dirfd, DirIVFilename, - syscall.O_RDONLY|syscall.O_NOFOLLOW, 0) - if err != nil { - return nil, err - } - fd := os.NewFile(uintptr(fdRaw), DirIVFilename) - defer fd.Close() - return fdReadDirIV(fd) -} - -// allZeroDirIV is preallocated to quickly check if the data read from disk is all zero -var allZeroDirIV = make([]byte, DirIVLen) - -// fdReadDirIV reads and verifies the DirIV from an opened gocryptfs.diriv file. -func fdReadDirIV(fd *os.File) (iv []byte, err error) { - // We want to detect if the file is bigger than DirIVLen, so - // make the buffer 1 byte bigger than necessary. - iv = make([]byte, DirIVLen+1) - n, err := fd.Read(iv) - if err != nil && err != io.EOF { - return nil, fmt.Errorf("read failed: %v", err) - } - iv = iv[0:n] - if len(iv) != DirIVLen { - return nil, fmt.Errorf("wanted %d bytes, got %d", DirIVLen, len(iv)) - } - if bytes.Equal(iv, allZeroDirIV) { - return nil, fmt.Errorf("diriv is all-zero") - } - return iv, nil -} - -// WriteDirIVAt - create a new gocryptfs.diriv file in the directory opened at -// "dirfd". On error we try to delete the incomplete file. -// This function is exported because it is used from fusefrontend, main, -// and also the automated tests. -func WriteDirIVAt(dirfd int) error { - // It makes sense to have the diriv files group-readable so the FS can - // be mounted from several users from a network drive (see - // https://github.com/rfjakob/gocryptfs/issues/387 ). - // - // Note that gocryptfs.conf is still created with 0400 permissions so the - // owner must explicitly chmod it to permit access. - const dirivPerms = 0440 - - iv := cryptocore.RandBytes(DirIVLen) - // 0400 permissions: gocryptfs.diriv should never be modified after creation. - // Don't use "ioutil.WriteFile", it causes trouble on NFS: - // https://github.com/rfjakob/gocryptfs/commit/7d38f80a78644c8ec4900cc990bfb894387112ed - fd, err := syscallcompat.Openat(dirfd, DirIVFilename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, dirivPerms) - if err != nil { - return err - } - // Wrap the fd in an os.File - we need the write retry logic. - f := os.NewFile(uintptr(fd), DirIVFilename) - _, err = f.Write(iv) - if err != nil { - f.Close() - // Delete incomplete gocryptfs.diriv file - syscallcompat.Unlinkat(dirfd, DirIVFilename, 0) - return err - } - err = f.Close() - if err != nil { - // Delete incomplete gocryptfs.diriv file - syscallcompat.Unlinkat(dirfd, DirIVFilename, 0) - return err - } - return nil -} - -// encryptAndHashName encrypts "name" and hashes it to a longname if it is -// too long. -// Returns ENAMETOOLONG if "name" is longer than 255 bytes. -func (be *NameTransform) EncryptAndHashName(name string, iv []byte) (string, error) { - // Prevent the user from creating files longer than 255 chars. - if len(name) > NameMax { - return "", syscall.ENAMETOOLONG - } - cName := be.EncryptName(name, iv) - if be.longNames && len(cName) > NameMax { - return be.HashLongName(cName), nil - } - return cName, nil -} - -// Dir is like filepath.Dir but returns "" instead of ".". -func Dir(path string) string { - d := filepath.Dir(path) - if d == "." { - return "" - } - return d -} diff --git a/app/libgocryptfs/gocryptfs_internal/nametransform/longnames.go b/app/libgocryptfs/gocryptfs_internal/nametransform/longnames.go deleted file mode 100644 index b098f06..0000000 --- a/app/libgocryptfs/gocryptfs_internal/nametransform/longnames.go +++ /dev/null @@ -1,153 +0,0 @@ -package nametransform - -import ( - "crypto/sha256" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "syscall" - - "../../rewrites/syscallcompat" -) - -const ( - // LongNameSuffix is the suffix used for files with long names. - // Files with long names are stored in two files: - // gocryptfs.longname.[sha256] <--- File content, prefix = gocryptfs.longname. - // gocryptfs.longname.[sha256].name <--- File name, suffix = .name - LongNameSuffix = ".name" - longNamePrefix = "gocryptfs.longname." -) - -// HashLongName - take the hash of a long string "name" and return -// "gocryptfs.longname.[sha256]" -// -// This function does not do any I/O. -func (n *NameTransform) HashLongName(name string) string { - hashBin := sha256.Sum256([]byte(name)) - hashBase64 := n.B64.EncodeToString(hashBin[:]) - return longNamePrefix + hashBase64 -} - -// Values returned by IsLongName -const ( - // LongNameContent is the file that stores the file content. - // Example: gocryptfs.longname.URrM8kgxTKYMgCk4hKk7RO9Lcfr30XQof4L_5bD9Iro= - LongNameContent = iota - // LongNameFilename is the file that stores the full encrypted filename. - // Example: gocryptfs.longname.URrM8kgxTKYMgCk4hKk7RO9Lcfr30XQof4L_5bD9Iro=.name - LongNameFilename = iota - // LongNameNone is used when the file does not have a long name. - // Example: i1bpTaVLZq7sRNA9mL_2Ig== - LongNameNone = iota -) - -// NameType - detect if cName is -// gocryptfs.longname.[sha256] ........ LongNameContent (content of a long name file) -// gocryptfs.longname.[sha256].name .... LongNameFilename (full file name of a long name file) -// else ................................ LongNameNone (normal file) -// -// This function does not do any I/O. -func NameType(cName string) int { - if !strings.HasPrefix(cName, longNamePrefix) { - return LongNameNone - } - if strings.HasSuffix(cName, LongNameSuffix) { - return LongNameFilename - } - return LongNameContent -} - -// IsLongContent returns true if "cName" is the content store of a long name -// file (looks like "gocryptfs.longname.[sha256]"). -// -// This function does not do any I/O. -func IsLongContent(cName string) bool { - return NameType(cName) == LongNameContent -} - -// RemoveLongNameSuffix removes the ".name" suffix from cName, returning the corresponding -// content file name. -// No check is made if cName actually is a LongNameFilename. -func RemoveLongNameSuffix(cName string) string { - return cName[:len(cName)-len(LongNameSuffix)] -} - -// ReadLongName - read cName + ".name" from the directory opened as dirfd. -// -// Symlink-safe through Openat(). -func ReadLongNameAt(dirfd int, cName string) (string, error) { - cName += LongNameSuffix - var f *os.File - { - fd, err := syscallcompat.Openat(dirfd, cName, syscall.O_RDONLY|syscall.O_NOFOLLOW, 0) - if err != nil { - return "", err - } - f = os.NewFile(uintptr(fd), "") - // fd runs out of scope here - } - defer f.Close() - // 256 (=255 padded to 16) bytes base64-encoded take 344 bytes: "AAAAAAA...AAA==" - lim := 344 - // Allocate a bigger buffer so we see whether the file is too big - buf := make([]byte, lim+1) - n, err := f.ReadAt(buf, 0) - if err != nil && err != io.EOF { - return "", err - } - if n == 0 { - return "", fmt.Errorf("ReadLongName: empty file") - } - if n > lim { - return "", fmt.Errorf("ReadLongName: size=%d > limit=%d", n, lim) - } - return string(buf[0:n]), nil -} - -// DeleteLongName deletes "hashName.name" in the directory opened at "dirfd". -// -// This function is symlink-safe through the use of Unlinkat(). -func DeleteLongNameAt(dirfd int, hashName string) error { - return syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0) -} - -// WriteLongName encrypts plainName and writes it into "hashName.name". -// For the convenience of the caller, plainName may also be a path and will be -// Base()named internally. -// -// This function is symlink-safe through the use of Openat(). -func (n *NameTransform) WriteLongNameAt(dirfd int, hashName string, plainName string) (err error) { - plainName = filepath.Base(plainName) - - // Encrypt the basename - dirIV, err := ReadDirIVAt(dirfd) - if err != nil { - return err - } - cName := n.EncryptName(plainName, dirIV) - - // Write the encrypted name into hashName.name - fdRaw, err := syscallcompat.Openat(dirfd, hashName+LongNameSuffix, - syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL, 0400) - if err != nil { - return err - } - fd := os.NewFile(uintptr(fdRaw), hashName+LongNameSuffix) - _, err = fd.Write([]byte(cName)) - if err != nil { - fd.Close() - // Delete incomplete longname file - syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0) - return err - } - err = fd.Close() - if err != nil { - // Delete incomplete longname file - syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0) - return err - } - return nil -} diff --git a/app/libgocryptfs/gocryptfs_internal/nametransform/names.go b/app/libgocryptfs/gocryptfs_internal/nametransform/names.go deleted file mode 100644 index a6fbbe7..0000000 --- a/app/libgocryptfs/gocryptfs_internal/nametransform/names.go +++ /dev/null @@ -1,133 +0,0 @@ -// Package nametransform encrypts and decrypts filenames. -package nametransform - -import ( - "bytes" - "crypto/aes" - "encoding/base64" - "path/filepath" - "syscall" - - "../eme" -) - -const ( - // Like ext4, we allow at most 255 bytes for a file name. - NameMax = 255 -) - -// NameTransformer is an interface used to transform filenames. -type NameTransformer interface { - DecryptName(cipherName string, iv []byte) (string, error) - EncryptName(plainName string, iv []byte) string - EncryptAndHashName(name string, iv []byte) (string, error) - HashLongName(name string) string - WriteLongNameAt(dirfd int, hashName string, plainName string) error - B64EncodeToString(src []byte) string - B64DecodeString(s string) ([]byte, error) -} - -// NameTransform is used to transform filenames. -type NameTransform struct { - emeCipher *eme.EMECipher - longNames bool - // B64 = either base64.URLEncoding or base64.RawURLEncoding, depending - // on the Raw64 feature flag - B64 *base64.Encoding - // Patterns to bypass decryption - BadnamePatterns []string -} - -// New returns a new NameTransform instance. -func New(e *eme.EMECipher, longNames bool, raw64 bool) *NameTransform { - b64 := base64.URLEncoding - if raw64 { - b64 = base64.RawURLEncoding - } - return &NameTransform{ - emeCipher: e, - longNames: longNames, - B64: b64, - } -} - -// DecryptName calls decryptName to try and decrypt a base64-encoded encrypted -// filename "cipherName", and failing that checks if it can be bypassed -func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error) { - res, err := n.decryptName(cipherName, iv) - if err != nil { - for _, pattern := range n.BadnamePatterns { - match, err := filepath.Match(pattern, cipherName) - if err == nil && match { // Pattern should have been validated already - // Find longest decryptable substring - // At least 16 bytes due to AES --> at least 22 characters in base64 - nameMin := n.B64.EncodedLen(aes.BlockSize) - for charpos := len(cipherName) - 1; charpos >= nameMin; charpos-- { - res, err = n.decryptName(cipherName[:charpos], iv) - if err == nil { - return res + cipherName[charpos:] + " GOCRYPTFS_BAD_NAME", nil - } - } - return cipherName + " GOCRYPTFS_BAD_NAME", nil - } - } - } - return res, err -} - -// decryptName decrypts a base64-encoded encrypted filename "cipherName" using the -// initialization vector "iv". -func (n *NameTransform) decryptName(cipherName string, iv []byte) (string, error) { - bin, err := n.B64.DecodeString(cipherName) - if err != nil { - return "", err - } - if len(bin) == 0 { - return "", syscall.EBADMSG - } - if len(bin)%aes.BlockSize != 0 { - return "", syscall.EBADMSG - } - bin = n.emeCipher.Decrypt(iv, bin) - bin, err = unPad16(bin) - if err != nil { - // unPad16 returns detailed errors including the position of the - // incorrect bytes. Kill the padding oracle by lumping everything into - // a generic error. - return "", syscall.EBADMSG - } - // A name can never contain a null byte or "/". Make sure we never return those - // to the kernel, even when we read a corrupted (or fuzzed) filesystem. - if bytes.Contains(bin, []byte{0}) || bytes.Contains(bin, []byte("/")) { - return "", syscall.EBADMSG - } - // The name should never be "." or "..". - if bytes.Equal(bin, []byte(".")) || bytes.Equal(bin, []byte("..")) { - return "", syscall.EBADMSG - } - plain := string(bin) - return plain, err -} - -// EncryptName encrypts "plainName", returns a base64-encoded "cipherName64", -// encrypted using EME (https://github.com/rfjakob/eme). -// -// This function is exported because in some cases, fusefrontend needs access -// to the full (not hashed) name if longname is used. -func (n *NameTransform) EncryptName(plainName string, iv []byte) (cipherName64 string) { - bin := []byte(plainName) - bin = pad16(bin) - bin = n.emeCipher.Encrypt(iv, bin) - cipherName64 = n.B64.EncodeToString(bin) - return cipherName64 -} - -// B64EncodeToString returns a Base64-encoded string -func (n *NameTransform) B64EncodeToString(src []byte) string { - return n.B64.EncodeToString(src) -} - -// B64DecodeString decodes a Base64-encoded string -func (n *NameTransform) B64DecodeString(s string) ([]byte, error) { - return n.B64.DecodeString(s) -} diff --git a/app/libgocryptfs/gocryptfs_internal/nametransform/pad16.go b/app/libgocryptfs/gocryptfs_internal/nametransform/pad16.go deleted file mode 100644 index 833be0e..0000000 --- a/app/libgocryptfs/gocryptfs_internal/nametransform/pad16.go +++ /dev/null @@ -1,64 +0,0 @@ -package nametransform - -import ( - "crypto/aes" - "errors" - "fmt" - "log" -) - -// pad16 - pad data to AES block size (=16 byte) using standard PKCS#7 padding -// https://tools.ietf.org/html/rfc5652#section-6.3 -func pad16(orig []byte) (padded []byte) { - oldLen := len(orig) - if oldLen == 0 { - log.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 unPad16(padded []byte) ([]byte, error) { - oldLen := len(padded) - if oldLen == 0 { - return nil, errors.New("Empty input") - } - if oldLen%aes.BlockSize != 0 { - return nil, errors.New("Unaligned size") - } - // The last byte is always a padding byte - padByte := padded[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") - } - // Padding more than 16 bytes make no sense - if padLen > aes.BlockSize { - return nil, fmt.Errorf("Padding too long, padLen=%d > 16", padLen) - } - // Padding cannot be as long as (or longer than) the whole string, - if padLen >= oldLen { - return nil, fmt.Errorf("Padding too long, oldLen=%d >= padLen=%d", oldLen, padLen) - } - // All padding bytes must be identical - for i := oldLen - padLen; i < oldLen; i++ { - if padded[i] != padByte { - return nil, fmt.Errorf("Padding byte at i=%d is invalid", i) - } - } - newLen := oldLen - padLen - return padded[0:newLen], nil -} diff --git a/app/libgocryptfs/gocryptfs_internal/siv_aead/benchmark.bash b/app/libgocryptfs/gocryptfs_internal/siv_aead/benchmark.bash deleted file mode 100755 index 40b57b3..0000000 --- a/app/libgocryptfs/gocryptfs_internal/siv_aead/benchmark.bash +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -eu - -cd "$(dirname "$0")" - -../stupidgcm/benchmark.bash diff --git a/app/libgocryptfs/gocryptfs_internal/siv_aead/siv_aead.go b/app/libgocryptfs/gocryptfs_internal/siv_aead/siv_aead.go deleted file mode 100644 index 4b61c5c..0000000 --- a/app/libgocryptfs/gocryptfs_internal/siv_aead/siv_aead.go +++ /dev/null @@ -1,97 +0,0 @@ -// Package siv_aead wraps the functions provided by siv -// in a crypto.AEAD interface. -package siv_aead - -import ( - "crypto/cipher" - "log" - - "../jacobsa_crypto/siv" -) - -type sivAead struct { - key []byte -} - -var _ cipher.AEAD = &sivAead{} - -const ( - // KeyLen is the required key length. The SIV algorithm supports other lengths, - // but we only support 64. - KeyLen = 64 -) - -// New returns a new cipher.AEAD implementation. -func New(key []byte) cipher.AEAD { - if len(key) != KeyLen { - // SIV supports 32, 48 or 64-byte keys, but in gocryptfs we - // exclusively use 64. - log.Panicf("Key must be %d byte long (you passed %d)", KeyLen, len(key)) - } - return new2(key) -} - -// Same as "New" without the 64-byte restriction. -func new2(keyIn []byte) cipher.AEAD { - // Create a private copy so the caller can zero the one he owns - key := append([]byte{}, keyIn...) - return &sivAead{ - key: key, - } -} - -func (s *sivAead) NonceSize() int { - // SIV supports any nonce size, but in gocryptfs we exclusively use 16. - return 16 -} - -func (s *sivAead) Overhead() int { - return 16 -} - -// Seal encrypts "in" using "nonce" and "authData" and appends the result to "dst" -func (s *sivAead) Seal(dst, nonce, plaintext, authData []byte) []byte { - if len(nonce) != 16 { - // SIV supports any nonce size, but in gocryptfs we exclusively use 16. - log.Panic("nonce must be 16 bytes long") - } - if len(s.key) == 0 { - log.Panic("Key has been wiped?") - } - // https://github.com/jacobsa/crypto/blob/master/siv/encrypt.go#L48: - // As per RFC 5297 section 3, you may use this function for nonce-based - // authenticated encryption by passing a nonce as the last associated - // data element. - associated := [][]byte{authData, nonce} - out, err := siv.Encrypt(dst, s.key, plaintext, associated) - if err != nil { - log.Panic(err) - } - return out -} - -// Open decrypts "in" using "nonce" and "authData" and appends the result to "dst" -func (s *sivAead) Open(dst, nonce, ciphertext, authData []byte) ([]byte, error) { - if len(nonce) != 16 { - // SIV supports any nonce size, but in gocryptfs we exclusively use 16. - log.Panic("nonce must be 16 bytes long") - } - if len(s.key) == 0 { - log.Panic("Key has been wiped?") - } - associated := [][]byte{authData, nonce} - dec, err := siv.Decrypt(s.key, ciphertext, associated) - return append(dst, dec...), err -} - -// Wipe tries to wipe the AES key from memory by overwriting it with zeros -// and setting the reference to nil. -// -// This is not bulletproof due to possible GC copies, but -// still raises to bar for extracting the key. -func (s *sivAead) Wipe() { - for i := range s.key { - s.key[i] = 0 - } - s.key = nil -} diff --git a/app/libgocryptfs/gocryptfs_internal/stupidgcm/autherr.go b/app/libgocryptfs/gocryptfs_internal/stupidgcm/autherr.go deleted file mode 100644 index e59f92e..0000000 --- a/app/libgocryptfs/gocryptfs_internal/stupidgcm/autherr.go +++ /dev/null @@ -1,8 +0,0 @@ -package stupidgcm - -import ( - "fmt" -) - -// ErrAuth is returned when the message authentication fails -var ErrAuth = fmt.Errorf("stupidgcm: message authentication failed") diff --git a/app/libgocryptfs/gocryptfs_internal/stupidgcm/benchmark.bash b/app/libgocryptfs/gocryptfs_internal/stupidgcm/benchmark.bash deleted file mode 100755 index 8681495..0000000 --- a/app/libgocryptfs/gocryptfs_internal/stupidgcm/benchmark.bash +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -exec ../speed/benchmark.bash diff --git a/app/libgocryptfs/gocryptfs_internal/stupidgcm/locking.go b/app/libgocryptfs/gocryptfs_internal/stupidgcm/locking.go deleted file mode 100644 index 68ab509..0000000 --- a/app/libgocryptfs/gocryptfs_internal/stupidgcm/locking.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build !without_openssl - -package stupidgcm - -// In general, OpenSSL is only threadsafe if you provide a locking function -// through CRYPTO_set_locking_callback. However, the GCM operations that -// stupidgcm uses never call that function. Additionally, the manual locking -// has been removed completely in openssl 1.1.0. - -/* -#include -#include - -static void dummy_callback(int mode, int n, const char *file, int line) { - printf("stupidgcm: thread locking is not implemented and should not be " - "needed. Please upgrade openssl.\n"); - // panic - __builtin_trap(); -} -static void set_dummy_callback() { - CRYPTO_set_locking_callback(dummy_callback); -} -*/ -import "C" - -func init() { - C.set_dummy_callback() -} diff --git a/app/libgocryptfs/gocryptfs_internal/stupidgcm/prefer.go b/app/libgocryptfs/gocryptfs_internal/stupidgcm/prefer.go deleted file mode 100644 index c067d09..0000000 --- a/app/libgocryptfs/gocryptfs_internal/stupidgcm/prefer.go +++ /dev/null @@ -1,28 +0,0 @@ -package stupidgcm - -import ( - "golang.org/x/sys/cpu" -) - -// PreferOpenSSL tells us if OpenSSL is faster than Go GCM on this machine. -// -// Go GCM is only faster if the CPU either: -// -// 1) Is X86_64 && has AES instructions && Go is v1.6 or higher -// 2) Is ARM64 && has AES instructions && Go is v1.11 or higher -// (commit https://github.com/golang/go/commit/4f1f503373cda7160392be94e3849b0c9b9ebbda) -// -// See https://github.com/rfjakob/gocryptfs/wiki/CPU-Benchmarks -// for benchmarks. -func PreferOpenSSL() bool { - if BuiltWithoutOpenssl { - return false - } - // Safe to call on other architectures - will just read false. - if cpu.X86.HasAES || cpu.ARM64.HasAES { - // Go stdlib is probably faster - return false - } - // Openssl is probably faster - return true -} diff --git a/app/libgocryptfs/gocryptfs_internal/stupidgcm/stupidgcm.go b/app/libgocryptfs/gocryptfs_internal/stupidgcm/stupidgcm.go deleted file mode 100644 index 5e5781b..0000000 --- a/app/libgocryptfs/gocryptfs_internal/stupidgcm/stupidgcm.go +++ /dev/null @@ -1,250 +0,0 @@ -// +build !without_openssl - -// Package stupidgcm is a thin wrapper for OpenSSL's GCM encryption and -// decryption functions. It only support 32-byte keys and 16-bit IVs. -package stupidgcm - -//#include -// #include -// #cgo pkg-config: libcrypto -import "C" - -import ( - "crypto/cipher" - "fmt" - "log" - "unsafe" -) - -const ( - // BuiltWithoutOpenssl indicates if openssl been disabled at compile-time - BuiltWithoutOpenssl = false - - keyLen = 32 - ivLen = 16 - tagLen = 16 -) - -// StupidGCM implements the cipher.AEAD interface -type StupidGCM struct { - key []byte - forceDecode bool -} - -// Verify that we satisfy the cipher.AEAD interface -var _ cipher.AEAD = &StupidGCM{} - -// New returns a new cipher.AEAD implementation.. -func New(keyIn []byte, forceDecode bool) cipher.AEAD { - if len(keyIn) != keyLen { - log.Panicf("Only %d-byte keys are supported", keyLen) - } - // Create a private copy of the key - key := append([]byte{}, keyIn...) - return &StupidGCM{key: key, forceDecode: forceDecode} -} - -// NonceSize returns the required size of the nonce / IV. -func (g *StupidGCM) NonceSize() int { - return ivLen -} - -// Overhead returns the number of bytes that are added for authentication. -func (g *StupidGCM) Overhead() int { - return tagLen -} - -// Seal encrypts "in" using "iv" and "authData" and append the result to "dst" -func (g *StupidGCM) Seal(dst, iv, in, authData []byte) []byte { - if len(iv) != ivLen { - log.Panicf("Only %d-byte IVs are supported", ivLen) - } - if len(in) == 0 { - log.Panic("Zero-length input data is not supported") - } - if len(g.key) != keyLen { - log.Panicf("Wrong key length: %d. Key has been wiped?", len(g.key)) - } - - // If the "dst" slice is large enough we can use it as our output buffer - outLen := len(in) + tagLen - var buf []byte - inplace := false - if cap(dst)-len(dst) >= outLen { - inplace = true - buf = dst[len(dst) : len(dst)+outLen] - } else { - buf = make([]byte, outLen) - } - - // https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode - - // Create scratch space "context" - ctx := C.EVP_CIPHER_CTX_new() - if ctx == nil { - log.Panic("EVP_CIPHER_CTX_new failed") - } - - // Set cipher to AES-256 - if C.EVP_EncryptInit_ex(ctx, C.EVP_aes_256_gcm(), nil, nil, nil) != 1 { - log.Panic("EVP_EncryptInit_ex I failed") - } - - // Use 16-byte IV - if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_GCM_SET_IVLEN, ivLen, nil) != 1 { - log.Panic("EVP_CIPHER_CTX_ctrl EVP_CTRL_GCM_SET_IVLEN failed") - } - - // Set key and IV - if C.EVP_EncryptInit_ex(ctx, nil, nil, (*C.uchar)(&g.key[0]), (*C.uchar)(&iv[0])) != 1 { - log.Panic("EVP_EncryptInit_ex II failed") - } - - // Provide authentication data - var resultLen C.int - if C.EVP_EncryptUpdate(ctx, nil, &resultLen, (*C.uchar)(&authData[0]), C.int(len(authData))) != 1 { - log.Panic("EVP_EncryptUpdate authData failed") - } - if int(resultLen) != len(authData) { - log.Panicf("Unexpected length %d", resultLen) - } - - // Encrypt "in" into "buf" - if C.EVP_EncryptUpdate(ctx, (*C.uchar)(&buf[0]), &resultLen, (*C.uchar)(&in[0]), C.int(len(in))) != 1 { - log.Panic("EVP_EncryptUpdate failed") - } - if int(resultLen) != len(in) { - log.Panicf("Unexpected length %d", resultLen) - } - - // Finalise encryption - // Because GCM is a stream encryption, this will not write out any data. - dummy := make([]byte, 16) - if C.EVP_EncryptFinal_ex(ctx, (*C.uchar)(&dummy[0]), &resultLen) != 1 { - log.Panic("EVP_EncryptFinal_ex failed") - } - if resultLen != 0 { - log.Panicf("Unexpected length %d", resultLen) - } - - // Get GMAC tag and append it to the ciphertext in "buf" - if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_GCM_GET_TAG, tagLen, (unsafe.Pointer)(&buf[len(in)])) != 1 { - log.Panic("EVP_CIPHER_CTX_ctrl EVP_CTRL_GCM_GET_TAG failed") - } - - // Free scratch space - C.EVP_CIPHER_CTX_free(ctx) - - if inplace { - return dst[:len(dst)+outLen] - } - return append(dst, buf...) -} - -// Open decrypts "in" using "iv" and "authData" and append the result to "dst" -func (g *StupidGCM) Open(dst, iv, in, authData []byte) ([]byte, error) { - if len(iv) != ivLen { - log.Panicf("Only %d-byte IVs are supported", ivLen) - } - if len(g.key) != keyLen { - log.Panicf("Wrong key length: %d. Key has been wiped?", len(g.key)) - } - if len(in) <= tagLen { - return nil, fmt.Errorf("stupidgcm: input data too short (%d bytes)", len(in)) - } - - // If the "dst" slice is large enough we can use it as our output buffer - outLen := len(in) - tagLen - var buf []byte - inplace := false - if cap(dst)-len(dst) >= outLen { - inplace = true - buf = dst[len(dst) : len(dst)+outLen] - } else { - buf = make([]byte, len(in)-tagLen) - } - - ciphertext := in[:len(in)-tagLen] - tag := in[len(in)-tagLen:] - - // https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode - - // Create scratch space "context" - ctx := C.EVP_CIPHER_CTX_new() - if ctx == nil { - log.Panic("EVP_CIPHER_CTX_new failed") - } - - // Set cipher to AES-256 - if C.EVP_DecryptInit_ex(ctx, C.EVP_aes_256_gcm(), nil, nil, nil) != 1 { - log.Panic("EVP_DecryptInit_ex I failed") - } - - // Use 16-byte IV - if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_GCM_SET_IVLEN, ivLen, nil) != 1 { - log.Panic("EVP_CIPHER_CTX_ctrl EVP_CTRL_GCM_SET_IVLEN failed") - } - - // Set key and IV - if C.EVP_DecryptInit_ex(ctx, nil, nil, (*C.uchar)(&g.key[0]), (*C.uchar)(&iv[0])) != 1 { - log.Panic("EVP_DecryptInit_ex II failed") - } - - // Set expected GMAC tag - if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_GCM_SET_TAG, tagLen, (unsafe.Pointer)(&tag[0])) != 1 { - log.Panic("EVP_CIPHER_CTX_ctrl failed") - } - - // Provide authentication data - var resultLen C.int - if C.EVP_DecryptUpdate(ctx, nil, &resultLen, (*C.uchar)(&authData[0]), C.int(len(authData))) != 1 { - log.Panic("EVP_DecryptUpdate authData failed") - } - if int(resultLen) != len(authData) { - log.Panicf("Unexpected length %d", resultLen) - } - - // Decrypt "ciphertext" into "buf" - if C.EVP_DecryptUpdate(ctx, (*C.uchar)(&buf[0]), &resultLen, (*C.uchar)(&ciphertext[0]), C.int(len(ciphertext))) != 1 { - log.Panic("EVP_DecryptUpdate failed") - } - if int(resultLen) != len(ciphertext) { - log.Panicf("Unexpected length %d", resultLen) - } - - // Check GMAC - dummy := make([]byte, 16) - res := C.EVP_DecryptFinal_ex(ctx, (*C.uchar)(&dummy[0]), &resultLen) - if resultLen != 0 { - log.Panicf("Unexpected length %d", resultLen) - } - - // Free scratch space - C.EVP_CIPHER_CTX_free(ctx) - - if res != 1 { - // The error code must always be checked by the calling function, because the decrypted buffer - // may contain corrupted data that we are returning in case the user forced reads - if g.forceDecode == true { - return append(dst, buf...), ErrAuth - } - return nil, ErrAuth - } - - if inplace { - return dst[:len(dst)+outLen], nil - } - return append(dst, buf...), nil -} - -// Wipe tries to wipe the AES key from memory by overwriting it with zeros -// and setting the reference to nil. -// -// This is not bulletproof due to possible GC copies, but -// still raises to bar for extracting the key. -func (g *StupidGCM) Wipe() { - for i := range g.key { - g.key[i] = 0 - } - g.key = nil -} diff --git a/app/libgocryptfs/gocryptfs_internal/stupidgcm/without_openssl.go b/app/libgocryptfs/gocryptfs_internal/stupidgcm/without_openssl.go deleted file mode 100644 index deac342..0000000 --- a/app/libgocryptfs/gocryptfs_internal/stupidgcm/without_openssl.go +++ /dev/null @@ -1,52 +0,0 @@ -// +build without_openssl - -package stupidgcm - -import ( - "fmt" - "os" - - "github.com/rfjakob/gocryptfs/internal/exitcodes" -) - -type StupidGCM struct{} - -const ( - // BuiltWithoutOpenssl indicates if openssl been disabled at compile-time - BuiltWithoutOpenssl = true -) - -func errExit() { - fmt.Fprintln(os.Stderr, "gocryptfs has been compiled without openssl support but you are still trying to use openssl") - os.Exit(exitcodes.OpenSSL) -} - -func New(_ []byte, _ bool) *StupidGCM { - errExit() - // Never reached - return &StupidGCM{} -} - -func (g *StupidGCM) NonceSize() int { - errExit() - return -1 -} - -func (g *StupidGCM) Overhead() int { - errExit() - return -1 -} - -func (g *StupidGCM) Seal(_, _, _, _ []byte) []byte { - errExit() - return nil -} - -func (g *StupidGCM) Open(_, _, _, _ []byte) ([]byte, error) { - errExit() - return nil, nil -} - -func (g *StupidGCM) Wipe() { - errExit() -} diff --git a/app/libgocryptfs/main.go b/app/libgocryptfs/main.go deleted file mode 100644 index 6762673..0000000 --- a/app/libgocryptfs/main.go +++ /dev/null @@ -1,1003 +0,0 @@ -package main - -import ( - "C" - "bytes" - "crypto/aes" - "crypto/cipher" - "fmt" - "golang.org/x/sys/unix" - "io" - "os" - "path/filepath" - "strings" - "syscall" - "unsafe" - - "./gocryptfs_internal/cryptocore" - "./gocryptfs_internal/eme" - "./gocryptfs_internal/nametransform" - "./gocryptfs_internal/stupidgcm" - "./rewrites/configfile" - "./rewrites/contentenc" - "./rewrites/syscallcompat" -) - -const ( - file_mode = uint32(0660) - folder_mode = uint32(0770) -) - -type Directory struct { - fd int - iv []byte -} - -type File struct { - fd *os.File - path string -} - -type SessionVars struct { - root_cipher_dir string - plainTextNames bool - nameTransform *nametransform.NameTransform - cryptoCore *cryptocore.CryptoCore - contentEnc *contentenc.ContentEnc - dirCache map[string]Directory - file_handles map[int]File - fileIDs map[int][]byte -} - -var sessions map[int]SessionVars - -func err_to_bool(e error) bool { - if e == nil { - return true - } - return false -} - -func wipe(d []byte) { - for i := range d { - d[i] = 0 - } - d = nil -} - -func clear_dirCache(sessionID int) { - for k, _ := range sessions[sessionID].dirCache { - delete(sessions[sessionID].dirCache, k) - } -} - -func openBackingDir(sessionID int, relPath string) (dirfd int, cName string, err error) { - dirRelPath := nametransform.Dir(relPath) - // With PlaintextNames, we don't need to read DirIVs. Easy. - if sessions[sessionID].plainTextNames { - dirfd, err = syscallcompat.OpenDirNofollow(sessions[sessionID].root_cipher_dir, dirRelPath) - if err != nil { - return -1, "", err - } - // If relPath is empty, cName is ".". - cName = filepath.Base(relPath) - return dirfd, cName, nil - } - dir, ok := sessions[sessionID].dirCache[dirRelPath] - if ok { - // If relPath is empty, cName is ".". - if relPath == "" { - cache_dirfd, err := syscall.Dup(dir.fd) - if err != nil { - return -1, "", err - } - return cache_dirfd, ".", nil - } - name := filepath.Base(relPath) - cName, err = sessions[sessionID].nameTransform.EncryptAndHashName(name, dir.iv) - if err != nil { - syscall.Close(dir.fd) - return -1, "", err - } - cache_dirfd, err := syscall.Dup(dir.fd) - if err != nil { - return -1, "", err - } - return cache_dirfd, cName, nil - } - // Open cipherdir (following symlinks) - dirfd, err = syscall.Open(sessions[sessionID].root_cipher_dir, syscall.O_DIRECTORY|syscallcompat.O_PATH, 0) - if err != nil { - return -1, "", err - } - // If relPath is empty, cName is ".". - if relPath == "" { - return dirfd, ".", nil - } - // Walk the directory tree - parts := strings.Split(relPath, "/") - for i, name := range parts { - iv, err := nametransform.ReadDirIVAt(dirfd) - if err != nil { - syscall.Close(dirfd) - return -1, "", err - } - cName, err = sessions[sessionID].nameTransform.EncryptAndHashName(name, iv) - if err != nil { - syscall.Close(dirfd) - return -1, "", err - } - // Last part? We are done. - if i == len(parts)-1 { - cache_dirfd, err := syscall.Dup(dirfd) - if err == nil { - var dirRelPathCopy strings.Builder - dirRelPathCopy.WriteString(dirRelPath) - sessions[sessionID].dirCache[dirRelPathCopy.String()] = Directory{cache_dirfd, iv} - } - break - } - // Not the last part? Descend into next directory. - dirfd2, err := syscallcompat.Openat(dirfd, cName, syscall.O_NOFOLLOW|syscall.O_DIRECTORY|syscallcompat.O_PATH, 0) - syscall.Close(dirfd) - if err != nil { - return -1, "", err - } - dirfd = dirfd2 - } - return dirfd, cName, nil -} - -func mkdirWithIv(dirfd int, cName string, mode uint32) error { - err := syscallcompat.Mkdirat(dirfd, cName, mode) - if err != nil { - return err - } - dirfd2, err := syscallcompat.Openat(dirfd, cName, syscall.O_DIRECTORY|syscall.O_NOFOLLOW|syscallcompat.O_PATH, 0) - if err == nil { - // Create gocryptfs.diriv - err = nametransform.WriteDirIVAt(dirfd2) - syscall.Close(dirfd2) - } - if err != nil { - // Delete inconsistent directory (missing gocryptfs.diriv!) - err2 := syscallcompat.Unlinkat(dirfd, cName, unix.AT_REMOVEDIR) - if err2 != nil { - return err2 - } - } - return err -} - -func mangleOpenFlags(flags uint32) (newFlags int) { - newFlags = int(flags) - // Convert WRONLY to RDWR. We always need read access to do read-modify-write cycles. - if (newFlags & syscall.O_ACCMODE) == syscall.O_WRONLY { - newFlags = newFlags ^ os.O_WRONLY | os.O_RDWR - } - // We also cannot open the file in append mode, we need to seek back for RMW - newFlags = newFlags &^ os.O_APPEND - // O_DIRECT accesses must be aligned in both offset and length. Due to our - // crypto header, alignment will be off, even if userspace makes aligned - // accesses. Running xfstests generic/013 on ext4 used to trigger lots of - // EINVAL errors due to missing alignment. Just fall back to buffered IO. - newFlags = newFlags &^ syscallcompat.O_DIRECT - // Create and Open are two separate FUSE operations, so O_CREAT should not - // be part of the open flags. - newFlags = newFlags &^ syscall.O_CREAT - // We always want O_NOFOLLOW to be safe against symlink races - newFlags |= syscall.O_NOFOLLOW - return newFlags -} - -func register_file_handle(sessionID int, file File) int { - handleID := -1 - c := 0 - for handleID == -1 { - _, ok := sessions[sessionID].file_handles[c] - if !ok { - handleID = c - } - c++ - } - sessions[sessionID].file_handles[handleID] = file - return handleID -} - -func readFileID(fd *os.File) ([]byte, error) { - // We read +1 byte to determine if the file has actual content - // and not only the header. A header-only file will be considered empty. - // This makes File ID poisoning more difficult. - readLen := contentenc.HeaderLen + 1 - buf := make([]byte, readLen) - _, err := fd.ReadAt(buf, 0) - if err != nil { - return nil, err - } - buf = buf[:contentenc.HeaderLen] - h, err := contentenc.ParseHeader(buf) - if err != nil { - return nil, err - } - return h.ID, nil -} - -func createHeader(fd *os.File) (fileID []byte, err error) { - h := contentenc.RandomHeader() - buf := h.Pack() - // Prevent partially written (=corrupt) header by preallocating the space beforehand - //NoPrealloc - err = syscallcompat.EnospcPrealloc(int(fd.Fd()), 0, contentenc.HeaderLen) - if err != nil { - return nil, err - } - // Actually write header - _, err = fd.WriteAt(buf, 0) - if err != nil { - return nil, err - } - return h.ID, err -} - -func doRead(sessionID, handleID int, dst_buff []byte, offset uint64, length uint64) ([]byte, bool) { - f, ok := sessions[sessionID].file_handles[handleID] - if !ok { - return nil, false - } - fd := f.fd - var fileID []byte - test_fileID, ok := sessions[sessionID].fileIDs[handleID] - if ok { - fileID = test_fileID - } else { - var err error - fileID, err = readFileID(fd) - if err != nil || fileID == nil { - return nil, false - } - sessions[sessionID].fileIDs[handleID] = fileID - } - - // Read the backing ciphertext in one go - blocks := sessions[sessionID].contentEnc.ExplodePlainRange(offset, length) - alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks) - skip := blocks[0].Skip - - ciphertext := sessions[sessionID].contentEnc.CReqPool.Get() - ciphertext = ciphertext[:int(alignedLength)] - n, err := fd.ReadAt(ciphertext, int64(alignedOffset)) - if err != nil && err != io.EOF { - return nil, false - } - // The ReadAt came back empty. We can skip all the decryption and return early. - if n == 0 { - sessions[sessionID].contentEnc.CReqPool.Put(ciphertext) - return dst_buff, true - } - // Truncate ciphertext buffer down to actually read bytes - ciphertext = ciphertext[0:n] - - firstBlockNo := blocks[0].BlockNo - - // Decrypt it - plaintext, err := sessions[sessionID].contentEnc.DecryptBlocks(ciphertext, firstBlockNo, fileID) - sessions[sessionID].contentEnc.CReqPool.Put(ciphertext) - if err != nil { - return nil, false - } - - // Crop down to the relevant part - var out []byte - lenHave := len(plaintext) - lenWant := int(skip + length) - if lenHave > lenWant { - out = plaintext[skip:lenWant] - } else if lenHave > int(skip) { - out = plaintext[skip:lenHave] - } - // else: out stays empty, file was smaller than the requested offset - - out = append(dst_buff, out...) - sessions[sessionID].contentEnc.PReqPool.Put(plaintext) - return out, true -} - -func doWrite(sessionID, handleID int, data []byte, offset uint64) (uint32, bool) { - fileWasEmpty := false - f, ok := sessions[sessionID].file_handles[handleID] - if !ok { - return 0, false - } - fd := f.fd - var err error - var fileID []byte - test_fileID, ok := sessions[sessionID].fileIDs[handleID] - if ok { - fileID = test_fileID - } else { - fileID, err = readFileID(fd) - // Write a new file header if the file is empty - if err == io.EOF { - fileID, err = createHeader(fd) - fileWasEmpty = true - } - if err != nil { - return 0, false - } - sessions[sessionID].fileIDs[handleID] = fileID - } - // Handle payload data - dataBuf := bytes.NewBuffer(data) - blocks := sessions[sessionID].contentEnc.ExplodePlainRange(offset, uint64(len(data))) - toEncrypt := make([][]byte, len(blocks)) - for i, b := range blocks { - blockData := dataBuf.Next(int(b.Length)) - // Incomplete block -> Read-Modify-Write - if b.IsPartial() { - // Read - oldData, success := doRead(sessionID, handleID, nil, b.BlockPlainOff(), sessions[sessionID].contentEnc.PlainBS()) - if !success { - return 0, false - } - // Modify - blockData = sessions[sessionID].contentEnc.MergeBlocks(oldData, blockData, int(b.Skip)) - } - // Write into the to-encrypt list - toEncrypt[i] = blockData - } - // Encrypt all blocks - ciphertext := sessions[sessionID].contentEnc.EncryptBlocks(toEncrypt, blocks[0].BlockNo, fileID) - // Preallocate so we cannot run out of space in the middle of the write. - // This prevents partially written (=corrupt) blocks. - cOff := int64(blocks[0].BlockCipherOff()) - - //NoPrealloc - err = syscallcompat.EnospcPrealloc(int(fd.Fd()), cOff, int64(len(ciphertext))) - if err != nil { - if fileWasEmpty { - syscall.Ftruncate(int(fd.Fd()), 0) - // Kill the file header again - gcf_close_file(sessionID, handleID) //f.fileTableEntry.ID = nil - } - return 0, false - } - // Write - _, err = fd.WriteAt(ciphertext, cOff) - // Return memory to CReqPool - sessions[sessionID].contentEnc.CReqPool.Put(ciphertext) - if err != nil { - return 0, false - } - return uint32(len(data)), true -} - -// Zero-pad the file of size plainSize to the next block boundary. This is a no-op -// if the file is already block-aligned. -func zeroPad(sessionID, handleID int, plainSize uint64) bool { - lastBlockLen := plainSize % sessions[sessionID].contentEnc.PlainBS() - if lastBlockLen == 0 { - // Already block-aligned - return true - } - missing := sessions[sessionID].contentEnc.PlainBS() - lastBlockLen - pad := make([]byte, missing) - _, success := doWrite(sessionID, handleID, pad, plainSize) - return success -} - -// truncateGrowFile extends a file using seeking or ftruncate performing RMW on -// the first and last block as necessary. New blocks in the middle become -// file holes unless they have been fallocate()'d beforehand. -func truncateGrowFile(sessionID, handleID int, oldPlainSz uint64, newPlainSz uint64) bool { - if newPlainSz <= oldPlainSz { - return false - } - newEOFOffset := newPlainSz - 1 - if oldPlainSz > 0 { - n1 := sessions[sessionID].contentEnc.PlainOffToBlockNo(oldPlainSz - 1) - n2 := sessions[sessionID].contentEnc.PlainOffToBlockNo(newEOFOffset) - // The file is grown within one block, no need to pad anything. - // Write a single zero to the last byte and let doWrite figure out the RMW. - if n1 == n2 { - buf := make([]byte, 1) - _, success := doWrite(sessionID, handleID, buf, newEOFOffset) - return success - } - } - // The truncate creates at least one new block. - // - // Make sure the old last block is padded to the block boundary. This call - // is a no-op if it is already block-aligned. - success := zeroPad(sessionID, handleID, oldPlainSz) - if !success { - return false - } - // The new size is block-aligned. In this case we can do everything ourselves - // and avoid the call to doWrite. - if newPlainSz%sessions[sessionID].contentEnc.PlainBS() == 0 { - // The file was empty, so it did not have a header. Create one. - if oldPlainSz == 0 { - id, err := createHeader(sessions[sessionID].file_handles[handleID].fd) - if err != nil { - return false - } - sessions[sessionID].fileIDs[handleID] = id - } - cSz := int64(sessions[sessionID].contentEnc.PlainSizeToCipherSize(newPlainSz)) - return err_to_bool(syscall.Ftruncate(int(sessions[sessionID].file_handles[handleID].fd.Fd()), cSz)) - } - // The new size is NOT aligned, so we need to write a partial block. - // Write a single zero to the last byte and let doWrite figure it out. - buf := make([]byte, 1) - _, success = doWrite(sessionID, handleID, buf, newEOFOffset) - return success -} - -func truncate(sessionID, handleID int, newSize uint64) bool { - fileFD := int(sessions[sessionID].file_handles[handleID].fd.Fd()) - /*// Common case first: Truncate to zero - if newSize == 0 { - err = syscall.Ftruncate(fileFD, 0) - if err != nil { - return false - } - // Truncate to zero kills the file header - f.fileTableEntry.ID = nil - return true - }*/ - // We need the old file size to determine if we are growing or shrinking - // the file - oldSize, _, success := gcf_get_attrs(sessionID, sessions[sessionID].file_handles[handleID].path) - if !success { - return false - } - - // File size stays the same - nothing to do - if newSize == oldSize { - return true - } - // File grows - if newSize > oldSize { - return truncateGrowFile(sessionID, handleID, oldSize, newSize) - } - - // File shrinks - blockNo := sessions[sessionID].contentEnc.PlainOffToBlockNo(newSize) - cipherOff := sessions[sessionID].contentEnc.BlockNoToCipherOff(blockNo) - plainOff := sessions[sessionID].contentEnc.BlockNoToPlainOff(blockNo) - lastBlockLen := newSize - plainOff - var data []byte - if lastBlockLen > 0 { - data, success = doRead(sessionID, handleID, nil, plainOff, lastBlockLen) - if !success { - return false - } - } - // Truncate down to the last complete block - err := syscall.Ftruncate(fileFD, int64(cipherOff)) - if err != nil { - return false - } - // Append partial block - if lastBlockLen > 0 { - _, success := doWrite(sessionID, handleID, data, plainOff) - return success - } - return true -} - -func init_new_session(root_cipher_dir string, masterkey []byte, cf *configfile.ConfFile) int { - // Initialize EME for filename encryption. - var emeCipher *eme.EMECipher - var err error - var emeBlockCipher cipher.Block - emeKey := cryptocore.HkdfDerive(masterkey, cryptocore.HkdfInfoEMENames, cryptocore.KeyLen) - emeBlockCipher, err = aes.NewCipher(emeKey) - for i := range emeKey { - emeKey[i] = 0 - } - if err == nil { - var new_session SessionVars - - new_session.plainTextNames = cf.IsFeatureFlagSet(configfile.FlagPlaintextNames) - - emeCipher = eme.New(emeBlockCipher) - new_session.nameTransform = nametransform.New(emeCipher, true, true) - - // Initialize contentEnc - cryptoBackend := cryptocore.BackendGoGCM - if cf.IsFeatureFlagSet(configfile.FlagAESSIV) { - cryptoBackend = cryptocore.BackendAESSIV - } else if stupidgcm.PreferOpenSSL() { - cryptoBackend = cryptocore.BackendOpenSSL - } - forcedecode := false - new_session.cryptoCore = cryptocore.New(masterkey, cryptoBackend, contentenc.DefaultIVBits, true, forcedecode) - new_session.contentEnc = contentenc.New(new_session.cryptoCore, contentenc.DefaultBS, forcedecode) - - //copying root_cipher_dir - var grcd strings.Builder - grcd.WriteString(root_cipher_dir) - new_session.root_cipher_dir = grcd.String() - - // New empty caches - new_session.dirCache = make(map[string]Directory) - new_session.file_handles = make(map[int]File) - new_session.fileIDs = make(map[int][]byte) - - //find unused sessionID - sessionID := -1 - c := 0 - for sessionID == -1 { - _, ok := sessions[c] - if !ok { - sessionID = c - } - c++ - } - if sessions == nil { - sessions = make(map[int]SessionVars) - } - sessions[sessionID] = new_session - return sessionID - } - return -1 -} - -//export gcf_init -func gcf_init(root_cipher_dir string, password, givenScryptHash, returnedScryptHashBuff []byte) int { - sessionID := -1 - cf, err := configfile.Load(filepath.Join(root_cipher_dir, configfile.ConfDefaultName)) - if err == nil { - masterkey := cf.GetMasterkey(password, givenScryptHash, returnedScryptHashBuff) - if masterkey != nil { - sessionID = init_new_session(root_cipher_dir, masterkey, cf) - wipe(masterkey) - } - } - return sessionID -} - -//export gcf_close -func gcf_close(sessionID int) { - sessions[sessionID].cryptoCore.Wipe() - for handleID, _ := range sessions[sessionID].file_handles { - gcf_close_file(sessionID, handleID) - } - clear_dirCache(sessionID) - delete(sessions, sessionID) -} - -//export gcf_is_closed -func gcf_is_closed(sessionID int) bool { - _, ok := sessions[sessionID] - return !ok -} - -//export gcf_create_volume -func gcf_create_volume(root_cipher_dir string, password []byte, logN int, creator string) bool { - err := configfile.Create(filepath.Join(root_cipher_dir, configfile.ConfDefaultName), password, false, logN, creator, false, false) - if err == nil { - dirfd, err := syscall.Open(root_cipher_dir, syscall.O_DIRECTORY|syscallcompat.O_PATH, 0) - if err == nil { - err = nametransform.WriteDirIVAt(dirfd) - syscall.Close(dirfd) - return err_to_bool(err) - } - } - return false -} - -//export gcf_change_password -func gcf_change_password(root_cipher_dir string, old_password, givenScryptHash, new_password, returnedScryptHashBuff []byte) bool { - success := false - cf, err := configfile.Load(filepath.Join(root_cipher_dir, configfile.ConfDefaultName)) - if err == nil { - masterkey := cf.GetMasterkey(old_password, givenScryptHash, nil) - if masterkey != nil { - logN := cf.ScryptObject.LogN() - scryptHash := cf.EncryptKey(masterkey, new_password, logN, len(returnedScryptHashBuff) > 0) - wipe(masterkey) - for i := range scryptHash { - returnedScryptHashBuff[i] = scryptHash[i] - scryptHash[i] = 0 - } - success = err_to_bool(cf.WriteFile()) - } - } - return success -} - -//export gcf_list_dir -func gcf_list_dir(sessionID int, dirName string) (*C.char, *C.int, C.int) { - parentDirFd, cDirName, err := openBackingDir(sessionID, dirName) - if err != nil { - return nil, nil, 0 - } - defer syscall.Close(parentDirFd) - // Read ciphertext directory - var cipherEntries []syscallcompat.DirEntry - fd, err := syscallcompat.Openat(parentDirFd, cDirName, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) - if err != nil { - return nil, nil, 0 - } - defer syscall.Close(fd) - cipherEntries, err = syscallcompat.Getdents(fd) - if err != nil { - return nil, nil, 0 - } - // Get DirIV (stays nil if PlaintextNames is used) - var cachedIV []byte - if !sessions[sessionID].plainTextNames { - // Read the DirIV from disk - cachedIV, err = nametransform.ReadDirIVAt(fd) - if err != nil { - return nil, nil, 0 - } - } - // Decrypted directory entries - var plain strings.Builder - var modes []uint32 - // Filter and decrypt filenames - for i := range cipherEntries { - cName := cipherEntries[i].Name - if dirName == "" && cName == configfile.ConfDefaultName { - // silently ignore "gocryptfs.conf" in the top level dir - continue - } - if sessions[sessionID].plainTextNames { - plain.WriteString(cipherEntries[i].Name + "\x00") - modes = append(modes, cipherEntries[i].Mode) - continue - } - if cName == nametransform.DirIVFilename { - // silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled - continue - } - // Handle long file name - isLong := nametransform.NameType(cName) - if isLong == nametransform.LongNameContent { - cNameLong, err := nametransform.ReadLongNameAt(fd, cName) - if err != nil { - continue - } - cName = cNameLong - } else if isLong == nametransform.LongNameFilename { - // ignore "gocryptfs.longname.*.name" - continue - } - name, err := sessions[sessionID].nameTransform.DecryptName(cName, cachedIV) - if err != nil { - continue - } - // Override the ciphertext name with the plaintext name but reuse the rest - // of the structure - cipherEntries[i].Name = name - plain.WriteString(cipherEntries[i].Name + "\x00") - modes = append(modes, cipherEntries[i].Mode) - } - p := C.malloc(C.ulong(C.sizeof_int * len(modes))) - for i := 0; i < len(modes); i++ { - offset := C.sizeof_int * uintptr(i) - *(*C.int)(unsafe.Pointer(uintptr(p) + offset)) = (C.int)(modes[i]) - } - return C.CString(plain.String()), (*C.int)(p), (C.int)(len(modes)) -} - -//export gcf_mkdir -func gcf_mkdir(sessionID int, newPath string) bool { - dirfd, cName, err := openBackingDir(sessionID, newPath) - if err != nil { - return false - } - defer syscall.Close(dirfd) - - if sessions[sessionID].plainTextNames { - err = syscallcompat.Mkdirat(dirfd, cName, folder_mode) - if err != nil { - return false - } - var ust unix.Stat_t - err = syscallcompat.Fstatat(dirfd, cName, &ust, unix.AT_SYMLINK_NOFOLLOW) - if err != nil { - return false - } - } else { - // We need write and execute permissions to create gocryptfs.diriv. - // Also, we need read permissions to open the directory (to avoid - // race-conditions between getting and setting the mode). - origMode := folder_mode - mode := folder_mode | 0700 - - // Handle long file name - if nametransform.IsLongContent(cName) { - // Create ".name" - err = sessions[sessionID].nameTransform.WriteLongNameAt(dirfd, cName, newPath) - if err != nil { - return false - } - - // Create directory - err = mkdirWithIv(dirfd, cName, mode) - if err != nil { - nametransform.DeleteLongNameAt(dirfd, cName) - return false - } - } else { - err = mkdirWithIv(dirfd, cName, mode) - if err != nil { - return false - } - } - // Set mode - if origMode != mode { - dirfd2, err := syscallcompat.Openat(dirfd, cName, - syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) - if err != nil { - return false - } - defer syscall.Close(dirfd2) - - var st syscall.Stat_t - err = syscall.Fstat(dirfd2, &st) - if err != nil { - return false - } - - // Preserve SGID bit if it was set due to inheritance. - origMode = uint32(st.Mode&^0777) | origMode - err = syscall.Fchmod(dirfd2, origMode) - if err != nil { - return false - } - } - } - return true -} - -//export gcf_rmdir -func gcf_rmdir(sessionID int, relPath string) bool { - defer clear_dirCache(sessionID) - parentDirFd, cName, err := openBackingDir(sessionID, relPath) - if err != nil { - return false - } - defer syscall.Close(parentDirFd) - if sessions[sessionID].plainTextNames { - // Unlinkat with AT_REMOVEDIR is equivalent to Rmdir - err = unix.Unlinkat(parentDirFd, cName, unix.AT_REMOVEDIR) - return err_to_bool(err) - } - dirfd, err := syscallcompat.Openat(parentDirFd, cName, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0) - if err != nil { - return false - } - defer syscall.Close(dirfd) - // Check directory contents - children, err := syscallcompat.Getdents(dirfd) - if err == io.EOF { - // The directory is empty - err = unix.Unlinkat(parentDirFd, cName, unix.AT_REMOVEDIR) - return err_to_bool(err) - } - if err != nil { - return false - } - // If the directory is not empty besides gocryptfs.diriv, do not even - // attempt the dance around gocryptfs.diriv. - if len(children) > 1 { - return false - } - // Move "gocryptfs.diriv" to the parent dir as "gocryptfs.diriv.rmdir.XYZ" - tmpName := fmt.Sprintf("%s.rmdir.%d", nametransform.DirIVFilename, cryptocore.RandUint64()) - err = syscallcompat.Renameat(dirfd, nametransform.DirIVFilename, parentDirFd, tmpName) - if err != nil { - return false - } - // Actual Rmdir - err = syscallcompat.Unlinkat(parentDirFd, cName, unix.AT_REMOVEDIR) - if err != nil { - // This can happen if another file in the directory was created in the - // meantime, undo the rename - err2 := syscallcompat.Renameat(parentDirFd, tmpName, dirfd, nametransform.DirIVFilename) - return err_to_bool(err2) - } - // Delete "gocryptfs.diriv.rmdir.XYZ" - err = syscallcompat.Unlinkat(parentDirFd, tmpName, 0) - // Delete .name file - if nametransform.IsLongContent(cName) { - nametransform.DeleteLongNameAt(parentDirFd, cName) - } - return true -} - -//export gcf_open_read_mode -func gcf_open_read_mode(sessionID int, path string) int { - newFlags := mangleOpenFlags(0) - dirfd, cName, err := openBackingDir(sessionID, path) - if err != nil { - return -1 - } - defer syscall.Close(dirfd) - fd, err := syscallcompat.Openat(dirfd, cName, newFlags, 0) - if err != nil { - return -1 - } - return register_file_handle(sessionID, File{os.NewFile(uintptr(fd), cName), path}) -} - -//export gcf_open_write_mode -func gcf_open_write_mode(sessionID int, path string) int { - newFlags := mangleOpenFlags(syscall.O_RDWR) - dirfd, cName, err := openBackingDir(sessionID, path) - if err != nil { - return -1 - } - defer syscall.Close(dirfd) - fd := -1 - // Handle long file name - if !sessions[sessionID].plainTextNames && nametransform.IsLongContent(cName) { - // Create ".name" - err = sessions[sessionID].nameTransform.WriteLongNameAt(dirfd, cName, path) - if err != nil { - return -1 - } - // Create content - fd, err = syscallcompat.Openat(dirfd, cName, newFlags|syscall.O_CREAT, file_mode) - if err != nil { - nametransform.DeleteLongNameAt(dirfd, cName) - } - } else { - // Create content, normal (short) file name - fd, err = syscallcompat.Openat(dirfd, cName, newFlags|syscall.O_CREAT, file_mode) - } - if err != nil { - // xfstests generic/488 triggers this - if err == syscall.EMFILE { - var lim syscall.Rlimit - syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim) - } - return -1 - } - return register_file_handle(sessionID, File{os.NewFile(uintptr(fd), cName), path}) -} - -//export gcf_truncate -func gcf_truncate(sessionID int, path string, offset uint64) bool { - handleID := gcf_open_write_mode(sessionID, path) - if handleID != -1 { - success := truncate(sessionID, handleID, offset) - gcf_close_file(sessionID, handleID) - return success - } - return false -} - -//export gcf_close_file -func gcf_close_file(sessionID, handleID int) { - f, ok := sessions[sessionID].file_handles[handleID] - if ok { - f.fd.Close() - delete(sessions[sessionID].file_handles, handleID) - _, ok := sessions[sessionID].fileIDs[handleID] - if ok { - delete(sessions[sessionID].fileIDs, handleID) - } - } -} - -//export gcf_read_file -func gcf_read_file(sessionID, handleID int, offset uint64, dst_buff []byte) uint32 { - length := uint64(len(dst_buff)) - if length > contentenc.MAX_KERNEL_WRITE { - return 0 - } - - out, _ := doRead(sessionID, handleID, dst_buff[:0], offset, length) - - return uint32(len(out)) -} - -//export gcf_write_file -func gcf_write_file(sessionID, handleID int, offset uint64, data []byte) uint32 { - length := uint64(len(data)) - if length > contentenc.MAX_KERNEL_WRITE { - return 0 - } - - written, _ := doWrite(sessionID, handleID, data, offset) - - return written -} - -//export gcf_get_attrs -func gcf_get_attrs(sessionID int, relPath string) (uint64, int64, bool) { - dirfd, cName, err := openBackingDir(sessionID, relPath) - if err != nil { - return 0, 0, false - } - var st unix.Stat_t - err = syscallcompat.Fstatat(dirfd, cName, &st, unix.AT_SYMLINK_NOFOLLOW) - syscall.Close(dirfd) - if err != nil { - return 0, 0, false - } - return sessions[sessionID].contentEnc.CipherSizeToPlainSize(uint64(st.Size)), st.Mtim.Sec, true -} - -//export gcf_rename -func gcf_rename(sessionID int, oldPath string, newPath string) bool { - defer clear_dirCache(sessionID) - oldDirfd, oldCName, err := openBackingDir(sessionID, oldPath) - if err != nil { - return false - } - defer syscall.Close(oldDirfd) - newDirfd, newCName, err := openBackingDir(sessionID, newPath) - if err != nil { - return false - } - defer syscall.Close(newDirfd) - - // Easy case. - if sessions[sessionID].plainTextNames { - return err_to_bool(syscallcompat.Renameat(oldDirfd, oldCName, newDirfd, newCName)) - } - // Long destination file name: create .name file - nameFileAlreadyThere := false - if nametransform.IsLongContent(newCName) { - err = sessions[sessionID].nameTransform.WriteLongNameAt(newDirfd, newCName, newPath) - // Failure to write the .name file is expected when the target path already - // exists. Since hashes are pretty unique, there is no need to modify the - // .name file in this case, and we ignore the error. - if err == syscall.EEXIST { - nameFileAlreadyThere = true - } else if err != nil { - return false - } - } - // Actual rename - err = syscallcompat.Renameat(oldDirfd, oldCName, newDirfd, newCName) - if err == syscall.ENOTEMPTY || err == syscall.EEXIST { - // If an empty directory is overwritten we will always get an error as - // the "empty" directory will still contain gocryptfs.diriv. - // Interestingly, ext4 returns ENOTEMPTY while xfs returns EEXIST. - // We handle that by trying to fs.Rmdir() the target directory and trying - // again. - if gcf_rmdir(sessionID, newPath) { - err = syscallcompat.Renameat(oldDirfd, oldCName, newDirfd, newCName) - } - } - if err != nil { - if nametransform.IsLongContent(newCName) && nameFileAlreadyThere == false { - // Roll back .name creation unless the .name file was already there - nametransform.DeleteLongNameAt(newDirfd, newCName) - } - return false - } - if nametransform.IsLongContent(oldCName) { - nametransform.DeleteLongNameAt(oldDirfd, oldCName) - } - return true -} - -//export gcf_remove_file -func gcf_remove_file(sessionID int, path string) bool { - dirfd, cName, err := openBackingDir(sessionID, path) - if err != nil { - return false - } - defer syscall.Close(dirfd) - // Delete content - err = syscallcompat.Unlinkat(dirfd, cName, 0) - if err != nil { - return false - } - // Delete ".name" file - if !sessions[sessionID].plainTextNames && nametransform.IsLongContent(cName) { - err = nametransform.DeleteLongNameAt(dirfd, cName) - } - return err_to_bool(err) -} - -func main() {} diff --git a/app/libgocryptfs/rewrites/configfile/config_file.go b/app/libgocryptfs/rewrites/configfile/config_file.go deleted file mode 100644 index 4e82661..0000000 --- a/app/libgocryptfs/rewrites/configfile/config_file.go +++ /dev/null @@ -1,325 +0,0 @@ -// Package configfile reads and writes gocryptfs.conf does the key -// wrapping. -package configfile - -import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "syscall" - - "../contentenc" - "../../gocryptfs_internal/cryptocore" - "../../gocryptfs_internal/exitcodes" -) -import "os" - -const ( - // ConfDefaultName is the default configuration file name. - // The dot "." is not used in base64url (RFC4648), hence - // we can never clash with an encrypted file. - ConfDefaultName = "gocryptfs.conf" - // ConfReverseName is the default configuration file name in reverse mode, - // the config file gets stored next to the plain-text files. Make it hidden - // (start with dot) to not annoy the user. - ConfReverseName = ".gocryptfs.reverse.conf" -) - -// ConfFile is the content of a config file. -type ConfFile struct { - // Creator is the gocryptfs version string. - // This only documents the config file for humans who look at it. The actual - // technical info is contained in FeatureFlags. - Creator string - // EncryptedKey holds an encrypted AES key, unlocked using a password - // hashed with scrypt - EncryptedKey []byte - // ScryptObject stores parameters for scrypt hashing (key derivation) - ScryptObject ScryptKDF - // Version is the On-Disk-Format version this filesystem uses - Version uint16 - // FeatureFlags is a 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 - // Filename is the name of the config file. Not exported to JSON. - filename string -} - -// randBytesDevRandom gets "n" random bytes from /dev/random or panics -func randBytesDevRandom(n int) []byte { - f, err := os.Open("/dev/random") - if err != nil { - log.Panic("Failed to open /dev/random: " + err.Error()) - } - defer f.Close() - b := make([]byte, n) - _, err = io.ReadFull(f, b) - if err != nil { - log.Panic("Failed to read random bytes: " + err.Error()) - } - return b -} - -// Create - create a new config with a random key encrypted with -// "password" and write it to "filename". -// Uses scrypt with cost parameter logN. -func Create(filename string, password []byte, plaintextNames bool, - logN int, creator string, aessiv bool, devrandom bool) error { - var cf ConfFile - cf.filename = filename - cf.Creator = creator - cf.Version = contentenc.CurrentVersion - - // Set feature flags - cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagGCMIV128]) - cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagHKDF]) - if plaintextNames { - cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagPlaintextNames]) - } else { - cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagDirIV]) - cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagEMENames]) - cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagLongNames]) - cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagRaw64]) - } - if aessiv { - cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagAESSIV]) - } - { - // Generate new random master key - var key []byte - if devrandom { - key = randBytesDevRandom(cryptocore.KeyLen) - } else { - key = cryptocore.RandBytes(cryptocore.KeyLen) - } - // Encrypt it using the password - // This sets ScryptObject and EncryptedKey - // Note: this looks at the FeatureFlags, so call it AFTER setting them. - cf.EncryptKey(key, password, logN, false) - for i := range key { - key[i] = 0 - } - // key runs out of scope here - } - // Write file to disk - return cf.WriteFile() -} - -// LoadAndDecrypt - read config file from disk and decrypt the -// contained key using "password". -// Returns the decrypted key and the ConfFile object -// -// If "password" is empty, the config file is read -// but the key is not decrypted (returns nil in its place). -func LoadAndDecrypt(filename string, password []byte) ([]byte, *ConfFile, error) { - cf, err := Load(filename) - if err != nil { - return nil, nil, err - } - if len(password) == 0 { - // We have validated the config file, but without a password we cannot - // decrypt the master key. Return only the parsed config. - return nil, cf, nil - // TODO: Make this an error in gocryptfs v1.7. All code should now call - // Load() instead of calling LoadAndDecrypt() with an empty password. - } - - // Decrypt the masterkey using the password - key, _, err := cf.DecryptMasterKey(password, false) - if err != nil { - return nil, nil, err - } - - return key, cf, err -} - -// Load loads and parses the config file at "filename". -func Load(filename string) (*ConfFile, error) { - var cf ConfFile - cf.filename = filename - - // Read from disk - js, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - if len(js) == 0 { - return nil, fmt.Errorf("Config file is empty") - } - - // Unmarshal - err = json.Unmarshal(js, &cf) - if err != nil { - return nil, err - } - - if cf.Version != contentenc.CurrentVersion { - return nil, fmt.Errorf("Unsupported on-disk format %d", cf.Version) - } - - // Check that all set feature flags are known - for _, flag := range cf.FeatureFlags { - if !cf.isFeatureFlagKnown(flag) { - return nil, fmt.Errorf("Unsupported feature flag %q", flag) - } - } - - // Check that all required feature flags are set - var requiredFlags []flagIota - if cf.IsFeatureFlagSet(FlagPlaintextNames) { - requiredFlags = requiredFlagsPlaintextNames - } else { - requiredFlags = requiredFlagsNormal - } - deprecatedFs := false - for _, i := range requiredFlags { - if !cf.IsFeatureFlagSet(i) { - fmt.Fprintf(os.Stderr, "Required feature flag %q is missing\n", knownFlags[i]) - deprecatedFs = true - } - } - if deprecatedFs { - return nil, exitcodes.NewErr("Deprecated filesystem", exitcodes.DeprecatedFS) - } - - // All good - return &cf, nil -} - -// DecryptMasterKey decrypts the masterkey stored in cf.EncryptedKey using -// password. -func (cf *ConfFile) DecryptMasterKey(password []byte, giveHash bool) (masterkey, scryptHash []byte, err error) { - // Generate derived key from password - scryptHash = cf.ScryptObject.DeriveKey(password) - - // Unlock master key using password-based key - useHKDF := cf.IsFeatureFlagSet(FlagHKDF) - ce := GetKeyEncrypter(scryptHash, useHKDF) - - masterkey, err = ce.DecryptBlock(cf.EncryptedKey, 0, nil) - - ce.Wipe() - ce = nil - - if err != nil { - return nil, nil, exitcodes.NewErr("Password incorrect.", exitcodes.PasswordIncorrect) - } - - if !giveHash { - // Purge scrypt-derived key - for i := range scryptHash { - scryptHash[i] = 0 - } - scryptHash = nil - } - - return masterkey, scryptHash, 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 []byte, logN int, giveHash bool) []byte { - // Generate scrypt-derived key from password - cf.ScryptObject = NewScryptKDF(logN) - scryptHash := cf.ScryptObject.DeriveKey(password) - - // Lock master key using password-based key - useHKDF := cf.IsFeatureFlagSet(FlagHKDF) - ce := GetKeyEncrypter(scryptHash, useHKDF) - cf.EncryptedKey = ce.EncryptBlock(key, 0, nil) - - if !giveHash { - // Purge scrypt-derived key - for i := range scryptHash { - scryptHash[i] = 0 - } - scryptHash = nil - } - ce.Wipe() - ce = nil - - return scryptHash -} - -// DroidFS function to allow masterkey to be decrypted directely using the scrypt hash and return it if requested -func (cf *ConfFile) GetMasterkey(password, givenScryptHash, returnedScryptHashBuff []byte) []byte { - var masterkey []byte - var err error - var scryptHash []byte - if len(givenScryptHash) > 0 { //decrypt with hash - useHKDF := cf.IsFeatureFlagSet(FlagHKDF) - ce := GetKeyEncrypter(givenScryptHash, useHKDF) - masterkey, err = ce.DecryptBlock(cf.EncryptedKey, 0, nil) - ce.Wipe() - ce = nil - if err == nil { - return masterkey - } - } else { //decrypt with password - masterkey, scryptHash, err = cf.DecryptMasterKey(password, len(returnedScryptHashBuff)>0) - //copy and wipe scryptHash - for i := range scryptHash { - returnedScryptHashBuff[i] = scryptHash[i] - scryptHash[i] = 0 - } - if err == nil { - return masterkey - } - } - return 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 - } - // For convenience for the user, add a newline at the end. - js = append(js, '\n') - _, err = fd.Write(js) - if err != nil { - return err - } - err = fd.Sync() - if err != nil { - // This can happen on network drives: FRITZ.NAS mounted on MacOS returns - // "operation not supported": https://github.com/rfjakob/gocryptfs/issues/390 - // Try sync instead - syscall.Sync() - } - err = fd.Close() - if err != nil { - return err - } - err = os.Rename(tmp, cf.filename) - return err -} - -// getKeyEncrypter is a helper function that returns the right ContentEnc -// instance for the "useHKDF" setting. -func GetKeyEncrypter(scryptHash []byte, useHKDF bool) *contentenc.ContentEnc { - IVLen := 96 - // gocryptfs v1.2 and older used 96-bit IVs for master key encryption. - // v1.3 adds the "HKDF" feature flag, which also enables 128-bit nonces. - if useHKDF { - IVLen = contentenc.DefaultIVBits - } - cc := cryptocore.New(scryptHash, cryptocore.BackendGoGCM, IVLen, useHKDF, false) - ce := contentenc.New(cc, 4096, false) - return ce -} diff --git a/app/libgocryptfs/rewrites/configfile/feature_flags.go b/app/libgocryptfs/rewrites/configfile/feature_flags.go deleted file mode 100644 index 2d609f2..0000000 --- a/app/libgocryptfs/rewrites/configfile/feature_flags.go +++ /dev/null @@ -1,74 +0,0 @@ -package configfile - -type flagIota int - -const ( - // FlagPlaintextNames indicates that filenames are unencrypted. - FlagPlaintextNames flagIota = iota - // FlagDirIV indicates that a per-directory IV file is used. - FlagDirIV - // FlagEMENames indicates EME (ECB-Mix-ECB) filename encryption. - // This flag is mandatory since gocryptfs v1.0. - FlagEMENames - // FlagGCMIV128 indicates 128-bit GCM IVs. - // This flag is mandatory since gocryptfs v1.0. - FlagGCMIV128 - // FlagLongNames allows file names longer than 176 bytes. - FlagLongNames - // FlagAESSIV selects an AES-SIV based crypto backend. - FlagAESSIV - // FlagRaw64 enables raw (unpadded) base64 encoding for file names - FlagRaw64 - // FlagHKDF enables HKDF-derived keys for use with GCM, EME and SIV - // instead of directly using the master key (GCM and EME) or the SHA-512 - // hashed master key (SIV). - // Note that this flag does not change the password hashing algorithm - // which always is scrypt. - FlagHKDF -) - -// knownFlags stores the known feature flags and their string representation -var knownFlags = map[flagIota]string{ - FlagPlaintextNames: "PlaintextNames", - FlagDirIV: "DirIV", - FlagEMENames: "EMENames", - FlagGCMIV128: "GCMIV128", - FlagLongNames: "LongNames", - FlagAESSIV: "AESSIV", - FlagRaw64: "Raw64", - FlagHKDF: "HKDF", -} - -// Filesystems that do not have these feature flags set are deprecated. -var requiredFlagsNormal = []flagIota{ - FlagDirIV, - FlagEMENames, - FlagGCMIV128, -} - -// Filesystems without filename encryption obviously don't have or need the -// filename related feature flags. -var requiredFlagsPlaintextNames = []flagIota{ - FlagGCMIV128, -} - -// isFeatureFlagKnown verifies that we understand a feature flag. -func (cf *ConfFile) isFeatureFlagKnown(flag string) bool { - for _, knownFlag := range knownFlags { - if knownFlag == flag { - return true - } - } - return false -} - -// IsFeatureFlagSet returns true if the feature flag "flagWant" is enabled. -func (cf *ConfFile) IsFeatureFlagSet(flagWant flagIota) bool { - flagString := knownFlags[flagWant] - for _, flag := range cf.FeatureFlags { - if flag == flagString { - return true - } - } - return false -} diff --git a/app/libgocryptfs/rewrites/configfile/scrypt.go b/app/libgocryptfs/rewrites/configfile/scrypt.go deleted file mode 100644 index 02f404f..0000000 --- a/app/libgocryptfs/rewrites/configfile/scrypt.go +++ /dev/null @@ -1,101 +0,0 @@ -package configfile - -import ( - "log" - "math" - - "golang.org/x/crypto/scrypt" - - "../../gocryptfs_internal/cryptocore" -) - -const ( - // ScryptDefaultLogN is the default scrypt logN configuration parameter. - // logN=16 (N=2^16) uses 64MB of memory and takes 4 seconds on my Atom Z3735F - // netbook. - ScryptDefaultLogN = 16 - // From RFC7914, section 2: - // At the current time, r=8 and p=1 appears to yield good - // results, but as memory latency and CPU parallelism increase, it is - // likely that the optimum values for both r and p will increase. - // We reject all lower values that we might get through modified config files. - scryptMinR = 8 - scryptMinP = 1 - // logN=10 takes 6ms on a Pentium G630. This should be fast enough for all - // purposes. We reject lower values. - scryptMinLogN = 10 - // We always generate 32-byte salts. Anything smaller than that is rejected. - scryptMinSaltLen = 32 -) - -// ScryptKDF is an instance of the scrypt key deriviation function. -type ScryptKDF struct { - // Salt is the random salt that is passed to scrypt - Salt []byte - // N: scrypt CPU/Memory cost parameter - N int - // R: scrypt block size parameter - R int - // P: scrypt parallelization parameter - P int - // KeyLen is the output data length - KeyLen int -} - -// NewScryptKDF returns a new instance of ScryptKDF. -func NewScryptKDF(logN int) ScryptKDF { - var s ScryptKDF - s.Salt = cryptocore.RandBytes(cryptocore.KeyLen) - if logN <= 0 { - s.N = 1 << ScryptDefaultLogN - } else { - s.N = 1 << uint32(logN) - } - s.R = 8 // Always 8 - s.P = 1 // Always 1 - s.KeyLen = cryptocore.KeyLen - return s -} - -// DeriveKey returns a new key from a supplied password. -func (s *ScryptKDF) DeriveKey(pw []byte) []byte { - if s.validateParams() { - k, err := scrypt.Key(pw, s.Salt, s.N, s.R, s.P, s.KeyLen) - if err != nil { - log.Panicf("DeriveKey failed: %v", err) - } - return k - } else { - return nil - } -} - -// 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) -} - -// validateParams checks that all parameters are at or above hardcoded limits. -// If not, it exists with an error message. -// This makes sure we do not get weak parameters passed through a -// rougue gocryptfs.conf. -func (s *ScryptKDF) validateParams() bool { - minN := 1 << scryptMinLogN - if s.N < minN { - return false//os.Exit(exitcodes.ScryptParams) - } - if s.R < scryptMinR { - return false//os.Exit(exitcodes.ScryptParams) - } - if s.P < scryptMinP { - return false//os.Exit(exitcodes.ScryptParams) - } - if len(s.Salt) < scryptMinSaltLen { - return false//os.Exit(exitcodes.ScryptParams) - } - if s.KeyLen < cryptocore.KeyLen { - return false//os.Exit(exitcodes.ScryptParams) - } - return true -} diff --git a/app/libgocryptfs/rewrites/contentenc/bpool.go b/app/libgocryptfs/rewrites/contentenc/bpool.go deleted file mode 100644 index c4517d3..0000000 --- a/app/libgocryptfs/rewrites/contentenc/bpool.go +++ /dev/null @@ -1,39 +0,0 @@ -package contentenc - -import ( - "log" - "sync" -) - -// bPool is a byte slice pool -type bPool struct { - sync.Pool - sliceLen int -} - -func newBPool(sliceLen int) bPool { - return bPool{ - Pool: sync.Pool{ - New: func() interface{} { return make([]byte, sliceLen) }, - }, - sliceLen: sliceLen, - } -} - -// Put grows the slice "s" to its maximum capacity and puts it into the pool. -func (b *bPool) Put(s []byte) { - s = s[:cap(s)] - if len(s) != b.sliceLen { - log.Panicf("wrong len=%d, want=%d", len(s), b.sliceLen) - } - b.Pool.Put(s) -} - -// Get returns a byte slice from the pool. -func (b *bPool) Get() (s []byte) { - s = b.Pool.Get().([]byte) - if len(s) != b.sliceLen { - log.Panicf("wrong len=%d, want=%d", len(s), b.sliceLen) - } - return s -} diff --git a/app/libgocryptfs/rewrites/contentenc/content.go b/app/libgocryptfs/rewrites/contentenc/content.go deleted file mode 100644 index 682a8fa..0000000 --- a/app/libgocryptfs/rewrites/contentenc/content.go +++ /dev/null @@ -1,335 +0,0 @@ -// Package contentenc encrypts and decrypts file blocks. -package contentenc - -import ( - "bytes" - "encoding/binary" - "errors" - "log" - "runtime" - "sync" - - "../../gocryptfs_internal/cryptocore" - "../../gocryptfs_internal/stupidgcm" -) - -// NonceMode determines how nonces are created. -type NonceMode int - -const ( - //value from FUSE doc - MAX_KERNEL_WRITE = 128 * 1024 - - - // DefaultBS is the default plaintext block size - DefaultBS = 4096 - // DefaultIVBits is the default length of IV, in bits. - // We always use 128-bit IVs for file content, but the - // master key in the config file is encrypted with a 96-bit IV for - // gocryptfs v1.2 and earlier. v1.3 switched to 128 bit. - DefaultIVBits = 128 - - _ = iota // skip zero - // RandomNonce chooses a random nonce. - RandomNonce NonceMode = iota - // ReverseDeterministicNonce chooses a deterministic nonce, suitable for - // use in reverse mode. - ReverseDeterministicNonce NonceMode = iota - // ExternalNonce derives a nonce from external sources. - ExternalNonce NonceMode = iota -) - -// ContentEnc is used to encipher and decipher file content. -type ContentEnc struct { - // Cryptographic primitives - cryptoCore *cryptocore.CryptoCore - // Plaintext block size - plainBS uint64 - // Ciphertext block size - cipherBS uint64 - // All-zero block of size cipherBS, for fast compares - allZeroBlock []byte - // All-zero block of size IVBitLen/8, for fast compares - allZeroNonce []byte - // Force decode even if integrity check fails (openSSL only) - forceDecode bool - - // Ciphertext block "sync.Pool" pool. Always returns cipherBS-sized byte - // slices (usually 4128 bytes). - cBlockPool bPool - // Plaintext block pool. Always returns plainBS-sized byte slices - // (usually 4096 bytes). - pBlockPool bPool - // Ciphertext request data pool. Always returns byte slices of size - // fuse.MAX_KERNEL_WRITE + encryption overhead. - // Used by Read() to temporarily store the ciphertext as it is read from - // disk. - CReqPool bPool - // Plaintext request data pool. Slice have size fuse.MAX_KERNEL_WRITE. - PReqPool bPool -} - -// New returns an initialized ContentEnc instance. -func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEnc { - if MAX_KERNEL_WRITE%plainBS == 0 { - cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen - // Take IV and GHASH overhead into account. - cReqSize := int(MAX_KERNEL_WRITE / plainBS * cipherBS) - // Unaligned reads (happens during fsck, could also happen with O_DIRECT?) - // touch one additional ciphertext and plaintext block. Reserve space for the - // extra block. - cReqSize += int(cipherBS) - pReqSize := MAX_KERNEL_WRITE + int(plainBS) - c := &ContentEnc{ - cryptoCore: cc, - plainBS: plainBS, - cipherBS: cipherBS, - allZeroBlock: make([]byte, cipherBS), - allZeroNonce: make([]byte, cc.IVLen), - forceDecode: forceDecode, - cBlockPool: newBPool(int(cipherBS)), - CReqPool: newBPool(cReqSize), - pBlockPool: newBPool(int(plainBS)), - PReqPool: newBPool(pReqSize), - } - return c - } else { - return nil - } -} - -// PlainBS returns the plaintext block size -func (be *ContentEnc) PlainBS() uint64 { - return be.plainBS -} - -// CipherBS returns the ciphertext block size -func (be *ContentEnc) CipherBS() uint64 { - return be.cipherBS -} - -// DecryptBlocks decrypts a number of blocks -func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, fileID []byte) ([]byte, error) { - cBuf := bytes.NewBuffer(ciphertext) - var err error - pBuf := bytes.NewBuffer(be.PReqPool.Get()[:0]) - blockNo := firstBlockNo - for cBuf.Len() > 0 { - cBlock := cBuf.Next(int(be.cipherBS)) - var pBlock []byte - pBlock, err = be.DecryptBlock(cBlock, blockNo, fileID) - if err != nil { - if !be.forceDecode || err != stupidgcm.ErrAuth { - break - } - } - pBuf.Write(pBlock) - be.pBlockPool.Put(pBlock) - blockNo++ - } - return pBuf.Bytes(), err -} - -// concatAD concatenates the block number and the file ID to a byte blob -// that can be passed to AES-GCM as associated data (AD). -// Result is: aData = [blockNo.bigEndian fileID]. -func concatAD(blockNo uint64, fileID []byte) (aData []byte) { - if fileID != nil && len(fileID) != headerIDLen { - // fileID is nil when decrypting the master key from the config file, - // and for symlinks and xattrs. - log.Panicf("wrong fileID length: %d", len(fileID)) - } - const lenUint64 = 8 - // Preallocate space to save an allocation in append() - aData = make([]byte, lenUint64, lenUint64+headerIDLen) - binary.BigEndian.PutUint64(aData, blockNo) - aData = append(aData, fileID...) - return aData -} - -// 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 passthrough. -func (be *ContentEnc) 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) { - return make([]byte, be.plainBS), nil - } - - if len(ciphertext) < be.cryptoCore.IVLen { - return nil, errors.New("Block is too short") - } - - // Extract nonce - nonce := ciphertext[:be.cryptoCore.IVLen] - if bytes.Equal(nonce, be.allZeroNonce) { - // Bug in tmpfs? - // https://github.com/rfjakob/gocryptfs/issues/56 - // http://www.spinics.net/lists/kernel/msg2370127.html - return nil, errors.New("all-zero nonce") - } - ciphertext = ciphertext[be.cryptoCore.IVLen:] - - // Decrypt - plaintext := be.pBlockPool.Get() - plaintext = plaintext[:0] - aData := concatAD(blockNo, fileID) - plaintext, err := be.cryptoCore.AEADCipher.Open(plaintext, nonce, ciphertext, aData) - if err != nil { - if be.forceDecode && err == stupidgcm.ErrAuth { - return plaintext, err - } - return nil, err - } - - return plaintext, nil -} - -// At some point, splitting the ciphertext into more groups will not improve -// performance, as spawning goroutines comes at a cost. -// 2 seems to work ok for now. -const encryptMaxSplit = 2 - -// encryptBlocksParallel splits the plaintext into parts and encrypts them -// in parallel. -func (be *ContentEnc) encryptBlocksParallel(plaintextBlocks [][]byte, ciphertextBlocks [][]byte, firstBlockNo uint64, fileID []byte) { - ncpu := runtime.NumCPU() - if ncpu > encryptMaxSplit { - ncpu = encryptMaxSplit - } - groupSize := len(plaintextBlocks) / ncpu - var wg sync.WaitGroup - for i := 0; i < ncpu; i++ { - wg.Add(1) - go func(i int) { - low := i * groupSize - high := (i + 1) * groupSize - if i == ncpu-1 { - // Last part picks up any left-over blocks - // - // The last part could run in the original goroutine, but - // doing that complicates the code, and, surprisingly, - // incurs a 1 % performance penalty. - high = len(plaintextBlocks) - } - be.doEncryptBlocks(plaintextBlocks[low:high], ciphertextBlocks[low:high], firstBlockNo+uint64(low), fileID) - wg.Done() - }(i) - } - wg.Wait() -} - -// EncryptBlocks is like EncryptBlock but takes multiple plaintext blocks. -// Returns a byte slice from CReqPool - so don't forget to return it -// to the pool. -func (be *ContentEnc) EncryptBlocks(plaintextBlocks [][]byte, firstBlockNo uint64, fileID []byte) []byte { - ciphertextBlocks := make([][]byte, len(plaintextBlocks)) - // For large writes, we parallelize encryption. - if len(plaintextBlocks) >= 32 && runtime.NumCPU() >= 2 { - be.encryptBlocksParallel(plaintextBlocks, ciphertextBlocks, firstBlockNo, fileID) - } else { - be.doEncryptBlocks(plaintextBlocks, ciphertextBlocks, firstBlockNo, fileID) - } - // Concatenate ciphertext into a single byte array. - tmp := be.CReqPool.Get() - out := bytes.NewBuffer(tmp[:0]) - for _, v := range ciphertextBlocks { - out.Write(v) - // Return the memory to cBlockPool - be.cBlockPool.Put(v) - } - return out.Bytes() -} - -// doEncryptBlocks is called by EncryptBlocks to do the actual encryption work -func (be *ContentEnc) doEncryptBlocks(in [][]byte, out [][]byte, firstBlockNo uint64, fileID []byte) { - for i, v := range in { - out[i] = be.EncryptBlock(v, firstBlockNo+uint64(i), fileID) - } -} - -// EncryptBlock - Encrypt plaintext using a random nonce. -// blockNo and fileID are used as associated data. -// The output is nonce + ciphertext + tag. -func (be *ContentEnc) EncryptBlock(plaintext []byte, blockNo uint64, fileID []byte) []byte { - // Get a fresh random nonce - nonce := be.cryptoCore.IVGenerator.Get() - return be.doEncryptBlock(plaintext, blockNo, fileID, nonce) -} - -// EncryptBlockNonce - Encrypt plaintext using a nonce chosen by the caller. -// blockNo and fileID are used as associated data. -// The output is nonce + ciphertext + tag. -// This function can only be used in SIV mode. -func (be *ContentEnc) EncryptBlockNonce(plaintext []byte, blockNo uint64, fileID []byte, nonce []byte) []byte { - if be.cryptoCore.AEADBackend != cryptocore.BackendAESSIV { - log.Panic("deterministic nonces are only secure in SIV mode") - } - return be.doEncryptBlock(plaintext, blockNo, fileID, nonce) -} - -// doEncryptBlock is the backend for EncryptBlock and EncryptBlockNonce. -// blockNo and fileID are used as associated data. -// The output is nonce + ciphertext + tag. -func (be *ContentEnc) doEncryptBlock(plaintext []byte, blockNo uint64, fileID []byte, nonce []byte) []byte { - // Empty block? - if len(plaintext) == 0 { - return plaintext - } - if len(nonce) != be.cryptoCore.IVLen { - log.Panic("wrong nonce length") - } - // Block is authenticated with block number and file ID - aData := concatAD(blockNo, fileID) - // Get a cipherBS-sized block of memory, copy the nonce into it and truncate to - // nonce length - cBlock := be.cBlockPool.Get() - copy(cBlock, nonce) - cBlock = cBlock[0:len(nonce)] - // Encrypt plaintext and append to nonce - ciphertext := be.cryptoCore.AEADCipher.Seal(cBlock, nonce, plaintext, aData) - overhead := int(be.cipherBS - be.plainBS) - if len(plaintext)+overhead != len(ciphertext) { - log.Panicf("unexpected ciphertext length: plaintext=%d, overhead=%d, ciphertext=%d", - len(plaintext), overhead, len(ciphertext)) - } - return ciphertext -} - -// MergeBlocks - Merge newData into oldData at offset -// New block may be bigger than both newData and oldData -func (be *ContentEnc) MergeBlocks(oldData []byte, newData []byte, offset int) []byte { - // Fastpath for small-file creation - if len(oldData) == 0 && offset == 0 { - return newData - } - - // 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] -} - -// Wipe tries to wipe secret keys from memory by overwriting them with zeros -// and/or setting references to nil. -func (be *ContentEnc) Wipe() { - be.cryptoCore.Wipe() - be.cryptoCore = nil -} diff --git a/app/libgocryptfs/rewrites/contentenc/file_header.go b/app/libgocryptfs/rewrites/contentenc/file_header.go deleted file mode 100644 index 548147f..0000000 --- a/app/libgocryptfs/rewrites/contentenc/file_header.go +++ /dev/null @@ -1,77 +0,0 @@ -package contentenc - -// Per-file header -// -// Format: [ "Version" uint16 big endian ] [ "Id" 16 random bytes ] - -import ( - "bytes" - "encoding/binary" - "encoding/hex" - "fmt" - "log" - - "../../gocryptfs_internal/cryptocore" -) - -const ( - // CurrentVersion is the current On-Disk-Format version - CurrentVersion = 2 - - headerVersionLen = 2 // uint16 - headerIDLen = 16 // 128 bit random file id - // HeaderLen is the total header length - HeaderLen = headerVersionLen + headerIDLen -) - -// FileHeader represents the header stored on each non-empty file. -type FileHeader struct { - Version uint16 - ID []byte -} - -// Pack - serialize fileHeader object -func (h *FileHeader) Pack() []byte { - if len(h.ID) != headerIDLen || h.Version != CurrentVersion { - log.Panic("FileHeader object not properly initialized") - } - buf := make([]byte, HeaderLen) - binary.BigEndian.PutUint16(buf[0:headerVersionLen], h.Version) - copy(buf[headerVersionLen:], h.ID) - return buf - -} - -// allZeroFileID is preallocated to quickly check if the data read from disk is all zero -var allZeroFileID = make([]byte, headerIDLen) -var allZeroHeader = make([]byte, HeaderLen) - -// ParseHeader - parse "buf" into fileHeader object -func ParseHeader(buf []byte) (*FileHeader, error) { - if len(buf) != HeaderLen { - return nil, fmt.Errorf("ParseHeader: invalid length, want=%d have=%d", HeaderLen, len(buf)) - } - if bytes.Equal(buf, allZeroHeader) { - return nil, fmt.Errorf("ParseHeader: header is all-zero. Header hexdump: %s", hex.EncodeToString(buf)) - } - var h FileHeader - h.Version = binary.BigEndian.Uint16(buf[0:headerVersionLen]) - if h.Version != CurrentVersion { - return nil, fmt.Errorf("ParseHeader: invalid version, want=%d have=%d. Header hexdump: %s", - CurrentVersion, h.Version, hex.EncodeToString(buf)) - } - h.ID = buf[headerVersionLen:] - if bytes.Equal(h.ID, allZeroFileID) { - return nil, fmt.Errorf("ParseHeader: file id is all-zero. Header hexdump: %s", - hex.EncodeToString(buf)) - } - return &h, nil -} - -// RandomHeader - create new fileHeader object with random Id -func RandomHeader() *FileHeader { - var h FileHeader - h.Version = CurrentVersion - h.ID = cryptocore.RandBytes(headerIDLen) - return &h -} diff --git a/app/libgocryptfs/rewrites/contentenc/intrablock.go b/app/libgocryptfs/rewrites/contentenc/intrablock.go deleted file mode 100644 index 55b0841..0000000 --- a/app/libgocryptfs/rewrites/contentenc/intrablock.go +++ /dev/null @@ -1,71 +0,0 @@ -package contentenc - -// IntraBlock identifies a part of a file block -type IntraBlock struct { - // BlockNo is the block number in the file - BlockNo uint64 - // Skip is an offset into the block payload - // In forward mode: block plaintext - // In reverse mode: offset into block ciphertext. Takes the header into - // account. - Skip uint64 - // Length of payload data in this block - // In forward mode: length of the plaintext - // In reverse mode: length of the ciphertext. Takes header and trailer into - // account. - Length uint64 - fs *ContentEnc -} - -// 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 -} - -// BlockCipherOff returns the ciphertext offset corresponding to BlockNo -func (ib *IntraBlock) BlockCipherOff() (offset uint64) { - return ib.fs.BlockNoToCipherOff(ib.BlockNo) -} - -// BlockPlainOff returns the plaintext offset corresponding to BlockNo -func (ib *IntraBlock) BlockPlainOff() (offset uint64) { - return ib.fs.BlockNoToPlainOff(ib.BlockNo) -} - -// 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] -} - -// JointCiphertextRange is the 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 -} - -// JointPlaintextRange is the plaintext range corresponding to the sum of all -// "blocks" (complete blocks) -func JointPlaintextRange(blocks []IntraBlock) (offset uint64, length uint64) { - firstBlock := blocks[0] - lastBlock := blocks[len(blocks)-1] - - offset = firstBlock.BlockPlainOff() - length = lastBlock.BlockPlainOff() + lastBlock.fs.PlainBS() - offset - - return offset, length -} diff --git a/app/libgocryptfs/rewrites/contentenc/offsets.go b/app/libgocryptfs/rewrites/contentenc/offsets.go deleted file mode 100644 index dd8e764..0000000 --- a/app/libgocryptfs/rewrites/contentenc/offsets.go +++ /dev/null @@ -1,135 +0,0 @@ -package contentenc - -import ( - "log" -) - -// Contentenc methods that translate offsets between ciphertext and plaintext - -// PlainOffToBlockNo converts a plaintext offset to the ciphertext block number. -func (be *ContentEnc) PlainOffToBlockNo(plainOffset uint64) uint64 { - return plainOffset / be.plainBS -} - -// CipherOffToBlockNo converts the ciphertext offset to the plaintext block number. -func (be *ContentEnc) CipherOffToBlockNo(cipherOffset uint64) uint64 { - if cipherOffset < HeaderLen { - log.Panicf("BUG: offset %d is inside the file header", cipherOffset) - } - return (cipherOffset - HeaderLen) / be.cipherBS -} - -// BlockNoToCipherOff gets the ciphertext offset of block "blockNo" -func (be *ContentEnc) BlockNoToCipherOff(blockNo uint64) uint64 { - return HeaderLen + blockNo*be.cipherBS -} - -// BlockNoToPlainOff gets the plaintext offset of block "blockNo" -func (be *ContentEnc) BlockNoToPlainOff(blockNo uint64) uint64 { - return blockNo * be.plainBS -} - -// CipherSizeToPlainSize calculates the plaintext size from a ciphertext size -func (be *ContentEnc) CipherSizeToPlainSize(cipherSize uint64) uint64 { - // Zero-sized files stay zero-sized - if cipherSize == 0 { - return 0 - } - - if cipherSize == HeaderLen { - // This can happen between createHeader() and Write() and is harmless. - return 0 - } - - if cipherSize < HeaderLen { - return 0 - } - - // Block number at last byte - blockNo := be.CipherOffToBlockNo(cipherSize - 1) - blockCount := blockNo + 1 - - overhead := be.BlockOverhead()*blockCount + HeaderLen - - if overhead > cipherSize { - return 0 - } - - return cipherSize - overhead -} - -// PlainSizeToCipherSize calculates the ciphertext size from a plaintext size -func (be *ContentEnc) PlainSizeToCipherSize(plainSize uint64) uint64 { - // Zero-sized files stay zero-sized - if plainSize == 0 { - return 0 - } - - // Block number at last byte - blockNo := be.PlainOffToBlockNo(plainSize - 1) - blockCount := blockNo + 1 - - overhead := be.BlockOverhead()*blockCount + HeaderLen - - return plainSize + overhead -} - -// ExplodePlainRange splits a plaintext byte range into (possibly partial) blocks -// Returns an empty slice if length == 0. -func (be *ContentEnc) 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 plaintext 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 -} - -// ExplodeCipherRange splits a ciphertext byte range into (possibly partial) -// blocks This is used in reverse mode when reading files -func (be *ContentEnc) ExplodeCipherRange(offset uint64, length uint64) []IntraBlock { - var blocks []IntraBlock - var nextBlock IntraBlock - nextBlock.fs = be - - for length > 0 { - nextBlock.BlockNo = be.CipherOffToBlockNo(offset) - nextBlock.Skip = offset - be.BlockNoToCipherOff(nextBlock.BlockNo) - - // This block can carry up to "maxLen" payload bytes - maxLen := be.cipherBS - nextBlock.Skip - nextBlock.Length = maxLen - // But if the user requested less, we truncate the block to "length". - if length < maxLen { - nextBlock.Length = length - } - - blocks = append(blocks, nextBlock) - offset += nextBlock.Length - length -= nextBlock.Length - } - return blocks -} - -// BlockOverhead returns the per-block overhead. -func (be *ContentEnc) BlockOverhead() uint64 { - return be.cipherBS - be.plainBS -} - -// MinUint64 returns the minimum of two uint64 values. -func MinUint64(x uint64, y uint64) uint64 { - if x < y { - return x - } - return y -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/emulate.go b/app/libgocryptfs/rewrites/syscallcompat/emulate.go deleted file mode 100644 index 91b592b..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/emulate.go +++ /dev/null @@ -1,29 +0,0 @@ -package syscallcompat - -import ( - "path/filepath" - "sync" - "syscall" -) - -var chdirMutex sync.Mutex - -// emulateMknodat emulates the syscall for platforms that don't have it -// in the kernel (darwin). -func emulateMknodat(dirfd int, path string, mode uint32, dev int) error { - if !filepath.IsAbs(path) { - chdirMutex.Lock() - defer chdirMutex.Unlock() - cwd, err := syscall.Open(".", syscall.O_RDONLY, 0) - if err != nil { - return err - } - defer syscall.Close(cwd) - err = syscall.Fchdir(dirfd) - if err != nil { - return err - } - defer syscall.Fchdir(cwd) - } - return syscall.Mknod(path, mode, dev) -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/getdents_linux.go b/app/libgocryptfs/rewrites/syscallcompat/getdents_linux.go deleted file mode 100644 index a609ac4..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/getdents_linux.go +++ /dev/null @@ -1,151 +0,0 @@ -// +build linux - -package syscallcompat - -// Other implementations of getdents in Go: -// https://github.com/ericlagergren/go-gnulib/blob/cb7a6e136427e242099b2c29d661016c19458801/dirent/getdents_unix.go -// https://github.com/golang/tools/blob/5831d16d18029819d39f99bdc2060b8eff410b6b/imports/fastwalk_unix.go - -import ( - "sync" - "bytes" - "syscall" - "unsafe" - - "golang.org/x/sys/unix" -) - -const sizeofDirent = int(unsafe.Sizeof(unix.Dirent{})) - -// maxReclen sanity check: Reclen should never be larger than this. -// Due to padding between entries, it is 280 even on 32-bit architectures. -// See https://github.com/rfjakob/gocryptfs/issues/197 for details. -const maxReclen = 280 - -type DirEntry struct { - Name string - Mode uint32 -} - -// getdents wraps unix.Getdents and converts the result to []fuse.DirEntry. -func getdents(fd int) ([]DirEntry, error) { - // Collect syscall result in smartBuf. - // "bytes.Buffer" is smart about expanding the capacity and avoids the - // exponential runtime of simple append(). - var smartBuf bytes.Buffer - tmp := make([]byte, 10000) - for { - n, err := unix.Getdents(fd, tmp) - // unix.Getdents has been observed to return EINTR on cifs mounts - if err == unix.EINTR { - if n > 0 { - smartBuf.Write(tmp[:n]) - } - continue - } else if err != nil { - if smartBuf.Len() > 0 { - return nil, syscall.EIO - } - return nil, err - } - if n == 0 { - break - } - smartBuf.Write(tmp[:n]) - } - // Make sure we have at least Sizeof(Dirent) of zeros after the last - // entry. This prevents a cast to Dirent from reading past the buffer. - smartBuf.Grow(sizeofDirent) - buf := smartBuf.Bytes() - // Count the number of directory entries in the buffer so we can allocate - // a fuse.DirEntry slice of the correct size at once. - var numEntries, offset int - for offset < len(buf) { - s := *(*unix.Dirent)(unsafe.Pointer(&buf[offset])) - if s.Reclen == 0 { - // EBADR = Invalid request descriptor - return nil, syscall.EBADR - } - if int(s.Reclen) > maxReclen { - return nil, syscall.EBADR - } - offset += int(s.Reclen) - numEntries++ - } - // Parse the buffer into entries. - // Note: syscall.ParseDirent() only returns the names, - // we want all the data, so we have to implement - // it on our own. - entries := make([]DirEntry, 0, numEntries) - offset = 0 - for offset < len(buf) { - s := *(*unix.Dirent)(unsafe.Pointer(&buf[offset])) - name, err := getdentsName(s) - if err != nil { - return nil, err - } - offset += int(s.Reclen) - if name == "." || name == ".." { - // os.File.Readdir() drops "." and "..". Let's be compatible. - continue - } - mode, err := convertDType(fd, name, s.Type) - if err != nil { - // The uint32file may have been deleted in the meantime. Just skip it - // and go on. - continue - } - entries = append(entries, DirEntry{ - Name: name, - Mode: mode, - }) - } - return entries, nil -} - -// getdentsName extracts the filename from a Dirent struct and returns it as -// a Go string. -func getdentsName(s unix.Dirent) (string, error) { - // After the loop, l contains the index of the first '\0'. - l := 0 - for l = range s.Name { - if s.Name[l] == 0 { - break - } - } - if l < 1 { - // EBADR = Invalid request descriptor - return "", syscall.EBADR - } - // Copy to byte slice. - name := make([]byte, l) - for i := range name { - name[i] = byte(s.Name[i]) - } - return string(name), nil -} - -var dtUnknownWarnOnce sync.Once - -func dtUnknownWarn(dirfd int) { - const XFS_SUPER_MAGIC = 0x58465342 // From man 2 statfs - var buf syscall.Statfs_t - syscall.Fstatfs(dirfd, &buf) -} - -// convertDType converts a Dirent.Type to at Stat_t.Mode value. -func convertDType(dirfd int, name string, dtype uint8) (uint32, error) { - if dtype != syscall.DT_UNKNOWN { - // Shift up by four octal digits = 12 bits - return uint32(dtype) << 12, nil - } - // DT_UNKNOWN: we have to call stat() - dtUnknownWarnOnce.Do(func() { dtUnknownWarn(dirfd) }) - var st unix.Stat_t - err := Fstatat(dirfd, name, &st, unix.AT_SYMLINK_NOFOLLOW) - if err != nil { - return 0, err - } - // The S_IFMT bit mask extracts the file type from the mode. - return st.Mode & syscall.S_IFMT, nil -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/getdents_other.go b/app/libgocryptfs/rewrites/syscallcompat/getdents_other.go deleted file mode 100644 index 754b108..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/getdents_other.go +++ /dev/null @@ -1 +0,0 @@ -package syscallcompat diff --git a/app/libgocryptfs/rewrites/syscallcompat/helpers.go b/app/libgocryptfs/rewrites/syscallcompat/helpers.go deleted file mode 100644 index e2a2215..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/helpers.go +++ /dev/null @@ -1,21 +0,0 @@ -package syscallcompat - -import ( - "os" - "syscall" -) - -// IsENOSPC tries to find out if "err" is a (potentially wrapped) ENOSPC error. -func IsENOSPC(err error) bool { - // syscallcompat.EnospcPrealloc returns the naked syscall error - if err == syscall.ENOSPC { - return true - } - // os.File.WriteAt returns &PathError - if err2, ok := err.(*os.PathError); ok { - if err2.Err == syscall.ENOSPC { - return true - } - } - return false -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/open_nofollow.go b/app/libgocryptfs/rewrites/syscallcompat/open_nofollow.go deleted file mode 100644 index 71cd34a..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/open_nofollow.go +++ /dev/null @@ -1,44 +0,0 @@ -package syscallcompat - -import ( - "path/filepath" - "strings" - "syscall" -) - -// OpenDirNofollow opens the dir at "relPath" in a way that is secure against -// symlink attacks. Symlinks that are part of "relPath" are never followed. -// This function is implemented by walking the directory tree, starting at -// "baseDir", using the Openat syscall with the O_NOFOLLOW flag. -// Symlinks that are part of the "baseDir" path are followed. -func OpenDirNofollow(baseDir string, relPath string) (fd int, err error) { - if !filepath.IsAbs(baseDir) { - return -1, syscall.EINVAL - } - if filepath.IsAbs(relPath) { - return -1, syscall.EINVAL - } - // Open the base dir (following symlinks) - dirfd, err := syscall.Open(baseDir, syscall.O_DIRECTORY|O_PATH, 0) - if err != nil { - return -1, err - } - // Caller wanted to open baseDir itself? - if relPath == "" { - return dirfd, nil - } - // Split the path into components - parts := strings.Split(relPath, "/") - // Walk the directory tree - var dirfd2 int - for _, name := range parts { - dirfd2, err = Openat(dirfd, name, syscall.O_NOFOLLOW|syscall.O_DIRECTORY|O_PATH, 0) - syscall.Close(dirfd) - if err != nil { - return -1, err - } - dirfd = dirfd2 - } - // Return fd to final directory - return dirfd, nil -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/sys_common.go b/app/libgocryptfs/rewrites/syscallcompat/sys_common.go deleted file mode 100644 index 6311510..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/sys_common.go +++ /dev/null @@ -1,221 +0,0 @@ -package syscallcompat - -import ( - "bytes" - "syscall" - - "golang.org/x/sys/unix" -) - -// PATH_MAX is the maximum allowed path length on Linux. -// It is not defined on Darwin, so we use the Linux value. -const PATH_MAX = 4096 - -// Readlinkat is a convenience wrapper around unix.Readlinkat() that takes -// care of buffer sizing. Implemented like os.Readlink(). -func Readlinkat(dirfd int, path string) (string, error) { - // Allocate the buffer exponentially like os.Readlink does. - for bufsz := 128; ; bufsz *= 2 { - buf := make([]byte, bufsz) - n, err := unix.Readlinkat(dirfd, path, buf) - if err != nil { - return "", err - } - if n < bufsz { - return string(buf[0:n]), nil - } - } -} - -// Faccessat exists both in Linux and in MacOS 10.10+, but the Linux version -// DOES NOT support any flags. Emulate AT_SYMLINK_NOFOLLOW like glibc does. -func Faccessat(dirfd int, path string, mode uint32) error { - var st unix.Stat_t - err := Fstatat(dirfd, path, &st, unix.AT_SYMLINK_NOFOLLOW) - if err != nil { - return err - } - if st.Mode&syscall.S_IFMT == syscall.S_IFLNK { - // Pretend that a symlink is always accessible - return nil - } - return unix.Faccessat(dirfd, path, mode, 0) -} - -// Openat wraps the Openat syscall. -func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { - /*if flags&syscall.O_CREAT != 0 { - // O_CREAT should be used with O_EXCL. O_NOFOLLOW has no effect with O_EXCL. - if flags&syscall.O_EXCL == 0 { - flags |= syscall.O_EXCL - } - } else { - // If O_CREAT is not used, we should use O_NOFOLLOW - if flags&syscall.O_NOFOLLOW == 0 { - flags |= syscall.O_NOFOLLOW - } - }*/ - if flags&syscall.O_CREAT == 0 { - // If O_CREAT is not used, we should use O_NOFOLLOW - if flags&syscall.O_NOFOLLOW == 0 { - flags |= syscall.O_NOFOLLOW - } - } - return unix.Openat(dirfd, path, flags, mode) -} - -// Renameat wraps the Renameat syscall. -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { - return unix.Renameat(olddirfd, oldpath, newdirfd, newpath) -} - -// Unlinkat syscall. -func Unlinkat(dirfd int, path string, flags int) (err error) { - return unix.Unlinkat(dirfd, path, flags) -} - -// Fchownat syscall. -func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { - // Why would we ever want to call this without AT_SYMLINK_NOFOLLOW? - if flags&unix.AT_SYMLINK_NOFOLLOW == 0 { - flags |= unix.AT_SYMLINK_NOFOLLOW - } - return unix.Fchownat(dirfd, path, uid, gid, flags) -} - -// Linkat exists both in Linux and in MacOS 10.10+. -func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { - return unix.Linkat(olddirfd, oldpath, newdirfd, newpath, flags) -} - -// Symlinkat syscall. -func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { - return unix.Symlinkat(oldpath, newdirfd, newpath) -} - -// Mkdirat syscall. -func Mkdirat(dirfd int, path string, mode uint32) (err error) { - return unix.Mkdirat(dirfd, path, mode) -} - -// Fstatat syscall. -func Fstatat(dirfd int, path string, stat *unix.Stat_t, flags int) (err error) { - // Why would we ever want to call this without AT_SYMLINK_NOFOLLOW? - if flags&unix.AT_SYMLINK_NOFOLLOW == 0 { - flags |= unix.AT_SYMLINK_NOFOLLOW - } - return unix.Fstatat(dirfd, path, stat, flags) -} - -const XATTR_SIZE_MAX = 65536 - -// Make the buffer 1kB bigger so we can detect overflows -const XATTR_BUFSZ = XATTR_SIZE_MAX + 1024 - -// Fgetxattr is a wrapper around unix.Fgetxattr that handles the buffer sizing. -func Fgetxattr(fd int, attr string) (val []byte, err error) { - // If the buffer is too small to fit the value, Linux and MacOS react - // differently: - // Linux: returns an ERANGE error and "-1" bytes. - // MacOS: truncates the value and returns "size" bytes. - // - // We choose the simple approach of buffer that is bigger than the limit on - // Linux, and return an error for everything that is bigger (which can - // only happen on MacOS). - // - // See https://github.com/pkg/xattr for a smarter solution. - // TODO: smarter buffer sizing? - buf := make([]byte, XATTR_BUFSZ) - sz, err := unix.Fgetxattr(fd, attr, buf) - if err == syscall.ERANGE { - // Do NOT return ERANGE - the user might retry ad inifinitum! - return nil, syscall.EOVERFLOW - } - if err != nil { - return nil, err - } - if sz >= XATTR_SIZE_MAX { - return nil, syscall.EOVERFLOW - } - // Copy only the actually used bytes to a new (smaller) buffer - // so "buf" never leaves the function and can be allocated on the stack. - val = make([]byte, sz) - copy(val, buf) - return val, nil -} - -// Lgetxattr is a wrapper around unix.Lgetxattr that handles the buffer sizing. -func Lgetxattr(path string, attr string) (val []byte, err error) { - // See the buffer sizing comments in Fgetxattr. - // TODO: smarter buffer sizing? - buf := make([]byte, XATTR_BUFSZ) - sz, err := unix.Lgetxattr(path, attr, buf) - if err == syscall.ERANGE { - // Do NOT return ERANGE - the user might retry ad inifinitum! - return nil, syscall.EOVERFLOW - } - if err != nil { - return nil, err - } - if sz >= XATTR_SIZE_MAX { - return nil, syscall.EOVERFLOW - } - // Copy only the actually used bytes to a new (smaller) buffer - // so "buf" never leaves the function and can be allocated on the stack. - val = make([]byte, sz) - copy(val, buf) - return val, nil -} - -// Flistxattr is a wrapper for unix.Flistxattr that handles buffer sizing and -// parsing the returned blob to a string slice. -func Flistxattr(fd int) (attrs []string, err error) { - // See the buffer sizing comments in Fgetxattr. - // TODO: smarter buffer sizing? - buf := make([]byte, XATTR_BUFSZ) - sz, err := unix.Flistxattr(fd, buf) - if err == syscall.ERANGE { - // Do NOT return ERANGE - the user might retry ad inifinitum! - return nil, syscall.EOVERFLOW - } - if err != nil { - return nil, err - } - if sz >= XATTR_SIZE_MAX { - return nil, syscall.EOVERFLOW - } - attrs = parseListxattrBlob(buf[:sz]) - return attrs, nil -} - -// Llistxattr is a wrapper for unix.Llistxattr that handles buffer sizing and -// parsing the returned blob to a string slice. -func Llistxattr(path string) (attrs []string, err error) { - // TODO: smarter buffer sizing? - buf := make([]byte, XATTR_BUFSZ) - sz, err := unix.Llistxattr(path, buf) - if err == syscall.ERANGE { - // Do NOT return ERANGE - the user might retry ad inifinitum! - return nil, syscall.EOVERFLOW - } - if err != nil { - return nil, err - } - if sz >= XATTR_SIZE_MAX { - return nil, syscall.EOVERFLOW - } - attrs = parseListxattrBlob(buf[:sz]) - return attrs, nil -} - -func parseListxattrBlob(buf []byte) (attrs []string) { - parts := bytes.Split(buf, []byte{0}) - for _, part := range parts { - if len(part) == 0 { - // Last part is empty, ignore - continue - } - attrs = append(attrs, string(part)) - } - return attrs -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/sys_darwin.go b/app/libgocryptfs/rewrites/syscallcompat/sys_darwin.go deleted file mode 100644 index 1a6b454..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/sys_darwin.go +++ /dev/null @@ -1,215 +0,0 @@ -package syscallcompat - -import ( - "log" - "path/filepath" - "runtime" - "syscall" - "time" - "unsafe" - - "golang.org/x/sys/unix" -) - -const ( - // O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined - // to zero there. - O_DIRECT = 0 - - // O_PATH is only defined on Linux - O_PATH = 0 - - // KAUTH_UID_NONE and KAUTH_GID_NONE are special values to - // revert permissions to the process credentials. - KAUTH_UID_NONE = ^uint32(0) - 100 - KAUTH_GID_NONE = ^uint32(0) - 100 -) - -// Unfortunately pthread_setugid_np does not have a syscall wrapper yet. -func pthread_setugid_np(uid uint32, gid uint32) (err error) { - _, _, e1 := syscall.RawSyscall(syscall.SYS_SETTID, uintptr(uid), uintptr(gid), 0) - if e1 != 0 { - err = e1 - } - return -} - -// Unfortunately fsetattrlist does not have a syscall wrapper yet. -func fsetattrlist(fd int, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { - _, _, e1 := syscall.Syscall6(syscall.SYS_FSETATTRLIST, uintptr(fd), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) - if e1 != 0 { - err = e1 - } - return -} - -// Setattrlist already has a syscall wrapper, but it is not exported. -func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { - _, _, e1 := syscall.Syscall6(syscall.SYS_SETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) - if e1 != 0 { - err = e1 - } - return -} - -// Sorry, fallocate is not available on OSX at all and -// fcntl F_PREALLOCATE is not accessible from Go. -// See https://github.com/rfjakob/gocryptfs/issues/18 if you want to help. -func EnospcPrealloc(fd int, off int64, len int64) error { - return nil -} - -// See above. -func Fallocate(fd int, mode uint32, off int64, len int64) error { - return syscall.EOPNOTSUPP -} - -// Dup3 is not available on Darwin, so we use Dup2 instead. -func Dup3(oldfd int, newfd int, flags int) (err error) { - if flags != 0 { - log.Panic("darwin does not support dup3 flags") - } - return syscall.Dup2(oldfd, newfd) -} - -//////////////////////////////////////////////////////// -//// Emulated Syscalls (see emulate.go) //////////////// -//////////////////////////////////////////////////////// - -func OpenatUser(dirfd int, path string, flags int, mode uint32, context *fuse.Context) (fd int, err error) { - if context != nil { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) - if err != nil { - return -1, err - } - defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) - } - - return Openat(dirfd, path, flags, mode) -} - -func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { - return emulateMknodat(dirfd, path, mode, dev) -} - -func MknodatUser(dirfd int, path string, mode uint32, dev int, context *fuse.Context) (err error) { - if context != nil { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) - if err != nil { - return err - } - defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) - } - - return Mknodat(dirfd, path, mode, dev) -} - -func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) { - return unix.Fchmodat(dirfd, path, mode, unix.AT_SYMLINK_NOFOLLOW) -} - -func SymlinkatUser(oldpath string, newdirfd int, newpath string, context *fuse.Context) (err error) { - if context != nil { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) - if err != nil { - return err - } - defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) - } - - return Symlinkat(oldpath, newdirfd, newpath) -} - -func MkdiratUser(dirfd int, path string, mode uint32, context *fuse.Context) (err error) { - if context != nil { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid) - if err != nil { - return err - } - defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) - } - - return Mkdirat(dirfd, path, mode) -} - -type attrList struct { - bitmapCount uint16 - _ uint16 - CommonAttr uint32 - VolAttr uint32 - DirAttr uint32 - FileAttr uint32 - Forkattr uint32 -} - -func timesToAttrList(a *time.Time, m *time.Time) (attrList attrList, attributes [2]unix.Timespec) { - attrList.bitmapCount = unix.ATTR_BIT_MAP_COUNT - attrList.CommonAttr = 0 - i := 0 - if m != nil { - attributes[i] = unix.Timespec(fuse.UtimeToTimespec(m)) - attrList.CommonAttr |= unix.ATTR_CMN_MODTIME - i += 1 - } - if a != nil { - attributes[i] = unix.Timespec(fuse.UtimeToTimespec(a)) - attrList.CommonAttr |= unix.ATTR_CMN_ACCTIME - i += 1 - } - return attrList, attributes -} - -// FutimesNano syscall. -func FutimesNano(fd int, a *time.Time, m *time.Time) (err error) { - attrList, attributes := timesToAttrList(a, m) - return fsetattrlist(fd, unsafe.Pointer(&attrList), unsafe.Pointer(&attributes), - unsafe.Sizeof(attributes), 0) -} - -// UtimesNanoAtNofollow is like UtimesNanoAt but never follows symlinks. -// -// Unfortunately we cannot use unix.UtimesNanoAt since it is broken and just -// ignores the provided 'dirfd'. In addition, it also lacks handling of 'nil' -// pointers (used to preserve one of both timestamps). -func UtimesNanoAtNofollow(dirfd int, path string, a *time.Time, m *time.Time) (err error) { - if !filepath.IsAbs(path) { - chdirMutex.Lock() - defer chdirMutex.Unlock() - var cwd int - cwd, err = syscall.Open(".", syscall.O_RDONLY, 0) - if err != nil { - return err - } - defer syscall.Close(cwd) - err = syscall.Fchdir(dirfd) - if err != nil { - return err - } - defer syscall.Fchdir(cwd) - } - - _p0, err := syscall.BytePtrFromString(path) - if err != nil { - return err - } - - attrList, attributes := timesToAttrList(a, m) - return setattrlist(_p0, unsafe.Pointer(&attrList), unsafe.Pointer(&attributes), - unsafe.Sizeof(attributes), unix.FSOPT_NOFOLLOW) -} - -func Getdents(fd int) ([]fuse.DirEntry, error) { - return emulateGetdents(fd) -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/sys_linux.go b/app/libgocryptfs/rewrites/syscallcompat/sys_linux.go deleted file mode 100644 index 044c3b5..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/sys_linux.go +++ /dev/null @@ -1,153 +0,0 @@ -// Package syscallcompat wraps Linux-specific syscalls. -package syscallcompat - -import ( - "fmt" - "io/ioutil" - "strconv" - "strings" - "sync" - "syscall" - "time" - - "golang.org/x/sys/unix" -) - -const ( - _FALLOC_FL_KEEP_SIZE = 0x01 - - // O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined - // to zero there. - O_DIRECT = syscall.O_DIRECT - - // O_PATH is only defined on Linux - O_PATH = unix.O_PATH -) - -var preallocWarn sync.Once - -// EnospcPrealloc preallocates ciphertext space without changing the file -// size. This guarantees that we don't run out of space while writing a -// ciphertext block (that would corrupt the block). -func EnospcPrealloc(fd int, off int64, len int64) (err error) { - for { - err = syscall.Fallocate(fd, _FALLOC_FL_KEEP_SIZE, off, len) - if err == syscall.EINTR { - // fallocate, like many syscalls, can return EINTR. This is not an - // error and just signifies that the operation was interrupted by a - // signal and we should try again. - continue - } - if err == syscall.EOPNOTSUPP { - // ZFS and ext3 do not support fallocate. Warn but continue anyway. - // https://github.com/rfjakob/gocryptfs/issues/22 - preallocWarn.Do(func() {}) - return nil - } - return err - } -} - -// Fallocate wraps the Fallocate syscall. -func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { - return syscall.Fallocate(fd, mode, off, len) -} - -func getSupplementaryGroups(pid uint32) (gids []int) { - procPath := fmt.Sprintf("/proc/%d/task/%d/status", pid, pid) - blob, err := ioutil.ReadFile(procPath) - if err != nil { - return nil - } - - lines := strings.Split(string(blob), "\n") - for _, line := range lines { - if strings.HasPrefix(line, "Groups:") { - f := strings.Fields(line[7:]) - gids = make([]int, len(f)) - for i := range gids { - val, err := strconv.ParseInt(f[i], 10, 32) - if err != nil { - return nil - } - gids[i] = int(val) - } - return gids - } - } - - return nil -} - -// Mknodat wraps the Mknodat syscall. -func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { - return syscall.Mknodat(dirfd, path, mode, dev) -} - -// Dup3 wraps the Dup3 syscall. We want to use Dup3 rather than Dup2 because Dup2 -// is not implemented on arm64. -func Dup3(oldfd int, newfd int, flags int) (err error) { - return syscall.Dup3(oldfd, newfd, flags) -} - -// FchmodatNofollow is like Fchmodat but never follows symlinks. -// -// This should be handled by the AT_SYMLINK_NOFOLLOW flag, but Linux -// does not implement it, so we have to perform an elaborate dance -// with O_PATH and /proc/self/fd. -// -// See also: Qemu implemented the same logic as fchmodat_nofollow(): -// https://git.qemu.org/?p=qemu.git;a=blob;f=hw/9pfs/9p-local.c#l335 -func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) { - // Open handle to the filename (but without opening the actual file). - // This succeeds even when we don't have read permissions to the file. - fd, err := syscall.Openat(dirfd, path, syscall.O_NOFOLLOW|O_PATH, 0) - if err != nil { - return err - } - defer syscall.Close(fd) - - // Now we can check the type without the risk of race-conditions. - // Return syscall.ELOOP if it is a symlink. - var st syscall.Stat_t - err = syscall.Fstat(fd, &st) - if err != nil { - return err - } - if st.Mode&syscall.S_IFMT == syscall.S_IFLNK { - return syscall.ELOOP - } - - // Change mode of the actual file. Fchmod does not work with O_PATH, - // but Chmod via /proc/self/fd works. - procPath := fmt.Sprintf("/proc/self/fd/%d", fd) - return syscall.Chmod(procPath, mode) -} - -func timesToTimespec(a *time.Time, m *time.Time) []unix.Timespec { - ts := make([]unix.Timespec, 2) - ta, _ := unix.TimeToTimespec(*a) - ts[0] = unix.Timespec(ta) - tm, _ := unix.TimeToTimespec(*m) - ts[1] = unix.Timespec(tm) - return ts -} - -// FutimesNano syscall. -func FutimesNano(fd int, a *time.Time, m *time.Time) (err error) { - ts := timesToTimespec(a, m) - // To avoid introducing a separate syscall wrapper for futimens() - // (as done in go-fuse, for example), we instead use the /proc/self/fd trick. - procPath := fmt.Sprintf("/proc/self/fd/%d", fd) - return unix.UtimesNanoAt(unix.AT_FDCWD, procPath, ts, 0) -} - -// UtimesNanoAtNofollow is like UtimesNanoAt but never follows symlinks. -func UtimesNanoAtNofollow(dirfd int, path string, a *time.Time, m *time.Time) (err error) { - ts := timesToTimespec(a, m) - return unix.UtimesNanoAt(dirfd, path, ts, unix.AT_SYMLINK_NOFOLLOW) -} - -func Getdents(fd int) ([]DirEntry, error) { - return getdents(fd) -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/unix2syscall_darwin.go b/app/libgocryptfs/rewrites/syscallcompat/unix2syscall_darwin.go deleted file mode 100644 index 5767a27..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/unix2syscall_darwin.go +++ /dev/null @@ -1,26 +0,0 @@ -package syscallcompat - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -// Unix2syscall converts a unix.Stat_t struct to a syscall.Stat_t struct. -func Unix2syscall(u unix.Stat_t) syscall.Stat_t { - return syscall.Stat_t{ - Dev: u.Dev, - Ino: u.Ino, - Nlink: u.Nlink, - Mode: u.Mode, - Uid: u.Uid, - Gid: u.Gid, - Rdev: u.Rdev, - Size: u.Size, - Blksize: u.Blksize, - Blocks: u.Blocks, - Atimespec: syscall.Timespec(u.Atim), - Mtimespec: syscall.Timespec(u.Mtim), - Ctimespec: syscall.Timespec(u.Ctim), - } -} diff --git a/app/libgocryptfs/rewrites/syscallcompat/unix2syscall_linux.go b/app/libgocryptfs/rewrites/syscallcompat/unix2syscall_linux.go deleted file mode 100644 index 87ac522..0000000 --- a/app/libgocryptfs/rewrites/syscallcompat/unix2syscall_linux.go +++ /dev/null @@ -1,28 +0,0 @@ -package syscallcompat - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -// Unix2syscall converts a unix.Stat_t struct to a syscall.Stat_t struct. -// A direct cast does not work because the padding is named differently in -// unix.Stat_t for some reason ("X__unused" in syscall, "_" in unix). -func Unix2syscall(u unix.Stat_t) syscall.Stat_t { - return syscall.Stat_t{ - Dev: u.Dev, - Ino: u.Ino, - Nlink: u.Nlink, - Mode: u.Mode, - Uid: u.Uid, - Gid: u.Gid, - Rdev: u.Rdev, - Size: u.Size, - Blksize: u.Blksize, - Blocks: u.Blocks, - Atim: syscall.NsecToTimespec(unix.TimespecToNsec(u.Atim)), - Mtim: syscall.NsecToTimespec(unix.TimespecToNsec(u.Mtim)), - Ctim: syscall.NsecToTimespec(unix.TimespecToNsec(u.Ctim)), - } -} diff --git a/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt index 6b31df4..7e43b71 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt @@ -111,7 +111,7 @@ class CreateActivity : VolumeActionActivity() { } } if (goodDirectory) { - if (GocryptfsVolume.createVolume(currentVolumePath, password, GocryptfsVolume.ScryptDefaultLogN, ConstValues.creator)) { + if (GocryptfsVolume.createVolume(currentVolumePath, password, false, GocryptfsVolume.ScryptDefaultLogN, ConstValues.creator)) { var returnedHash: ByteArray? = null if (checkbox_save_password.isChecked){ returnedHash = ByteArray(GocryptfsVolume.KeyLen) diff --git a/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt index b76f67b..7d77a77 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt @@ -14,15 +14,15 @@ class GocryptfsVolume(var sessionID: Int) { private external fun native_is_closed(sessionID: Int): Boolean private external fun native_list_dir(sessionID: Int, dir_path: String): MutableList private external fun native_open_read_mode(sessionID: Int, file_path: String): Int - private external fun native_open_write_mode(sessionID: Int, file_path: String): Int + private external fun native_open_write_mode(sessionID: Int, file_path: String, mode: Int): Int private external fun native_read_file(sessionID: Int, handleID: Int, offset: Long, buff: ByteArray): Int private external fun native_write_file(sessionID: Int, handleID: Int, offset: Long, buff: ByteArray, buff_size: Int): Int - private external fun native_truncate(sessionID: Int, file_path: String, offset: Long): Boolean + private external fun native_truncate(sessionID: Int, handleID: Int, offset: Long): Boolean private external fun native_path_exists(sessionID: Int, file_path: String): Boolean private external fun native_get_size(sessionID: Int, file_path: String): Long private external fun native_close_file(sessionID: Int, handleID: Int) private external fun native_remove_file(sessionID: Int, file_path: String): Boolean - private external fun native_mkdir(sessionID: Int, dir_path: String): Boolean + private external fun native_mkdir(sessionID: Int, dir_path: String, mode: Int): Boolean private external fun native_rmdir(sessionID: Int, dir_path: String): Boolean private external fun native_rename(sessionID: Int, old_path: String, new_path: String): Boolean @@ -30,7 +30,7 @@ class GocryptfsVolume(var sessionID: Int) { const val KeyLen = 32 const val ScryptDefaultLogN = 16 const val DefaultBS = 4096 - external fun createVolume(root_cipher_dir: String, password: CharArray, logN: Int, creator: String): Boolean + external fun createVolume(root_cipher_dir: String, password: CharArray, plainTextNames: Boolean, logN: Int, creator: String): Boolean external fun init(root_cipher_dir: String, password: CharArray?, givenHash: ByteArray?, returnedHash: ByteArray?): Int external fun changePassword(root_cipher_dir: String, old_password: CharArray?, givenHash: ByteArray?, new_password: CharArray, returnedHash: ByteArray?): Boolean @@ -66,7 +66,7 @@ class GocryptfsVolume(var sessionID: Int) { fun mkdir(dir_path: String): Boolean { synchronized(this){ - return native_mkdir(sessionID, dir_path) + return native_mkdir(sessionID, dir_path, 0) } } @@ -108,7 +108,7 @@ class GocryptfsVolume(var sessionID: Int) { fun openWriteMode(file_path: String): Int { synchronized(this){ - return native_open_write_mode(sessionID, file_path) + return native_open_write_mode(sessionID, file_path, 0) } } @@ -124,9 +124,9 @@ class GocryptfsVolume(var sessionID: Int) { } } - fun truncate(file_path: String, offset: Long): Boolean { + fun truncate(handleID: Int, offset: Long): Boolean { synchronized(this) { - return native_truncate(sessionID, file_path, offset) + return native_truncate(sessionID, handleID, offset) } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_operations/FileOperationService.kt b/app/src/main/java/sushi/hardcore/droidfs/file_operations/FileOperationService.kt index 449efa6..a65e271 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_operations/FileOperationService.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_operations/FileOperationService.kt @@ -7,9 +7,9 @@ import android.graphics.drawable.Icon import android.net.Uri import android.os.* import androidx.documentfile.provider.DocumentFile +import sushi.hardcore.droidfs.GocryptfsVolume import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.explorers.ExplorerElement -import sushi.hardcore.droidfs.GocryptfsVolume import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.Wiper import java.io.File diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt index 3302cfc..58ad05f 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt @@ -90,7 +90,7 @@ class TextEditor: FileViewerActivity() { } } if (offset == content.size.toLong()){ - success = gocryptfsVolume.truncate(filePath, offset) + success = gocryptfsVolume.truncate(handleID, offset) } gocryptfsVolume.closeFile(handleID) buff.close() diff --git a/app/src/main/native/gocryptfs_jni.c b/app/src/main/native/gocryptfs_jni.c index 47d2fd0..8b1463e 100644 --- a/app/src/main/native/gocryptfs_jni.c +++ b/app/src/main/native/gocryptfs_jni.c @@ -33,6 +33,7 @@ void jbyteArray_to_unsignedCharArray(const jbyte* src, unsigned char* dst, const JNIEXPORT jboolean JNICALL Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_createVolume(JNIEnv *env, jclass clazz, jstring jroot_cipher_dir, jcharArray jpassword, + jboolean plainTextNames, jint logN, jstring jcreator) { const char* root_cipher_dir = (*env)->GetStringUTFChars(env, jroot_cipher_dir, NULL); @@ -45,7 +46,7 @@ Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_createVolume(JNIEnv * jcharArray_to_charArray(jchar_password, password, password_len); GoSlice go_password = {password, password_len, password_len}; - GoUint8 result = gcf_create_volume(gofilename, go_password, logN, gocreator); + GoUint8 result = gcf_create_volume(gofilename, go_password, plainTextNames, logN, gocreator); (*env)->ReleaseStringUTFChars(env, jroot_cipher_dir, root_cipher_dir); (*env)->ReleaseStringUTFChars(env, jcreator, creator); @@ -317,11 +318,12 @@ Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1open_1read_1mode(JNIEnv *env JNIEXPORT jint JNICALL Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1open_1write_1mode(JNIEnv *env, jobject thiz, jint sessionID, - jstring jfile_path) { + jstring jfile_path, + jint mode) { const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); GoString go_file_path = {file_path, strlen(file_path)}; - GoInt handleID = gcf_open_write_mode(sessionID, go_file_path); + GoInt handleID = gcf_open_write_mode(sessionID, go_file_path, mode); (*env)->ReleaseStringUTFChars(env, jfile_path, file_path); @@ -362,15 +364,8 @@ Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1read_1file(JNIEnv *env, jobj JNIEXPORT jboolean JNICALL Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1truncate(JNIEnv *env, jobject thiz, jint sessionID, - jstring jfile_path, jlong offset) { - const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); - GoString go_file_path = {file_path, strlen(file_path)}; - - GoUint8 result = gcf_truncate(sessionID, go_file_path, offset); - - (*env)->ReleaseStringUTFChars(env, jfile_path, file_path); - - return result; + jint handleID, jlong offset) { + return gcf_truncate(sessionID, handleID, offset); } JNIEXPORT void JNICALL @@ -395,11 +390,11 @@ Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1remove_1file(JNIEnv *env, jo JNIEXPORT jboolean JNICALL Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1mkdir(JNIEnv *env, jobject thiz, - jint sessionID, jstring jdir_path) { + jint sessionID, jstring jdir_path, jint mode) { const char* dir_path = (*env)->GetStringUTFChars(env, jdir_path, NULL); GoString go_dir_path = {dir_path, strlen(dir_path)}; - GoUint8 result = gcf_mkdir(sessionID, go_dir_path); + GoUint8 result = gcf_mkdir(sessionID, go_dir_path, mode); (*env)->ReleaseStringUTFChars(env, jdir_path, dir_path); diff --git a/app/src/main/res/layout/activity_image_viewer.xml b/app/src/main/res/layout/activity_image_viewer.xml index 062665e..74efc0e 100644 --- a/app/src/main/res/layout/activity_image_viewer.xml +++ b/app/src/main/res/layout/activity_image_viewer.xml @@ -71,7 +71,7 @@ android:src="@drawable/exo_icon_previous"/>