Skip to content

Commit

Permalink
feat: refactor code to use reader-writer approach
Browse files Browse the repository at this point in the history
  • Loading branch information
mrf345 committed Sep 3, 2024
1 parent 118925e commit adc6a28
Show file tree
Hide file tree
Showing 34 changed files with 745 additions and 784 deletions.
16 changes: 14 additions & 2 deletions cmd/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package cmd

import (
"context"
"os"

"github.com/mrf345/safelock-cli/safelock"
"github.com/mrf345/safelock-cli/slErrs"
"github.com/mrf345/safelock-cli/utils"
"github.com/spf13/cobra"
)
Expand All @@ -16,6 +18,7 @@ var decryptCmd = &cobra.Command{
var err error
var pwd string
var sl *safelock.Safelock
var inputFile *os.File
const example = "example: safelock-cli decrypt encrypted.bin decrypted_files"

switch len(args) {
Expand All @@ -31,6 +34,8 @@ var decryptCmd = &cobra.Command{

if useSha256 {
sl = safelock.NewSha256()
} else if useSha512 {
sl = safelock.NewSha512()
} else {
sl = safelock.New()
}
Expand All @@ -40,10 +45,17 @@ var decryptCmd = &cobra.Command{
}

sl.Quiet = beQuiet
sl.Registry.TempDir = tempDir
inputPath, outputPath := args[0], args[1]

if err = sl.Decrypt(context.TODO(), inputPath, outputPath, pwd); err != nil {
if inputFile, err = os.Open(inputPath); err != nil {
utils.PrintErrsAndExit((&slErrs.ErrInvalidInputPath{
Path: inputPath,
Err: err,
}).Error())
}
defer inputFile.Close()

if err = sl.Decrypt(context.TODO(), inputFile, outputPath, pwd); err != nil {
utils.PrintErrsAndExit(err.Error())
}
},
Expand Down
16 changes: 14 additions & 2 deletions cmd/encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package cmd

import (
"context"
"os"

"github.com/spf13/cobra"

"github.com/mrf345/safelock-cli/safelock"
"github.com/mrf345/safelock-cli/slErrs"
"github.com/mrf345/safelock-cli/utils"
)

Expand All @@ -17,6 +19,7 @@ var encryptCmd = &cobra.Command{
var err error
var pwd string
var sl *safelock.Safelock
var outputFile *os.File
const example = "example: safelock-cli encrypt test.txt encrypted.bin"

switch len(args) {
Expand All @@ -32,6 +35,8 @@ var encryptCmd = &cobra.Command{

if useSha256 {
sl = safelock.NewSha256()
} else if useSha512 {
sl = safelock.NewSha512()
} else {
sl = safelock.New()
}
Expand All @@ -41,10 +46,17 @@ var encryptCmd = &cobra.Command{
}

sl.Quiet = beQuiet
sl.Registry.TempDir = tempDir
inputPath, outputPath := []string{args[0]}, args[1]

if err = sl.Encrypt(context.TODO(), inputPath, outputPath, pwd); err != nil {
if outputFile, err = os.OpenFile(outputPath, os.O_RDWR|os.O_CREATE, 0776); err != nil {
utils.PrintErrsAndExit((&slErrs.ErrInvalidOutputPath{
Path: outputPath,
Err: err,
}).Error())
}
defer outputFile.Close()

if err = sl.Encrypt(context.TODO(), inputPath, outputFile, pwd); err != nil {
utils.PrintErrsAndExit(err.Error())
}
},
Expand Down
13 changes: 7 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import (
)

var useSha256 bool
var useSha512 bool
var beQuiet bool
var tempDir string

var rootCmd = &cobra.Command{
Use: "safelock-cli",
Short: "Simple tool to encrypt/decrypt files with AES encryption",
Long: "Simple command-line tool to encrypt and decrypt files with AES encryption",
Use: "safelock-cli",
Short: "Simple tool to encrypt/decrypt files with AES encryption",
Long: "Simple command-line tool to encrypt and decrypt files with AES encryption",
Version: "0.4.0",
CompletionOptions: cobra.CompletionOptions{
DisableDefaultCmd: true,
},
Expand All @@ -29,7 +30,7 @@ func Execute() {
}

func init() {
rootCmd.PersistentFlags().BoolVar(&useSha256, "sha256", false, "use SHA256 (faster) instead of SHA512")
rootCmd.PersistentFlags().BoolVar(&useSha256, "sha256", false, "use sha256 for hashing")
rootCmd.PersistentFlags().BoolVar(&useSha512, "sha512", false, "use sha512 for hashing")
rootCmd.PersistentFlags().BoolVar(&beQuiet, "quiet", false, "disable output logs")
rootCmd.PersistentFlags().StringVar(&tempDir, "temp-dir", os.TempDir(), "directory for temporary files")
}
10 changes: 0 additions & 10 deletions errors/contextExpired.go

This file was deleted.

13 changes: 0 additions & 13 deletions errors/invalidDirectory.go

This file was deleted.

13 changes: 0 additions & 13 deletions errors/invalidFile.go

This file was deleted.

11 changes: 0 additions & 11 deletions errors/main.go

This file was deleted.

2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ⚡ Fast files encryption (AES-GSM) command-line tool and package.
//
// Checkout [safelock-cli/safelock] for package references and examples, And the GitHub [repo] for updates.
// See [safelock-cli/safelock] for package references and examples, And the GitHub [repo] for updates.
//
// # Install
//
Expand Down
113 changes: 113 additions & 0 deletions safelock/core.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package safelock

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"

slErrs "github.com/mrf345/safelock-cli/slErrs"
"golang.org/x/crypto/pbkdf2"
)

type asyncGcmItem struct {
gcm *cipher.AEAD
nonce *[]byte
}

type asyncGcm struct {
items chan *asyncGcmItem
pwd string
config EncryptionConfig
errs chan<- error
done chan bool
}

func newAsyncGcm(pwd string, config EncryptionConfig, errs chan<- error) *asyncGcm {
ag := &asyncGcm{
pwd: pwd,
config: config,
errs: errs,
done: make(chan bool, 1),
items: make(chan *asyncGcmItem, config.GcmBufferSize),
}
go ag.load()
return ag
}

func (ag *asyncGcm) load() {
var err error

for {
var gcm cipher.AEAD
var nonce = make([]byte, ag.config.NonceLength)

select {
case <-ag.done:
close(ag.items)
close(ag.done)
return
default:
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
ag.errs <- fmt.Errorf("failed to create random nonce > %w", err)
return
}

if gcm, err = getGCM(ag.pwd, nonce, ag.config); err != nil {
ag.errs <- fmt.Errorf("failed to create new GCM > %w", err)
return
}

ag.items <- &asyncGcmItem{
gcm: &gcm,
nonce: &nonce,
}
}
}
}

func getGCM(pwd string, nonce []byte, config EncryptionConfig) (gcm cipher.AEAD, err error) {
var block cipher.Block

key := pbkdf2.Key([]byte(pwd), nonce, config.KeyLength, config.IterationCount, config.Hash)

if block, err = aes.NewCipher(key); err != nil {
err = fmt.Errorf("failed to create new cipher > %w", err)
return
}

if gcm, err = cipher.NewGCM(block); err != nil {
err = fmt.Errorf("failed to create new GCM > %w", err)
return
}

return
}

func (ag *asyncGcm) encryptChunk(chunk []byte) []byte {
item := <-ag.items
return append(
(*item.gcm).Seal(nil, *item.nonce, chunk[:], nil),
*item.nonce...,
)
}

func decryptChunk(chunk []byte, pwd string, limit int, config EncryptionConfig) (output []byte, err error) {
var gcm cipher.AEAD

encrypted := chunk[:limit-(config.NonceLength)]
nonce := chunk[limit-(config.NonceLength) : limit]

if gcm, err = getGCM(pwd, nonce, config); err != nil {
err = fmt.Errorf("failed to create new GCM > %w", err)
return
}

if output, err = gcm.Open(nil, nonce, encrypted, nil); err != nil {
err = &slErrs.ErrFailedToAuthenticate{Msg: err.Error()}
return
}

return
}
Loading

0 comments on commit adc6a28

Please sign in to comment.