Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
radumarias authored Oct 3, 2024
1 parent 5da1984 commit 439af93
Showing 1 changed file with 55 additions and 55 deletions.
110 changes: 55 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
[![Open Source Helpers](https://www.codetriage.com/radumarias/rencfs/badges/users.svg)](https://www.codetriage.com/radumarias/rencfs)

> [!WARNING]
> **This crate hasn't been audited, it's using `ring` crate which is a well-known audited library, so in principle at
least the primitives should offer similar level of security.
> This is still under development. Please do not use it with sensitive data for now, please wait for a
> **This crate hasn't been audited; it's using `ring` crate, which is a well-known audited library, so in principle, at
least the primitives should offer a similar level of security.
> This is still under development. Please do not use it with sensitive data for now; please wait for a
stable release.
> It's mostly ideal for experimental and learning projects.**
An encrypted file system written in Rust that is mounted with FUSE on Linux. It can be used to create encrypted directories.

You can then safely backup the encrypted directory to an untrusted server without worrying about the data being exposed.
You can also store it in any cloud storage like Google Drive, Dropbox, etc. and have it synced across multiple devices.
You can then safely back up the encrypted directory to an untrusted server without worrying about the data being exposed.
You can also store it in a cloud storage service like Google Drive, Dropbox, etc., and have it synced across multiple devices.

You can use it as CLI or as a library to build your custom FUSE implementation or other apps that work with encrypted data.

Expand All @@ -36,7 +36,7 @@ Create a `simple`, `performant`, `modular` and `ergonomic` yet `very secure` `en

# Blog and tutorial

There will be a [series](https://medium.com/@xorio42/list/828492b94c23) of articles about the evolution of this project trying to keep it like a tutorial. This is the [first one](https://systemweakness.com/the-hitchhikers-guide-to-building-an-encrypted-filesystem-in-rust-4d678c57d65c).
There will be a [series](https://medium.com/@xorio42/list/828492b94c23) of articles about the evolution of this project, trying to keep it like a tutorial. This is the [first one](https://systemweakness.com/the-hitchhikers-guide-to-building-an-encrypted-filesystem-in-rust-4d678c57d65c).

# Crate of the week in [This Week in Rust](https://this-week-in-rust.org/)

Expand All @@ -49,7 +49,7 @@ It was [crate of the week](https://this-week-in-rust.org/blog/2024/08/14/this-we

# Key features

Some of these are still being worked on, marked with `[WIP]`.
Some of these are still being worked on and marked with `[WIP]`.

- `Security` using well-known audited `AEAD` cryptography primitives;
- `[WIP]` `Data integrity`, data is written with `WAL` to ensure integrity even on crash or power loss;
Expand All @@ -71,24 +71,24 @@ Some of these are still being worked on, marked with `[WIP]`.

# Functionality

Some of these are still being worked on, marked with `[WIP]`.
Some of these are still being worked on and marked with `[WIP]`.

- It keeps all `encrypted` data and `master encryption key` in a dedicated directory with files structured on `inodes` (with
metadata info), files for binary content and directories with files/directories entries. All data, metadata and also filenames
are encrypted. For new files it generates unique inodes in multi instance run and offline mode.
- The password is collected from CLI, and it's saved in OS `keyring` while app is running. This is because for security concerns we
clear the password from memory on inactivity, and we derive it again from password just when needed.
metadata info), files for binary content, and directories with files/directories entries. All data, metadata, and filenames
are encrypted. For new files, it generates unique inodes in a multi-instance run and offline mode.
- The password is collected from CLI and saved in the OS's `keyring` while the app is running. This is because, for security concerns, we
clear the password from memory on inactivity, and we derive it again from the password just when needed.
- Master encryption key is also encrypted with another key derived from the password. This gives the ability to change
the
password without re-encrypting all data, we just `re-encrypt` the `master key`.
- Files are `encrypted` in `chunks` of `256KB`, so when making a change, we just re-encrypt that chunks.
- `Fast seek` on read and write, so if you're watching a movie, you can seek to any position, and that would be instant.
This is because we can seek to particular chunk.
- Encryption key is `zeroize`d in mem on dispose and idle. Also, it's `mlock`ed while used to prevent being moved to swap. It's
- `Fast seek` on read and write, so if you're watching a movie, you can seek any position, and that would be instant.
This is because we can seek a particular chunk.
- The encryption key is `zeroize` in the mem when disposing and idle. Also, it's `mlock`ed while used to prevent being moved to swap. It's
also `mprotect`ed while not in use.
- `[WIP]` Ensure file integrity by saving each change to WAL, so on crash or power loss we apply the pending
changes on the next start. This makes the write operations atomic.
- Multiple writes in parallel to the same file, ideal for torrent like applications.
- `[WIP]` Ensure file integrity by saving each change to WAL, so for crashes or power loss, we apply the pending
changes at the next start. This makes the write operations atomic.
- Multiple writes in parallel to the same file, ideal for torrent-like applications.

# Docs

Expand All @@ -102,9 +102,9 @@ For detailed description of the various sequence flows please look into [Flows](
- [ring](https://crates.io/crates/ring) for encryption and [argon2](https://crates.io/crates/argon2) for key derivation
function (generating key from password used to encrypt the master encryption key)
- [rand_chacha](https://crates.io/crates/rand_chacha) for random generators
- [shush-rs](https://crates.io/crates/shush-rs) for keeping pass and encryption keys safe in memory and zeroing them when
not used. It keeps encryption keys in memory only while being used, and when not active it will release and zeroing
them in memory. It locks memory page as well, preventing it from being written to swap.
- [shush-rs](https://crates.io/crates/shush-rs) keeps pass and encryption keys safe in memory and zero them when
not used. It keeps encryption keys in memory only while being used, and when not active, it will release and zeroing
them in memory. It locks the memory page as well, preventing it from being written to swap.
- [blake3](https://crates.io/crates/blake3) for hashing
- password saved in OS keyring using [keyring](https://crates.io/crates/keyring)
- [tracing](https://crates.io/crates/tracing) for logs
Expand All @@ -129,8 +129,8 @@ For detailed description of the various sequence flows please look into [Flows](

## What separates us

[Asked](https://chatgpt.com/share/66e7a5a5-d254-8003-9359-9b1556b75fe9) ChatGPT if there are other solutions out there which offers all the key functionalities we do, seems like there are none :)
You can see the [key features](README.md#key-features) that separates us.
[Asked](https://chatgpt.com/share/66e7a5a5-d254-8003-9359-9b1556b75fe9) ChatGPT if there are other solutions out there which offer all the key functionalities we do, seems like there are none :)
You can see the [key features](README.md#key-features) that separate us.

# Usage

Expand All @@ -154,7 +154,7 @@ Start a container to set up mount in it
docker run -it --device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor:unconfined xorio42/rencfs:latest /bin/sh
```

In the container create mount and data directories
In the container, create mount and data directories

```bash
mkdir fsmnt && mkdir fsdata
Expand All @@ -174,13 +174,13 @@ Get the container ID
docker ps
```

In another terminal, attach to running container with the above ID
In another terminal, attach to the running container with the above ID

```bash
docker exec -it <ID> /bin/sh
```

From here you can play with it by creating files in `fsmnt` directory
From here, you can play with it by creating files in `fsmnt` directory

```bash
cd fsmnt
Expand Down Expand Up @@ -266,11 +266,11 @@ You can specify the encryption algorithm by adding this argument to the command
```

Where `CIPHER` is the encryption algorithm. You can check the available ciphers with `rencfs --help`.
Default value is `ChaCha20Poly1305`.
The default value is `ChaCha20Poly1305`.

### Log level

You can specify the log level adding the `--log-level` argument to the command line. Possible
You can specify the log level by adding the `--log-level` argument to the command line. Possible
values: `TRACE`, `DEBUG`, `INFO` (default), `WARN`, `ERROR`.

```bash
Expand All @@ -290,7 +290,7 @@ If you want to give it a quick try and not setup anything locally you can

[![Open Rustlings On Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/?repo=radumarias%2Frencfs&ref=main)

You can compile it, run it, and give it a quick try in browser. After you start it from above
You can compile it, run it, and give it a quick try in the browser. After you start it from above

```bash
sudo apt-get update && sudo apt-get install fuse3
Expand All @@ -310,10 +310,10 @@ cat test.txt

## Locally

For now the `FUSE` (`fuse3` crate) only works on `Linux`, so to start the project you will need to be on Linux.
For now, the `FUSE` (`fuse3` crate) only works on `Linux`, so to start the project, you will need to be on Linux.
Instead, you can [Develop inside a Container](#developing-inside-a-container), which will start a local Linux container, the IDE will connect to it,
you can build and start the app in there and also use terminal to test it.
On windows you can start it in [WSL](https://harsimranmaan.medium.com/install-and-setup-rust-development-environment-on-wsl2-dccb4bf63700).
and you can build and start the app there and also use the terminal to test it.
On Windows, you can start it in [WSL](https://harsimranmaan.medium.com/install-and-setup-rust-development-environment-on-wsl2-dccb4bf63700).

### Getting the sources

Expand Down Expand Up @@ -341,7 +341,7 @@ logged out, or it may not succeed at all.
If, after installation, running `rustc --version` in the console fails, this is the most likely reason.
In that case please add it to the `PATH` manually.
Project is setup to use `nightly` toolchain in `rust-toolchain.toml`, on first build you will see it fetch the nightly.
The project is set up to use the `nightly` toolchain in `rust-toolchain. tool`; on the first build, you will see it fetch the nightly.
Make sure to add this to your `$PATH` too
Expand All @@ -356,7 +356,7 @@ cargo install cargo-generate-rpm
### Other dependencies
Also, these deps are required (or based on your distribution):
Also, these dependencies are required (or based on your distribution):
#### Arch
Expand Down Expand Up @@ -396,7 +396,7 @@ cargo run --release -- mount --mount-point MOUNT_POINT --data-dir DATA_DIR
#### Dev settings
If you don't want to be prompted for password, you can set this env var and run like this:
If you don't want to be prompted for a password, you can set this env var and run it like this:
```bash
RENCFS_PASSWORD=PASS cargo run --release -- mount --mount-point MOUNT_POINT --data-dir DATA_DIR
Expand Down Expand Up @@ -440,23 +440,23 @@ The minimum supported version is `1.75`.
# Future
- Plan is to implement it also on macOS and Windows
The plan is to implement it also on macOS and Windows
- **Systemd service** is being worked on [rencfs-daemon](https://github.com/radumarias/rencfs-daemon)
- **GUI** is being worked on [rencfs-desktop](https://github.com/radumarias/rencfs-desktop) and [rencfs-kotlin](https://github.com/radumarias/rencfs-kotlin)
- **Mobile apps** for **Android** and **iOS** are being worked on [rencfs-kotlin](https://github.com/radumarias/rencfs-kotlin)
# Performance
`Aes256Gcm` is slightly faster than `ChaCha20Poly1305` by a factor of **1.28** on average. This is because of the hardware acceleration of AES
on most CPUs via AES-NI. But where hardware acceleration is not available `ChaCha20Poly1305` is faster. Also `ChaChaPoly1305` is better at `SIMD`.
on most CPUs via AES-NI. However, where hardware acceleration is not available, `ChaCha20Poly1305` is faster. Also `ChaChaPoly1305` is better at `SIMD`.
# Cipher comparison
## AES-GCM vs. ChaCha20-Poly1305
- If you have hardware acceleration (e.g. `AES-NI`), then `AES-GCM` provides better performance. On my benchmarks, it was
faster by a factor of **1.28** on average.
If you do not have a hardware acceleration, `AES-GCM` is either slower than `ChaCha20-Poly1305`, or it leaks your
If you do not have hardware acceleration, `AES-GCM` is either slower than `ChaCha20-Poly1305`, or it leaks your
encryption
keys in cache timing.
- `AES-GCM` can target multiple security levels (`128-bit`, `192-bit`, `256-bit`), whereas `ChaCha20-Poly1305` is only defined at
Expand Down Expand Up @@ -484,50 +484,50 @@ Both are good options. `AES-GCM` can be faster with **hardware support**, but **
# ⚠️ Security Warning: Hazmat!
- **Phantom reads**: reading older content from a file, this is not possible. Data is written with WAL and periodically
- **Phantom reads**: Reading older content from a file is not possible. Data is written with WAL and periodically
flushed to file. This ensures data integrity and maintains change order.
One problem that may occur is if we do a truncate we change the content of the file, but the process is killed before
we write the metadata with the new filesize. In this case, next time we mount the system, we are still seeing the old
filesize. However, the content of the file could be bigger, and we read until the old size offset, so we would not
One problem that may occur is if we do a truncation, we change the content of the file, but the process is killed before
we write the metadata with the new file size. In this case, the next time we mount the system, we will still see the old
files. However, the content of the file could be bigger, and we read until the old size offset, so we would not
pick up
the new zeros bytes written on truncating by increasing the size. If content is smaller the read would stop and
the new zeros bytes are written on truncating by increasing the size. If content is smaller, the read would stop and
end-of-file of the actual content, so this would not be such a big issue
- **What kind of metadata does it leak**: close to none. The filename, actual file size and other file attrs (times,
permissions, other flags) are kept encrypted. What it could possibly leak is the following
- If a directory has children, we keep those children in a directory with name as inode number with encrypted names
- If a directory has children, we keep those children in a directory with name as inode number and encrypted names
of children as files in it.
So we could see how many children a directory has.
However, we can't identify that actual directory name,
However, we can't identify that actual directory name;
we can just see its inode number (internal representation like an ID for each file), and we cannot see the actual
filenames of directory or children.
filenames of the directory or children.
Also, we cannot identify which file content corresponds to a directory child
- Each file content is saved in a separate file, so we could see the size of the encrypted content, but not the
- Each file content is saved in a separate file, so we can see the size of the encrypted content but not the
actual filesize
- We can also see the last time the file was accessed
- It's always recommended to use encrypted disks for at least your sensitive data, this project is not a replacement for
- It's always recommended to use encrypted disks for at least your sensitive data; this project is not a replacement for
that
- To reduce the risk of encryption key from being exposed from memory, it's recommended to disable memory dumps on the
- To reduce the risk of the encryption key being exposed from memory, it's recommended to disable memory dumps on the
OS level. Please see [here](https://www.cyberciti.biz/faq/disable-core-dumps-in-linux-with-systemd-sysctl/) how to do
it on Linux
- **Cold boot attacks**: to reduce the risk of this, we keep the encryption key in memory just as long as we really
need it to encrypt/decrypt data, and we are zeroing it after that. We also remove it from memory after a period of
inactivity
- Please note this project was not audited by any security expert. It's built with security in mind and tries to
follow all the best practices, but it's not guaranteed to be secure
- **Also, please back up your data, the project is still in development, and there might be bugs that can lead to data
- **Also, please back up your data; the project is still in development, and there might be bugs that can lead to data
loss**
# Considerations
- Please note, this project doesn't try to reinvent the wheel or be better than already proven implementations
- This project doesn't want to be a replacement in any way of already proven file encryption solutions. If you really
- Please note that this project doesn't try to reinvent the wheel or be better than already proven implementations
- This project doesn't want to be a replacement in any way for already proven file encryption solutions. If you really
want close to bulletproof solutions, then maybe this is not the ideal one for you. But is trying to offer a simple use
of an encryption solution that should be used taking into consideration all the security concerns from above
of an encryption solution that should be used, taking into consideration all the security concerns from above
- It started as a learning project of Rust programming language, and I feel like keep building more on it
- It's a fairly simple and standard implementation that tries to respect all security standards, correctly use secure and robust
- It's a fairly simple and standard implementation that tries to respect all security standards and correctly use secure and robust
primitives so that it can be extended from this. Indeed, it doesn't have the maturity yet to "fight" other well-known
implementations.
But it can be a project from which others can learn or build upon or why not for some to actually use it keeping in
But it can be a project from which others can learn or build upon, or why not for some to actually use it, keeping in
mind all the above
# Contribute
Expand Down

0 comments on commit 439af93

Please sign in to comment.