Kapak - A simple-to-use file encryption script
Published: 2023-01-28 00:34:18

Hey Dev,
I've recently published a Python package. It's called **Kapak** (means mold). You can check it out [here](https://github.com/amis-shokoohi/kapak).

**Kapak** is a **file encryption** script/library and it takes advantage of `AES_256_CBC` cipher.

* [Installation](#installation)
* [CLI Usage](#cli-usage)
  * [Encrypt file](#cli-usage-encrypt-file)
  * [Encrypt stdin](#cli-usage-encrypt-stdin)
  * [Password file](#cli-usage-password-file)
* [Integration](#integration)
  * [Encrypt file](#integration-encrypt-file)
  * [Encrypt stdin](#integration-encrypt-stdin)
  * [Encrypt anything](#integration-encrypt-anything)
* [Feedback](#feedback)

## <a name="installation"></a>Installation
Installing with `pip`:
```
pip install kapak
```

## <a name="cli-usage"></a>CLI Usage

```
kapak [global options] [command] [command options] [input]
kapak [encrypt | e] [options] [input]
kapak [decrypt | d] [options] [input]
```
For more help run:
```
kapak --help
```

### <a name="cli-usage-encrypt-file"></a>Encrypt file
```
$ kapak encrypt -o ./image.jpg.kpk ./image.jpg
Enter password:
Confirm password:
■■■■■■■■■■ 100%
```
```
$ kapak decrypt -o ./image.jpg ./image.jpg.kpk
Enter password:
■■■■■■■■■■ 100%
```

### <a name="cli-usage-encrypt-stdin"></a>Encrypt stdin
```
$ echo 'secret stuff' | kapak encrypt | base64
Enter password:
Confirm password:
AAAAbWth...t/ILJW/v
```
```
$ echo 'AAAAbWth...t/ILJW/v' | base64 --decode | kapak decrypt
Enter password:
secret stuff
```
> You can change the buffer size by passing `-b` or `--buffer-size` option followed by a number.
```
$ cat ./text.txt | kapak encrypt -b 1024 > ./text.txt.kpk
Enter password:
Confirm password:
```
```
$ kapak decrypt -b 1024 ./text.txt.kpk > ./text.txt
Enter password:
```

### <a name="cli-usage-password-file"></a>Password file
You can put the password in a file and then pass it with `-p` or `--password-file` option if you want to use **Kapak** non-interactively.
```
$ echo 'P@ssw0rd' > ./password.txt
$ kapak encrypt -p ./password.txt -o ./image.jpg.kpk ./image.jpg
■■■■■■■■■■ 100%
```
```
$ kapak decrypt -p ./password.txt -o ./image.jpg ./image.jpg.kpk
■■■■■■■■■■ 100%
```
> Make sure to shred the password file afterwards. (If it's on an SSD then good luck shreding it)

## <a name="integration"></a>Integration
You can also integrate **Kapak** into your Python projects.

### <a name="integration-encrypt-file"></a>Encrypt file
```py
from pathlib import Path
from kapak.aes import encrypt

input_file = Path("image.jpg")
output_file = Path("image.jpg.kpk")

with input_file.open("rb") as src, output_file.open("wb") as dst:
    total_len = input_file.stat().st_size
    progress = 0
    for chunk_len in encrypt(src, dst, "P@ssw0rd"):
        progress += chunk_len
        print(f"{progress}/{total_len}")
```
> `kapak.aes.encrypt` is a generator. It yields the length of encrypted data on every iteration.
```py
from pathlib import Path
from itertools import accumulate
from kapak.aes import decrypt

input_file = Path("image.jpg.kpk")
output_file = Path("image.jpg")

with input_file.open("rb") as src, output_file.open("wb") as dst:
    total_len = input_file.stat().st_size
    for progress in accumulate(decrypt(src, dst, "P@ssw0rd")):
        print(f"{progress}/{total_len}")
```
> `kapak.aes.decrypt` is a generator. It yields the length of decrypted data on every iteration.

### <a name="integration-encrypt-stdin"></a>Encrypt stdin
```py
import sys
from io import BytesIO
from kapak.aes import encrypt

with BytesIO() as dst:
    for _ in encrypt(
        src=sys.stdin.buffer,
        dst=dst,
        password="P@ssw0rd",
        buffer_size=1024
    ):
        pass
    encrypted_data = dst.getvalue()
    print(encrypted_data.hex())
```

### <a name="integration-encrypt-anything"></a>Encrypt anything
```py
from io import BytesIO
from kapak.aes import encrypt

anything = b"anything"

with BytesIO(anything) as src, BytesIO() as dst:
    for _ in encrypt(
        src=src,
        dst=dst,
        password="P@ssw0rd",
        buffer_size=1024
    ):
        pass
    encrypted_data = dst.getvalue()
    print(encrypted_data.hex())
```

## <a name="feedback"></a>Feedback 🤩
I'd be happy checking your feedbacks.