From 38d884fd1a9867f69a7e82f5cf38fcd499fd90ac Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:39:10 +0100 Subject: [PATCH 1/9] pr: add volariscore (#1) * docs: update readme to include more information * feat: add volariscore code - copied from dexios * fix: fixing cargolocks --- Cargo.lock | 564 +- LICENSE | 2 +- crates/volaris-core/Cargo.toml | 19 +- crates/volaris-core/LICENSE | 25 + crates/volaris-core/README.md | 89 + crates/volaris-core/src/cipher.rs | 124 + crates/volaris-core/src/header.rs | 723 +++ crates/volaris-core/src/key.rs | 221 + crates/volaris-core/src/lib.rs | 39 + crates/volaris-core/src/primitives.rs | 136 + crates/volaris-core/src/protected.rs | 79 + crates/volaris-core/src/stream.rs | 406 ++ crates/volaris-core/src/visual.rs | 21 + crates/volaris-core/src/wordlist.lst | 7771 +++++++++++++++++++++++++ 14 files changed, 10214 insertions(+), 5 deletions(-) create mode 100644 crates/volaris-core/LICENSE create mode 100644 crates/volaris-core/README.md create mode 100644 crates/volaris-core/src/cipher.rs create mode 100644 crates/volaris-core/src/header.rs create mode 100644 crates/volaris-core/src/key.rs create mode 100644 crates/volaris-core/src/primitives.rs create mode 100644 crates/volaris-core/src/protected.rs create mode 100644 crates/volaris-core/src/stream.rs create mode 100644 crates/volaris-core/src/visual.rs create mode 100644 crates/volaris-core/src/wordlist.lst diff --git a/Cargo.lock b/Cargo.lock index d5734b2..b96c657 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,10 +2,572 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "argon2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4ce4441f99dbd377ca8a8f57b698c44d0d6e712d8329b5040da5a64aa1ce73" +dependencies = [ + "base64ct", + "blake2", + "password-hash", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "balloon-hash" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fdbafd8c776e0a7c250b5dfaf4723477e0d92b42c5a91ce4e50bd9bb2dcc9a1" +dependencies = [ + "crypto-bigint", + "digest", + "password-hash", +] + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "blake3" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cc" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "windows-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "deoxys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00603a49e114bd99d87a4ab8d480f36ecd1451a9d6474f66973d1a829ff77789" +dependencies = [ + "aead", + "aes", + "subtle", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "indicatif" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" +dependencies = [ + "console", + "lazy_static", + "number_prefix", + "regex", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "volaris" version = "0.0.0" [[package]] name = "volaris-core" -version = "0.0.0" +version = "0.0.1" +dependencies = [ + "aead", + "aes-gcm", + "anyhow", + "argon2", + "balloon-hash", + "blake3", + "chacha20poly1305", + "deoxys", + "indicatif", + "rand", + "zeroize", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/LICENSE b/LICENSE index 1cb9026..38283c6 100644 --- a/LICENSE +++ b/LICENSE @@ -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: diff --git a/crates/volaris-core/Cargo.toml b/crates/volaris-core/Cargo.toml index 838a4d1..97aadb0 100644 --- a/crates/volaris-core/Cargo.toml +++ b/crates/volaris-core/Cargo.toml @@ -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 ", "greendoescode "] +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 } diff --git a/crates/volaris-core/LICENSE b/crates/volaris-core/LICENSE new file mode 100644 index 0000000..d9b4021 --- /dev/null +++ b/crates/volaris-core/LICENSE @@ -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. diff --git a/crates/volaris-core/README.md b/crates/volaris-core/README.md new file mode 100644 index 0000000..55b35a5 --- /dev/null +++ b/crates/volaris-core/README.md @@ -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 audited1 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/). + +1 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!) diff --git a/crates/volaris-core/src/cipher.rs b/crates/volaris-core/src/cipher.rs new file mode 100644 index 0000000..9b1c1e7 --- /dev/null +++ b/crates/volaris-core/src/cipher.rs @@ -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), + XChaCha(Box), + DeoxysII(Box), +} + +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 { + 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>, + ) -> aead::Result> { + 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>, + ) -> aead::Result> { + 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), + } + } +} diff --git a/crates/volaris-core/src/header.rs b/crates/volaris-core/src/header.rs new file mode 100644 index 0000000..1d3f9f0 --- /dev/null +++ b/crates/volaris-core/src/header.rs @@ -0,0 +1,723 @@ +//! The Volaris header is an encrypted file/data header that stores specific information needed for decryption. +//! +//! This includes: +//! * header version +//! * salt +//! * nonce +//! * encryption algorithm +//! * whether the file was encrypted in "memory" or stream mode +//! +//! It allows for serialization, deserialization, and has a convenience function for quickly writing the header to a file. +//! +//! # Examples +//! +//! ```rust,ignore +//! 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(); +//! ``` +//! +//! ```rust,ignore +//! let mut output_file = File::create("test").unwrap(); +//! +//! header.write(&mut output_file).unwrap(); +//! ``` +//! + +use crate::{ + key::{argon2id_hash, balloon_hash}, + protected::Protected, +}; + +use super::primitives::{get_nonce_len, Algorithm, Mode, ENCRYPTED_MASTER_KEY_LEN, SALT_LEN}; +use anyhow::{Context, Result}; +use std::io::{Cursor, Read, Seek, Write}; + +/// This defines the latest header version, so program's using this can easily stay up to date. +/// +/// It's also here to just help users keep track +pub const HEADER_VERSION: HeaderVersion = HeaderVersion::V5; + +/// This stores all possible versions of the header +#[allow(clippy::module_name_repetitions)] +#[derive(PartialEq, Eq, Clone, Copy, PartialOrd)] +pub enum HeaderVersion { + V1, + V2, + V3, + V4, + V5, +} + +impl std::fmt::Display for HeaderVersion { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + HeaderVersion::V1 => write!(f, "V1"), + HeaderVersion::V2 => write!(f, "V2"), + HeaderVersion::V3 => write!(f, "V3"), + HeaderVersion::V4 => write!(f, "V4"), + HeaderVersion::V5 => write!(f, "V5"), + } + } +} + +/// This is the Header's type - it contains the specific details that are needed to decrypt the data +/// +/// It contains the header's version, the "mode" that was used to encrypt the data, and the algorithm used. +/// +/// This needs to be manually created for encrypting data +#[allow(clippy::module_name_repetitions)] +pub struct HeaderType { + pub version: HeaderVersion, + pub algorithm: Algorithm, + pub mode: Mode, +} + +/// This is the `HeaderType` struct, but in the format of raw bytes +/// +/// This does not need to be used outside of this core library +struct HeaderTag { + pub version: [u8; 2], + pub algorithm: [u8; 2], + pub mode: [u8; 2], +} + +/// This is the main `Header` struct, and it contains all of the information about the encrypted data +/// +/// It contains the `HeaderType`, the nonce, and the salt +/// +/// This needs to be manually created for encrypting data +pub struct Header { + pub header_type: HeaderType, + pub nonce: Vec, + pub salt: Option<[u8; SALT_LEN]>, // option as v4+ use the keyslots + pub keyslots: Option>, +} + +pub const ARGON2ID_LATEST: i32 = 3; +pub const BLAKE3BALLOON_LATEST: i32 = 5; + +/// This is in place to make `Keyslot` handling a **lot** easier +/// You may use the constants `ARGON2ID_LATEST` and `BLAKE3BALLOON_LATEST` for defining versions +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum HashingAlgorithm { + Argon2id(i32), + Blake3Balloon(i32), +} + +impl std::fmt::Display for HashingAlgorithm { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + HashingAlgorithm::Argon2id(i) => write!(f, "Argon2id (param v{})", i), + HashingAlgorithm::Blake3Balloon(i) => write!(f, "BLAKE3-Balloon (param v{})", i), + } + } +} + +impl HashingAlgorithm { + /// A simple helper function that will hash a value with the appropriate algorithm and version + pub fn hash( + &self, + raw_key: Protected>, + salt: &[u8; SALT_LEN], + ) -> Result, anyhow::Error> { + match self { + HashingAlgorithm::Argon2id(i) => match i { + 1 => argon2id_hash(raw_key, salt, &HeaderVersion::V1), + 2 => argon2id_hash(raw_key, salt, &HeaderVersion::V2), + 3 => argon2id_hash(raw_key, salt, &HeaderVersion::V3), + _ => Err(anyhow::anyhow!( + "argon2id is not supported with the parameters provided." + )), + }, + HashingAlgorithm::Blake3Balloon(i) => match i { + 4 => balloon_hash(raw_key, salt, &HeaderVersion::V4), + 5 => balloon_hash(raw_key, salt, &HeaderVersion::V5), + _ => Err(anyhow::anyhow!( + "Balloon hashing is not supported with the parameters provided." + )), + }, + } + } +} + +/// This defines a keyslot that is used with header V4 and above. +/// A keyslot contains information about the key, and the encrypted key itself +#[derive(Clone)] +pub struct Keyslot { + pub hash_algorithm: HashingAlgorithm, + pub encrypted_key: [u8; ENCRYPTED_MASTER_KEY_LEN], + pub nonce: Vec, + pub salt: [u8; SALT_LEN], +} + +impl Keyslot { + /// This is used to convert a keyslot into bytes - ideal for writing headers + #[must_use] + pub fn serialize(&self) -> [u8; 2] { + match self.hash_algorithm { + HashingAlgorithm::Argon2id(i) => match i { + 1 => [0xDF, 0xA1], + 2 => [0xDF, 0xA2], + 3 => [0xDF, 0xA3], + _ => [0x00, 0x00], + }, + HashingAlgorithm::Blake3Balloon(i) => match i { + 4 => [0xDF, 0xB4], + 5 => [0xDF, 0xB5], + _ => [0x00, 0x00], + }, + } + } +} + +impl Header { + /// This is a private function (used by other header functions) for returning the `HeaderType`'s raw bytes + /// + /// It's used for serialization, and has it's own dedicated function as it will be used often + fn get_tag(&self) -> HeaderTag { + let version = self.serialize_version(); + let algorithm = self.serialize_algorithm(); + let mode = self.serialize_mode(); + HeaderTag { + version, + algorithm, + mode, + } + } + + /// This is a private function used for serialization + /// + /// It converts a `HeaderVersion` into the associated raw bytes + fn serialize_version(&self) -> [u8; 2] { + match self.header_type.version { + HeaderVersion::V1 => { + let info: [u8; 2] = [0xDE, 0x01]; + info + } + HeaderVersion::V2 => { + let info: [u8; 2] = [0xDE, 0x02]; + info + } + HeaderVersion::V3 => { + let info: [u8; 2] = [0xDE, 0x03]; + info + } + HeaderVersion::V4 => { + let info: [u8; 2] = [0xDE, 0x04]; + info + } + HeaderVersion::V5 => { + let info: [u8; 2] = [0xDE, 0x05]; + info + } + } + } + + /// This is used for deserializing raw bytes from a reader into a `Header` struct + /// + /// This also returns the AAD, read from the header. AAD is only generated in `HeaderVersion::V3` and above - it will be blank in older versions. + /// + /// The AAD needs to be passed to decryption functions in order to validate the header, and decrypt the data. + /// + /// The AAD for older versions is empty as no AAD is the default for AEADs, and the header validation was not in place prior to V3. + /// + /// NOTE: This leaves the cursor at 64 bytes into the buffer, as that is the size of the header + /// + /// # Examples + /// + /// ```rust,ignore + /// 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(); + /// ``` + /// + #[allow(clippy::too_many_lines)] + pub fn deserialize(reader: &mut (impl Read + Seek)) -> Result<(Self, Vec)> { + let mut version_bytes = [0u8; 2]; + reader + .read_exact(&mut version_bytes) + .context("Unable to read version from the header")?; + reader + .seek(std::io::SeekFrom::Current(-2)) + .context("Unable to seek back to start of header")?; + + let version = match version_bytes { + [0xDE, 0x01] => HeaderVersion::V1, + [0xDE, 0x02] => HeaderVersion::V2, + [0xDE, 0x03] => HeaderVersion::V3, + [0xDE, 0x04] => HeaderVersion::V4, + [0xDE, 0x05] => HeaderVersion::V5, + _ => return Err(anyhow::anyhow!("Error getting version from header")), + }; + + let header_length: usize = match version { + HeaderVersion::V1 | HeaderVersion::V2 | HeaderVersion::V3 => 64, + HeaderVersion::V4 => 128, + HeaderVersion::V5 => 416, + }; + + let mut full_header_bytes = vec![0u8; header_length]; + reader + .read_exact(&mut full_header_bytes) + .context("Unable to read full bytes of the header")?; + + let mut cursor = Cursor::new(full_header_bytes.clone()); + cursor + .seek(std::io::SeekFrom::Start(2)) + .context("Unable to seek past version bytes")?; // seek past the version bytes as we already have those + + let mut algorithm_bytes = [0u8; 2]; + cursor + .read_exact(&mut algorithm_bytes) + .context("Unable to read algorithm's bytes from header")?; + + let algorithm = match algorithm_bytes { + [0x0E, 0x01] => Algorithm::XChaCha20Poly1305, + [0x0E, 0x02] => Algorithm::Aes256Gcm, + [0x0E, 0x03] => Algorithm::DeoxysII256, + _ => return Err(anyhow::anyhow!("Error getting encryption mode from header")), + }; + + let mut mode_bytes = [0u8; 2]; + cursor + .read_exact(&mut mode_bytes) + .context("Unable to read encryption mode's bytes from header")?; + + let mode = match mode_bytes { + [0x0C, 0x01] => Mode::StreamMode, + [0x0C, 0x02] => Mode::MemoryMode, + _ => return Err(anyhow::anyhow!("Error getting cipher mode from header")), + }; + + let header_type = HeaderType { + version, + algorithm, + mode, + }; + + let nonce_len = get_nonce_len(&header_type.algorithm, &header_type.mode); + let mut salt = [0u8; 16]; + let mut nonce = vec![0u8; nonce_len]; + + let keyslots: Option> = match header_type.version { + HeaderVersion::V1 | HeaderVersion::V3 => { + cursor + .read_exact(&mut salt) + .context("Unable to read salt from header")?; + cursor + .read_exact(&mut [0; 16]) + .context("Unable to read empty bytes from header")?; + cursor + .read_exact(&mut nonce) + .context("Unable to read nonce from header")?; + cursor + .read_exact(&mut vec![0u8; 26 - nonce_len]) + .context("Unable to read final padding from header")?; + + None + } + HeaderVersion::V2 => { + cursor + .read_exact(&mut salt) + .context("Unable to read salt from header")?; + cursor + .read_exact(&mut nonce) + .context("Unable to read nonce from header")?; + cursor + .read_exact(&mut vec![0u8; 26 - nonce_len]) + .context("Unable to read empty bytes from header")?; + cursor + .read_exact(&mut [0u8; 16]) + .context("Unable to read final padding from header")?; + + None + } + HeaderVersion::V4 => { + let mut master_key_encrypted = [0u8; 48]; + let master_key_nonce_len = get_nonce_len(&algorithm, &Mode::MemoryMode); + let mut master_key_nonce = vec![0u8; master_key_nonce_len]; + cursor + .read_exact(&mut salt) + .context("Unable to read salt from header")?; + cursor + .read_exact(&mut nonce) + .context("Unable to read nonce from header")?; + cursor + .read_exact(&mut vec![0u8; 26 - nonce_len]) + .context("Unable to read padding from header")?; + cursor + .read_exact(&mut master_key_encrypted) + .context("Unable to read encrypted master key from header")?; + cursor + .read_exact(&mut master_key_nonce) + .context("Unable to read master key nonce from header")?; + cursor + .read_exact(&mut vec![0u8; 32 - master_key_nonce_len]) + .context("Unable to read padding from header")?; + + let keyslot = Keyslot { + encrypted_key: master_key_encrypted, + hash_algorithm: HashingAlgorithm::Blake3Balloon(4), + nonce: master_key_nonce.clone(), + salt, + }; + let keyslots = vec![keyslot]; + Some(keyslots) + } + HeaderVersion::V5 => { + cursor + .read_exact(&mut nonce) + .context("Unable to read nonce from header")?; + cursor + .read_exact(&mut vec![0u8; 26 - nonce_len]) + .context("Unable to read padding from header")?; // here we reach the 32 bytes + + let keyslot_nonce_len = get_nonce_len(&algorithm, &Mode::MemoryMode); + + let mut keyslots: Vec = Vec::new(); + for _ in 0..4 { + let mut identifier = [0u8; 2]; + cursor + .read_exact(&mut identifier) + .context("Unable to read keyslot identifier from header")?; + + if identifier[..1] != [0xDF] { + continue; + } + + let mut encrypted_key = [0u8; 48]; + let mut nonce = vec![0u8; keyslot_nonce_len]; + let mut padding = vec![0u8; 24 - keyslot_nonce_len]; + let mut salt = [0u8; SALT_LEN]; + + cursor + .read_exact(&mut encrypted_key) + .context("Unable to read keyslot encrypted bytes from header")?; + + cursor + .read_exact(&mut nonce) + .context("Unable to read keyslot nonce from header")?; + + cursor + .read_exact(&mut padding) + .context("Unable to read keyslot padding from header")?; + + cursor + .read_exact(&mut salt) + .context("Unable to read keyslot salt from header")?; + + cursor + .read_exact(&mut [0u8; 6]) + .context("Unable to read keyslot padding from header")?; + + let hash_algorithm = match identifier { + [0xDF, 0xA1] => HashingAlgorithm::Argon2id(1), + [0xDF, 0xA2] => HashingAlgorithm::Argon2id(2), + [0xDF, 0xA3] => HashingAlgorithm::Argon2id(3), + [0xDF, 0xB4] => HashingAlgorithm::Blake3Balloon(4), + [0xDF, 0xB5] => HashingAlgorithm::Blake3Balloon(5), + _ => return Err(anyhow::anyhow!("Key hashing algorithm not identified")), + }; + + let keyslot = Keyslot { + hash_algorithm, + encrypted_key, + nonce, + salt, + }; + + keyslots.push(keyslot); + } + + Some(keyslots) + } + }; + + let aad = match header_type.version { + HeaderVersion::V1 | HeaderVersion::V2 => Vec::::new(), + HeaderVersion::V3 => full_header_bytes.clone(), + HeaderVersion::V4 => { + let master_key_nonce_len = get_nonce_len(&algorithm, &Mode::MemoryMode); + let mut aad = Vec::new(); + + // this is for the version/algorithm/mode/salt/nonce + aad.extend_from_slice(&full_header_bytes[..48]); + + // this is for the padding that's appended to the end of the master key's nonce + // the master key/master key nonce aren't included as they may change + // the master key nonce length will be fixed, as otherwise the algorithm has changed + // and that requires re-encrypting anyway + aad.extend_from_slice(&full_header_bytes[(96 + master_key_nonce_len)..]); + aad + } + HeaderVersion::V5 => { + let mut aad = Vec::new(); + aad.extend_from_slice(&full_header_bytes[..32]); + aad + } + }; + + Ok(( + Header { + header_type, + nonce, + salt: Some(salt), + keyslots, + }, + aad, + )) + } + + /// This is a private function used for serialization + /// + /// It converts an `Algorithm` into the associated raw bytes + fn serialize_algorithm(&self) -> [u8; 2] { + match self.header_type.algorithm { + Algorithm::XChaCha20Poly1305 => { + let info: [u8; 2] = [0x0E, 0x01]; + info + } + Algorithm::Aes256Gcm => { + let info: [u8; 2] = [0x0E, 0x02]; + info + } + Algorithm::DeoxysII256 => { + let info: [u8; 2] = [0x0E, 0x03]; + info + } + } + } + + /// This is a private function used for serialization + /// + /// It converts a `Mode` into the associated raw bytes + fn serialize_mode(&self) -> [u8; 2] { + match self.header_type.mode { + Mode::StreamMode => { + let info: [u8; 2] = [0x0C, 0x01]; + info + } + Mode::MemoryMode => { + let info: [u8; 2] = [0x0C, 0x02]; + info + } + } + } + + /// This is a private function (called by `serialize()`) + /// + /// It serializes V3 headers + fn serialize_v3(&self, tag: &HeaderTag) -> Vec { + let padding = + vec![0u8; 26 - get_nonce_len(&self.header_type.algorithm, &self.header_type.mode)]; + let mut header_bytes = Vec::::new(); + header_bytes.extend_from_slice(&tag.version); + header_bytes.extend_from_slice(&tag.algorithm); + header_bytes.extend_from_slice(&tag.mode); + header_bytes.extend_from_slice(&self.salt.unwrap()); + header_bytes.extend_from_slice(&[0; 16]); + header_bytes.extend_from_slice(&self.nonce); + header_bytes.extend_from_slice(&padding); + header_bytes + } + + /// This is a private function (called by `serialize()`) + /// + /// It serializes V4 headers + fn serialize_v4(&self, tag: &HeaderTag) -> Vec { + let padding = + vec![0u8; 26 - get_nonce_len(&self.header_type.algorithm, &self.header_type.mode)]; + let padding2 = + vec![0u8; 32 - get_nonce_len(&self.header_type.algorithm, &Mode::MemoryMode)]; + + let keyslot = self.keyslots.clone().unwrap(); + + let mut header_bytes = Vec::::new(); + header_bytes.extend_from_slice(&tag.version); + header_bytes.extend_from_slice(&tag.algorithm); + header_bytes.extend_from_slice(&tag.mode); + header_bytes.extend_from_slice(&self.salt.unwrap_or(keyslot[0].salt)); + header_bytes.extend_from_slice(&self.nonce); + header_bytes.extend_from_slice(&padding); + header_bytes.extend_from_slice(&keyslot[0].encrypted_key); + header_bytes.extend_from_slice(&keyslot[0].nonce); + header_bytes.extend_from_slice(&padding2); + header_bytes + } + + /// This is a private function (called by `serialize()`) + /// + /// It serializes V5 headers + fn serialize_v5(&self, tag: &HeaderTag) -> Vec { + let padding = + vec![0u8; 26 - get_nonce_len(&self.header_type.algorithm, &self.header_type.mode)]; + + let keyslots = self.keyslots.clone().unwrap(); + + let mut header_bytes = Vec::::new(); + + // start of header static info + header_bytes.extend_from_slice(&tag.version); + header_bytes.extend_from_slice(&tag.algorithm); + header_bytes.extend_from_slice(&tag.mode); + header_bytes.extend_from_slice(&self.nonce); + header_bytes.extend_from_slice(&padding); + // end of header static info + + for keyslot in &keyslots { + let keyslot_nonce_len = get_nonce_len(&self.header_type.algorithm, &Mode::MemoryMode); + + header_bytes.extend_from_slice(&keyslot.serialize()); + header_bytes.extend_from_slice(&keyslot.encrypted_key); + header_bytes.extend_from_slice(&keyslot.nonce); + header_bytes.extend_from_slice(&vec![0u8; 24 - keyslot_nonce_len]); + header_bytes.extend_from_slice(&keyslot.salt); + header_bytes.extend_from_slice(&[0u8; 6]); + } + + for _ in 0..(4 - keyslots.len()) { + header_bytes.extend_from_slice(&[0u8; 96]); + } + + header_bytes + } + + /// This serializes a `Header` struct, and returns the raw bytes + /// + /// The returned bytes may be used as AAD, or written to a file + /// + /// NOTE: This should **NOT** be used for validating or creating AAD. + /// + /// It only has support for V3 headers and above + /// + /// Create AAD with `create_aad()`. + /// + /// Use the AAD returned from `deserialize()` for validation. + /// + /// # Examples + /// + /// ```rust,ignore + /// let header_bytes = header.serialize().unwrap(); + /// ``` + /// + pub fn serialize(&self) -> Result> { + let tag = self.get_tag(); + match self.header_type.version { + HeaderVersion::V1 => Err(anyhow::anyhow!( + "Serializing V1 headers has been deprecated" + )), + HeaderVersion::V2 => Err(anyhow::anyhow!( + "Serializing V2 headers has been deprecated" + )), + HeaderVersion::V3 => Ok(self.serialize_v3(&tag)), + HeaderVersion::V4 => Ok(self.serialize_v4(&tag)), + HeaderVersion::V5 => Ok(self.serialize_v5(&tag)), + } + } + + #[must_use] + pub fn get_size(&self) -> u64 { + match self.header_type.version { + HeaderVersion::V1 | HeaderVersion::V2 | HeaderVersion::V3 => 64, + HeaderVersion::V4 => 128, + HeaderVersion::V5 => 416, + } + } + + /// This is for creating AAD + /// + /// It only has support for V3 headers and above + /// + /// It will return the bytes used for AAD + /// + /// You may view more about what is used as AAD [here](https://brxken128.github.io/Volaris/Volaris-core/Headers.html#authenticating-the-header-with-aad-v840). + pub fn create_aad(&self) -> Result> { + let tag = self.get_tag(); + match self.header_type.version { + HeaderVersion::V1 => Err(anyhow::anyhow!( + "Serializing V1 headers has been deprecated" + )), + HeaderVersion::V2 => Err(anyhow::anyhow!( + "Serializing V2 headers has been deprecated" + )), + HeaderVersion::V3 => Ok(self.serialize_v3(&tag)), + HeaderVersion::V4 => { + let padding = + vec![ + 0u8; + 26 - get_nonce_len(&self.header_type.algorithm, &self.header_type.mode) + ]; + let master_key_nonce_len = + get_nonce_len(&self.header_type.algorithm, &Mode::MemoryMode); + let padding2 = vec![0u8; 32 - master_key_nonce_len]; + let mut header_bytes = Vec::::new(); + header_bytes.extend_from_slice(&tag.version); + header_bytes.extend_from_slice(&tag.algorithm); + header_bytes.extend_from_slice(&tag.mode); + header_bytes.extend_from_slice( + &self.salt.unwrap_or( + self.keyslots.as_ref().ok_or_else(|| { + anyhow::anyhow!("Cannot find a salt within the keyslot/header.") + })?[0] + .salt, + ), + ); + header_bytes.extend_from_slice(&self.nonce); + header_bytes.extend_from_slice(&padding); + header_bytes.extend_from_slice(&padding2); + Ok(header_bytes) + } + HeaderVersion::V5 => { + let mut header_bytes = Vec::::new(); + header_bytes.extend_from_slice(&tag.version); + header_bytes.extend_from_slice(&tag.algorithm); + header_bytes.extend_from_slice(&tag.mode); + header_bytes.extend_from_slice(&self.nonce); + header_bytes.extend_from_slice(&vec![ + 0u8; + 26 - get_nonce_len( + &self.header_type.algorithm, + &self.header_type.mode + ) + ]); + Ok(header_bytes) + } + } + } + + /// This is a convenience function for writing a header to a writer + /// + /// # Examples + /// + /// ```rust,ignore + /// let mut output_file = File::create("test").unwrap(); + /// + /// header.write(&mut output_file).unwrap(); + /// ``` + /// + pub fn write(&self, writer: &mut impl Write) -> Result<()> { + let header_bytes = self.serialize()?; + writer + .write(&header_bytes) + .context("Unable to write header")?; + + Ok(()) + } +} diff --git a/crates/volaris-core/src/key.rs b/crates/volaris-core/src/key.rs new file mode 100644 index 0000000..6892267 --- /dev/null +++ b/crates/volaris-core/src/key.rs @@ -0,0 +1,221 @@ +//! This module handles key-related functionality within `Volaris-core` +//! +//! It contains methods for `argon2id` and `balloon` hashing, and securely generating a salt +//! +//! # Examples +//! +//! ```rust,ignore +//! let salt = gen_salt(); +//! let secret_data = "secure key".as_bytes().to_vec(); +//! let raw_key = Protected::new(secret_data); +//! let key = argon2id_hash(raw_key, &salt, &HeaderVersion::V3).unwrap(); +//! ``` +use anyhow::Result; +use rand::{prelude::StdRng, Rng, SeedableRng}; +use zeroize::Zeroize; + +use crate::cipher::Ciphers; +use crate::header::{Header, HeaderVersion}; +use crate::primitives::{MASTER_KEY_LEN, SALT_LEN}; +use crate::protected::Protected; + +/// This handles `argon2id` hashing of a raw key +/// +/// It requires a user to generate the salt +/// +/// `HeaderVersion` is required as the parameters are linked to specific header versions +/// +/// It returns a `Protected<[u8; 32]>` - `Protected` wrappers are used for all sensitive information within `Volaris-core` +/// +/// This function ensures that `raw_key` is securely erased from memory once hashed +/// +/// # Examples +/// +/// ```rust,ignore +/// let salt = gen_salt(); +/// let secret_data = "secure key".as_bytes().to_vec(); +/// let raw_key = Protected::new(secret_data); +/// let key = argon2id_hash(raw_key, &salt, &HeaderVersion::V3).unwrap(); +/// ``` +/// +pub fn argon2id_hash( + raw_key: Protected>, + salt: &[u8; SALT_LEN], + version: &HeaderVersion, +) -> Result> { + use argon2::Argon2; + use argon2::Params; + + let params = match version { + HeaderVersion::V1 => { + // 8MiB of memory, 8 iterations, 4 levels of parallelism + Params::new(8192, 8, 4, Some(Params::DEFAULT_OUTPUT_LEN)) + .map_err(|_| anyhow::anyhow!("Error initialising argon2id parameters"))? + } + HeaderVersion::V2 => { + // 256MiB of memory, 8 iterations, 4 levels of parallelism + Params::new(262_144, 8, 4, Some(Params::DEFAULT_OUTPUT_LEN)) + .map_err(|_| anyhow::anyhow!("Error initialising argon2id parameters"))? + } + HeaderVersion::V3 => { + // 256MiB of memory, 10 iterations, 4 levels of parallelism + Params::new(262_144, 10, 4, Some(Params::DEFAULT_OUTPUT_LEN)) + .map_err(|_| anyhow::anyhow!("Error initialising argon2id parameters"))? + } + HeaderVersion::V4 | HeaderVersion::V5 => { + return Err(anyhow::anyhow!( + "argon2id is not supported on header versions above V3." + )) + } + }; + + let mut key = [0u8; 32]; + let argon2 = Argon2::new(argon2::Algorithm::Argon2id, argon2::Version::V0x13, params); + let result = argon2.hash_password_into(raw_key.expose(), salt, &mut key); + drop(raw_key); + + if result.is_err() { + return Err(anyhow::anyhow!("Error while hashing your key")); + } + + Ok(Protected::new(key)) +} + +/// This handles BLAKE3-Balloon hashing of a raw key +/// +/// It requires a user to generate the salt +/// +/// `HeaderVersion` is required as the parameters are linked to specific header versions +/// +/// It's only supported on header versions V4 and above. +/// +/// It returns a `Protected<[u8; 32]>` - `Protected` wrappers are used for all sensitive information within `Volaris-core` +/// +/// This function ensures that `raw_key` is securely erased from memory once hashed +/// +/// # Examples +/// +/// ```rust,ignore +/// let salt = gen_salt(); +/// let secret_data = "secure key".as_bytes().to_vec(); +/// let raw_key = Protected::new(secret_data); +/// let key = balloon_hash(raw_key, &salt, &HeaderVersion::V4).unwrap(); +/// ``` +/// +pub fn balloon_hash( + raw_key: Protected>, + salt: &[u8; SALT_LEN], + version: &HeaderVersion, +) -> Result> { + use balloon_hash::Balloon; + + let params = match version { + HeaderVersion::V1 | HeaderVersion::V2 | HeaderVersion::V3 => { + return Err(anyhow::anyhow!( + "Balloon hashing is not supported in header versions below V4." + )); + } + HeaderVersion::V4 => balloon_hash::Params::new(262_144, 1, 1) + .map_err(|_| anyhow::anyhow!("Error initialising balloon hashing parameters"))?, + HeaderVersion::V5 => balloon_hash::Params::new(278_528, 1, 1) + .map_err(|_| anyhow::anyhow!("Error initialising balloon hashing parameters"))?, + }; + + let mut key = [0u8; 32]; + let balloon = Balloon::::new(balloon_hash::Algorithm::Balloon, params, None); + let result = balloon.hash_into(raw_key.expose(), salt, &mut key); + drop(raw_key); + + if result.is_err() { + return Err(anyhow::anyhow!("Error while hashing your key")); + } + + Ok(Protected::new(key)) +} + +/// This is a helper function for retrieving the key used for encrypting the data +/// +/// In header versions below V4, this is just the hashed password +/// +/// In header versions >= V4, this is a cryptographically-secure random value +/// +/// In header versions >= V4, this function will iterate through all available keyslots, looking for a match. If it finds a match, it will return the decrypted master key. +#[allow(clippy::module_name_repetitions)] +pub fn decrypt_master_key( + raw_key: Protected>, + header: &Header, + // TODO: use custom error instead of anyhow +) -> Result> { + match header.header_type.version { + HeaderVersion::V1 | HeaderVersion::V2 | HeaderVersion::V3 => { + argon2id_hash(raw_key, &header.salt.ok_or_else(|| anyhow::anyhow!("Missing salt within the header!"))?, &header.header_type.version) + } + HeaderVersion::V4 => { + let keyslots = header.keyslots.as_ref().ok_or_else(|| anyhow::anyhow!("Unable to find a keyslot!"))?; + let keyslot = keyslots.first().ok_or_else(|| anyhow::anyhow!("Unable to find a match with the key you provided (maybe you supplied the wrong key?)"))?; + let key = keyslot.hash_algorithm.hash(raw_key, &keyslot.salt)?; + + let cipher = Ciphers::initialize(key, &header.header_type.algorithm)?; + cipher + .decrypt(&keyslot.nonce, keyslot.encrypted_key.as_slice()) + .map(vec_to_arr) + .map(Protected::new) + .map_err(|_| anyhow::anyhow!("Cannot decrypt master key")) + } + HeaderVersion::V5 => { + header + .keyslots + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Unable to find a keyslot!"))? + .iter() + .find_map(|keyslot| { + let key = keyslot.hash_algorithm.hash(raw_key.clone(), &keyslot.salt).ok()?; + + let cipher = Ciphers::initialize(key, &header.header_type.algorithm).ok()?; + cipher + .decrypt(&keyslot.nonce, keyslot.encrypted_key.as_slice()) + .map(vec_to_arr) + .map(Protected::new) + .ok() + }) + .ok_or_else(|| anyhow::anyhow!("Unable to find a match with the key you provided (maybe you supplied the wrong key?)")) + } + } +} + +// TODO: choose better place for this util +/// This is a simple helper function, used for converting the 32-byte master key `Vec`s to `[u8; 32]` +#[must_use] +pub fn vec_to_arr(mut master_key_vec: Vec) -> [u8; N] { + let mut master_key = [0u8; N]; + let len = N.min(master_key_vec.len()); + master_key[..len].copy_from_slice(&master_key_vec[..len]); + master_key_vec.zeroize(); + master_key +} + +/// This function is used for autogenerating a passphrase, from a wordlist +/// +/// It consists of n words, from the EFF large wordlist. The default amount of words is 7. +/// +/// Each word is separated with `-`. +/// +/// This provides adequate protection, while also remaining somewhat memorable. +#[must_use] +pub fn generate_passphrase(total_words: &i32) -> Protected { + let collection = include_str!("wordlist.lst"); + let words = collection.lines().collect::>(); + + let mut passphrase = String::new(); + + for i in 0..*total_words { + let index = StdRng::from_entropy().gen_range(0..=words.len()); + let word = words[index]; + passphrase.push_str(word); + if i < total_words - 1 { + passphrase.push('-'); + } + } + + Protected::new(passphrase) +} diff --git a/crates/volaris-core/src/lib.rs b/crates/volaris-core/src/lib.rs index 8b13789..c8e761f 100644 --- a/crates/volaris-core/src/lib.rs +++ b/crates/volaris-core/src/lib.rs @@ -1 +1,40 @@ +//! ## 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 audited1 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/). +//! +//! 1 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)). +//! +//! You can read more about Volaris, Volaris-Core and the technical details [in the project's main documentation](https://github.com/volarisapp/volaris/readme.md)! +//! +//! ## 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!) +#![forbid(unsafe_code)] +#![warn(clippy::all)] +pub const CORE_VERSION: &str = env!("CARGO_PKG_VERSION"); + +pub mod cipher; +pub mod header; +pub mod key; +pub mod primitives; +pub mod protected; +pub mod stream; +pub use aead::Payload; +pub use zeroize::Zeroize; + +#[cfg(feature = "visual")] +pub mod visual; diff --git a/crates/volaris-core/src/primitives.rs b/crates/volaris-core/src/primitives.rs new file mode 100644 index 0000000..08c68c9 --- /dev/null +++ b/crates/volaris-core/src/primitives.rs @@ -0,0 +1,136 @@ +//! This module contains all cryptographic primitives used by `Volaris-core` +use crate::protected::Protected; +use rand::{prelude::ThreadRng, RngCore}; + +/// This is the streaming block size +/// +/// NOTE: Stream mode can be used to encrypt files less than this size, provided the implementation +/// is correct +pub const BLOCK_SIZE: usize = 1_048_576; // 1024*1024 bytes + +/// This is the length of the salt used for password hashing +pub const SALT_LEN: usize = 16; // bytes + +pub const MASTER_KEY_LEN: usize = 32; +pub const ENCRYPTED_MASTER_KEY_LEN: usize = 48; +pub const ALGORITHMS_LEN: usize = 3; + +/// This is an `enum` containing all AEADs supported by `Volaris-core` +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Algorithm { + Aes256Gcm, + XChaCha20Poly1305, + DeoxysII256, +} + +/// This is an array containing all AEADs supported by `Volaris-core`. +/// +/// It can be used by and end-user application to show a list of AEADs that they may use +pub static ALGORITHMS: [Algorithm; ALGORITHMS_LEN] = [ + Algorithm::XChaCha20Poly1305, + Algorithm::Aes256Gcm, + Algorithm::DeoxysII256, +]; + +impl std::fmt::Display for Algorithm { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Algorithm::Aes256Gcm => write!(f, "AES-256-GCM"), + Algorithm::XChaCha20Poly1305 => write!(f, "XChaCha20-Poly1305"), + Algorithm::DeoxysII256 => write!(f, "Deoxys-II-256"), + } + } +} + +/// This defines the possible modes used for encrypting/decrypting +#[derive(PartialEq, Eq)] +pub enum Mode { + MemoryMode, + StreamMode, +} + +impl std::fmt::Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Mode::MemoryMode => write!(f, "Memory Mode"), + Mode::StreamMode => write!(f, "Stream Mode"), + } + } +} + +/// This can be used to generate a nonce for encryption +/// It requires both the algorithm and the mode, so it can correctly determine the nonce length +/// This nonce can be passed directly to `EncryptionStreams::initialize()` +/// +/// # Examples +/// +/// ```rust +/// # use Volaris_core::primitives::*; +/// let nonce = gen_nonce(&Algorithm::XChaCha20Poly1305, &Mode::StreamMode); +/// ``` +/// +#[must_use] +pub fn gen_nonce(algorithm: &Algorithm, mode: &Mode) -> Vec { + let nonce_len = get_nonce_len(algorithm, mode); + let mut nonce = vec![0u8; nonce_len]; + ThreadRng::default().fill_bytes(&mut nonce); + nonce +} + +/// This function calculates the length of the nonce, depending on the data provided +/// +/// Stream mode nonces are 4 bytes less than their "memory" mode counterparts, due to `aead::StreamLE31` +/// +/// `StreamLE31` contains a 31-bit little endian counter, and a 1-bit "last block" flag, stored as the last 4 bytes of the nonce, this is done to prevent nonce-reuse +#[must_use] +pub fn get_nonce_len(algorithm: &Algorithm, mode: &Mode) -> usize { + let mut nonce_len = match algorithm { + Algorithm::Aes256Gcm => 12, + Algorithm::XChaCha20Poly1305 => 24, + Algorithm::DeoxysII256 => 15, + }; + + if mode == &Mode::StreamMode { + nonce_len -= 4; + } + + nonce_len +} + +/// Generates a new protected master key of the specified `MASTER_KEY_LEN`. +/// +/// This can be used to generate a master key for encryption. +/// It uses `ThreadRng` to securely generate completely random bytes, with extra protection +/// from some side-channel attacks +/// +/// # Examples +/// +/// ```rust +/// # use Volaris_core::primitives::*; +/// let master_key = gen_master_key(); +/// ``` +/// +#[must_use] +pub fn gen_master_key() -> Protected<[u8; MASTER_KEY_LEN]> { + let mut master_key = [0u8; MASTER_KEY_LEN]; + ThreadRng::default().fill_bytes(&mut master_key); + Protected::new(master_key) +} + +/// Generates a salt, of the specified `SALT_LEN` +/// +/// This salt can be directly passed to `argon2id_hash()` or `balloon_hash()` +/// +/// # Examples +/// +/// ```rust +/// # use Volaris_core::primitives::*; +/// let salt = gen_salt(); +/// ``` +/// +#[must_use] +pub fn gen_salt() -> [u8; SALT_LEN] { + let mut salt = [0u8; SALT_LEN]; + ThreadRng::default().fill_bytes(&mut salt); + salt +} diff --git a/crates/volaris-core/src/protected.rs b/crates/volaris-core/src/protected.rs new file mode 100644 index 0000000..f48c0fe --- /dev/null +++ b/crates/volaris-core/src/protected.rs @@ -0,0 +1,79 @@ +//! This is a basic wrapper for secret/hidden values +//! +//! It implements zeroize-on-drop, meaning the data is securely erased from memory once it goes out of scope. +//! You may call `drop()` prematurely if you wish to erase it sooner. +//! +//! `Protected` values are also hidden from `fmt::Debug`, and will display `[REDACTED]` instead. +//! +//! The only way to access the data within a `Protected` value is to call `.expose()` - this is to prevent accidental leakage. +//! This also makes any `Protected` value easier to audit, as you are able to quickly view wherever the data is accessed. +//! +//! `Protected` values are not able to be copied within memory, to prevent accidental leakage. They are able to be `cloned` however - but this is always explicit and you will be aware of it. +//! +//! I'd like to give a huge thank you to the authors of the [secrecy crate](https://crates.io/crates/secrecy), +//! as that crate's functionality inspired this implementation. +//! +//! # Examples +//! +//! ```rust,ignore +//! let secret_data = "this is classified information".to_string(); +//! let protected_data = Protected::new(secret_data); +//! +//! // the only way to access the data within the `Protected` wrapper +//! // is by calling `.expose()` +//! let value = protected_data.expose(); +//! ``` +//! + +use std::fmt::Debug; +use zeroize::Zeroize; + +#[derive(Clone)] +pub struct Protected +where + T: Zeroize, +{ + data: T, +} + +impl std::ops::Deref for Protected +where + T: Zeroize, +{ + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl Protected +where + T: Zeroize, +{ + pub fn new(value: T) -> Self { + Protected { data: value } + } + + pub fn expose(&self) -> &T { + &self.data + } +} + +impl Drop for Protected +where + T: Zeroize, +{ + fn drop(&mut self) { + self.data.zeroize(); + } +} + +impl Debug for Protected +where + T: Zeroize, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("[REDACTED]") + } +} diff --git a/crates/volaris-core/src/stream.rs b/crates/volaris-core/src/stream.rs new file mode 100644 index 0000000..5692f78 --- /dev/null +++ b/crates/volaris-core/src/stream.rs @@ -0,0 +1,406 @@ +//! This module contains all of the LE31 STREAM objects and functionality +//! +//! This is where streaming mode encryption, decryption and initialization is handled. +//! +//! There are also some convenience functions for quickly encrypting and decrypting files. +//! +//! # 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(); +//! +//! // this nonce should be read from somewhere, not generated +//! let nonce = gen_nonce(&Algorithm::XChaCha20Poly1305, &Mode::StreamMode); +//! +//! let decrypt_stream = DecryptionStreams::initialize(key, &nonce, &Algorithm::XChaCha20Poly1305).unwrap(); +//! +//! let mut input_file = File::open("input.encrypted").unwrap(); +//! let mut output_file = File::create("output").unwrap(); +//! +//! // aad should be retrieved from the `Header` (with `Header::deserialize()`) +//! let aad = Vec::new(); +//! +//! decrypt_stream.decrypt_file(&mut input_file, &mut output_file, &aad); +//! ``` + +use std::io::{Read, Write}; + +use aead::{ + stream::{DecryptorLE31, EncryptorLE31}, + KeyInit, Payload, +}; +use aes_gcm::Aes256Gcm; +use anyhow::Context; +use chacha20poly1305::XChaCha20Poly1305; +use deoxys::DeoxysII256; +// use rand::{prelude::StdRng, Rng, SeedableRng, RngCore}; +use zeroize::Zeroize; + +use crate::primitives::{Algorithm, BLOCK_SIZE}; +use crate::protected::Protected; + +/// This `enum` contains streams for that are used solely for encryption +/// +/// It has definitions for all AEADs supported by `Volaris-core` +pub enum EncryptionStreams { + Aes256Gcm(Box>), + XChaCha20Poly1305(Box>), + DeoxysII256(Box>), +} + +/// This `enum` contains streams for that are used solely for decryption +/// +/// It has definitions for all AEADs supported by `Volaris-core` +pub enum DecryptionStreams { + Aes256Gcm(Box>), + XChaCha20Poly1305(Box>), + DeoxysII256(Box>), +} + +impl EncryptionStreams { + /// This method can be used to quickly create an `EncryptionStreams` object + /// + /// It requies a 32-byte hashed key, which will be dropped once the stream has been initialized + /// + /// It requires a pre-generated nonce, which you may generate with `gen_nonce()` + /// + /// If the nonce length is not exact, you will receive an error. + /// + /// It will create the stream with the specified algorithm, and it will also generate the appropriate nonce + /// + /// The `EncryptionStreams` object is returned + /// + /// # 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 nonce = gen_nonce(&Algorithm::XChaCha20Poly1305, &Mode::StreamMode); + /// let encrypt_stream = EncryptionStreams::initialize(key, &nonce, &Algorithm::XChaCha20Poly1305).unwrap(); + /// ``` + /// + pub fn initialize( + key: Protected<[u8; 32]>, + nonce: &[u8], + algorithm: &Algorithm, + ) -> anyhow::Result { + let streams = match algorithm { + Algorithm::Aes256Gcm => { + if nonce.len() != 8 { + return Err(anyhow::anyhow!("Nonce is not the correct length")); + } + + let cipher = Aes256Gcm::new_from_slice(key.expose()) + .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?; + + let stream = EncryptorLE31::from_aead(cipher, nonce.into()); + EncryptionStreams::Aes256Gcm(Box::new(stream)) + } + Algorithm::XChaCha20Poly1305 => { + if nonce.len() != 20 { + return Err(anyhow::anyhow!("Nonce is not the correct length")); + } + + let cipher = XChaCha20Poly1305::new_from_slice(key.expose()) + .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?; + + let stream = EncryptorLE31::from_aead(cipher, nonce.into()); + EncryptionStreams::XChaCha20Poly1305(Box::new(stream)) + } + Algorithm::DeoxysII256 => { + if nonce.len() != 11 { + return Err(anyhow::anyhow!("Nonce is not the correct length")); + } + + let cipher = DeoxysII256::new_from_slice(key.expose()) + .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?; + + let stream = EncryptorLE31::from_aead(cipher, nonce.into()); + EncryptionStreams::DeoxysII256(Box::new(stream)) + } + }; + + drop(key); + Ok(streams) + } + + /// This is used for encrypting the *next* block of data in streaming mode + /// + /// It requires either some plaintext, or an `aead::Payload` (that contains the plaintext and the AAD) + pub fn encrypt_next<'msg, 'aad>( + &mut self, + payload: impl Into>, + ) -> aead::Result> { + match self { + EncryptionStreams::Aes256Gcm(s) => s.encrypt_next(payload), + EncryptionStreams::XChaCha20Poly1305(s) => s.encrypt_next(payload), + EncryptionStreams::DeoxysII256(s) => s.encrypt_next(payload), + } + } + + /// This is used for encrypting the *last* block of data in streaming mode. It consumes the stream object to prevent further usage. + /// + /// It requires either some plaintext, or an `aead::Payload` (that contains the plaintext and the AAD) + pub fn encrypt_last<'msg, 'aad>( + self, + payload: impl Into>, + ) -> aead::Result> { + match self { + EncryptionStreams::Aes256Gcm(s) => s.encrypt_last(payload), + EncryptionStreams::XChaCha20Poly1305(s) => s.encrypt_last(payload), + EncryptionStreams::DeoxysII256(s) => s.encrypt_last(payload), + } + } + + /// This is a convenience function for reading from a reader, encrypting, and writing to the writer. + /// + /// Every single block is provided with the AAD + /// + /// Valid AAD must be provided if you are using `HeaderVersion::V3` and above. It must be empty if the `HeaderVersion` is lower. + /// + /// You are free to use a custom AAD, just ensure that it is present for decryption, or else you will receive an error. + /// + /// This does not handle writing the header. + /// + /// # Examples + /// + /// ```rust,ignore + /// let mut input_file = File::open("input").unwrap(); + /// let mut output_file = File::create("output.encrypted").unwrap(); + /// + /// // aad should be generated from the header (only for encryption) + /// let aad = header.serialize().unwrap(); + /// + /// let encrypt_stream = EncryptionStreams::initialize(key, &nonce, &Algorithm::XChaCha20Poly1305).unwrap(); + /// encrypt_stream.encrypt_file(&mut input_file, &mut output_file, &aad); + /// ``` + /// + pub fn encrypt_file( + mut self, + reader: &mut impl Read, + writer: &mut impl Write, + aad: &[u8], + ) -> anyhow::Result<()> { + #[cfg(feature = "visual")] + let pb = crate::visual::create_spinner(); + + let mut read_buffer = vec![0u8; BLOCK_SIZE].into_boxed_slice(); + loop { + let read_count = reader + .read(&mut read_buffer) + .context("Unable to read from the reader")?; + if read_count == BLOCK_SIZE { + // aad is just empty bytes normally + // create_aad returns empty bytes if the header isn't V3+ + // this means we don't need to do anything special in regards to older versions + let payload = Payload { + aad, + msg: read_buffer.as_ref(), + }; + + let encrypted_data = self + .encrypt_next(payload) + .map_err(|_| anyhow::anyhow!("Unable to encrypt the data"))?; + + writer + .write_all(&encrypted_data) + .context("Unable to write to the output")?; + } else { + // if we read something less than BLOCK_SIZE, and have hit the end of the file + let payload = Payload { + aad, + msg: &read_buffer[..read_count], + }; + + let encrypted_data = self + .encrypt_last(payload) + .map_err(|_| anyhow::anyhow!("Unable to encrypt the data"))?; + + writer + .write_all(&encrypted_data) + .context("Unable to write to the output")?; + break; + } + } + read_buffer.zeroize(); + writer.flush().context("Unable to flush the output")?; + + #[cfg(feature = "visual")] + pb.finish_and_clear(); + + Ok(()) + } +} + +impl DecryptionStreams { + /// This method can be used to quickly create an `DecryptionStreams` object + /// + /// It requies a 32-byte hashed key, which will be dropped once the stream has been initialized + /// + /// It requires the same nonce that was returned upon initializing `EncryptionStreams` + /// + /// It will create the stream with the specified algorithm + /// + /// The `DecryptionStreams` object will be returned + /// + /// # 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(); + /// + /// // this nonce should be read from somewhere, not generated + /// let nonce = gen_nonce(&Algorithm::XChaCha20Poly1305, &Mode::StreamMode); + /// + /// let decrypt_stream = DecryptionStreams::initialize(key, &nonce, &Algorithm::XChaCha20Poly1305).unwrap(); + /// ``` + /// + pub fn initialize( + key: Protected<[u8; 32]>, + nonce: &[u8], + algorithm: &Algorithm, + ) -> anyhow::Result { + let streams = match algorithm { + Algorithm::Aes256Gcm => { + let cipher = Aes256Gcm::new_from_slice(key.expose()) + .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?; + + let stream = DecryptorLE31::from_aead(cipher, nonce.into()); + DecryptionStreams::Aes256Gcm(Box::new(stream)) + } + Algorithm::XChaCha20Poly1305 => { + let cipher = XChaCha20Poly1305::new_from_slice(key.expose()) + .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?; + + let stream = DecryptorLE31::from_aead(cipher, nonce.into()); + DecryptionStreams::XChaCha20Poly1305(Box::new(stream)) + } + Algorithm::DeoxysII256 => { + let cipher = DeoxysII256::new_from_slice(key.expose()) + .map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?; + + let stream = DecryptorLE31::from_aead(cipher, nonce.into()); + DecryptionStreams::DeoxysII256(Box::new(stream)) + } + }; + + drop(key); + Ok(streams) + } + + /// This is used for decrypting the *next* block of data in streaming mode + /// + /// It requires either some plaintext, or an `aead::Payload` (that contains the plaintext and the AAD) + /// + /// Whatever you provided as AAD while encrypting must be present during decryption, or else you will receive an error. + pub fn decrypt_next<'msg, 'aad>( + &mut self, + payload: impl Into>, + ) -> aead::Result> { + match self { + DecryptionStreams::Aes256Gcm(s) => s.decrypt_next(payload), + DecryptionStreams::XChaCha20Poly1305(s) => s.decrypt_next(payload), + DecryptionStreams::DeoxysII256(s) => s.decrypt_next(payload), + } + } + + /// This is used for decrypting the *last* block of data in streaming mode. It consumes the stream object to prevent further usage. + /// + /// It requires either some plaintext, or an `aead::Payload` (that contains the plaintext and the AAD) + /// + /// Whatever you provided as AAD while encrypting must be present during decryption, or else you will receive an error. + pub fn decrypt_last<'msg, 'aad>( + self, + payload: impl Into>, + ) -> aead::Result> { + match self { + DecryptionStreams::Aes256Gcm(s) => s.decrypt_last(payload), + DecryptionStreams::XChaCha20Poly1305(s) => s.decrypt_last(payload), + DecryptionStreams::DeoxysII256(s) => s.decrypt_last(payload), + } + } + + /// This is a convenience function for reading from a reader, decrypting, and writing to the writer. + /// + /// Every single block is provided with the AAD + /// + /// Valid AAD must be provided if you are using `HeaderVersion::V3` and above. It must be empty if the `HeaderVersion` is lower. Whatever you provided as AAD while encrypting must be present during decryption, or else you will receive an error. + /// + /// This does not handle writing the header. + /// + /// # Examples + /// + /// ```rust,ignore + /// let mut input_file = File::open("input.encrypted").unwrap(); + /// let mut output_file = File::create("output").unwrap(); + /// + /// // aad should be retrieved from the `Header` (with `Header::deserialize()`) + /// let aad = Vec::new(); + /// + /// let decrypt_stream = DecryptionStreams::initialize(key, &nonce, &Algorithm::XChaCha20Poly1305).unwrap(); + /// decrypt_stream.decrypt_file(&mut input_file, &mut output_file, &aad); + /// ``` + /// + pub fn decrypt_file( + mut self, + reader: &mut impl Read, + writer: &mut impl Write, + aad: &[u8], + ) -> anyhow::Result<()> { + #[cfg(feature = "visual")] + let pb = crate::visual::create_spinner(); + + let mut buffer = vec![0u8; BLOCK_SIZE + 16].into_boxed_slice(); + loop { + let read_count = reader.read(&mut buffer)?; + if read_count == (BLOCK_SIZE + 16) { + let payload = Payload { + aad, + msg: buffer.as_ref(), + }; + + let mut decrypted_data = self.decrypt_next(payload).map_err(|_| { + anyhow::anyhow!("Unable to decrypt the data. This means either: you're using the wrong key, this isn't an encrypted file, or the header has been tampered with.") + })?; + + writer + .write_all(&decrypted_data) + .context("Unable to write to the output")?; + + decrypted_data.zeroize(); + } else { + // if we read something less than BLOCK_SIZE+16, and have hit the end of the file + let payload = Payload { + aad, + msg: &buffer[..read_count], + }; + + let mut decrypted_data = self.decrypt_last(payload).map_err(|_| { + anyhow::anyhow!("Unable to decrypt the final block of data. This means either: you're using the wrong key, this isn't an encrypted file, or the header has been tampered with.") + })?; + + writer + .write_all(&decrypted_data) + .context("Unable to write to the output file")?; + + decrypted_data.zeroize(); + break; + } + } + + writer.flush().context("Unable to flush the output")?; + + #[cfg(feature = "visual")] + pb.finish_and_clear(); + + Ok(()) + } +} diff --git a/crates/volaris-core/src/visual.rs b/crates/volaris-core/src/visual.rs new file mode 100644 index 0000000..8ed6584 --- /dev/null +++ b/crates/volaris-core/src/visual.rs @@ -0,0 +1,21 @@ +//! This module offers visual functionality within `Volaris-core`. +//! +//! It isn't rather populated, nor does `Volaris` itself use it, but the option is always there. +//! +//! This can be enabled with the `visual` feature, and you will notice a blue spinner on encryption and decryption - useful for knowing that something is still happening. + +#[cfg(feature = "visual")] +use indicatif::{ProgressBar, ProgressStyle}; + +#[cfg(feature = "visual")] +#[must_use] +/// This creates a visual spinner, which can be enabled with the `visual` feature. +/// +/// The spinner is used for both encrypting and decrypting, provided the feature is enabled. +pub fn create_spinner() -> ProgressBar { + let pb = ProgressBar::new_spinner(); + pb.enable_steady_tick(120); + pb.set_style(ProgressStyle::default_spinner().template("{spinner:.cyan}")); + + pb +} diff --git a/crates/volaris-core/src/wordlist.lst b/crates/volaris-core/src/wordlist.lst new file mode 100644 index 0000000..0522960 --- /dev/null +++ b/crates/volaris-core/src/wordlist.lst @@ -0,0 +1,7771 @@ +abacus +abdomen +abdominal +abide +abiding +ability +ablaze +able +abnormal +abrasion +abrasive +abreast +abridge +abroad +abruptly +absence +absentee +absently +absinthe +absolute +absolve +abstain +abstract +absurd +accent +acclaim +acclimate +accompany +account +accuracy +accurate +accustom +acetone +achiness +aching +acid +acorn +acquaint +acquire +acre +acrobat +acronym +acting +action +activate +activator +active +activism +activist +activity +actress +acts +acutely +acuteness +aeration +aerobics +aerosol +aerospace +afar +affair +affected +affecting +affection +affidavit +affiliate +affirm +affix +afflicted +affluent +afford +affront +aflame +afloat +aflutter +afoot +afraid +afterglow +afterlife +aftermath +aftermost +afternoon +aged +ageless +agency +agenda +agent +aggregate +aghast +agile +agility +aging +agnostic +agonize +agonizing +agony +agreeable +agreeably +agreed +agreeing +agreement +aground +ahead +ahoy +aide +aids +aim +ajar +alabaster +alarm +albatross +album +alfalfa +algebra +algorithm +alias +alibi +alienable +alienate +aliens +alike +alive +alkaline +alkalize +almanac +almighty +almost +aloe +aloft +aloha +alone +alongside +aloof +alphabet +alright +although +altitude +alto +aluminum +alumni +always +amaretto +amaze +amazingly +amber +ambiance +ambiguity +ambiguous +ambition +ambitious +ambulance +ambush +amendable +amendment +amends +amenity +amiable +amicably +amid +amigo +amino +amiss +ammonia +ammonium +amnesty +amniotic +among +amount +amperage +ample +amplifier +amplify +amply +amuck +amulet +amusable +amused +amusement +amuser +amusing +anaconda +anaerobic +anagram +anatomist +anatomy +anchor +anchovy +ancient +android +anemia +anemic +aneurism +anew +angelfish +angelic +anger +angled +angler +angles +angling +angrily +angriness +anguished +angular +animal +animate +animating +animation +animator +anime +animosity +ankle +annex +annotate +announcer +annoying +annually +annuity +anointer +another +answering +antacid +antarctic +anteater +antelope +antennae +anthem +anthill +anthology +antibody +antics +antidote +antihero +antiquely +antiques +antiquity +antirust +antitoxic +antitrust +antiviral +antivirus +antler +antonym +antsy +anvil +anybody +anyhow +anymore +anyone +anyplace +anything +anytime +anyway +anywhere +aorta +apache +apostle +appealing +appear +appease +appeasing +appendage +appendix +appetite +appetizer +applaud +applause +apple +appliance +applicant +applied +apply +appointee +appraisal +appraiser +apprehend +approach +approval +approve +apricot +april +apron +aptitude +aptly +aqua +aqueduct +arbitrary +arbitrate +ardently +area +arena +arguable +arguably +argue +arise +armadillo +armband +armchair +armed +armful +armhole +arming +armless +armoire +armored +armory +armrest +army +aroma +arose +around +arousal +arrange +array +arrest +arrival +arrive +arrogance +arrogant +arson +art +ascend +ascension +ascent +ascertain +ashamed +ashen +ashes +ashy +aside +askew +asleep +asparagus +aspect +aspirate +aspire +aspirin +astonish +astound +astride +astrology +astronaut +astronomy +astute +atlantic +atlas +atom +atonable +atop +atrium +atrocious +atrophy +attach +attain +attempt +attendant +attendee +attention +attentive +attest +attic +attire +attitude +attractor +attribute +atypical +auction +audacious +audacity +audible +audibly +audience +audio +audition +augmented +august +authentic +author +autism +autistic +autograph +automaker +automated +automatic +autopilot +available +avalanche +avatar +avenge +avenging +avenue +average +aversion +avert +aviation +aviator +avid +avoid +await +awaken +award +aware +awhile +awkward +awning +awoke +awry +axis +babble +babbling +babied +baboon +backache +backboard +backboned +backdrop +backed +backer +backfield +backfire +backhand +backing +backlands +backlash +backless +backlight +backlit +backlog +backpack +backpedal +backrest +backroom +backshift +backside +backslid +backspace +backspin +backstab +backstage +backtalk +backtrack +backup +backward +backwash +backwater +backyard +bacon +bacteria +bacterium +badass +badge +badland +badly +badness +baffle +baffling +bagel +bagful +baggage +bagged +baggie +bagginess +bagging +baggy +bagpipe +baguette +baked +bakery +bakeshop +baking +balance +balancing +balcony +balmy +balsamic +bamboo +banana +banish +banister +banjo +bankable +bankbook +banked +banker +banking +banknote +bankroll +banner +bannister +banshee +banter +barbecue +barbed +barbell +barber +barcode +barge +bargraph +barista +baritone +barley +barmaid +barman +barn +barometer +barrack +barracuda +barrel +barrette +barricade +barrier +barstool +bartender +barterer +bash +basically +basics +basil +basin +basis +basket +batboy +batch +bath +baton +bats +battalion +battered +battering +battery +batting +battle +bauble +bazooka +blabber +bladder +blade +blah +blame +blaming +blanching +blandness +blank +blaspheme +blasphemy +blast +blatancy +blatantly +blazer +blazing +bleach +bleak +bleep +blemish +blend +bless +blighted +blimp +bling +blinked +blinker +blinking +blinks +blip +blissful +blitz +blizzard +bloated +bloating +blob +blog +bloomers +blooming +blooper +blot +blouse +blubber +bluff +bluish +blunderer +blunt +blurb +blurred +blurry +blurt +blush +blustery +boaster +boastful +boasting +boat +bobbed +bobbing +bobble +bobcat +bobsled +bobtail +bodacious +body +bogged +boggle +bogus +boil +bok +bolster +bolt +bonanza +bonded +bonding +bondless +boned +bonehead +boneless +bonelike +boney +bonfire +bonnet +bonsai +bonus +bony +boogeyman +boogieman +book +boondocks +booted +booth +bootie +booting +bootlace +bootleg +boots +boozy +borax +boring +borough +borrower +borrowing +boss +botanical +botanist +botany +botch +both +bottle +bottling +bottom +bounce +bouncing +bouncy +bounding +boundless +bountiful +bovine +boxcar +boxer +boxing +boxlike +boxy +breach +breath +breeches +breeching +breeder +breeding +breeze +breezy +brethren +brewery +brewing +briar +bribe +brick +bride +bridged +brigade +bright +brilliant +brim +bring +brink +brisket +briskly +briskness +bristle +brittle +broadband +broadcast +broaden +broadly +broadness +broadside +broadways +broiler +broiling +broken +broker +bronchial +bronco +bronze +bronzing +brook +broom +brought +browbeat +brownnose +browse +browsing +bruising +brunch +brunette +brunt +brush +brussels +brute +brutishly +bubble +bubbling +bubbly +buccaneer +bucked +bucket +buckle +buckshot +buckskin +bucktooth +buckwheat +buddhism +buddhist +budding +buddy +budget +buffalo +buffed +buffer +buffing +buffoon +buggy +bulb +bulge +bulginess +bulgur +bulk +bulldog +bulldozer +bullfight +bullfrog +bullhorn +bullion +bullish +bullpen +bullring +bullseye +bullwhip +bully +bunch +bundle +bungee +bunion +bunkbed +bunkhouse +bunkmate +bunny +bunt +busboy +bush +busily +busload +bust +busybody +buzz +cabana +cabbage +cabbie +cabdriver +cable +caboose +cache +cackle +cacti +cactus +caddie +caddy +cadet +cadillac +cadmium +cage +cahoots +cake +calamari +calamity +calcium +calculate +calculus +caliber +calibrate +calm +caloric +calorie +calzone +camcorder +cameo +camera +camisole +camper +campfire +camping +campsite +campus +canal +canary +cancel +candied +candle +candy +cane +canine +canister +cannabis +canned +canning +cannon +cannot +canola +canon +canopener +canopy +canteen +canyon +capable +capably +capacity +cape +capillary +capital +capitol +capped +capricorn +capsize +capsule +caption +captivate +captive +captivity +capture +caramel +carat +caravan +carbon +cardboard +carded +cardiac +cardigan +cardinal +cardstock +carefully +caregiver +careless +caress +caretaker +cargo +caring +carless +carload +carmaker +carnage +carnation +carnival +carnivore +carol +carpenter +carpentry +carpool +carport +carried +carrot +carrousel +carry +cartel +cartload +carton +cartoon +cartridge +cartwheel +carve +carving +carwash +cascade +case +cash +casing +casino +casket +cassette +casually +casualty +catacomb +catalog +catalyst +catalyze +catapult +cataract +catatonic +catcall +catchable +catcher +catching +catchy +caterer +catering +catfight +catfish +cathedral +cathouse +catlike +catnap +catnip +catsup +cattail +cattishly +cattle +catty +catwalk +caucasian +caucus +causal +causation +cause +causing +cauterize +caution +cautious +cavalier +cavalry +caviar +cavity +cedar +celery +celestial +celibacy +celibate +celtic +cement +census +ceramics +ceremony +certainly +certainty +certified +certify +cesarean +cesspool +chafe +chaffing +chain +chair +chalice +challenge +chamber +chamomile +champion +chance +change +channel +chant +chaos +chaperone +chaplain +chapped +chaps +chapter +character +charbroil +charcoal +charger +charging +chariot +charity +charm +charred +charter +charting +chase +chasing +chaste +chastise +chastity +chatroom +chatter +chatting +chatty +cheating +cheddar +cheek +cheer +cheese +cheesy +chef +chemicals +chemist +chemo +cherisher +cherub +chess +chest +chevron +chevy +chewable +chewer +chewing +chewy +chief +chihuahua +childcare +childhood +childish +childless +childlike +chili +chill +chimp +chip +chirping +chirpy +chitchat +chivalry +chive +chloride +chlorine +choice +chokehold +choking +chomp +chooser +choosing +choosy +chop +chosen +chowder +chowtime +chrome +chubby +chuck +chug +chummy +chump +chunk +churn +chute +cider +cilantro +cinch +cinema +cinnamon +circle +circling +circular +circulate +circus +citable +citadel +citation +citizen +citric +citrus +city +civic +civil +clad +claim +clambake +clammy +clamor +clamp +clamshell +clang +clanking +clapped +clapper +clapping +clarify +clarinet +clarity +clash +clasp +class +clatter +clause +clavicle +claw +clay +clean +clear +cleat +cleaver +cleft +clench +clergyman +clerical +clerk +clever +clicker +client +climate +climatic +cling +clinic +clinking +clip +clique +cloak +clobber +clock +clone +cloning +closable +closure +clothes +clothing +cloud +clover +clubbed +clubbing +clubhouse +clump +clumsily +clumsy +clunky +clustered +clutch +clutter +coach +coagulant +coastal +coaster +coasting +coastland +coastline +coat +coauthor +cobalt +cobbler +cobweb +cocoa +coconut +cod +coeditor +coerce +coexist +coffee +cofounder +cognition +cognitive +cogwheel +coherence +coherent +cohesive +coil +coke +cola +cold +coleslaw +coliseum +collage +collapse +collar +collected +collector +collide +collie +collision +colonial +colonist +colonize +colony +colossal +colt +coma +come +comfort +comfy +comic +coming +comma +commence +commend +comment +commerce +commode +commodity +commodore +common +commotion +commute +commuting +compacted +compacter +compactly +compactor +companion +company +compare +compel +compile +comply +component +composed +composer +composite +compost +composure +compound +compress +comprised +computer +computing +comrade +concave +conceal +conceded +concept +concerned +concert +conch +concierge +concise +conclude +concrete +concur +condense +condiment +condition +condone +conducive +conductor +conduit +cone +confess +confetti +confidant +confident +confider +confiding +configure +confined +confining +confirm +conflict +conform +confound +confront +confused +confusing +confusion +congenial +congested +congrats +congress +conical +conjoined +conjure +conjuror +connected +connector +consensus +consent +console +consoling +consonant +constable +constant +constrain +constrict +construct +consult +consumer +consuming +contact +container +contempt +contend +contented +contently +contents +contest +context +contort +contour +contrite +control +contusion +convene +convent +copartner +cope +copied +copier +copilot +coping +copious +copper +copy +coral +cork +cornball +cornbread +corncob +cornea +corned +corner +cornfield +cornflake +cornhusk +cornmeal +cornstalk +corny +coronary +coroner +corporal +corporate +corral +correct +corridor +corrode +corroding +corrosive +corsage +corset +cortex +cosigner +cosmetics +cosmic +cosmos +cosponsor +cost +cottage +cotton +couch +cough +could +countable +countdown +counting +countless +country +county +courier +covenant +cover +coveted +coveting +coyness +cozily +coziness +cozy +crabbing +crabgrass +crablike +crabmeat +cradle +cradling +crafter +craftily +craftsman +craftwork +crafty +cramp +cranberry +crane +cranial +cranium +crank +crate +crave +craving +crawfish +crawlers +crawling +crayfish +crayon +crazed +crazily +craziness +crazy +creamed +creamer +creamlike +crease +creasing +creatable +create +creation +creative +creature +credible +credibly +credit +creed +creme +creole +crepe +crept +crescent +crested +cresting +crestless +crevice +crewless +crewman +crewmate +crib +cricket +cried +crier +crimp +crimson +cringe +cringing +crinkle +crinkly +crisped +crisping +crisply +crispness +crispy +criteria +critter +croak +crock +crook +croon +crop +cross +crouch +crouton +crowbar +crowd +crown +crucial +crudely +crudeness +cruelly +cruelness +cruelty +crumb +crummiest +crummy +crumpet +crumpled +cruncher +crunching +crunchy +crusader +crushable +crushed +crusher +crushing +crust +crux +crying +cryptic +crystal +cubbyhole +cube +cubical +cubicle +cucumber +cuddle +cuddly +cufflink +culinary +culminate +culpable +culprit +cultivate +cultural +culture +cupbearer +cupcake +cupid +cupped +cupping +curable +curator +curdle +cure +curfew +curing +curled +curler +curliness +curling +curly +curry +curse +cursive +cursor +curtain +curtly +curtsy +curvature +curve +curvy +cushy +cusp +cussed +custard +custodian +custody +customary +customer +customize +customs +cut +cycle +cyclic +cycling +cyclist +cylinder +cymbal +cytoplasm +cytoplast +dab +dad +daffodil +dagger +daily +daintily +dainty +dairy +daisy +dallying +dance +dancing +dandelion +dander +dandruff +dandy +danger +dangle +dangling +daredevil +dares +daringly +darkened +darkening +darkish +darkness +darkroom +darling +darn +dart +darwinism +dash +dastardly +data +datebook +dating +daughter +daunting +dawdler +dawn +daybed +daybreak +daycare +daydream +daylight +daylong +dayroom +daytime +dazzler +dazzling +deacon +deafening +deafness +dealer +dealing +dealmaker +dealt +dean +debatable +debate +debating +debit +debrief +debtless +debtor +debug +debunk +decade +decaf +decal +decathlon +decay +deceased +deceit +deceiver +deceiving +december +decency +decent +deception +deceptive +decibel +decidable +decimal +decimeter +decipher +deck +declared +decline +decode +decompose +decorated +decorator +decoy +decrease +decree +dedicate +dedicator +deduce +deduct +deed +deem +deepen +deeply +deepness +deface +defacing +defame +default +defeat +defection +defective +defendant +defender +defense +defensive +deferral +deferred +defiance +defiant +defile +defiling +define +definite +deflate +deflation +deflator +deflected +deflector +defog +deforest +defraud +defrost +deftly +defuse +defy +degraded +degrading +degrease +degree +dehydrate +deity +dejected +delay +delegate +delegator +delete +deletion +delicacy +delicate +delicious +delighted +delirious +delirium +deliverer +delivery +delouse +delta +deluge +delusion +deluxe +demanding +demeaning +demeanor +demise +democracy +democrat +demote +demotion +demystify +denatured +deniable +denial +denim +denote +dense +density +dental +dentist +denture +deny +deodorant +deodorize +departed +departure +depict +deplete +depletion +deplored +deploy +deport +depose +depraved +depravity +deprecate +depress +deprive +depth +deputize +deputy +derail +deranged +derby +derived +desecrate +deserve +deserving +designate +designed +designer +designing +deskbound +desktop +deskwork +desolate +despair +despise +despite +destiny +destitute +destruct +detached +detail +detection +detective +detector +detention +detergent +detest +detonate +detonator +detoxify +detract +deuce +devalue +deviancy +deviant +deviate +deviation +deviator +device +devious +devotedly +devotee +devotion +devourer +devouring +devoutly +dexterity +dexterous +diabetes +diabetic +diabolic +diagnoses +diagnosis +diagram +dial +diameter +diaper +diaphragm +diary +dice +dicing +dictate +dictation +dictator +difficult +diffused +diffuser +diffusion +diffusive +dig +dilation +diligence +diligent +dill +dilute +dime +diminish +dimly +dimmed +dimmer +dimness +dimple +diner +dingbat +dinghy +dinginess +dingo +dingy +dining +dinner +diocese +dioxide +diploma +dipped +dipper +dipping +directed +direction +directive +directly +directory +direness +dirtiness +disabled +disagree +disallow +disarm +disarray +disaster +disband +disbelief +disburse +discard +discern +discharge +disclose +discolor +discount +discourse +discover +discuss +disdain +disengage +disfigure +disgrace +dish +disinfect +disjoin +disk +dislike +disliking +dislocate +dislodge +disloyal +dismantle +dismay +dismiss +dismount +disobey +disorder +disown +disparate +disparity +dispatch +dispense +dispersal +dispersed +disperser +displace +display +displease +disposal +dispose +disprove +dispute +disregard +disrupt +dissuade +distance +distant +distaste +distill +distinct +distort +distract +distress +district +distrust +ditch +ditto +ditzy +dividable +divided +dividend +dividers +dividing +divinely +diving +divinity +divisible +divisibly +division +divisive +divorcee +dizziness +dizzy +doable +docile +dock +doctrine +document +dodge +dodgy +doily +doing +dole +dollar +dollhouse +dollop +dolly +dolphin +domain +domelike +domestic +dominion +dominoes +donated +donation +donator +donor +donut +doodle +doorbell +doorframe +doorknob +doorman +doormat +doornail +doorpost +doorstep +doorstop +doorway +doozy +dork +dormitory +dorsal +dosage +dose +dotted +doubling +douche +dove +down +dowry +doze +drab +dragging +dragonfly +dragonish +dragster +drainable +drainage +drained +drainer +drainpipe +dramatic +dramatize +drank +drapery +drastic +draw +dreaded +dreadful +dreadlock +dreamboat +dreamily +dreamland +dreamless +dreamlike +dreamt +dreamy +drearily +dreary +drench +dress +drew +dribble +dried +drier +drift +driller +drilling +drinkable +drinking +dripping +drippy +drivable +driven +driver +driveway +driving +drizzle +drizzly +drone +drool +droop +dropbox +dropkick +droplet +dropout +dropper +drove +drown +drowsily +drudge +drum +dry +dubbed +dubiously +duchess +duckbill +ducking +duckling +ducktail +ducky +duct +dude +duffel +dugout +duh +duke +duller +dullness +duly +dumping +dumpling +dumpster +duo +dupe +duplex +duplicate +duplicity +durable +durably +duration +duress +during +dusk +dust +dutiful +duty +duvet +dwarf +dweeb +dwelled +dweller +dwelling +dwindle +dwindling +dynamic +dynamite +dynasty +dyslexia +dyslexic +each +eagle +earache +eardrum +earflap +earful +earlobe +early +earmark +earmuff +earphone +earpiece +earplugs +earring +earshot +earthen +earthlike +earthling +earthly +earthworm +earthy +earwig +easeful +easel +easiest +easily +easiness +easing +eastbound +eastcoast +easter +eastward +eatable +eaten +eatery +eating +eats +ebay +ebony +ebook +ecard +eccentric +echo +eclair +eclipse +ecologist +ecology +economic +economist +economy +ecosphere +ecosystem +edge +edginess +edging +edgy +edition +editor +educated +education +educator +eel +effective +effects +efficient +effort +eggbeater +egging +eggnog +eggplant +eggshell +egomaniac +egotism +egotistic +either +eject +elaborate +elastic +elated +elbow +eldercare +elderly +eldest +electable +election +elective +elephant +elevate +elevating +elevation +elevator +eleven +elf +eligible +eligibly +eliminate +elite +elitism +elixir +elk +ellipse +elliptic +elm +elongated +elope +eloquence +eloquent +elsewhere +elude +elusive +elves +email +embargo +embark +embassy +embattled +embellish +ember +embezzle +emblaze +emblem +embody +embolism +emboss +embroider +emcee +emerald +emergency +emission +emit +emote +emoticon +emotion +empathic +empathy +emperor +emphases +emphasis +emphasize +emphatic +empirical +employed +employee +employer +emporium +empower +emptier +emptiness +empty +emu +enable +enactment +enamel +enchanted +enchilada +encircle +enclose +enclosure +encode +encore +encounter +encourage +encroach +encrust +encrypt +endanger +endeared +endearing +ended +ending +endless +endnote +endocrine +endorphin +endorse +endowment +endpoint +endurable +endurance +enduring +energetic +energize +energy +enforced +enforcer +engaged +engaging +engine +engorge +engraved +engraver +engraving +engross +engulf +enhance +enigmatic +enjoyable +enjoyably +enjoyer +enjoying +enjoyment +enlarged +enlarging +enlighten +enlisted +enquirer +enrage +enrich +enroll +enslave +ensnare +ensure +entail +entangled +entering +entertain +enticing +entire +entitle +entity +entomb +entourage +entrap +entree +entrench +entrust +entryway +entwine +enunciate +envelope +enviable +enviably +envious +envision +envoy +envy +enzyme +epic +epidemic +epidermal +epidermis +epidural +epilepsy +epileptic +epilogue +epiphany +episode +equal +equate +equation +equator +equinox +equipment +equity +equivocal +eradicate +erasable +erased +eraser +erasure +ergonomic +errand +errant +erratic +error +erupt +escalate +escalator +escapable +escapade +escapist +escargot +eskimo +esophagus +espionage +espresso +esquire +essay +essence +essential +establish +estate +esteemed +estimate +estimator +estranged +estrogen +etching +eternal +eternity +ethanol +ether +ethically +ethics +euphemism +evacuate +evacuee +evade +evaluate +evaluator +evaporate +evasion +evasive +even +everglade +evergreen +everybody +everyday +everyone +evict +evidence +evident +evil +evoke +evolution +evolve +exact +exalted +example +excavate +excavator +exceeding +exception +excess +exchange +excitable +exciting +exclaim +exclude +excluding +exclusion +exclusive +excretion +excretory +excursion +excusable +excusably +excuse +exemplary +exemplify +exemption +exerciser +exert +exes +exfoliate +exhale +exhaust +exhume +exile +existing +exit +exodus +exonerate +exorcism +exorcist +expand +expanse +expansion +expansive +expectant +expedited +expediter +expel +expend +expenses +expensive +expert +expire +expiring +explain +expletive +explicit +explode +exploit +explore +exploring +exponent +exporter +exposable +expose +exposure +express +expulsion +exquisite +extended +extending +extent +extenuate +exterior +external +extinct +extortion +extradite +extras +extrovert +extrude +extruding +exuberant +fable +fabric +fabulous +facebook +facecloth +facedown +faceless +facelift +faceplate +faceted +facial +facility +facing +facsimile +faction +factoid +factor +factsheet +factual +faculty +fade +fading +failing +falcon +fall +false +falsify +fame +familiar +family +famine +famished +fanatic +fancied +fanciness +fancy +fanfare +fang +fanning +fantasize +fantastic +fantasy +fascism +fastball +faster +fasting +fastness +faucet +favorable +favorably +favored +favoring +favorite +fax +feast +federal +fedora +feeble +feed +feel +feisty +feline +feminine +feminism +feminist +feminize +femur +fence +fencing +fender +ferment +fernlike +ferocious +ferocity +ferret +ferris +ferry +fervor +fester +festival +festive +festivity +fetal +fetch +fever +fiber +fiction +fiddle +fiddling +fidelity +fidgeting +fidgety +fifteen +fifth +fiftieth +fifty +figment +figure +figurine +filing +filled +filler +filling +film +filter +filth +filtrate +finale +finalist +finalize +finally +finance +financial +finch +fineness +finer +finicky +finished +finisher +finishing +finite +finless +finlike +fiscally +fit +five +flaccid +flagman +flagpole +flagship +flagstick +flagstone +flail +flakily +flaky +flame +flammable +flanked +flanking +flannels +flap +flaring +flashback +flashbulb +flashcard +flashily +flashing +flashy +flask +flatbed +flatfoot +flatly +flatness +flatten +flattered +flatterer +flattery +flattop +flatware +flatworm +flavored +flavorful +flavoring +flaxseed +fled +fleshed +fleshy +flick +flier +flight +flinch +fling +flint +flip +flirt +float +flock +flogging +flop +floral +florist +floss +flounder +flyable +flyaway +flyer +flying +flyover +flypaper +foam +foe +fog +foil +folic +folk +follicle +follow +fondling +fondly +fondness +fondue +font +food +fool +footage +football +footbath +footboard +footer +footgear +foothill +foothold +footing +footless +footman +footnote +footpad +footpath +footprint +footrest +footsie +footsore +footwear +footwork +fossil +foster +founder +founding +fountain +fox +foyer +fraction +fracture +fragile +fragility +fragment +fragrance +fragrant +frail +frame +framing +frantic +fraternal +frayed +fraying +frays +freckled +freckles +freebase +freebee +freebie +freedom +freefall +freehand +freeing +freeload +freely +freemason +freeness +freestyle +freeware +freeway +freewill +freezable +freezing +freight +french +frenzied +frenzy +frequency +frequent +fresh +fretful +fretted +friction +friday +fridge +fried +friend +frighten +frightful +frigidity +frigidly +frill +fringe +frisbee +frisk +fritter +frivolous +frolic +from +front +frostbite +frosted +frostily +frosting +frostlike +frosty +froth +frown +frozen +fructose +frugality +frugally +fruit +frustrate +frying +gab +gaffe +gag +gainfully +gaining +gains +gala +gallantly +galleria +gallery +galley +gallon +gallows +gallstone +galore +galvanize +gambling +game +gaming +gamma +gander +gangly +gangrene +gangway +gap +garage +garbage +garden +gargle +garland +garlic +garment +garnet +garnish +garter +gas +gatherer +gathering +gating +gauging +gauntlet +gauze +gave +gawk +gazing +gear +gecko +geek +geiger +gem +gender +generic +generous +genetics +genre +gentile +gentleman +gently +gents +geography +geologic +geologist +geology +geometric +geometry +geranium +gerbil +geriatric +germicide +germinate +germless +germproof +gestate +gestation +gesture +getaway +getting +getup +giant +gibberish +giblet +giddily +giddiness +giddy +gift +gigabyte +gigahertz +gigantic +giggle +giggling +giggly +gigolo +gilled +gills +gimmick +girdle +giveaway +given +giver +giving +gizmo +gizzard +glacial +glacier +glade +gladiator +gladly +glamorous +glamour +glance +glancing +glandular +glare +glaring +glass +glaucoma +glazing +gleaming +gleeful +glider +gliding +glimmer +glimpse +glisten +glitch +glitter +glitzy +gloater +gloating +gloomily +gloomy +glorified +glorifier +glorify +glorious +glory +gloss +glove +glowing +glowworm +glucose +glue +gluten +glutinous +glutton +gnarly +gnat +goal +goatskin +goes +goggles +going +goldfish +goldmine +goldsmith +golf +goliath +gonad +gondola +gone +gong +good +gooey +goofball +goofiness +goofy +google +goon +gopher +gore +gorged +gorgeous +gory +gosling +gossip +gothic +gotten +gout +gown +grab +graceful +graceless +gracious +gradation +graded +grader +gradient +grading +gradually +graduate +graffiti +grafted +grafting +grain +granddad +grandkid +grandly +grandma +grandpa +grandson +granite +granny +granola +grant +granular +grape +graph +grapple +grappling +grasp +grass +gratified +gratify +grating +gratitude +gratuity +gravel +graveness +graves +graveyard +gravitate +gravity +gravy +gray +grazing +greasily +greedily +greedless +greedy +green +greeter +greeting +grew +greyhound +grid +grief +grievance +grieving +grievous +grill +grimace +grimacing +grime +griminess +grimy +grinch +grinning +grip +gristle +grit +groggily +groggy +groin +groom +groove +grooving +groovy +grope +ground +grouped +grout +grove +grower +growing +growl +grub +grudge +grudging +grueling +gruffly +grumble +grumbling +grumbly +grumpily +grunge +grunt +guacamole +guidable +guidance +guide +guiding +guileless +guise +gulf +gullible +gully +gulp +gumball +gumdrop +gumminess +gumming +gummy +gurgle +gurgling +guru +gush +gusto +gusty +gutless +guts +gutter +guy +guzzler +gyration +habitable +habitant +habitat +habitual +hacked +hacker +hacking +hacksaw +had +haggler +haiku +half +halogen +halt +halved +halves +hamburger +hamlet +hammock +hamper +hamster +hamstring +handbag +handball +handbook +handbrake +handcart +handclap +handclasp +handcraft +handcuff +handed +handful +handgrip +handgun +handheld +handiness +handiwork +handlebar +handled +handler +handling +handmade +handoff +handpick +handprint +handrail +handsaw +handset +handsfree +handshake +handstand +handwash +handwork +handwoven +handwrite +handyman +hangnail +hangout +hangover +hangup +hankering +hankie +hanky +haphazard +happening +happier +happiest +happily +happiness +happy +harbor +hardcopy +hardcore +hardcover +harddisk +hardened +hardener +hardening +hardhat +hardhead +hardiness +hardly +hardness +hardship +hardware +hardwired +hardwood +hardy +harmful +harmless +harmonica +harmonics +harmonize +harmony +harness +harpist +harsh +harvest +hash +hassle +haste +hastily +hastiness +hasty +hatbox +hatchback +hatchery +hatchet +hatching +hatchling +hate +hatless +hatred +haunt +haven +hazard +hazelnut +hazily +haziness +hazing +hazy +headache +headband +headboard +headcount +headdress +headed +header +headfirst +headgear +heading +headlamp +headless +headlock +headphone +headpiece +headrest +headroom +headscarf +headset +headsman +headstand +headstone +headway +headwear +heap +heat +heave +heavily +heaviness +heaving +hedge +hedging +heftiness +hefty +helium +helmet +helper +helpful +helping +helpless +helpline +hemlock +hemstitch +hence +henchman +henna +herald +herbal +herbicide +herbs +heritage +hermit +heroics +heroism +herring +herself +hertz +hesitancy +hesitant +hesitate +hexagon +hexagram +hubcap +huddle +huddling +huff +hug +hula +hulk +hull +human +humble +humbling +humbly +humid +humiliate +humility +humming +hummus +humongous +humorist +humorless +humorous +humpback +humped +humvee +hunchback +hundredth +hunger +hungrily +hungry +hunk +hunter +hunting +huntress +huntsman +hurdle +hurled +hurler +hurling +hurray +hurricane +hurried +hurry +hurt +husband +hush +husked +huskiness +hut +hybrid +hydrant +hydrated +hydration +hydrogen +hydroxide +hyperlink +hypertext +hyphen +hypnoses +hypnosis +hypnotic +hypnotism +hypnotist +hypnotize +hypocrisy +hypocrite +ibuprofen +ice +iciness +icing +icky +icon +icy +idealism +idealist +idealize +ideally +idealness +identical +identify +identity +ideology +idiocy +idiom +idly +igloo +ignition +ignore +iguana +illicitly +illusion +illusive +image +imaginary +imagines +imaging +imbecile +imitate +imitation +immature +immerse +immersion +imminent +immobile +immodest +immorally +immortal +immovable +immovably +immunity +immunize +impaired +impale +impart +impatient +impeach +impeding +impending +imperfect +imperial +impish +implant +implement +implicate +implicit +implode +implosion +implosive +imply +impolite +important +importer +impose +imposing +impotence +impotency +impotent +impound +imprecise +imprint +imprison +impromptu +improper +improve +improving +improvise +imprudent +impulse +impulsive +impure +impurity +iodine +iodize +ion +ipad +iphone +ipod +irate +irk +iron +irregular +irrigate +irritable +irritably +irritant +irritate +islamic +islamist +isolated +isolating +isolation +isotope +issue +issuing +italicize +italics +item +itinerary +itunes +ivory +ivy +jab +jackal +jacket +jackknife +jackpot +jailbird +jailbreak +jailer +jailhouse +jalapeno +jam +janitor +january +jargon +jarring +jasmine +jaundice +jaunt +java +jawed +jawless +jawline +jaws +jaybird +jaywalker +jazz +jeep +jeeringly +jellied +jelly +jersey +jester +jet +jiffy +jigsaw +jimmy +jingle +jingling +jinx +jitters +jittery +job +jockey +jockstrap +jogger +jogging +john +joining +jokester +jokingly +jolliness +jolly +jolt +jot +jovial +joyfully +joylessly +joyous +joyride +joystick +jubilance +jubilant +judge +judgingly +judicial +judiciary +judo +juggle +juggling +jugular +juice +juiciness +juicy +jujitsu +jukebox +july +jumble +jumbo +jump +junction +juncture +june +junior +juniper +junkie +junkman +junkyard +jurist +juror +jury +justice +justifier +justify +justly +justness +juvenile +kabob +kangaroo +karaoke +karate +karma +kebab +keenly +keenness +keep +keg +kelp +kennel +kept +kerchief +kerosene +kettle +kick +kiln +kilobyte +kilogram +kilometer +kilowatt +kilt +kimono +kindle +kindling +kindly +kindness +kindred +kinetic +kinfolk +king +kinship +kinsman +kinswoman +kissable +kisser +kissing +kitchen +kite +kitten +kitty +kiwi +kleenex +knapsack +knee +knelt +knickers +knoll +koala +kooky +kosher +krypton +kudos +kung +labored +laborer +laboring +laborious +labrador +ladder +ladies +ladle +ladybug +ladylike +lagged +lagging +lagoon +lair +lake +lance +landed +landfall +landfill +landing +landlady +landless +landline +landlord +landmark +landmass +landmine +landowner +landscape +landside +landslide +language +lankiness +lanky +lantern +lapdog +lapel +lapped +lapping +laptop +lard +large +lark +lash +lasso +last +latch +late +lather +latitude +latrine +latter +latticed +launch +launder +laundry +laurel +lavender +lavish +laxative +lazily +laziness +lazy +lecturer +left +legacy +legal +legend +legged +leggings +legible +legibly +legislate +lego +legroom +legume +legwarmer +legwork +lemon +lend +length +lens +lent +leotard +lesser +letdown +lethargic +lethargy +letter +lettuce +level +leverage +levers +levitate +levitator +liability +liable +liberty +librarian +library +licking +licorice +lid +life +lifter +lifting +liftoff +ligament +likely +likeness +likewise +liking +lilac +lilly +lily +limb +limeade +limelight +limes +limit +limping +limpness +line +lingo +linguini +linguist +lining +linked +linoleum +linseed +lint +lion +lip +liquefy +liqueur +liquid +lisp +list +litigate +litigator +litmus +litter +little +livable +lived +lively +liver +livestock +lividly +living +lizard +lubricant +lubricate +lucid +luckily +luckiness +luckless +lucrative +ludicrous +lugged +lukewarm +lullaby +lumber +luminance +luminous +lumpiness +lumping +lumpish +lunacy +lunar +lunchbox +luncheon +lunchroom +lunchtime +lung +lurch +lure +luridness +lurk +lushly +lushness +luster +lustfully +lustily +lustiness +lustrous +lusty +luxurious +luxury +lying +lyrically +lyricism +lyricist +lyrics +macarena +macaroni +macaw +mace +machine +machinist +magazine +magenta +maggot +magical +magician +magma +magnesium +magnetic +magnetism +magnetize +magnifier +magnify +magnitude +magnolia +mahogany +maimed +majestic +majesty +majorette +majority +makeover +maker +makeshift +making +malformed +malt +mama +mammal +mammary +mammogram +manager +managing +manatee +mandarin +mandate +mandatory +mandolin +manger +mangle +mango +mangy +manhandle +manhole +manhood +manhunt +manicotti +manicure +manifesto +manila +mankind +manlike +manliness +manly +manmade +manned +mannish +manor +manpower +mantis +mantra +manual +many +map +marathon +marauding +marbled +marbles +marbling +march +mardi +margarine +margarita +margin +marigold +marina +marine +marital +maritime +marlin +marmalade +maroon +married +marrow +marry +marshland +marshy +marsupial +marvelous +marxism +mascot +masculine +mashed +mashing +massager +masses +massive +mastiff +matador +matchbook +matchbox +matcher +matching +matchless +material +maternal +maternity +math +mating +matriarch +matrimony +matrix +matron +matted +matter +maturely +maturing +maturity +mauve +maverick +maximize +maximum +maybe +mayday +mayflower +moaner +moaning +mobile +mobility +mobilize +mobster +mocha +mocker +mockup +modified +modify +modular +modulator +module +moisten +moistness +moisture +molar +molasses +mold +molecular +molecule +molehill +mollusk +mom +monastery +monday +monetary +monetize +moneybags +moneyless +moneywise +mongoose +mongrel +monitor +monkhood +monogamy +monogram +monologue +monopoly +monorail +monotone +monotype +monoxide +monsieur +monsoon +monstrous +monthly +monument +moocher +moodiness +moody +mooing +moonbeam +mooned +moonlight +moonlike +moonlit +moonrise +moonscape +moonshine +moonstone +moonwalk +mop +morale +morality +morally +morbidity +morbidly +morphine +morphing +morse +mortality +mortally +mortician +mortified +mortify +mortuary +mosaic +mossy +most +mothball +mothproof +motion +motivate +motivator +motive +motocross +motor +motto +mountable +mountain +mounted +mounting +mourner +mournful +mouse +mousiness +moustache +mousy +mouth +movable +move +movie +moving +mower +mowing +much +muck +mud +mug +mulberry +mulch +mule +mulled +mullets +multiple +multiply +multitask +multitude +mumble +mumbling +mumbo +mummified +mummify +mummy +mumps +munchkin +mundane +municipal +muppet +mural +murkiness +murky +murmuring +muscular +museum +mushily +mushiness +mushroom +mushy +music +musket +muskiness +musky +mustang +mustard +muster +mustiness +musty +mutable +mutate +mutation +mute +mutilated +mutilator +mutiny +mutt +mutual +muzzle +myself +myspace +mystified +mystify +myth +nacho +nag +nail +name +naming +nanny +nanometer +nape +napkin +napped +napping +nappy +narrow +nastily +nastiness +national +native +nativity +natural +nature +naturist +nautical +navigate +navigator +navy +nearby +nearest +nearly +nearness +neatly +neatness +nebula +nebulizer +nectar +negate +negation +negative +neglector +negligee +negligent +negotiate +nemeses +nemesis +neon +nephew +nerd +nervous +nervy +nest +net +neurology +neuron +neurosis +neurotic +neuter +neutron +never +next +nibble +nickname +nicotine +niece +nifty +nimble +nimbly +nineteen +ninetieth +ninja +nintendo +ninth +nuclear +nuclei +nucleus +nugget +nullify +number +numbing +numbly +numbness +numeral +numerate +numerator +numeric +numerous +nuptials +nursery +nursing +nurture +nutcase +nutlike +nutmeg +nutrient +nutshell +nuttiness +nutty +nuzzle +nylon +oaf +oak +oasis +oat +obedience +obedient +obituary +object +obligate +obliged +oblivion +oblivious +oblong +obnoxious +oboe +obscure +obscurity +observant +observer +observing +obsessed +obsession +obsessive +obsolete +obstacle +obstinate +obstruct +obtain +obtrusive +obtuse +obvious +occultist +occupancy +occupant +occupier +occupy +ocean +ocelot +octagon +octane +october +octopus +ogle +oil +oink +ointment +okay +old +olive +olympics +omega +omen +ominous +omission +omit +omnivore +onboard +oncoming +ongoing +onion +online +onlooker +only +onscreen +onset +onshore +onslaught +onstage +onto +onward +onyx +oops +ooze +oozy +opacity +opal +open +operable +operate +operating +operation +operative +operator +opium +opossum +opponent +oppose +opposing +opposite +oppressed +oppressor +opt +opulently +osmosis +other +otter +ouch +ought +ounce +outage +outback +outbid +outboard +outbound +outbreak +outburst +outcast +outclass +outcome +outdated +outdoors +outer +outfield +outfit +outflank +outgoing +outgrow +outhouse +outing +outlast +outlet +outline +outlook +outlying +outmatch +outmost +outnumber +outplayed +outpost +outpour +output +outrage +outrank +outreach +outright +outscore +outsell +outshine +outshoot +outsider +outskirts +outsmart +outsource +outspoken +outtakes +outthink +outward +outweigh +outwit +oval +ovary +oven +overact +overall +overarch +overbid +overbill +overbite +overblown +overboard +overbook +overbuilt +overcast +overcoat +overcome +overcook +overcrowd +overdraft +overdrawn +overdress +overdrive +overdue +overeager +overeater +overexert +overfed +overfeed +overfill +overflow +overfull +overgrown +overhand +overhang +overhaul +overhead +overhear +overheat +overhung +overjoyed +overkill +overlabor +overlaid +overlap +overlay +overload +overlook +overlord +overlying +overnight +overpass +overpay +overplant +overplay +overpower +overprice +overrate +overreach +overreact +override +overripe +overrule +overrun +overshoot +overshot +oversight +oversized +oversleep +oversold +overspend +overstate +overstay +overstep +overstock +overstuff +oversweet +overtake +overthrow +overtime +overtly +overtone +overture +overturn +overuse +overvalue +overview +overwrite +owl +oxford +oxidant +oxidation +oxidize +oxidizing +oxygen +oxymoron +oyster +ozone +paced +pacemaker +pacific +pacifier +pacifism +pacifist +pacify +padded +padding +paddle +paddling +padlock +pagan +pager +paging +pajamas +palace +palatable +palm +palpable +palpitate +paltry +pampered +pamperer +pampers +pamphlet +panama +pancake +pancreas +panda +pandemic +pang +panhandle +panic +panning +panorama +panoramic +panther +pantomime +pantry +pants +pantyhose +paparazzi +papaya +paper +paprika +papyrus +parabola +parachute +parade +paradox +paragraph +parakeet +paralegal +paralyses +paralysis +paralyze +paramedic +parameter +paramount +parasail +parasite +parasitic +parcel +parched +parchment +pardon +parish +parka +parking +parkway +parlor +parmesan +parole +parrot +parsley +parsnip +partake +parted +parting +partition +partly +partner +partridge +party +passable +passably +passage +passcode +passenger +passerby +passing +passion +passive +passivism +passover +passport +password +pasta +pasted +pastel +pastime +pastor +pastrami +pasture +pasty +patchwork +patchy +paternal +paternity +path +patience +patient +patio +patriarch +patriot +patrol +patronage +patronize +pauper +pavement +paver +pavestone +pavilion +paving +pawing +payable +payback +paycheck +payday +payee +payer +paying +payment +payphone +payroll +pebble +pebbly +pecan +pectin +peculiar +peddling +pediatric +pedicure +pedigree +pedometer +pegboard +pelican +pellet +pelt +pelvis +penalize +penalty +pencil +pendant +pending +penholder +penknife +pennant +penniless +penny +penpal +pension +pentagon +pentagram +pep +perceive +percent +perch +percolate +perennial +perfected +perfectly +perfume +periscope +perish +perjurer +perjury +perkiness +perky +perm +peroxide +perpetual +perplexed +persecute +persevere +persuaded +persuader +pesky +peso +pessimism +pessimist +pester +pesticide +petal +petite +petition +petri +petroleum +petted +petticoat +pettiness +petty +petunia +phantom +phobia +phoenix +phonebook +phoney +phonics +phoniness +phony +phosphate +photo +phrase +phrasing +placard +placate +placidly +plank +planner +plant +plasma +plaster +plastic +plated +platform +plating +platinum +platonic +platter +platypus +plausible +plausibly +playable +playback +player +playful +playgroup +playhouse +playing +playlist +playmaker +playmate +playoff +playpen +playroom +playset +plaything +playtime +plaza +pleading +pleat +pledge +plentiful +plenty +plethora +plexiglas +pliable +plod +plop +plot +plow +ploy +pluck +plug +plunder +plunging +plural +plus +plutonium +plywood +poach +pod +poem +poet +pogo +pointed +pointer +pointing +pointless +pointy +poise +poison +poker +poking +polar +police +policy +polio +polish +politely +polka +polo +polyester +polygon +polygraph +polymer +poncho +pond +pony +popcorn +pope +poplar +popper +poppy +popsicle +populace +popular +populate +porcupine +pork +porous +porridge +portable +portal +portfolio +porthole +portion +portly +portside +poser +posh +posing +possible +possibly +possum +postage +postal +postbox +postcard +posted +poster +posting +postnasal +posture +postwar +pouch +pounce +pouncing +pound +pouring +pout +powdered +powdering +powdery +power +powwow +pox +praising +prance +prancing +pranker +prankish +prankster +prayer +praying +preacher +preaching +preachy +preamble +precinct +precise +precision +precook +precut +predator +predefine +predict +preface +prefix +preflight +preformed +pregame +pregnancy +pregnant +preheated +prelaunch +prelaw +prelude +premiere +premises +premium +prenatal +preoccupy +preorder +prepaid +prepay +preplan +preppy +preschool +prescribe +preseason +preset +preshow +president +presoak +press +presume +presuming +preteen +pretended +pretender +pretense +pretext +pretty +pretzel +prevail +prevalent +prevent +preview +previous +prewar +prewashed +prideful +pried +primal +primarily +primary +primate +primer +primp +princess +print +prior +prism +prison +prissy +pristine +privacy +private +privatize +prize +proactive +probable +probably +probation +probe +probing +probiotic +problem +procedure +process +proclaim +procreate +procurer +prodigal +prodigy +produce +product +profane +profanity +professed +professor +profile +profound +profusely +progeny +prognosis +program +progress +projector +prologue +prolonged +promenade +prominent +promoter +promotion +prompter +promptly +prone +prong +pronounce +pronto +proofing +proofread +proofs +propeller +properly +property +proponent +proposal +propose +props +prorate +protector +protegee +proton +prototype +protozoan +protract +protrude +proud +provable +proved +proven +provided +provider +providing +province +proving +provoke +provoking +provolone +prowess +prowler +prowling +proximity +proxy +prozac +prude +prudishly +prune +pruning +pry +psychic +public +publisher +pucker +pueblo +pug +pull +pulmonary +pulp +pulsate +pulse +pulverize +puma +pumice +pummel +punch +punctual +punctuate +punctured +pungent +punisher +punk +pupil +puppet +puppy +purchase +pureblood +purebred +purely +pureness +purgatory +purge +purging +purifier +purify +purist +puritan +purity +purple +purplish +purposely +purr +purse +pursuable +pursuant +pursuit +purveyor +pushcart +pushchair +pusher +pushiness +pushing +pushover +pushpin +pushup +pushy +putdown +putt +puzzle +puzzling +pyramid +pyromania +python +quack +quadrant +quail +quaintly +quake +quaking +qualified +qualifier +qualify +quality +qualm +quantum +quarrel +quarry +quartered +quarterly +quarters +quartet +quench +query +quicken +quickly +quickness +quicksand +quickstep +quiet +quill +quilt +quintet +quintuple +quirk +quit +quiver +quizzical +quotable +quotation +quote +rabid +race +racing +racism +rack +racoon +radar +radial +radiance +radiantly +radiated +radiation +radiator +radio +radish +raffle +raft +rage +ragged +raging +ragweed +raider +railcar +railing +railroad +railway +raisin +rake +raking +rally +ramble +rambling +ramp +ramrod +ranch +rancidity +random +ranged +ranger +ranging +ranked +ranking +ransack +ranting +rants +rare +rarity +rascal +rash +rasping +ravage +raven +ravine +raving +ravioli +ravishing +reabsorb +reach +reacquire +reaction +reactive +reactor +reaffirm +ream +reanalyze +reappear +reapply +reappoint +reapprove +rearrange +rearview +reason +reassign +reassure +reattach +reawake +rebalance +rebate +rebel +rebirth +reboot +reborn +rebound +rebuff +rebuild +rebuilt +reburial +rebuttal +recall +recant +recapture +recast +recede +recent +recess +recharger +recipient +recital +recite +reckless +reclaim +recliner +reclining +recluse +reclusive +recognize +recoil +recollect +recolor +reconcile +reconfirm +reconvene +recopy +record +recount +recoup +recovery +recreate +rectal +rectangle +rectified +rectify +recycled +recycler +recycling +reemerge +reenact +reenter +reentry +reexamine +referable +referee +reference +refill +refinance +refined +refinery +refining +refinish +reflected +reflector +reflex +reflux +refocus +refold +reforest +reformat +reformed +reformer +reformist +refract +refrain +refreeze +refresh +refried +refueling +refund +refurbish +refurnish +refusal +refuse +refusing +refutable +refute +regain +regalia +regally +reggae +regime +region +register +registrar +registry +regress +regretful +regroup +regular +regulate +regulator +rehab +reheat +rehire +rehydrate +reimburse +reissue +reiterate +rejoice +rejoicing +rejoin +rekindle +relapse +relapsing +relatable +related +relation +relative +relax +relay +relearn +release +relenting +reliable +reliably +reliance +reliant +relic +relieve +relieving +relight +relish +relive +reload +relocate +relock +reluctant +rely +remake +remark +remarry +rematch +remedial +remedy +remember +reminder +remindful +remission +remix +remnant +remodeler +remold +remorse +remote +removable +removal +removed +remover +removing +rename +renderer +rendering +rendition +renegade +renewable +renewably +renewal +renewed +renounce +renovate +renovator +rentable +rental +rented +renter +reoccupy +reoccur +reopen +reorder +repackage +repacking +repaint +repair +repave +repaying +repayment +repeal +repeated +repeater +repent +rephrase +replace +replay +replica +reply +reporter +repose +repossess +repost +repressed +reprimand +reprint +reprise +reproach +reprocess +reproduce +reprogram +reps +reptile +reptilian +repugnant +repulsion +repulsive +repurpose +reputable +reputably +request +require +requisite +reroute +rerun +resale +resample +rescuer +reseal +research +reselect +reseller +resemble +resend +resent +reset +reshape +reshoot +reshuffle +residence +residency +resident +residual +residue +resigned +resilient +resistant +resisting +resize +resolute +resolved +resonant +resonate +resort +resource +respect +resubmit +result +resume +resupply +resurface +resurrect +retail +retainer +retaining +retake +retaliate +retention +rethink +retinal +retired +retiree +retiring +retold +retool +retorted +retouch +retrace +retract +retrain +retread +retreat +retrial +retrieval +retriever +retry +return +retying +retype +reunion +reunite +reusable +reuse +reveal +reveler +revenge +revenue +reverb +revered +reverence +reverend +reversal +reverse +reversing +reversion +revert +revisable +revise +revision +revisit +revivable +revival +reviver +reviving +revocable +revoke +revolt +revolver +revolving +reward +rewash +rewind +rewire +reword +rework +rewrap +rewrite +rhyme +ribbon +ribcage +rice +riches +richly +richness +rickety +ricotta +riddance +ridden +ride +riding +rifling +rift +rigging +rigid +rigor +rimless +rimmed +rind +rink +rinse +rinsing +riot +ripcord +ripeness +ripening +ripping +ripple +rippling +riptide +rise +rising +risk +risotto +ritalin +ritzy +rival +riverbank +riverbed +riverboat +riverside +riveter +riveting +roamer +roaming +roast +robbing +robe +robin +robotics +robust +rockband +rocker +rocket +rockfish +rockiness +rocking +rocklike +rockslide +rockstar +rocky +rogue +roman +romp +rope +roping +roster +rosy +rotten +rotting +rotunda +roulette +rounding +roundish +roundness +roundup +roundworm +routine +routing +rover +roving +royal +rubbed +rubber +rubbing +rubble +rubdown +ruby +ruckus +rudder +rug +ruined +rule +rumble +rumbling +rummage +rumor +runaround +rundown +runner +running +runny +runt +runway +rupture +rural +ruse +rush +rust +rut +sabbath +sabotage +sacrament +sacred +sacrifice +sadden +saddlebag +saddled +saddling +sadly +sadness +safari +safeguard +safehouse +safely +safeness +saffron +saga +sage +sagging +saggy +said +saint +sake +salad +salami +salaried +salary +saline +salon +saloon +salsa +salt +salutary +salute +salvage +salvaging +salvation +same +sample +sampling +sanction +sanctity +sanctuary +sandal +sandbag +sandbank +sandbar +sandblast +sandbox +sanded +sandfish +sanding +sandlot +sandpaper +sandpit +sandstone +sandstorm +sandworm +sandy +sanitary +sanitizer +sank +santa +sapling +sappiness +sappy +sarcasm +sarcastic +sardine +sash +sasquatch +sassy +satchel +satiable +satin +satirical +satisfied +satisfy +saturate +saturday +sauciness +saucy +sauna +savage +savanna +saved +savings +savior +savor +saxophone +say +scabbed +scabby +scalded +scalding +scale +scaling +scallion +scallop +scalping +scam +scandal +scanner +scanning +scant +scapegoat +scarce +scarcity +scarecrow +scared +scarf +scarily +scariness +scarring +scary +scavenger +scenic +schedule +schematic +scheme +scheming +schilling +schnapps +scholar +science +scientist +scion +scoff +scolding +scone +scoop +scooter +scope +scorch +scorebook +scorecard +scored +scoreless +scorer +scoring +scorn +scorpion +scotch +scoundrel +scoured +scouring +scouting +scouts +scowling +scrabble +scraggly +scrambled +scrambler +scrap +scratch +scrawny +screen +scribble +scribe +scribing +scrimmage +script +scroll +scrooge +scrounger +scrubbed +scrubber +scruffy +scrunch +scrutiny +scuba +scuff +sculptor +sculpture +scurvy +scuttle +secluded +secluding +seclusion +second +secrecy +secret +sectional +sector +secular +securely +security +sedan +sedate +sedation +sedative +sediment +seduce +seducing +segment +seismic +seizing +seldom +selected +selection +selective +selector +self +seltzer +semantic +semester +semicolon +semifinal +seminar +semisoft +semisweet +senate +senator +send +senior +senorita +sensation +sensitive +sensitize +sensually +sensuous +sepia +september +septic +septum +sequel +sequence +sequester +series +sermon +serotonin +serpent +serrated +serve +service +serving +sesame +sessions +setback +setting +settle +settling +setup +sevenfold +seventeen +seventh +seventy +severity +shabby +shack +shaded +shadily +shadiness +shading +shadow +shady +shaft +shakable +shakily +shakiness +shaking +shaky +shale +shallot +shallow +shame +shampoo +shamrock +shank +shanty +shape +shaping +share +sharpener +sharper +sharpie +sharply +sharpness +shawl +sheath +shed +sheep +sheet +shelf +shell +shelter +shelve +shelving +sherry +shield +shifter +shifting +shiftless +shifty +shimmer +shimmy +shindig +shine +shingle +shininess +shining +shiny +ship +shirt +shivering +shock +shone +shoplift +shopper +shopping +shoptalk +shore +shortage +shortcake +shortcut +shorten +shorter +shorthand +shortlist +shortly +shortness +shorts +shortwave +shorty +shout +shove +showbiz +showcase +showdown +shower +showgirl +showing +showman +shown +showoff +showpiece +showplace +showroom +showy +shrank +shrapnel +shredder +shredding +shrewdly +shriek +shrill +shrimp +shrine +shrink +shrivel +shrouded +shrubbery +shrubs +shrug +shrunk +shucking +shudder +shuffle +shuffling +shun +shush +shut +shy +siamese +siberian +sibling +siding +sierra +siesta +sift +sighing +silenced +silencer +silent +silica +silicon +silk +silliness +silly +silo +silt +silver +similarly +simile +simmering +simple +simplify +simply +sincere +sincerity +singer +singing +single +singular +sinister +sinless +sinner +sinuous +sip +siren +sister +sitcom +sitter +sitting +situated +situation +sixfold +sixteen +sixth +sixties +sixtieth +sixtyfold +sizable +sizably +size +sizing +sizzle +sizzling +skater +skating +skedaddle +skeletal +skeleton +skeptic +sketch +skewed +skewer +skid +skied +skier +skies +skiing +skilled +skillet +skillful +skimmed +skimmer +skimming +skimpily +skincare +skinhead +skinless +skinning +skinny +skintight +skipper +skipping +skirmish +skirt +skittle +skydiver +skylight +skyline +skype +skyrocket +skyward +slab +slacked +slacker +slacking +slackness +slacks +slain +slam +slander +slang +slapping +slapstick +slashed +slashing +slate +slather +slaw +sled +sleek +sleep +sleet +sleeve +slept +sliceable +sliced +slicer +slicing +slick +slider +slideshow +sliding +slighted +slighting +slightly +slimness +slimy +slinging +slingshot +slinky +slip +slit +sliver +slobbery +slogan +sloped +sloping +sloppily +sloppy +slot +slouching +slouchy +sludge +slug +slum +slurp +slush +sly +small +smartly +smartness +smasher +smashing +smashup +smell +smelting +smile +smilingly +smirk +smite +smith +smitten +smock +smog +smoked +smokeless +smokiness +smoking +smoky +smolder +smooth +smother +smudge +smudgy +smuggler +smuggling +smugly +smugness +snack +snagged +snaking +snap +snare +snarl +snazzy +sneak +sneer +sneeze +sneezing +snide +sniff +snippet +snipping +snitch +snooper +snooze +snore +snoring +snorkel +snort +snout +snowbird +snowboard +snowbound +snowcap +snowdrift +snowdrop +snowfall +snowfield +snowflake +snowiness +snowless +snowman +snowplow +snowshoe +snowstorm +snowsuit +snowy +snub +snuff +snuggle +snugly +snugness +speak +spearfish +spearhead +spearman +spearmint +species +specimen +specked +speckled +specks +spectacle +spectator +spectrum +speculate +speech +speed +spellbind +speller +spelling +spendable +spender +spending +spent +spew +sphere +spherical +sphinx +spider +spied +spiffy +spill +spilt +spinach +spinal +spindle +spinner +spinning +spinout +spinster +spiny +spiral +spirited +spiritism +spirits +spiritual +splashed +splashing +splashy +splatter +spleen +splendid +splendor +splice +splicing +splinter +splotchy +splurge +spoilage +spoiled +spoiler +spoiling +spoils +spoken +spokesman +sponge +spongy +sponsor +spoof +spookily +spooky +spool +spoon +spore +sporting +sports +sporty +spotless +spotlight +spotted +spotter +spotting +spotty +spousal +spouse +spout +sprain +sprang +sprawl +spray +spree +sprig +spring +sprinkled +sprinkler +sprint +sprite +sprout +spruce +sprung +spry +spud +spur +sputter +spyglass +squabble +squad +squall +squander +squash +squatted +squatter +squatting +squeak +squealer +squealing +squeamish +squeegee +squeeze +squeezing +squid +squiggle +squiggly +squint +squire +squirt +squishier +squishy +stability +stabilize +stable +stack +stadium +staff +stage +staging +stagnant +stagnate +stainable +stained +staining +stainless +stalemate +staleness +stalling +stallion +stamina +stammer +stamp +stand +stank +staple +stapling +starboard +starch +stardom +stardust +starfish +stargazer +staring +stark +starless +starlet +starlight +starlit +starring +starry +starship +starter +starting +startle +startling +startup +starved +starving +stash +state +static +statistic +statue +stature +status +statute +statutory +staunch +stays +steadfast +steadier +steadily +steadying +steam +steed +steep +steerable +steering +steersman +stegosaur +stellar +stem +stench +stencil +step +stereo +sterile +sterility +sterilize +sterling +sternness +sternum +stew +stick +stiffen +stiffly +stiffness +stifle +stifling +stillness +stilt +stimulant +stimulate +stimuli +stimulus +stinger +stingily +stinging +stingray +stingy +stinking +stinky +stipend +stipulate +stir +stitch +stock +stoic +stoke +stole +stomp +stonewall +stoneware +stonework +stoning +stony +stood +stooge +stool +stoop +stoplight +stoppable +stoppage +stopped +stopper +stopping +stopwatch +storable +storage +storeroom +storewide +storm +stout +stove +stowaway +stowing +straddle +straggler +strained +strainer +straining +strangely +stranger +strangle +strategic +strategy +stratus +straw +stray +streak +stream +street +strength +strenuous +strep +stress +stretch +strewn +stricken +strict +stride +strife +strike +striking +strive +striving +strobe +strode +stroller +strongbox +strongly +strongman +struck +structure +strudel +struggle +strum +strung +strut +stubbed +stubble +stubbly +stubborn +stucco +stuck +student +studied +studio +study +stuffed +stuffing +stuffy +stumble +stumbling +stump +stung +stunned +stunner +stunning +stunt +stupor +sturdily +sturdy +styling +stylishly +stylist +stylized +stylus +suave +subarctic +subatomic +subdivide +subdued +subduing +subfloor +subgroup +subheader +subject +sublease +sublet +sublevel +sublime +submarine +submerge +submersed +submitter +subpanel +subpar +subplot +subprime +subscribe +subscript +subsector +subside +subsiding +subsidize +subsidy +subsoil +subsonic +substance +subsystem +subtext +subtitle +subtly +subtotal +subtract +subtype +suburb +subway +subwoofer +subzero +succulent +such +suction +sudden +sudoku +suds +sufferer +suffering +suffice +suffix +suffocate +suffrage +sugar +suggest +suing +suitable +suitably +suitcase +suitor +sulfate +sulfide +sulfite +sulfur +sulk +sullen +sulphate +sulphuric +sultry +superbowl +superglue +superhero +superior +superjet +superman +supermom +supernova +supervise +supper +supplier +supply +support +supremacy +supreme +surcharge +surely +sureness +surface +surfacing +surfboard +surfer +surgery +surgical +surging +surname +surpass +surplus +surprise +surreal +surrender +surrogate +surround +survey +survival +survive +surviving +survivor +sushi +suspect +suspend +suspense +sustained +sustainer +swab +swaddling +swagger +swampland +swan +swapping +swarm +sway +swear +sweat +sweep +swell +swept +swerve +swifter +swiftly +swiftness +swimmable +swimmer +swimming +swimsuit +swimwear +swinger +swinging +swipe +swirl +switch +swivel +swizzle +swooned +swoop +swoosh +swore +sworn +swung +sycamore +sympathy +symphonic +symphony +symptom +synapse +syndrome +synergy +synopses +synopsis +synthesis +synthetic +syrup +system +tabasco +tabby +tableful +tables +tablet +tableware +tabloid +tackiness +tacking +tackle +tackling +tacky +taco +tactful +tactical +tactics +tactile +tactless +tadpole +taekwondo +tag +tainted +take +taking +talcum +talisman +tall +talon +tamale +tameness +tamer +tamper +tank +tanned +tannery +tanning +tantrum +tapeless +tapered +tapering +tapestry +tapioca +tapping +taps +tarantula +target +tarmac +tarnish +tarot +tartar +tartly +tartness +task +tassel +taste +tastiness +tasting +tasty +tattered +tattle +tattling +tattoo +taunt +tavern +thank +that +thaw +theater +theatrics +thee +theft +theme +theology +theorize +thermal +thermos +thesaurus +these +thesis +thespian +thicken +thicket +thickness +thieving +thievish +thigh +thimble +thing +think +thinly +thinner +thinness +thinning +thirstily +thirsting +thirsty +thirteen +thirty +thong +thorn +those +thousand +thrash +thread +threaten +threefold +thrift +thrill +thrive +thriving +throat +throbbing +throng +throttle +throwaway +throwback +thrower +throwing +thud +thumb +thumping +thursday +thus +thwarting +thyself +tiara +tibia +tidal +tidbit +tidiness +tidings +tidy +tiger +tighten +tightly +tightness +tightrope +tightwad +tigress +tile +tiling +till +tilt +timid +timing +timothy +tinderbox +tinfoil +tingle +tingling +tingly +tinker +tinkling +tinsel +tinsmith +tint +tinwork +tiny +tipoff +tipped +tipper +tipping +tiptoeing +tiptop +tiring +tissue +trace +tracing +track +traction +tractor +trade +trading +tradition +traffic +tragedy +trailing +trailside +train +traitor +trance +tranquil +transfer +transform +translate +transpire +transport +transpose +trapdoor +trapeze +trapezoid +trapped +trapper +trapping +traps +trash +travel +traverse +travesty +tray +treachery +treading +treadmill +treason +treat +treble +tree +trekker +tremble +trembling +tremor +trench +trend +trespass +triage +trial +triangle +tribesman +tribunal +tribune +tributary +tribute +triceps +trickery +trickily +tricking +trickle +trickster +tricky +tricolor +tricycle +trident +tried +trifle +trifocals +trillion +trilogy +trimester +trimmer +trimming +trimness +trinity +trio +tripod +tripping +triumph +trivial +trodden +trolling +trombone +trophy +tropical +tropics +trouble +troubling +trough +trousers +trout +trowel +truce +truck +truffle +trump +trunks +trustable +trustee +trustful +trusting +trustless +truth +try +tubby +tubeless +tubular +tucking +tuesday +tug +tuition +tulip +tumble +tumbling +tummy +turban +turbine +turbofan +turbojet +turbulent +turf +turkey +turmoil +turret +turtle +tusk +tutor +tutu +tux +tweak +tweed +tweet +tweezers +twelve +twentieth +twenty +twerp +twice +twiddle +twiddling +twig +twilight +twine +twins +twirl +twistable +twisted +twister +twisting +twisty +twitch +twitter +tycoon +tying +tyke +udder +ultimate +ultimatum +ultra +umbilical +umbrella +umpire +unabashed +unable +unadorned +unadvised +unafraid +unaired +unaligned +unaltered +unarmored +unashamed +unaudited +unawake +unaware +unbaked +unbalance +unbeaten +unbend +unbent +unbiased +unbitten +unblended +unblessed +unblock +unbolted +unbounded +unboxed +unbraided +unbridle +unbroken +unbuckled +unbundle +unburned +unbutton +uncanny +uncapped +uncaring +uncertain +unchain +unchanged +uncharted +uncheck +uncivil +unclad +unclaimed +unclamped +unclasp +uncle +unclip +uncloak +unclog +unclothed +uncoated +uncoiled +uncolored +uncombed +uncommon +uncooked +uncork +uncorrupt +uncounted +uncouple +uncouth +uncover +uncross +uncrown +uncrushed +uncured +uncurious +uncurled +uncut +undamaged +undated +undaunted +undead +undecided +undefined +underage +underarm +undercoat +undercook +undercut +underdog +underdone +underfed +underfeed +underfoot +undergo +undergrad +underhand +underline +underling +undermine +undermost +underpaid +underpass +underpay +underrate +undertake +undertone +undertook +undertow +underuse +underwear +underwent +underwire +undesired +undiluted +undivided +undocked +undoing +undone +undrafted +undress +undrilled +undusted +undying +unearned +unearth +unease +uneasily +uneasy +uneatable +uneaten +unedited +unelected +unending +unengaged +unenvied +unequal +unethical +uneven +unexpired +unexposed +unfailing +unfair +unfasten +unfazed +unfeeling +unfiled +unfilled +unfitted +unfitting +unfixable +unfixed +unflawed +unfocused +unfold +unfounded +unframed +unfreeze +unfrosted +unfrozen +unfunded +unglazed +ungloved +unglue +ungodly +ungraded +ungreased +unguarded +unguided +unhappily +unhappy +unharmed +unhealthy +unheard +unhearing +unheated +unhelpful +unhidden +unhinge +unhitched +unholy +unhook +unicorn +unicycle +unified +unifier +uniformed +uniformly +unify +unimpeded +uninjured +uninstall +uninsured +uninvited +union +uniquely +unisexual +unison +unissued +unit +universal +universe +unjustly +unkempt +unkind +unknotted +unknowing +unknown +unlaced +unlatch +unlawful +unleaded +unlearned +unleash +unless +unleveled +unlighted +unlikable +unlimited +unlined +unlinked +unlisted +unlit +unlivable +unloaded +unloader +unlocked +unlocking +unlovable +unloved +unlovely +unloving +unluckily +unlucky +unmade +unmanaged +unmanned +unmapped +unmarked +unmasked +unmasking +unmatched +unmindful +unmixable +unmixed +unmolded +unmoral +unmovable +unmoved +unmoving +unnamable +unnamed +unnatural +unneeded +unnerve +unnerving +unnoticed +unopened +unopposed +unpack +unpadded +unpaid +unpainted +unpaired +unpaved +unpeeled +unpicked +unpiloted +unpinned +unplanned +unplanted +unpleased +unpledged +unplowed +unplug +unpopular +unproven +unquote +unranked +unrated +unraveled +unreached +unread +unreal +unreeling +unrefined +unrelated +unrented +unrest +unretired +unrevised +unrigged +unripe +unrivaled +unroasted +unrobed +unroll +unruffled +unruly +unrushed +unsaddle +unsafe +unsaid +unsalted +unsaved +unsavory +unscathed +unscented +unscrew +unsealed +unseated +unsecured +unseeing +unseemly +unseen +unselect +unselfish +unsent +unsettled +unshackle +unshaken +unshaved +unshaven +unsheathe +unshipped +unsightly +unsigned +unskilled +unsliced +unsmooth +unsnap +unsocial +unsoiled +unsold +unsolved +unsorted +unspoiled +unspoken +unstable +unstaffed +unstamped +unsteady +unsterile +unstirred +unstitch +unstopped +unstuck +unstuffed +unstylish +unsubtle +unsubtly +unsuited +unsure +unsworn +untagged +untainted +untaken +untamed +untangled +untapped +untaxed +unthawed +unthread +untidy +untie +until +untimed +untimely +untitled +untoasted +untold +untouched +untracked +untrained +untreated +untried +untrimmed +untrue +untruth +unturned +untwist +untying +unusable +unused +unusual +unvalued +unvaried +unvarying +unveiled +unveiling +unvented +unviable +unvisited +unvocal +unwanted +unwarlike +unwary +unwashed +unwatched +unweave +unwed +unwelcome +unwell +unwieldy +unwilling +unwind +unwired +unwitting +unwomanly +unworldly +unworn +unworried +unworthy +unwound +unwoven +unwrapped +unwritten +unzip +upbeat +upchuck +upcoming +upcountry +update +upfront +upgrade +upheaval +upheld +uphill +uphold +uplifted +uplifting +upload +upon +upper +upright +uprising +upriver +uproar +uproot +upscale +upside +upstage +upstairs +upstart +upstate +upstream +upstroke +upswing +uptake +uptight +uptown +upturned +upward +upwind +uranium +urban +urchin +urethane +urgency +urgent +urging +urologist +urology +usable +usage +useable +used +uselessly +user +usher +usual +utensil +utility +utilize +utmost +utopia +utter +vacancy +vacant +vacate +vacation +vagabond +vagrancy +vagrantly +vaguely +vagueness +valiant +valid +valium +valley +valuables +value +vanilla +vanish +vanity +vanquish +vantage +vaporizer +variable +variably +varied +variety +various +varmint +varnish +varsity +varying +vascular +vaseline +vastly +vastness +veal +vegan +veggie +vehicular +velcro +velocity +velvet +vendetta +vending +vendor +veneering +vengeful +venomous +ventricle +venture +venue +venus +verbalize +verbally +verbose +verdict +verify +verse +version +versus +vertebrae +vertical +vertigo +very +vessel +vest +veteran +veto +vexingly +viability +viable +vibes +vice +vicinity +victory +video +viewable +viewer +viewing +viewless +viewpoint +vigorous +village +villain +vindicate +vineyard +vintage +violate +violation +violator +violet +violin +viper +viral +virtual +virtuous +virus +visa +viscosity +viscous +viselike +visible +visibly +vision +visiting +visitor +visor +vista +vitality +vitalize +vitally +vitamins +vivacious +vividly +vividness +vixen +vocalist +vocalize +vocally +vocation +voice +voicing +void +volatile +volley +voltage +volumes +voter +voting +voucher +vowed +vowel +voyage +wackiness +wad +wafer +waffle +waged +wager +wages +waggle +wagon +wake +waking +walk +walmart +walnut +walrus +waltz +wand +wannabe +wanted +wanting +wasabi +washable +washbasin +washboard +washbowl +washcloth +washday +washed +washer +washhouse +washing +washout +washroom +washstand +washtub +wasp +wasting +watch +water +waviness +waving +wavy +whacking +whacky +wham +wharf +wheat +whenever +whiff +whimsical +whinny +whiny +whisking +whoever +whole +whomever +whoopee +whooping +whoops +why +wick +widely +widen +widget +widow +width +wieldable +wielder +wife +wifi +wikipedia +wildcard +wildcat +wilder +wildfire +wildfowl +wildland +wildlife +wildly +wildness +willed +willfully +willing +willow +willpower +wilt +wimp +wince +wincing +wind +wing +winking +winner +winnings +winter +wipe +wired +wireless +wiring +wiry +wisdom +wise +wish +wisplike +wispy +wistful +wizard +wobble +wobbling +wobbly +wok +wolf +wolverine +womanhood +womankind +womanless +womanlike +womanly +womb +woof +wooing +wool +woozy +word +work +worried +worrier +worrisome +worry +worsening +worshiper +worst +wound +woven +wow +wrangle +wrath +wreath +wreckage +wrecker +wrecking +wrench +wriggle +wriggly +wrinkle +wrinkly +wrist +writing +written +wrongdoer +wronged +wrongful +wrongly +wrongness +wrought +xbox +xerox +yahoo +yam +yanking +yapping +yard +yarn +yeah +yearbook +yearling +yearly +yearning +yeast +yelling +yelp +yen +yesterday +yiddish +yield +yin +yippee +yoga +yogurt +yonder +yoyo +yummy +zap +zealous +zebra +zen +zeppelin +zero +zestfully +zesty +zigzagged +zipfile +zipping +zippy +zips +zit +zodiac +zombie +zone +zoning +zookeeper +zoologist +zoology +zoom From 6830fe41f6c2f0a06d01b582efc1b581b91399e8 Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:48:01 +0100 Subject: [PATCH 2/9] docs: change volarisapp to volar-is --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb7064d..df503c2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Volaris -![GitHub License](https://img.shields.io/github/license/volarisapp/Volaris) ![GitHub Issues](https://img.shields.io/github/issues/volarisapp/Volaris) ![GitHub Stars](https://img.shields.io/github/stars/volarisapp/Volaris) +![GitHub License](https://img.shields.io/github/license/volar-is/Volaris) ![GitHub Issues](https://img.shields.io/github/issues/volar-is/Volaris) ![GitHub Stars](https://img.shields.io/github/stars/volar-is/Volaris) ## Introduction From da1662a2b6e97ca5523872d4349a2bb6d11188ae Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:56:09 +0100 Subject: [PATCH 3/9] ci: create rust auditing --- .github/workflow/Audit.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflow/Audit.yml diff --git a/.github/workflow/Audit.yml b/.github/workflow/Audit.yml new file mode 100644 index 0000000..b76865d --- /dev/null +++ b/.github/workflow/Audit.yml @@ -0,0 +1,16 @@ +# A routine check to see if there are any Rust-specific security vulnerabilities +# in the repo we should be aware of. + +name: audit +on: + workflow_dispatch: + schedule: + - cron: "0 0 * * 1" # every Monday +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/audit-check@v1.2.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} From 3878c5e3a7a0aa3d57e933e20733358adc3ad71c Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:59:39 +0100 Subject: [PATCH 4/9] fix: delete workflow folder --- .github/workflow/Audit.yml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .github/workflow/Audit.yml diff --git a/.github/workflow/Audit.yml b/.github/workflow/Audit.yml deleted file mode 100644 index b76865d..0000000 --- a/.github/workflow/Audit.yml +++ /dev/null @@ -1,16 +0,0 @@ -# A routine check to see if there are any Rust-specific security vulnerabilities -# in the repo we should be aware of. - -name: audit -on: - workflow_dispatch: - schedule: - - cron: "0 0 * * 1" # every Monday -jobs: - audit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions-rs/audit-check@v1.2.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} From 70ae059dc25faa9f686b632ceba2d9b8f3e53108 Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:00:20 +0100 Subject: [PATCH 5/9] fix: fix audit.yml --- .github/workflows/audit.yml | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index f0e1b52..9db8958 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -1,27 +1,16 @@ -name: "Audit Dependencies" +# A routine check to see if there are any Rust-specific security vulnerabilities +# in the repo we should be aware of. + +name: audit on: - push: - paths: - # Run if workflow changes - - '.github/workflows/audit.yml' - # Run on changed dependencies - - '**/Cargo.toml' - - '**/Cargo.lock' - # Run if the configuration file changes - - '**/audit.toml' - # Rerun periodicly to pick up new advisories - schedule: - - cron: '0 0 * * *' - # Run manually workflow_dispatch: - + schedule: + - cron: "0 0 * * 1" # every Monday jobs: audit: runs-on: ubuntu-latest - permissions: - contents: read - issues: write steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/audit@v1 - name: Audit Rust Dependencies + - uses: actions/checkout@v3 + - uses: actions-rs/audit-check@v1.2.0 + with: + token: ${{ secrets.TOKEN }} From f0357de1277e71fbee37ab42967e2800ff247f3f Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:03:51 +0100 Subject: [PATCH 6/9] fix: audit.yml fix, again --- .github/workflows/audit.yml | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 9db8958..84e22d0 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -1,16 +1,29 @@ -# A routine check to see if there are any Rust-specific security vulnerabilities -# in the repo we should be aware of. - -name: audit +name: "Audit Dependencies" on: - workflow_dispatch: + push: + paths: + # Run if workflow changes + - '.github/workflows/audit.yml' + # Run on changed dependencies + - '**/Cargo.toml' + - '**/Cargo.lock' + # Run if the configuration file changes + - '**/audit.toml' + # Rerun periodicly to pick up new advisories schedule: - - cron: "0 0 * * 1" # every Monday + - cron: '0 0 * * *' + # Run manually + workflow_dispatch: + jobs: audit: runs-on: ubuntu-latest + permissions: + contents: read + issues: write steps: - - uses: actions/checkout@v3 - - uses: actions-rs/audit-check@v1.2.0 + - uses: actions/checkout@v4 + - uses: actions-rust-lang/audit@v1 + name: Audit Rust Dependencies with: token: ${{ secrets.TOKEN }} From 7ac470808871d03fd1a49835ae0d1e70eace817f Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:06:40 +0100 Subject: [PATCH 7/9] chore: change volarisapp to volar-is --- crates/volaris-core/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/volaris-core/README.md b/crates/volaris-core/README.md index 55b35a5..725a0a2 100644 --- a/crates/volaris-core/README.md +++ b/crates/volaris-core/README.md @@ -16,12 +16,12 @@ own risk ## Who uses volaris-Core? -This library is implemented by [volaris](https://github.com/volarisapp/volaris), a +This library is implemented by [volaris](https://github.com/volar-is/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)). +[open a Github issue](https://github.com/volar-is/volaris/issues)). ## Features @@ -79,7 +79,7 @@ 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/)! +[in the project's main documentation](https://github.com/volar-is/volaris/)! ## Thank you! From 9a0dff3fc9a4275f95132eef49c53c129b9dafb2 Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:07:02 +0100 Subject: [PATCH 8/9] chore: change volarisapp to volar-is --- crates/volaris-core/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/volaris-core/src/lib.rs b/crates/volaris-core/src/lib.rs index c8e761f..f60fba7 100644 --- a/crates/volaris-core/src/lib.rs +++ b/crates/volaris-core/src/lib.rs @@ -12,12 +12,12 @@ //! //! ## Who uses Volaris-Core? //! -//! This library is implemented by [Volaris](https://github.com/volarisapp/Volaris), a secure multi-interface file +//! This library is implemented by [Volaris](https://github.com/volar-is/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)). +//! 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/volar-is/Volaris/issues)). //! -//! You can read more about Volaris, Volaris-Core and the technical details [in the project's main documentation](https://github.com/volarisapp/volaris/readme.md)! +//! You can read more about Volaris, Volaris-Core and the technical details [in the project's main documentation](https://github.com/volar-is/volaris/readme.md)! //! //! ## Thank you! //! From 160a0588a664f5a557a18d5eb2a19c11f488234b Mon Sep 17 00:00:00 2001 From: leo <77177015+greendoescode@users.noreply.github.com> Date: Mon, 24 Jun 2024 22:48:38 +0100 Subject: [PATCH 9/9] docs: update to include security info --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index df503c2..fe4734b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,13 @@ Volaris is an encryption tool designed to prioritize privacy and security. Built - **Rust-Based Security**: Leveraging Rust’s safety and performance features. - **Modern Encryption Standards**: Uses the latest encryption algorithms to ensure data security. +## Security + +Volaris uses modern cryptographic AEADs (XChaCha20-Poly1305 + AES-256-GCM), +with audited backends to ensure the safety and integrity of +your data. It's extremely easy to use Volaris before uploading your files to a +cloud service, to ensure that no prying eyes can read them. + ## Current Status Volaris is currently in development. We are working hard to bring you a secure and user-friendly encryption tool. Stay tuned for updates and releases.