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 |