You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
5.1 KiB
Go
199 lines
5.1 KiB
Go
// gocryptfs is an encrypted overlay filesystem written in Go.
|
|
// See README.md ( https://github.com/rfjakob/gocryptfs/blob/master/README.md )
|
|
// and the official website ( https://nuetzlich.net/gocryptfs/ ) for details.
|
|
package main
|
|
|
|
import (
|
|
"C"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"libgocryptfs/v2/internal/configfile"
|
|
"libgocryptfs/v2/internal/contentenc"
|
|
"libgocryptfs/v2/internal/cryptocore"
|
|
"libgocryptfs/v2/internal/nametransform"
|
|
"libgocryptfs/v2/internal/stupidgcm"
|
|
"libgocryptfs/v2/internal/syscallcompat"
|
|
)
|
|
|
|
type Directory struct {
|
|
fd int
|
|
iv []byte
|
|
}
|
|
|
|
type File struct {
|
|
fd *os.File
|
|
path string
|
|
}
|
|
|
|
type Volume struct {
|
|
volumeID int
|
|
rootCipherDir 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 OpenedVolumes map[int]Volume
|
|
|
|
func wipe(d []byte) {
|
|
for i := range d {
|
|
d[i] = 0
|
|
}
|
|
d = nil
|
|
}
|
|
|
|
func clearDirCache(volumeID int) {
|
|
for k := range OpenedVolumes[volumeID].dirCache {
|
|
delete(OpenedVolumes[volumeID].dirCache, k)
|
|
}
|
|
}
|
|
|
|
func errToBool(err error) bool {
|
|
return err == nil
|
|
}
|
|
|
|
func registerNewVolume(rootCipherDir string, masterkey []byte, cf *configfile.ConfFile) int {
|
|
var newVolume Volume
|
|
|
|
newVolume.plainTextNames = cf.IsFeatureFlagSet(configfile.FlagPlaintextNames)
|
|
|
|
cryptoBackend, err := cf.ContentEncryption()
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
if cryptoBackend == cryptocore.BackendXChaCha20Poly1305 && stupidgcm.PreferOpenSSLXchacha20poly1305() {
|
|
cryptoBackend = cryptocore.BackendXChaCha20Poly1305OpenSSL
|
|
} else if cryptoBackend == cryptocore.BackendGoGCM && stupidgcm.PreferOpenSSLAES256GCM() {
|
|
cryptoBackend = cryptocore.BackendOpenSSL
|
|
}
|
|
newVolume.cryptoCore = cryptocore.New(masterkey, cryptoBackend, cryptoBackend.NonceSize*8, cf.IsFeatureFlagSet(configfile.FlagHKDF))
|
|
newVolume.contentEnc = contentenc.New(newVolume.cryptoCore, contentenc.DefaultBS)
|
|
var badname []string
|
|
newVolume.nameTransform = nametransform.New(
|
|
newVolume.cryptoCore.EMECipher,
|
|
true,
|
|
cf.IsFeatureFlagSet(configfile.FlagRaw64),
|
|
badname,
|
|
!cf.IsFeatureFlagSet(configfile.FlagDirIV),
|
|
)
|
|
|
|
//copying rootCipherDir
|
|
var grcd strings.Builder
|
|
grcd.WriteString(rootCipherDir)
|
|
newVolume.rootCipherDir = grcd.String()
|
|
|
|
// New empty caches
|
|
newVolume.dirCache = make(map[string]Directory)
|
|
newVolume.file_handles = make(map[int]File)
|
|
newVolume.fileIDs = make(map[int][]byte)
|
|
|
|
//find unused volumeID
|
|
volumeID := -1
|
|
c := 0
|
|
for volumeID == -1 {
|
|
_, ok := OpenedVolumes[c]
|
|
if !ok {
|
|
volumeID = c
|
|
}
|
|
c++
|
|
}
|
|
if OpenedVolumes == nil {
|
|
OpenedVolumes = make(map[int]Volume)
|
|
}
|
|
OpenedVolumes[volumeID] = newVolume
|
|
return volumeID
|
|
}
|
|
|
|
//export gcf_init
|
|
func gcf_init(rootCipherDir string, password, givenScryptHash, returnedScryptHashBuff []byte) int {
|
|
volumeID := -1
|
|
cf, err := configfile.Load(filepath.Join(rootCipherDir, configfile.ConfDefaultName))
|
|
if err == nil {
|
|
masterkey := cf.GetMasterkey(password, givenScryptHash, returnedScryptHashBuff)
|
|
if masterkey != nil {
|
|
volumeID = registerNewVolume(rootCipherDir, masterkey, cf)
|
|
wipe(masterkey)
|
|
}
|
|
}
|
|
return volumeID
|
|
}
|
|
|
|
//export gcf_close
|
|
func gcf_close(volumeID int) {
|
|
OpenedVolumes[volumeID].cryptoCore.Wipe()
|
|
for handleID := range OpenedVolumes[volumeID].file_handles {
|
|
gcf_close_file(volumeID, handleID)
|
|
}
|
|
clearDirCache(volumeID)
|
|
delete(OpenedVolumes, volumeID)
|
|
}
|
|
|
|
//export gcf_is_closed
|
|
func gcf_is_closed(volumeID int) bool {
|
|
_, ok := OpenedVolumes[volumeID]
|
|
return !ok
|
|
}
|
|
|
|
//export gcf_change_password
|
|
func gcf_change_password(rootCipherDir string, oldPassword, givenScryptHash, new_password, returnedScryptHashBuff []byte) bool {
|
|
success := false
|
|
cf, err := configfile.Load(filepath.Join(rootCipherDir, configfile.ConfDefaultName))
|
|
if err == nil {
|
|
masterkey := cf.GetMasterkey(oldPassword, 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 = errToBool(cf.WriteFile())
|
|
}
|
|
}
|
|
return success
|
|
}
|
|
|
|
//export gcf_create_volume
|
|
func gcf_create_volume(rootCipherDir string, password []byte, plaintextNames bool, xchacha int8, logN int, creator string) bool {
|
|
var useXChaCha bool
|
|
switch xchacha {
|
|
case 1:
|
|
useXChaCha = true
|
|
case 0:
|
|
useXChaCha = false
|
|
default:
|
|
useXChaCha = !stupidgcm.CpuHasAES()
|
|
}
|
|
err := configfile.Create(&configfile.CreateArgs{
|
|
Filename: filepath.Join(rootCipherDir, configfile.ConfDefaultName),
|
|
Password: password,
|
|
PlaintextNames: plaintextNames,
|
|
LogN: logN,
|
|
Creator: creator,
|
|
AESSIV: false,
|
|
DeterministicNames: false,
|
|
XChaCha20Poly1305: useXChaCha,
|
|
})
|
|
if err == nil {
|
|
if plaintextNames {
|
|
return true
|
|
} else {
|
|
dirfd, err := syscall.Open(rootCipherDir, syscall.O_DIRECTORY|syscallcompat.O_PATH, 0)
|
|
if err == nil {
|
|
err = nametransform.WriteDirIVAt(dirfd)
|
|
syscall.Close(dirfd)
|
|
return errToBool(err)
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|