diff options
author | Jakob Unterwurzacher | 2015-09-06 10:38:43 +0200 |
---|---|---|
committer | Jakob Unterwurzacher | 2015-09-06 10:42:34 +0200 |
commit | 58d1e24b7c4eb69376dd0ec230c42ea9aeb70f2d (patch) | |
tree | ac99fc15a5ab2f34fc85ac13188ffa6e4dc11815 | |
parent | ad3a1a88994bbf54e95295d70f7424b67894da3e (diff) |
Add OpenSSL support for file content encryption/decryption
This brings streaming read performance from 30MB/s to 81MB/s
(similar improvement for writes)
-rw-r--r-- | cryptfs/cryptfs.go | 15 | ||||
-rw-r--r-- | cryptfs/cryptfs_content.go | 3 | ||||
-rw-r--r-- | cryptfs/openssl_aead.go | 93 | ||||
-rw-r--r-- | frontend/fe_fs.go | 4 | ||||
-rw-r--r-- | main.go | 3 |
5 files changed, 110 insertions, 8 deletions
diff --git a/cryptfs/cryptfs.go b/cryptfs/cryptfs.go index 9ec511a..40a9024 100644 --- a/cryptfs/cryptfs.go +++ b/cryptfs/cryptfs.go @@ -20,21 +20,26 @@ type CryptFS struct { cipherBS uint64 } -func NewCryptFS(key [16]byte) *CryptFS { +func NewCryptFS(key [16]byte, useOpenssl bool) *CryptFS { b, err := aes.NewCipher(key[:]) if err != nil { panic(err) } - g, err := cipher.NewGCM(b) - if err != nil { - panic(err) + var gcm cipher.AEAD + if useOpenssl { + gcm = opensslGCM{key} + } else { + gcm, err = cipher.NewGCM(b) + if err != nil { + panic(err) + } } return &CryptFS{ blockCipher: b, - gcm: g, + gcm: gcm, plainBS: DEFAULT_PLAINBS, cipherBS: DEFAULT_PLAINBS + NONCE_LEN + AUTH_TAG_LEN, } diff --git a/cryptfs/cryptfs_content.go b/cryptfs/cryptfs_content.go index 512bca9..4658529 100644 --- a/cryptfs/cryptfs_content.go +++ b/cryptfs/cryptfs_content.go @@ -49,8 +49,11 @@ func (be *CryptFS) DecryptBlock(ciphertext []byte) ([]byte, error) { // Decrypt var plaintext []byte + plaintext, err := be.gcm.Open(plaintext, nonce, ciphertext, nil) + if err != nil { + Warn.Printf("DecryptBlock: %s\n", err.Error()) return nil, err } diff --git a/cryptfs/openssl_aead.go b/cryptfs/openssl_aead.go new file mode 100644 index 0000000..02f50d8 --- /dev/null +++ b/cryptfs/openssl_aead.go @@ -0,0 +1,93 @@ +package cryptfs + +// Implements cipher.AEAD with OpenSSL backend + +import ( + "bytes" + "github.com/spacemonkeygo/openssl" +) + +type opensslGCM struct { + key [16]byte +} + +func (be opensslGCM) Overhead() int { + return AUTH_TAG_LEN +} + +func (be opensslGCM) NonceSize() int { + return NONCE_LEN +} + +// Seal encrypts and authenticates plaintext, authenticates the +// additional data and appends the result to dst, returning the updated +// slice. The nonce must be NonceSize() bytes long and unique for all +// time, for a given key. +// +// The plaintext and dst may alias exactly or not at all. +func (be opensslGCM) Seal(dst, nonce, plaintext, data []byte) []byte { + + cipherBuf := bytes.NewBuffer(dst) + + ectx, err := openssl.NewGCMEncryptionCipherCtx(128, nil, be.key[:], nonce[:]) + if err != nil { + panic(err) + } + part, err := ectx.EncryptUpdate(plaintext) + if err != nil { + panic(err) + } + cipherBuf.Write(part) + part, err = ectx.EncryptFinal() + if err != nil { + panic(err) + } + cipherBuf.Write(part) + part, err = ectx.GetTag() + if err != nil { + panic(err) + } + cipherBuf.Write(part) + + return cipherBuf.Bytes() +} + +// Open decrypts and authenticates ciphertext, authenticates the +// additional data and, if successful, appends the resulting plaintext +// to dst, returning the updated slice. The nonce must be NonceSize() +// bytes long and both it and the additional data must match the +// value passed to Seal. +// +// The ciphertext and dst may alias exactly or not at all. +func (be opensslGCM) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { + + if len(data) > 0 { + panic("Extra data is not supported") + } + + l := len(ciphertext) + tag := ciphertext[l-AUTH_TAG_LEN:l] + ciphertext = ciphertext[0:l-AUTH_TAG_LEN] + plainBuf := bytes.NewBuffer(dst) + + dctx, err := openssl.NewGCMDecryptionCipherCtx(128, nil, be.key[:], nonce[:]) + if err != nil { + return nil, err + } + part, err := dctx.DecryptUpdate(ciphertext) + if err != nil { + return nil, err + } + plainBuf.Write(part) + err = dctx.SetTag(tag) + if err != nil { + return nil, err + } + part, err = dctx.DecryptFinal() + if err != nil { + return nil, err + } + plainBuf.Write(part) + + return plainBuf.Bytes(), nil +} diff --git a/frontend/fe_fs.go b/frontend/fe_fs.go index 012d7f0..4d49194 100644 --- a/frontend/fe_fs.go +++ b/frontend/fe_fs.go @@ -27,14 +27,14 @@ type nullTracer struct {} func (nullTracer) Trace(op cluefs.FsOperTracer) {} -func NewFS(key [16]byte, backing string) *FS { +func NewFS(key [16]byte, backing string, useOpenssl bool) *FS { var nt nullTracer clfs, err := cluefs.NewClueFS(backing, nt) if err != nil { panic(err) } return &FS { - CryptFS: cryptfs.NewCryptFS(key), + CryptFS: cryptfs.NewCryptFS(key, useOpenssl), ClueFS: clfs, backing: backing, } @@ -11,6 +11,7 @@ import ( const ( PROGRAM_NAME = "gocryptfs" + USE_OPENSSL = true ) func main() { @@ -22,7 +23,7 @@ func main() { // Create the file system object var key [16]byte - cfs := frontend.NewFS(key, conf.GetShadowDir()) + cfs := frontend.NewFS(key, conf.GetShadowDir(), USE_OPENSSL) // Mount the file system mountOpts := []fuse.MountOption{ |