diff options
Diffstat (limited to 'cryptfs')
| -rw-r--r-- | cryptfs/config_file.go | 104 | ||||
| -rw-r--r-- | cryptfs/cryptfs.go | 1 | ||||
| -rw-r--r-- | cryptfs/nonce.go | 9 | 
3 files changed, 110 insertions, 4 deletions
| diff --git a/cryptfs/config_file.go b/cryptfs/config_file.go new file mode 100644 index 0000000..752ed09 --- /dev/null +++ b/cryptfs/config_file.go @@ -0,0 +1,104 @@ +package cryptfs + +import ( +	"errors" +	"io/ioutil" +	"encoding/json" +) +import "os" + +const ( +	// Changing this string breaks backward compatability +	testBlockData = "gocryptfs test block" + +	// The dot "." is not used in base64url (RFC4648), hence +	// we can never clash with an encrypted file. +	ConfDefaultName = "gocryptfs.conf" +) + +type confFile struct { +	// File the config is saved in. Lowercase => not exported to JSON. +	filename string +	// Unencrypted AES key +	Key [16]byte +	// GCM ciphertext with auth tag to verify the key is correct +	TestBlock []byte +} + +// CreateConfFile - create a new config file with "key" and write to "filename" +func CreateConfFile(filename string, key [16]byte) error { +	var cf confFile +	cf.filename = filename +	cf.Key = key + +	// Generate test block +	cfs := NewCryptFS(cf.Key, false) +	cf.TestBlock = cfs.EncryptBlock([]byte(testBlockData)) + +	// Write file to disk +	err := cf.WriteFile() + +	return err +} + +// LoadConfFile - read config file from disk and verify the key using the +// embedded TestBlock +func LoadConfFile(filename string) (*confFile, error) { +	// Read from disk +	js, err := ioutil.ReadFile(filename) +	if err != nil { +		return nil, err +	} +	var cf confFile +	err = json.Unmarshal(js, &cf) +	if err != nil { +		return nil, err +	} +	cf.filename = filename + +	// Try to decrypt the test block to see if the key is correct +	// +	// Speed does not matter here. Use built-in crypto. +	cfs := NewCryptFS(cf.Key, false) +	d, err := cfs.DecryptBlock(cf.TestBlock) +	if err != nil { +		return nil, err +	} +	ds := string(d) +	if ds != testBlockData { +		return nil, errors.New("Invalid test block content: " + ds) +	} +	return &cf, nil +} + +// WriteFile - write out config in JSON format to file "filename.tmp" +// then rename over "filename" +func (cf *confFile) WriteFile() error { +	tmp := cf.filename + ".tmp" +	fd, err := os.Create(tmp) +	if err != nil { +		return err +	} +	js, err := json.Marshal(cf) +	if err != nil { +		return err +	} +	_, err = fd.Write(js) +	if err != nil { +		return err +	} +	err = fd.Sync() +	if err != nil { +		return err +	} +	err = fd.Close() +	if err != nil { +		return err +	} +	err = os.Rename(tmp, cf.filename) +	if err != nil { +		return err +	} + +	return nil +} diff --git a/cryptfs/cryptfs.go b/cryptfs/cryptfs.go index 40a9024..8927d74 100644 --- a/cryptfs/cryptfs.go +++ b/cryptfs/cryptfs.go @@ -8,6 +8,7 @@ import (  )  const ( +	KEY_LEN = 16  	NONCE_LEN = 12  	AUTH_TAG_LEN = 16  	DEFAULT_PLAINBS = 4096 diff --git a/cryptfs/nonce.go b/cryptfs/nonce.go index f93f59c..3e464a3 100644 --- a/cryptfs/nonce.go +++ b/cryptfs/nonce.go @@ -16,8 +16,9 @@ type nonce96 struct {  var gcmNonce nonce96 -func (n *nonce96) randBytes(len int) []byte { -	b := make([]byte, len) +// Get "n" random bytes from /dev/urandom or panic +func RandBytes(n int) []byte { +	b := make([]byte, n)  	_, err := rand.Read(b)  	if err != nil {  		panic("Could not get random bytes for nonce") @@ -26,9 +27,9 @@ func (n *nonce96) randBytes(len int) []byte {  }  func (n *nonce96) init() { -	b := n.randBytes(8) +	b := RandBytes(8)  	n.low64 = binary.BigEndian.Uint64(b) -	b = n.randBytes(4) +	b = RandBytes(4)  	n.high32 = binary.BigEndian.Uint32(b)  	n.ready = 1  	return | 
