From 97eb4e9fa117079d7b549f96c6ed31403f5a7c60 Mon Sep 17 00:00:00 2001 From: Ryan Prairie Date: Tue, 28 Dec 2021 00:25:30 -0500 Subject: [PATCH] Add IO buffering to encryptfile & decryptfile Add IO buffering with bufio to encryptfile and decryptfile with a buffer size of 10KB. By default, golang IO operations arent buffered and so adding buffering is a key way to gain some performance. Obviously this doesnt work for everything. For imacry, im not 100% sure it will work. IO optimization is tricky. The reason we used a stream cypher and reading blocks 1KB at a time is not to hog memory and allow more concurrency, unfortunately this leads to possible unnecessary reads. Buffering IO can possibly get around part of that issue. Hopefully the buffer size of 10KB(or 10 blocks) can help cut down on that without hogging too much memory. The only real way to know for sure is extensive benchmarking which I probably will not do. Who knows, maybe I will in the future. --- pkg/decryptfile/decryptfile.go | 13 ++++++++++++- pkg/encryptfile/encryptfile.go | 16 ++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/pkg/decryptfile/decryptfile.go b/pkg/decryptfile/decryptfile.go index 9cff91e..163ff0a 100644 --- a/pkg/decryptfile/decryptfile.go +++ b/pkg/decryptfile/decryptfile.go @@ -1,6 +1,7 @@ package decryptfile import ( + "bufio" "crypto/aes" "crypto/cipher" "fmt" @@ -44,6 +45,8 @@ func (df DecryptFile) Do(filePath string) error { return fmt.Errorf("decryptfile.Do error: %w", err) } + outfileBuf := bufio.NewWriterSize(outfile, 10240) + // Get the initialization vector from the beginning of the input file. iv := make([]byte, cipherBlock.BlockSize()) if _, err := infile.Read(iv); err != nil { @@ -57,11 +60,19 @@ func (df DecryptFile) Do(filePath string) error { n, err := infile.Read(buf) if n > 0 { stream.XORKeyStream(buf, buf[:n]) - outfile.Write(buf[:n]) + _, err := outfileBuf.Write(buf[:n]) + if err != nil { + return fmt.Errorf("decryptfile.Do error: %w", err) + } + } // EOF has been reached if err == io.EOF { + err := outfileBuf.Flush() + if err != nil { + return fmt.Errorf("decryptfile.Do error: %w", err) + } break } diff --git a/pkg/encryptfile/encryptfile.go b/pkg/encryptfile/encryptfile.go index 7e8d266..c005619 100644 --- a/pkg/encryptfile/encryptfile.go +++ b/pkg/encryptfile/encryptfile.go @@ -1,6 +1,7 @@ package encryptfile import ( + "bufio" "crypto/aes" "crypto/cipher" "crypto/rand" @@ -48,7 +49,10 @@ func (ef EncryptFile) Do(filePath string) error { return fmt.Errorf("encryptfile.Do error: %w", err) } - outfile.Write(iv) + // write buffer with size of 10KB + outfileBuf := bufio.NewWriterSize(outfile, 10240) + + outfileBuf.Write(iv) buf := make([]byte, 1024) stream := cipher.NewCTR(cipherBlock, iv) @@ -56,11 +60,19 @@ func (ef EncryptFile) Do(filePath string) error { n, err := infile.Read(buf) if n > 0 { stream.XORKeyStream(buf, buf[:n]) - outfile.Write(buf[:n]) + _, err := outfileBuf.Write(buf[:n]) + if err != nil { + return fmt.Errorf("encryptfile.Do error: %w", err) + } + } // if it gets EOF break out of loop if err == io.EOF { + err := outfileBuf.Flush() + if err != nil { + return fmt.Errorf("encryptfile.Do error: %w", err) + } break }