Skip to content

Commit

Permalink
Merge pull request #9 from mrf345/reader-writer-refactor
Browse files Browse the repository at this point in the history
Reader writer refactor and improve performance (~3.6x faster)
  • Loading branch information
mrf345 authored Sep 3, 2024
2 parents 118925e + 9b65803 commit 878b73c
Show file tree
Hide file tree
Showing 43 changed files with 1,687 additions and 1,219 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ go.work.sum
# env file
.env
*.sla
safelock-cli
1,034 changes: 661 additions & 373 deletions LICENSE

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
c ?= 2

test:
go test -count=2 ./...
go clean -testcache && go test -count=$(c) ./...
lint:
golangci-lint run
docs:
Expand Down
78 changes: 17 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ safelock-cli
</a>
</h1>

Fast files encryption (AES-GCM) package and command-line tool built for speed with Go ⚡
Fast files encryption (AES-GCM) package and command-line tool built for speed with Go and [Archiver](https://github.com/mholt/archiver)

### Install

Expand Down Expand Up @@ -39,78 +39,34 @@ And to decrypt
```shell
safelock-cli decrypt encrypted_file_path decrypted_files_path
```
> [!NOTE]
> If you want it to run silently with no interaction
> [!TIP]
> If you want it to run silently with no interaction use `--quiet` and pipe the password
```shell
echo "password123456" | safelock-cli encrypt path_to_encrypt encrypted_file_path --quiet
```

<details>
<summary>Simple example of using it within a package</summary>

> Checkout [GoDocs](https://pkg.go.dev/github.com/mrf345/safelock-cli/safelock) for more examples and references
```go
package main

import "github.com/mrf345/safelock-cli/safelock"

func main() {
lock := safelock.New()
inputPaths := []string{"/home/testing/important"}
outputPath := "/home/testing/encrypted.sla"
password := "testing123456"

// Encrypts `inputPaths` with the default settings
if err := lock.Encrypt(nil, inputPaths, outputPath, password); err != nil {
panic(err)
}

// Decrypts `outputPath` with the default settings
if err := lock.Decrypt(nil, outputPath, "/home/testing", password); err != nil {
panic(err)
}
}
```
</details>
You can find interactive examples of using it as a package to [encrypt](https://pkg.go.dev/github.com/mrf345/safelock-cli/safelock#example-Safelock.Encrypt) and [decrypt](https://pkg.go.dev/github.com/mrf345/safelock-cli/safelock#example-Safelock.Decrypt).

### Performance

With the default settings it should be about **three times** faster than `gpgtar`

```shell
> du -hs testing/
1.2G testing/
> time gpgtar -e -o testing.gpg -c --yes --batch --gpg-args "--passphrase testing123456" testing/
real 0m40.141s
user 0m33.933s
sys 0m6.930s
> time echo "testing123456" | safelock-cli encrypt testing/ testing.sla --quiet
real 0m8.403s
user 0m10.790s
sys 0m4.832s
```
With the default settings it should be about **19.1** times faster than `gpgtar`

> [!TIP]
> You can get slightly better performance using the `--sha256` flag (less secure)
> [!NOTE]
> You can reproduce the results by running [benchmark/bench_and_plot.py](benchmark/bench_and_plot.py) (based on [matplotlib](https://github.com/matplotlib/matplotlib) and [hyperfine](https://github.com/sharkdp/hyperfine))
```shell
> time echo "testing123456" | safelock-cli encrypt testing/ testing.sla --quiet --sha256
real 0m8.188s
user 0m10.441s
sys 0m4.709s
```
<p align="center">
<img src="benchmark/encryption-time.webp" align="center" alt="encryption time" />
<img src="benchmark/decryption-time.webp" align="center" alt="encryption time" />
</p>

And no major file size difference
And you could gain a slight file size reduction

```shell
> ls -lh --block-size=MB testing.gpg
-rw-rw-r-- 1 user user 1247MB Aug 10 12:15 testing.gpg
> du -hs test/
1.2G test/

> ls -lh --block-size=MB testing.sla
-rw-rw-r-- 1 user user 1273MB Aug 10 11:30 testing.sla
> ls -lh --block-size=MB test.sla test.gpg
-rw-r--r-- 1 mrf3 mrf3 1.2G Sep 3 17:55 test.gpg
-rw-r--r-- 1 mrf3 mrf3 959M Sep 3 17:29 test.sla
```
96 changes: 96 additions & 0 deletions benchmark/bench_and_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import os
import json
import random

import matplotlib.pyplot as plt
from matplotlib.colors import XKCD_COLORS as colors_map

safelock_cmd = "safelock-cli"
pwd = "123456789"
rest = "60s"
input_path = "test"
output_name = "test"
output_dir = "safelock_dump"
runs = 3
figure_width = 14
figure_height = 2.5
bar_width = 0.6
measure = "Seconds"
root = os.getcwd()

def encrypt():
err = os.system(
f"hyperfine --runs {runs} --prepare "
f"'sleep {rest}' "
f"'echo \"{pwd}\" | {safelock_cmd} encrypt {input_path} {output_name}.sla --quiet' "
f"'echo \"{pwd}\" | {safelock_cmd} encrypt {input_path} {output_name}_sha256.sla --quiet --sha256' "
f"'echo \"{pwd}\" | {safelock_cmd} encrypt {input_path} {output_name}_sha512.sla --quiet --sha512' "
f"'gpgtar -e -o test.gpg -c --yes --batch --gpg-args \"--passphrase {pwd}\" Videos/' "
f"--export-json {root}/encryption.json"
)

if err:
exit(err)

def decrypt():
err = os.system(
f"hyperfine --runs {runs} --prepare "
f"'rm -rf {output_dir} {output_name}_1_ && mkdir {output_dir} && sleep {rest}' "
f"'echo \"{pwd}\" | {safelock_cmd} decrypt {output_name}.sla {output_dir} --quiet' "
f"'echo \"{pwd}\" | {safelock_cmd} decrypt {output_name}_sha256.sla {output_dir} --quiet --sha256' "
f"'echo \"{pwd}\" | {safelock_cmd} decrypt {output_name}_sha512.sla {output_dir} --quiet --sha512' "
f"'gpgtar -d --yes --batch --gpg-args \"--passphrase {pwd}\" test.gpg' "
f"--export-json {root}/decryption.json"
)

if err:
exit(err)

def get_label(i):
label = i['command']

if 'gpg' in label:
label = 'gpgtar'
elif 'sha256' in label:
label = 'safelock --sha256'
elif 'sha512' in label:
label = 'safelock --sha512'
else:
label = 'safelock'

return f"{label}\n{i['median']:.3f}s"

os.chdir(os.path.expanduser("~"))
encrypt()
decrypt()
os.chdir(root)

with open("encryption.json") as f:
data = sorted(json.load(f)['results'], key=lambda i: i['median'])
commands = [get_label(i) for i in data]
scores = [i['median'] for i in data]

colors = [random.choice(list(colors_map.values())) for _ in scores]

plt.margins(3.5)

fig, ax = plt.subplots()
ax.set_title('Encryption Time')
ax.set_xlabel(measure)
ax.barh(commands, scores, bar_width, color=colors)
fig.set_size_inches(w=figure_width, h=figure_height)
fig.tight_layout()
fig.savefig("encryption-time.webp", transparent=True, format="webp")

with open("decryption.json") as f:
data = sorted(json.load(f)['results'], key=lambda i: i['median'])
commands = [get_label(i) for i in data]
decryption = [i['median'] for i in data]

fig, ax = plt.subplots()
ax.set_title('Decryption Time')
ax.set_xlabel(measure)
ax.barh(commands, decryption, bar_width, color=colors)
fig.set_size_inches(w=figure_width, h=figure_height)
fig.tight_layout()
fig.savefig("decryption-time.webp", transparent=True, format="webp")
Binary file added benchmark/decryption-time.webp
Binary file not shown.
84 changes: 84 additions & 0 deletions benchmark/decryption.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"results": [
{
"command": "echo \"123456789\" | safelock-cli decrypt test.sla safelock_dump --quiet",
"mean": 2.591056303126667,
"stddev": 0.3072584303134709,
"median": 2.4638408214600003,
"user": 2.6658728066666666,
"system": 1.96781978,
"min": 2.36783672846,
"max": 2.94149135946,
"times": [
2.94149135946,
2.36783672846,
2.4638408214600003
],
"exit_codes": [
0,
0,
0
]
},
{
"command": "echo \"123456789\" | safelock-cli decrypt test_sha256.sla safelock_dump --quiet --sha256",
"mean": 2.1992803144599997,
"stddev": 0.4012681619295813,
"median": 2.05163752946,
"user": 2.160165473333333,
"system": 1.6608864466666666,
"min": 1.8927501014600001,
"max": 2.65345331246,
"times": [
2.65345331246,
1.8927501014600001,
2.05163752946
],
"exit_codes": [
0,
0,
0
]
},
{
"command": "echo \"123456789\" | safelock-cli decrypt test_sha512.sla safelock_dump --quiet --sha512",
"mean": 2.1854930261266667,
"stddev": 0.34595596536873846,
"median": 2.12447426646,
"user": 2.5949568066666666,
"system": 1.4746104466666665,
"min": 1.8741061304600002,
"max": 2.55789868146,
"times": [
2.55789868146,
2.12447426646,
1.8741061304600002
],
"exit_codes": [
0,
0,
0
]
},
{
"command": "gpgtar -d --yes --batch --gpg-args \"--passphrase 123456789\" test.gpg",
"mean": 7.854353938126668,
"stddev": 1.707887720081897,
"median": 7.8766436114600005,
"user": 0.22827714,
"system": 1.6720551133333332,
"min": 6.1354304734600005,
"max": 9.55098772946,
"times": [
9.55098772946,
7.8766436114600005,
6.1354304734600005
],
"exit_codes": [
0,
0,
0
]
}
]
}
Binary file added benchmark/encryption-time.webp
Binary file not shown.
84 changes: 84 additions & 0 deletions benchmark/encryption.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"results": [
{
"command": "echo \"123456789\" | safelock-cli encrypt test test.sla --quiet",
"mean": 2.3078756149333333,
"stddev": 0.019208610839248,
"median": 2.3030128716,
"user": 3.5797244999999998,
"system": 1.2082247399999997,
"min": 2.2915656946,
"max": 2.3290482786,
"times": [
2.3290482786,
2.2915656946,
2.3030128716
],
"exit_codes": [
0,
0,
0
]
},
{
"command": "echo \"123456789\" | safelock-cli encrypt test test_sha256.sla --quiet --sha256",
"mean": 2.364359243266667,
"stddev": 0.11326688774625213,
"median": 2.3016267516,
"user": 3.891836833333333,
"system": 1.2837120733333334,
"min": 2.2963380466000003,
"max": 2.4951129316,
"times": [
2.4951129316,
2.2963380466000003,
2.3016267516
],
"exit_codes": [
0,
0,
0
]
},
{
"command": "echo \"123456789\" | safelock-cli encrypt test test_sha512.sla --quiet --sha512",
"mean": 2.4259253342666667,
"stddev": 0.228772730074746,
"median": 2.3097034366,
"user": 4.034212833333334,
"system": 1.2618734066666664,
"min": 2.2785945276,
"max": 2.6894780386,
"times": [
2.6894780386,
2.2785945276,
2.3097034366
],
"exit_codes": [
0,
0,
0
]
},
{
"command": "gpgtar -e -o test.gpg -c --yes --batch --gpg-args \"--passphrase 123456789\" test/",
"mean": 44.27242020093333,
"stddev": 1.1158441010334361,
"median": 44.070407816599996,
"user": 34.355086166666666,
"system": 10.122625073333332,
"min": 43.2713822446,
"max": 45.4754705416,
"times": [
43.2713822446,
45.4754705416,
44.070407816599996
],
"exit_codes": [
0,
0,
0
]
}
]
}
Loading

0 comments on commit 878b73c

Please sign in to comment.