Skip to content

Commit

Permalink
pr: add volariscore (#1)
Browse files Browse the repository at this point in the history
* docs: update readme to include more information

* feat: add volariscore code - copied from dexios

* fix: fixing cargolocks
  • Loading branch information
greendoescode authored Jun 14, 2024
1 parent 2bf1447 commit 38d884f
Show file tree
Hide file tree
Showing 14 changed files with 10,214 additions and 5 deletions.
564 changes: 563 additions & 1 deletion Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 2-Clause License

Copyright (c) 2024, brxken128
Copyright (c) 2024, brxken128, greendoescode

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Expand Down
19 changes: 16 additions & 3 deletions crates/volaris-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
[package]
name = "volaris-core"
version = "0.0.0"
version = "0.0.1"
edition = "2021"
authors.workspace = true
license.workspace = true
description = "The core cryptography behind Volaris"
readme = "README.md"
license = "BSD-2-Clause"
authors = ["brxken128 <[email protected]>", "greendoescode <[email protected]>"]
homepage = "https://github.com/volarisapp/volaris"

[dependencies]
anyhow = "1.0.65"
aes-gcm = "0.10.1"
chacha20poly1305 = "0.10.1"
deoxys = { version = "0.1.0" }
aead = { version = "0.5.1", features = ["stream"] }
zeroize = "1.5.0"
argon2 = "0.4.1"
balloon-hash = "0.3.0"
blake3 = { version = "1.3.3", features = ["traits-preview"] }
rand = "0.8.5"
indicatif = { version = "0.16.2", optional = true }
25 changes: 25 additions & 0 deletions crates/volaris-core/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
BSD 2-Clause License

Copyright (c) 2024, brxken128, greendoescode
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
89 changes: 89 additions & 0 deletions crates/volaris-core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
## What is it?

Volaris-Core is a library used for managing cryptographic functions and headers
that adhere to the volaris format.

## Security

Volaris-Core uses modern, secure and audited<sup>1</sup> AEADs for encryption and
decryption.

You may find the audits for both AES-256-GCM and XChaCha20-Poly1305 on
[the NCC Group's website](https://research.nccgroup.com/2020/02/26/public-report-rustcrypto-aes-gcm-and-chacha20poly1305-implementation-review/).

<sup>1</sup> Deoxys-II-256 does not have an official audit, so use it at your
own risk

## Who uses volaris-Core?

This library is implemented by [volaris](https://github.com/volarisapp/volaris), a
secure multi-interface file encryption utility.

Volaris-Core makes it easy to integrate the volaris format into your own projects
(and if there's a feature that you'd like to see, please don't hesitate to
[open a Github issue](https://github.com/volarisapp/volaris/issues)).

## Features

- Convenience functions for encrypting/decrypting
- 3 AEADs (XChaCha20-Poly1305, AES-256-GCM, Deoxys-II-256)
- Easy management of encrypted headers (no more worrying about where to store a
nonce!)
- Easy `argon2id` hashing with secure parameters
- Easy `balloon` hashing with secure parameters and BLAKE3
- Frequent updates and feature additions!

## Examples

Deserializing a header:

```rust
let header_bytes: [u8; 64] = [
222, 2, 14, 1, 12, 1, 142, 88, 243, 144, 119, 187, 189, 190, 121, 90, 211, 56, 185, 14, 76,
45, 16, 5, 237, 72, 7, 203, 13, 145, 13, 155, 210, 29, 128, 142, 241, 233, 42, 168, 243,
129, 0, 0, 0, 0, 0, 0, 214, 45, 3, 4, 11, 212, 129, 123, 192, 157, 185, 109, 151, 225, 233,
161,
];

let mut cursor = Cursor::new(header_bytes);

// the cursor may be a file, this is just an example

let (header, aad) = Header::deserialize(&mut cursor).unwrap();
```

Writing a header to a file:

```rust
let mut output_file = File::create("test").unwrap();
header.write(&mut output_file).unwrap();
```

Encrypting and decrypting in-memory:

```rust
// obviously the key should contain data, not be an empty vec
let raw_key = Protected::new(vec![0u8; 128]);
let salt = gen_salt();
let key = balloon_hash(raw_key, &salt, &HeaderVersion::V4).unwrap();
let cipher = Ciphers::initialize(key, &Algorithm::XChaCha20Poly1305).unwrap();

let secret = "super secret information";

let nonce = gen_nonce(&Algorithm::XChaCha20Poly1305, &Mode::MemoryMode);
let encrypted_data = cipher.encrypt(&nonce, secret.as_bytes()).unwrap();

let decrypted_data = cipher.decrypt(&nonce, encrypted_data.as_slice()).unwrap();

assert_eq!(secret, decrypted_data);
```

You can read more about volaris, Volaris-Core and the technical details
[in the project's main documentation](https://github.com/volarisapp/volaris/)!

## Thank you!

Volaris-Core exclusively uses AEADs provided by the
[RustCrypto Team](https://github.com/RustCrypto), so I'd like to give them a
huge thank you for their hard work (this wouldn't have been possible without
them!)
124 changes: 124 additions & 0 deletions crates/volaris-core/src/cipher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//! This module is used for standard, typical encryption and decryption.
//!
//! The data is fully loaded into memory before encryption/decryption, and it is processed within the same "block"
//!
//! # Examples
//! ```rust,ignore
//! // obviously the key should contain data, not be an empty vec
//! let raw_key = Protected::new(vec![0u8; 128]);
//! let salt = gen_salt();
//! let key = balloon_hash(raw_key, &salt, &HeaderVersion::V4).unwrap();
//! let cipher = Ciphers::initialize(key, &Algorithm::XChaCha20Poly1305).unwrap();
//!
//! let secret = "super secret information";
//!
//! let nonce = gen_nonce(&Algorithm::XChaCha20Poly1305, &Mode::MemoryMode);
//! let encrypted_data = cipher.encrypt(&nonce, secret.as_bytes()).unwrap();
//!
//! let decrypted_data = cipher.decrypt(&nonce, encrypted_data.as_slice()).unwrap();
//!
//! assert_eq!(secret, decrypted_data);
//! ```
use aead::{Aead, AeadInPlace, KeyInit, Payload};
use aes_gcm::Aes256Gcm;
use chacha20poly1305::XChaCha20Poly1305;
use deoxys::DeoxysII256;

use crate::primitives::Algorithm;
use crate::protected::Protected;

/// This `enum` defines all possible cipher types, for each AEAD that is supported by `Volaris-core`
pub enum Ciphers {
Aes256Gcm(Box<Aes256Gcm>),
XChaCha(Box<XChaCha20Poly1305>),
DeoxysII(Box<DeoxysII256>),
}

impl Ciphers {
/// This can be used to quickly initialise a `Cipher`
///
/// The returned `Cipher` can be used for both encryption and decryption
///
/// You just need to provide the `argon2id`/`balloon` hashed key, and the algorithm to use
///
/// # Examples
/// ```rust,ignore
/// // obviously the key should contain data, not be an empty vec
/// let raw_key = Protected::new(vec![0u8; 128]);
/// let salt = gen_salt();
/// let key = balloon_hash(raw_key, &salt, &HeaderVersion::V4).unwrap();
/// let cipher = Ciphers::initialize(key, &Algorithm::XChaCha20Poly1305).unwrap();
/// ```
///
pub fn initialize(key: Protected<[u8; 32]>, algorithm: &Algorithm) -> anyhow::Result<Self> {
let cipher = match algorithm {
Algorithm::Aes256Gcm => {
let cipher = Aes256Gcm::new_from_slice(key.expose())
.map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;

Ciphers::Aes256Gcm(Box::new(cipher))
}
Algorithm::XChaCha20Poly1305 => {
let cipher = XChaCha20Poly1305::new_from_slice(key.expose())
.map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;

Ciphers::XChaCha(Box::new(cipher))
}
Algorithm::DeoxysII256 => {
let cipher = DeoxysII256::new_from_slice(key.expose())
.map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;

Ciphers::DeoxysII(Box::new(cipher))
}
};

drop(key);
Ok(cipher)
}

/// This can be used to encrypt data with a given `Ciphers` object
///
/// It requires the nonce, and either some plaintext, or an `aead::Payload` (that contains the plaintext and the AAD)
pub fn encrypt<'msg, 'aad>(
&self,
nonce: &[u8],
plaintext: impl Into<Payload<'msg, 'aad>>,
) -> aead::Result<Vec<u8>> {
match self {
Ciphers::Aes256Gcm(c) => c.encrypt(nonce.as_ref().into(), plaintext),
Ciphers::XChaCha(c) => c.encrypt(nonce.as_ref().into(), plaintext),
Ciphers::DeoxysII(c) => c.encrypt(nonce.as_ref().into(), plaintext),
}
}

pub fn encrypt_in_place(
&self,
nonce: &[u8],
aad: &[u8],
buffer: &mut dyn aead::Buffer,
) -> Result<(), aead::Error> {
match self {
Ciphers::Aes256Gcm(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
Ciphers::XChaCha(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
Ciphers::DeoxysII(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
}
}

/// This can be used to decrypt data with a given `Ciphers` object
///
/// It requires the nonce used for encryption, and either some plaintext, or an `aead::Payload` (that contains the plaintext and the AAD)
///
/// NOTE: The data will not decrypt successfully if an AAD was provided for encryption, but is not present/has been modified while decrypting
pub fn decrypt<'msg, 'aad>(
&self,
nonce: &[u8],
ciphertext: impl Into<Payload<'msg, 'aad>>,
) -> aead::Result<Vec<u8>> {
match self {
Ciphers::Aes256Gcm(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
Ciphers::XChaCha(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
Ciphers::DeoxysII(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
}
}
}
Loading

0 comments on commit 38d884f

Please sign in to comment.