Skip to content

Short flag support #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ File Encryptor is a command-line tool written in Go that provides secure file en
- Support for **all file types**: text, images (JPG, PNG), videos, spreadsheets, and more
- Parallel processing for faster encryption and decryption of large files

**File Support Note**:
**File Support Note**:
- The tool supports all file types, including:
- **Text**: TXT, CSV, JSON
- **Media**: JPG, PNG, MP4
Expand All @@ -32,7 +32,7 @@ Example usage ensures seamless encryption and decryption without data corruption

2. Clone this repository:
```bash
git clone https://github.com/yourusername/file-encryptor.git
git clone https://github.com/sd416/file-encryptor.git
```

3. Navigate to the project directory:
Expand All @@ -42,7 +42,7 @@ Example usage ensures seamless encryption and decryption without data corruption

4. Build the project:
```bash
go build -o file-encryptor main.go
go build -o file-encryptor cmd/file-encryptor/main.go
```

## Usage
Expand All @@ -60,21 +60,29 @@ ssh-keygen -t rsa -b 4096 -f my_ssh_key

#### Encrypt a file using an RSA public key:
```bash
./file-encryptor -e --file <input_file> --key my_ssh_key.pub
./file-encryptor -e --file <input_file> --key <public_key_file>
# or using short flags
./file-encryptor -e -f <input_file> -k <public_key_file>
```
Example:
```bash
./file-encryptor -e --file picture.jpg --key my_ssh_key.pub
# or
./file-encryptor -e -f picture.jpg -k my_ssh_key.pub
```
- The encrypted file will be saved as `picture.jpg.enc`.

#### Encrypt a file using a password:
```bash
./file-encryptor -e --file <input_file> --password <your_password>
# or using short flags
./file-encryptor -e -f <input_file> -p <your_password>
```
Example:
```bash
./file-encryptor -e --file document.pdf --password myStrongPassword123
# or
./file-encryptor -e -f document.pdf -p myStrongPassword123
```

---
Expand All @@ -83,21 +91,29 @@ Example:

#### Decrypt a file using an RSA private key:
```bash
./file-encryptor -d --file <encrypted_file> --key my_ssh_key
./file-encryptor -d --file <encrypted_file> --key <private_key_file>
# or using short flags
./file-encryptor -d -f <encrypted_file> -k <private_key_file>
```
Example:
```bash
./file-encryptor -d --file picture.jpg.enc --key my_ssh_key
# or
./file-encryptor -d -f picture.jpg.enc -k my_ssh_key
```
- The decrypted file will retain its original extension (e.g., `picture.jpg`).

#### Decrypt a file using a password:
```bash
./file-encryptor -d --file <encrypted_file> --password <your_password>
# or using short flags
./file-encryptor -d -f <encrypted_file> -p <your_password>
```
Example:
```bash
./file-encryptor -d --file document.pdf.enc --password myStrongPassword123
# or
./file-encryptor -d -f document.pdf.enc -p myStrongPassword123
```

---
Expand Down Expand Up @@ -126,4 +142,3 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
This tool is provided as-is, without any warranties. Always ensure you have backups of your important files before encryption.

---

29 changes: 21 additions & 8 deletions cmd/file-encryptor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,23 @@ import (

func main() {
logger := logging.NewLogger()
logger.LogDebug("Starting file encryptor")

encrypt := flag.Bool("e", false, "Encrypt the file")
decrypt := flag.Bool("d", false, "Decrypt the file")

// Define both short and long flag names for file and key
file := flag.String("file", "", "File to encrypt or decrypt")
key := flag.String("key", "", "Path to the key file (public key for encryption, private key for decryption)")
flag.StringVar(file, "f", "", "File to encrypt or decrypt (shorthand)") //Bind short flag to the same variable
key := flag.String("key", "", "Path to the key file")
flag.StringVar(key, "k", "", "Path to the key file (shorthand)") //Bind short flag to the same variable

password := flag.String("password", "", "Password for encryption/decryption (alternative to key file)")
flag.StringVar(password, "p", "", "Password for encryption/decryption (shorthand)") //Bind short flag to the same variable
flag.Parse()
logger.LogDebug("Parsed command line flags")

// Use the flag values after parsing.
if err := validateFlags(*encrypt, *decrypt, *file, *key, *password); err != nil {
logger.LogError(err.Error())
flag.Usage()
Expand All @@ -36,16 +45,18 @@ func main() {
operation = "Decryption"
outputFile, err = handleDecryption(*file, *key, *password, logger)
}
logger.LogDebugf("Operation: %s, Output file: %s", operation, outputFile)

if err != nil {
logger.LogError(fmt.Sprintf("%v", err))
if os.IsNotExist(err) {
logger.Log("Please check if the specified file and key exist and are readable.")
logger.LogInfo("Please check if the specified file and key exist and are readable.")
}
os.Exit(1)
}

logger.Log(fmt.Sprintf("File %s completed. Output file: %s", strings.ToLower(operation), outputFile))
logger.LogInfo(fmt.Sprintf("File %s completed. Output file: %s", strings.ToLower(operation), outputFile))
logger.LogDebug("File encryption/decryption completed")
}

func validateFlags(encrypt, decrypt bool, file, key, password string) error {
Expand All @@ -54,22 +65,22 @@ func validateFlags(encrypt, decrypt bool, file, key, password string) error {
}

if file == "" {
return fmt.Errorf("please provide the --file argument")
return fmt.Errorf("please provide the --file or -f argument")
}

if key == "" && password == "" {
return fmt.Errorf("please provide either --key or --password argument")
return fmt.Errorf("please provide either --key or -k or --password or -p argument")
}

if key != "" && password != "" {
return fmt.Errorf("please provide either --key or --password, not both")
return fmt.Errorf("please provide either --key or -k or --password or -p, not both")
}

return nil
}

func handleEncryption(file, key, password string, logger *logging.Logger) (string, error) {
logger.Log("Starting file encryption")
logger.LogInfo("Starting file encryption")
var encryptor crypto.Encryptor
var err error

Expand All @@ -78,6 +89,7 @@ func handleEncryption(file, key, password string, logger *logging.Logger) (strin
} else {
encryptor, err = crypto.NewPasswordEncryptor(password)
}
logger.LogDebugf("Initialized encryptor: %T", encryptor)

if err != nil {
return "", fmt.Errorf("error initializing encryptor: %v", err)
Expand All @@ -89,7 +101,7 @@ func handleEncryption(file, key, password string, logger *logging.Logger) (strin
}

func handleDecryption(file, key, password string, logger *logging.Logger) (string, error) {
logger.Log("Starting file decryption")
logger.LogInfo("Starting file decryption")
var decryptor crypto.Decryptor
var err error

Expand All @@ -98,6 +110,7 @@ func handleDecryption(file, key, password string, logger *logging.Logger) (strin
} else {
decryptor, err = crypto.NewPasswordDecryptor(password)
}
logger.LogDebugf("Initialized decryptor: %T", decryptor)

if err != nil {
return "", fmt.Errorf("error initializing decryptor: %v", err)
Expand Down
75 changes: 43 additions & 32 deletions pkg/crypto/aes.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,55 @@
package crypto

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

func EncryptAES(plaintext, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(key) != 32 {
return nil, fmt.Errorf("invalid key size: expected 32 bytes, got %d", len(key))
}

ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("failed to create cipher: %v", err)
}

stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, fmt.Errorf("failed to generate IV: %v", err)
}

return ciphertext, nil
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

return ciphertext, nil
}

func DecryptAES(ciphertext, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}

if len(ciphertext) < aes.BlockSize {
return nil, err
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]

stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(ciphertext, ciphertext)

return ciphertext, nil
}
if len(key) != 32 {
return nil, fmt.Errorf("invalid key size: expected 32 bytes, got %d", len(key))
}

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

if len(ciphertext) < aes.BlockSize {
return nil, fmt.Errorf("ciphertext too short")
}

iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]

stream := cipher.NewCFBDecrypter(block, iv)
plaintext := make([]byte, len(ciphertext))
stream.XORKeyStream(plaintext, ciphertext)

return plaintext, nil
}
27 changes: 16 additions & 11 deletions pkg/fileops/fileops.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import (
"io"
"os"
"path/filepath"
"strings"
"time"
)

const chunkSize = 64 * 1024 // 64KB chunks

func EncryptFile(inputFile, outputFile string, encryptor crypto.Encryptor, logger *logging.Logger) error {
logger.Log(fmt.Sprintf("Starting encryption of file: %s", inputFile))
logger.LogInfo(fmt.Sprintf("Starting encryption of file: %s", inputFile))
startTime := time.Now()

inFile, err := os.Open(inputFile)
Expand Down Expand Up @@ -73,12 +74,12 @@ func EncryptFile(inputFile, outputFile string, encryptor crypto.Encryptor, logge
return err
}

logger.Log(fmt.Sprintf("Encryption completed in %v", time.Since(startTime)))
logger.LogInfof("Encryption completed in %v", time.Since(startTime))
return nil
}

func DecryptFile(inputFile, outputFile string, decryptor crypto.Decryptor, logger *logging.Logger) error {
logger.Log(fmt.Sprintf("Starting decryption of file: %s", inputFile))
logger.LogInfo(fmt.Sprintf("Starting decryption of file: %s", inputFile))
startTime := time.Now()

inFile, err := os.Open(inputFile)
Expand All @@ -94,7 +95,10 @@ func DecryptFile(inputFile, outputFile string, decryptor crypto.Decryptor, logge
if err != nil {
return err
}
outputFile += extension
// FIX: Construct outputFile correctly to avoid double extension
outputFile = strings.TrimSuffix(outputFile, filepath.Ext(outputFile)) // Remove existing extension (if any)
outputFile += extension


outFile, err := os.Create(outputFile)
if err != nil {
Expand Down Expand Up @@ -125,7 +129,7 @@ func DecryptFile(inputFile, outputFile string, decryptor crypto.Decryptor, logge
return err
}

logger.Log(fmt.Sprintf("Decryption completed in %v", time.Since(startTime)))
logger.LogInfof("Decryption completed in %v", time.Since(startTime))
return nil
}

Expand Down Expand Up @@ -167,21 +171,22 @@ func readLengthAndData(r *bufio.Reader) ([]byte, error) {

func processFileContent(r *bufio.Reader, w *bufio.Writer, stream cipher.Stream) error {
buf := make([]byte, chunkSize)
outBuf := make([]byte, chunkSize)

for {
n, err := r.Read(buf)
if n > 0 {
encrypted := make([]byte, n)
stream.XORKeyStream(encrypted, buf[:n])
if _, err := w.Write(encrypted); err != nil {
return err
stream.XORKeyStream(outBuf[:n], buf[:n])
if _, err := w.Write(outBuf[:n]); err != nil {
return fmt.Errorf("write error: %v", err)
}
}
if err == io.EOF {
break
}
if err != nil {
return err
return fmt.Errorf("read error: %v", err)
}
}
return nil
return w.Flush()
}
Loading