Skip to content

Commit

Permalink
Encrypt and decrypt archives
Browse files Browse the repository at this point in the history
  • Loading branch information
angelsolaorbaiceta committed Sep 5, 2024
1 parent 9ce9acf commit 489845f
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 0 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,32 @@ Listing the contents of an archive:
$ aar list -f archive.aarch
```

Encrypting an archive:

```bash
$ aar encrypt -f archive.aarch
Password: <password>
```

Where `<password>` is the password you want to use to encrypt the archive, with a minimum length of 8 characters.
It removes the original _.aarch_ file and creates a new one with the encrypted data, with extension _.aarch.enc_.

> [!NOTE]
> The encryption is done using the AES-256-GCM algorithm, and it only works for angel archives.
Decrypting an archive:

```bash
$ aar decrypt -f archive.aarch.enc
Password: <password>
```

Where `<password>` is the password you used to encrypt the archive.
It removes the encrypted _.aarch.enc_ file and creates a new one with the decrypted data, with extension _.aarch_.

> [!NOTE]
> The decryption is done using the AES-256-GCM algorithm, and it only works for encrypted angel archives.
## File Format

### Archive Header
Expand Down
47 changes: 47 additions & 0 deletions cmd/aar/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"flag"
"fmt"
"os"
"syscall"

"github.com/angelsolaorbaiceta/aar/cmd"
"golang.org/x/term"
)

func main() {
Expand All @@ -19,6 +21,12 @@ func main() {

listCmd = flag.NewFlagSet("list", flag.ExitOnError)
listFileNameFlag = listCmd.String("f", "", "Filename of the archive to list")

encryptCmd = flag.NewFlagSet("encrypt", flag.ExitOnError)
encryptFileNameFlag = encryptCmd.String("f", "", "Filename of the archive to encrypt")

decryptCmd = flag.NewFlagSet("decrypt", flag.ExitOnError)
decryptFileNameFlag = decryptCmd.String("f", "", "Filename of the archive to decrypt")
)

if len(os.Args) < 2 {
Expand Down Expand Up @@ -48,6 +56,20 @@ func main() {
validateFileName(*listFileNameFlag)
cmd.ListArchive(*listFileNameFlag)

case "encrypt":
encryptCmd.Parse(os.Args[2:])
validateFileName(*encryptFileNameFlag)
password := promptPassword()

cmd.EncryptArchive(*encryptFileNameFlag, password)

case "decrypt":
decryptCmd.Parse(os.Args[2:])
validateFileName(*decryptFileNameFlag)
password := promptPassword()

cmd.DecryptArchive(*decryptFileNameFlag, password)

default:
fmt.Fprintf(os.Stderr, "Usage: aar <command> [options]\n")
os.Exit(1)
Expand All @@ -69,3 +91,28 @@ func createArchive(fileName string, fileNames []string) {

cmd.CreateArchive(fileName, fileNames)
}

func promptPassword() string {
fmt.Print("Password: ")

// Disable input echoing
passwordBytes, err := term.ReadPassword(int(syscall.Stdin))
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading password: %v\n", err)
os.Exit(1)
}

fmt.Println() // Move to the next line after password input

password := string(passwordBytes)
validatePassword(password)

return password
}

func validatePassword(password string) {
if len(password) < 8 {
fmt.Fprintf(os.Stderr, "The password must be at least 8 characters long.\n")
os.Exit(1)
}
}
107 changes: 107 additions & 0 deletions cmd/cypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package cmd

import (
"fmt"
"os"

"github.com/angelsolaorbaiceta/aar/archive"
)

func EncryptArchive(fileName, password string) {
// Read the archive
reader, err := os.OpenFile(fileName, os.O_RDONLY, 0)
if err != nil {
fmt.Fprintf(os.Stderr, "Error opening archive file: %v\n", err)
os.Exit(1)
}

arch, err := archive.ReadArchive(reader)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading archive: %v\n", err)
os.Exit(1)
}

// Encrypt the archive
encArch, err := arch.Encrypt(password)
if err != nil {
fmt.Fprintf(os.Stderr, "Error encrypting archive: %v\n", err)
os.Exit(1)
}

// Write the encrypted archive to disk
encFileName := fileName + ".enc"
encFile, err := os.Create(encFileName)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating encrypted archive file: %v\n", err)
os.Exit(1)
}
defer encFile.Close()

if err := encArch.Write(encFile); err != nil {
fmt.Fprintf(os.Stderr, "Error writing encrypted archive file: %v\n", err)
os.Exit(1)
}

fmt.Fprintf(os.Stderr, "Archive encrypted successfully to %s\n", encFileName)

// Remove the original archive
if err := os.Remove(fileName); err != nil {
fmt.Fprintf(os.Stderr, "Error removing original archive: %v\n", err)
os.Exit(1)
}
}

func DecryptArchive(fileName, password string) {
// Read the encrypted archive
reader, err := os.OpenFile(fileName, os.O_RDONLY, 0)
if err != nil {
fmt.Fprintf(os.Stderr, "Error opening encrypted archive file: %v\n", err)
os.Exit(1)
}

encArch, err := archive.ReadEncryptedArchive(reader)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading encrypted archive: %v\n", err)
os.Exit(1)
}

// Decrypt the archive
arch, err := encArch.Decrypt(password)
if err != nil {
fmt.Fprintf(os.Stderr, "Error decrypting archive: %v\n", err)
os.Exit(1)
}

// Write the decrypted archive to disk
decFileName := decryptFileName(fileName)
decFile, err := os.Create(decFileName)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating decrypted archive file: %v\n", err)
os.Exit(1)
}
defer decFile.Close()

if err := arch.Write(decFile); err != nil {
fmt.Fprintf(os.Stderr, "Error writing decrypted archive file: %v\n", err)
os.Exit(1)
}

fmt.Fprintf(os.Stderr, "Archive decrypted successfully to %s\n", decFileName)

// Remove the encrypted archive
if err := os.Remove(fileName); err != nil {
fmt.Fprintf(os.Stderr, "Error removing encrypted archive: %v\n", err)
os.Exit(1)
}
}

// decryptFileName returns the decrypted file name from the encrypted file name.
// If the file name doesn't end with ".enc", it appends ".dec" to the file name.
// Otherwise, it removes the ".enc" extension.
func decryptFileName(fileName string) string {
if len(fileName) < 4 || fileName[len(fileName)-4:] != ".enc" {
return fileName + ".dec"
}

return fileName[:len(fileName)-4]
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ require (
github.com/stretchr/testify v1.9.0
github.com/ulikunitz/xz v0.5.12
golang.org/x/crypto v0.26.0
golang.org/x/term v0.23.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.23.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down

0 comments on commit 489845f

Please sign in to comment.