From afc02e2253d88857f6b73c24b6d931aa6ad86219 Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Wed, 14 Feb 2018 16:12:53 +0100 Subject: [PATCH] Initial implementation for RustySecrets v0.1.0 --- .gitignore | 6 + .rustfmt.toml | 2 + .travis.yml | 21 ++ CHANGELOG.md | 10 + Cargo.lock | 666 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 47 +++ LICENSE | 29 ++ README.md | 108 ++++++ build.rs | 40 +++ src/cli.rs | 178 ++++++++++ src/cmds/mod.rs | 5 + src/cmds/recover.rs | 78 +++++ src/cmds/split.rs | 66 ++++ src/errors.rs | 68 ++++ src/input.rs | 38 +++ src/logger.rs | 45 +++ src/main.rs | 107 ++++++ src/version.rs | 5 + tests/resources/secret.txt | 2 + tests/tests.rs | 65 ++++ 20 files changed, 1586 insertions(+) create mode 100644 .gitignore create mode 100644 .rustfmt.toml create mode 100644 .travis.yml create mode 100644 CHANGELOG.md create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.rs create mode 100644 src/cli.rs create mode 100644 src/cmds/mod.rs create mode 100644 src/cmds/recover.rs create mode 100644 src/cmds/split.rs create mode 100644 src/errors.rs create mode 100644 src/input.rs create mode 100644 src/logger.rs create mode 100644 src/main.rs create mode 100644 src/version.rs create mode 100644 tests/resources/secret.txt create mode 100644 tests/tests.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f2e972d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..0173980 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,2 @@ +error_on_line_overflow = false +max_width = 120 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..29911d4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +language: rust + +os: + - linux + - osx + +rust: + - stable + - beta + - nightly + +cache: cargo + +before_cache: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r $HOME/.cargo + +matrix: + allow_failures: + - rust: nightly + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..981a12c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## [Unreleased](https://github.com/SpinResearch/rustysecrets-cli/compare/0.1.0...master) + +> Nothing yet. + +## [0.1.0](https://github.com/SpinResearch/rustysecrets-cli/releases/tag/0.1.0) - 2017-08-02 **(alpha release)** + +> First alpha release + diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6961beb --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,666 @@ +[[package]] +name = "ansi_term" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "atty" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cmake" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "coco" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "colored" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "error-chain" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "gcc" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "gdi32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "git-build-version" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "git2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "git2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lamport_sigs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libgit2-sys" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libressl-pnacl-sys" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pnacl-build-helper 1.4.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libz-sys" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "matches" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "merkle" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "merkle_sigs" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lamport_sigs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "merkle 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mime" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-sys" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pkg-config" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pnacl-build-helper" +version = "1.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "protobuf" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quick-error" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "remove_dir_all" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ring" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rusty_secrets" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "merkle_sigs 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustysecrets-cli" +version = "0.1.0-pre" +dependencies = [ + "clap 2.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "git-build-version 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rusty_secrets 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "safemem" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "tempdir" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicase" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "untrusted" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "user32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vcpkg" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" +"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859" +"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" +"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" +"checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4" +"checksum bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a6577517ecd0ee0934f48a7295a89aaef3e6dfafeac404f94c0b3448518ddfe" +"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" +"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" +"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0" +"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum clap 2.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c07b9257a00f3fc93b7f3c417fc15607ec7a56823bc2c37ec744e266387de5b" +"checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" +"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" +"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" +"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" +"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" +"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" +"checksum git-build-version 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b55fb1209e98deef256214972a0bff1341eaf6773390a9ebebb9276c3aef1e" +"checksum git2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "33a96eeef227403006cdb59ea6e05baad8cddde6b79abed753d96ccee136bad2" +"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lamport_sigs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5dff26ae558be16afda65815c847447c81eede19c639982e49e33bd15973d857" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" +"checksum libgit2-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f8d1217daf6e0812f78c3b81b987b94edc000e8f700aee456c6e7940f818b3e" +"checksum libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cbc058951ab6a3ef35ca16462d7642c4867e6403520811f28537a4e2f2db3e71" +"checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16" +"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" +"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum merkle 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6311caa1c5c71548021dfc5f6113fca485d453185fdc44da92bafe266f6a5fe" +"checksum merkle_sigs 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94367864019d3b781c28c67d0a7057da0df498525982869c47ecfd73ece29f26" +"checksum mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e00e17be181010a91dbfefb01660b17311059dc8c7f48b9017677721e732bd" +"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" +"checksum openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)" = "89c47ee94c352eea9ddaf8e364be7f978a3bb6d66d73176572484238dd5a5c3f" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum pnacl-build-helper 1.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dfbe13ee77c06fb633d71c72438bd983286bb3521863a753ade8e951c7efb090" +"checksum protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bec26e67194b7d991908145fdf21b7cae8b08423d96dcb9e860cd31f854b9506" +"checksum quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb6ccf8db7bbcb9c2eae558db5ab4f3da1c2a87e4e597ed394726bc8ea6ca1d" +"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" +"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" +"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" +"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d2f806b0fcdabd98acd380dc8daef485e22bcb7cddc811d1337967f2528cf5" +"checksum ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6f7d28b30a72c01b458428e0ae988d4149c20d902346902be881e3edc4bb325c" +"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" +"checksum rusty_secrets 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6bf3e7412367e6c177a5dcdcafc448e7b8d3c6d56d4d45aaa93a20fe192b3fb" +"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" +"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f73eebdb68c14bcb24aef74ea96079830e7fa7b31a6106e42ea7ee887c1e134e" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" +"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" +"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" +"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" +"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2" +"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" +"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" +"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" +"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" +"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4204099 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "rustysecrets-cli" +version = "0.1.0-pre" +authors = ["Romain Ruetschi "] + +description = "rustysecrets-cli is a command-line wrapper around RustySecrets, a Rust implementation of threshold Shamir's secret sharing" +license = "BSD-3-Clause" +readme = "README.md" +homepage = "https://github.com/SpinResearch/rustysecrets-cli" +documentation = "https://github.com/SpinResearch/rustysecrets-cli#readme" +repository = "https://github.com/SpinResearch/rustysecrets-cli" + +build = "build.rs" + +[[bin]] +name = "rustysecrets" +path = "src/main.rs" + +[dependencies] +rusty_secrets = "^0.1.0" +clap = "^2.26" +colored = "^1.5" +error-chain = "^0.11.0" +mime = "^0.3" +log = { version = "^0.4", features = ["std"] } + +[dev-dependencies] +tempdir = "^0.3" +colored = "^1.5" + +[build-dependencies] +clap = "^2.26" +mime = "^0.3" +git-build-version = "*" + +[profile.release] +lto = true + +[package.metadata.release] +sign-commit = true +upload-doc = false +pre-release-commit-message = "Release version {{version}}" +pro-release-commit-message = "Bump version to {{version}}" +tag-message = "Release version {{version}}" +tag-prefix = "v" +dev-version-ext = "pre" + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..887b1fa --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, Spin Research +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* 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. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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/README.md b/README.md new file mode 100644 index 0000000..6be4ffb --- /dev/null +++ b/README.md @@ -0,0 +1,108 @@ + +# RustySecrets CLI + +[![Build Status](https://travis-ci.org/SpinResearch/rustysecrets-cli.svg?branch=master&style=flat)](https://travis-ci.org/SpinResearch/rustysecrets-cli) +[![Crates.io](https://img.shields.io/crates/v/rustysecrets-cli.svg)](https://crates.io/crates/rustysecrets-cli) +[![license](https://img.shields.io/github/license/SpinResearch/rustysecrets-cli.svg)](License) + +> *rustysecrets-cli* is a command-line wrapper around [RustySecrets](https://github.com/SpinResearch/RustySecrets), a Rust implementation of threshold [Shamir's secret sharing](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing). + +## Installation + + $ cargo install rustysecrets-cli + +## Usage + +```bash +$ mkdir shares +$ cat > secret.txt +These programs were never about terrorism: they’re about economic spying, +social control, and diplomatic manipulation. They’re about power. +^D + +$ rustysecrets split secret.txt -o shares -k 7 -n 10 -m text/plain +$ ls shares/ +share_0 share_1 share_2 share_3 share_4 share_5 share_6 share_7 share_8 share_9 + +$ rustysecrets recover shares/share_{0-6} + info: Version: INITIAL_RELEASE + info: MIME-Type: text/plain +These programs were never about terrorism: they’re about economic spying, +social control, and diplomatic manipulation. They’re about power. + +$ rustysecrets recover shares/share_{0-2} + error: Could not recover secret +caused by: Not enough shares provided! +``` + +## Documentation + +### `rustysecrets` + +``` +USAGE: + rustysecrets + +OPTIONS: + -h, --help Prints help information + -V, --version Prints version information + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + recover Recover the secret from the shares [aliases: r] + split Split a secret into shares [aliases: s] +``` + +### `rustysecrets split` + +> Split a secret into shares + +``` +USAGE: + rustysecrets split [OPTIONS] --output -k -n + +OPTIONS: + -o, --output Path to the directory to output the shares to + -m, --mime The MIME type of the secret + -h, --help Prints help information + -k Number of shares necessary to recover the secret + -n Total number of generated shares + -r, --raw Include this flag to generate raw shares (ie. without a MIME type) + -t, --share-tmpl Template for the share names. Defaults to 'share_{{num}}' + -s, --sign Sign the shares + -v, --verbose Enable verbose mode + +ARGS: + Path to the file containing the secret to split, or - to read from stdin +``` + +### `rustysecrets recover` + +> Recover the secret from the shares + +``` +USAGE: + rustysecrets recover [OPTIONS] ... + +OPTIONS: + -o, --output Path to file to output the secret to, prints to stdout if omitted + -h, --help Prints help information + -r, --raw Include this flag if the shares are raw (ie. do not contain a MIME type) + -v, --verbose Enable verbose mode + --verify Verify the shares signatures + +ARGS: + ... Paths to shares to recover the secret from +``` + +## Bug Reporting + +Please report bugs either as pull requests or as issues in [the issue +tracker](https://github.com/SpinResearch/rustysecrets-cli). *rustysecrets-cli* has a +**full disclosure** vulnerability policy. **Please do NOT attempt to report +any security vulnerability in this code privately to anybody.** + +## License + +RustySecrets CLI is released under the BSD3 license. See [LICENSE](LICENSE) for more informations. + diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..b74debe --- /dev/null +++ b/build.rs @@ -0,0 +1,40 @@ + +extern crate git_build_version; +extern crate mime; +extern crate clap; + +use clap::Shell; + +use std::env; +use std::path::Path; +use std::fs; + +include!("src/cli.rs"); + +fn main() { + gen_completions(); + expose_git_describe(); +} + +fn gen_completions() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + let mut path_buf = Path::new(&out_dir).to_path_buf(); + path_buf.pop(); + path_buf.pop(); + path_buf.push("rustysecrets-completions"); + let path = path_buf.as_path(); + + if !path.exists() { + fs::create_dir(path).unwrap(); + } + + let mut app = build_cli(); + app.gen_completions("rustysecrets", Shell::Bash, &path); + app.gen_completions("rustysecrets", Shell::Zsh, &path); + app.gen_completions("rustysecrets", Shell::Fish, &path); + // app.gen_completions("rustysecrets", Shell::PowerShell, &outdir); +} + +fn expose_git_describe() { + git_build_version::write_version(".").expect("Saving git version"); +} diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..d333fcb --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,178 @@ +use clap::{App, AppSettings, Arg, SubCommand}; + +pub fn build_cli() -> App<'static, 'static> { + App::new("RustySecrets CLI") + .version("0.2-pre") + .author("SpinResearch") + .about("Split a secret of an arbitrary length in n different shares and k-out-of-n shares are required to recover it.") + .setting(AppSettings::SubcommandRequiredElseHelp) + .setting(AppSettings::VersionlessSubcommands) + .setting(AppSettings::ColoredHelp) + .setting(AppSettings::UnifiedHelpMessage) + .subcommand(SubCommand::with_name("split") + .about("Split a secret into shares") + .visible_alias("s") + .setting(AppSettings::ColoredHelp) + .setting(AppSettings::UnifiedHelpMessage) + .arg(Arg::with_name("verbose") + .short("v") + .long("verbose") + .help("Enable verbose mode")) + .arg(Arg::with_name("k") + .short("k") + .required(true) + .takes_value(true) + .validator(validators::num::strictly_positive) + .help("Number of shares necessary to recover the secret")) + .arg(Arg::with_name("n") + .short("n") + .required(true) + .takes_value(true) + .validator(validators::num::strictly_positive) + .help("Total number of generated shares")) + .arg(Arg::with_name("share-tmpl") + .short("t") + .long("share-tmpl") + .takes_value(true) + .validator(validators::rusty_secrets::share_tmpl) + .help("Template for the share names. Defaults to 'share_{{num}}'")) + .arg(Arg::with_name("DIR") + .short("o") + .long("output") + .required(true) + .takes_value(true) + .validator(validators::fs::directory) + .help("Path to the directory to output the shares to")) + .arg(Arg::with_name("MIME") + .short("m") + .long("mime") + .takes_value(true) + .validator(validators::mime_type) + .help("The MIME type of the secret")) + .arg(Arg::with_name("raw") + .short("r") + .long("raw") + .conflicts_with("MIME") + .help("Include this flag to generate raw shares (ie. without a MIME type)")) + .arg(Arg::with_name("sign") + .short("s") + .long("sign") + .help("Sign the shares")) + .arg(Arg::with_name("INPUT") + .required(true) + .validator(validators::fs::file_or_stdin) + .help("Path to the file containing the secret to split, or - to read from stdin"))) + .subcommand(SubCommand::with_name("recover") + .about("Recover the secret from the shares") + .visible_alias("r") + .setting(AppSettings::ColoredHelp) + .setting(AppSettings::UnifiedHelpMessage) + .arg(Arg::with_name("verbose") + .short("v") + .long("verbose") + .help("Enable verbose mode")) + .arg(Arg::with_name("SHARES") + .required(true) + .takes_value(true) + .multiple(true) + .validator(validators::fs::file) + .help("Paths to shares to recover the secret from")) + .arg(Arg::with_name("raw") + .short("r") + .long("raw") + .help("Include this flag if the shares are raw (ie. do not contain a MIME type)")) + .arg(Arg::with_name("verify") + .long("verify") + .help("Verify the shares signatures")) + .arg(Arg::with_name("FILE") + .short("o") + .long("output") + .takes_value(true) + .help("Path to file to output the secret to, prints to stdout if omitted"))) +} + +#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] +pub mod validators { + + pub mod rusty_secrets { + + pub fn share_tmpl(value: String) -> Result<(), String> { + if !value.contains("{{num}}") { + return Err("Invalid share template, must contain '{[num]}'".to_string()); + } + + Ok(()) + } + + } + + pub mod num { + + pub fn strictly_positive(value: String) -> Result<(), String> { + let n = value.parse::(); + + if n.is_err() { + return Err(format!("{} is not a positive number", value)); + } + + if n.unwrap() < 1 { + return Err(format!("{} is not strictly positive", value)); + } + + Ok(()) + } + + } + + pub fn mime_type(value: String) -> Result<(), String> { + use mime::Mime; + + if value.parse::().is_err() { + return Err(format!("{} is not a valid MIME type", value)); + } + + Ok(()) + } + + pub mod fs { + + use std::path::Path; + + pub fn file(value: String) -> Result<(), String> { + let path = Path::new(&value); + + if !path.exists() { + return Err(format!("'{}' does not exists", value)); + } + + if !path.is_file() { + return Err(format!("'{}' is not a file", value)); + } + + Ok(()) + } + + pub fn file_or_stdin(value: String) -> Result<(), String> { + if value == "-" { + return Ok(()); + } + + file(value) + } + + pub fn directory(value: String) -> Result<(), String> { + let path = Path::new(&value); + + if !path.exists() { + return Err(format!("'{}' does not exists", value)); + } + + if !path.is_dir() { + return Err(format!("'{}' is not a directory", value)); + } + + Ok(()) + } + + } +} diff --git a/src/cmds/mod.rs b/src/cmds/mod.rs new file mode 100644 index 0000000..4f85538 --- /dev/null +++ b/src/cmds/mod.rs @@ -0,0 +1,5 @@ +mod split; +mod recover; + +pub use self::split::split; +pub use self::recover::recover; diff --git a/src/cmds/recover.rs b/src/cmds/recover.rs new file mode 100644 index 0000000..110f9f8 --- /dev/null +++ b/src/cmds/recover.rs @@ -0,0 +1,78 @@ +use rusty_secrets::{sss, wrapped_secrets}; + +use errors::*; + +use std::path::Path; +use std::fs::File; +use std::io::{self, Read, Write}; + +pub fn recover(shares_paths: Vec<&Path>, output_path: Option<&Path>, verify_signatures: bool, raw: bool) -> Result<()> { + let mut shares = Vec::with_capacity(shares_paths.len()); + + for share_path in shares_paths { + if !share_path.exists() { + bail!(ErrorKind::ShareDoesNotExists(format!( + "{}", + share_path.display() + ),)) + } + if !share_path.is_file() { + bail!(ErrorKind::ShareIsNotAFile(format!( + "{}", + share_path.display() + ),)) + } + + debug!("Reading share {:?}... ", share_path); + + let mut share_file = + File::open(share_path).chain_err(|| ErrorKind::CannotOpenShare(format!("{}", share_path.display())))?; + + let mut share = String::new(); + let size = share_file + .read_to_string(&mut share) + .chain_err(|| ErrorKind::CannotReadShare(format!("{}", share_path.display())))?; + + debug!("Read {} bytes.", size); + + shares.push(share); + } + + debug!("Recovering secret... "); + + let secret = if raw { + sss::recover_secret(&shares, verify_signatures).chain_err(|| ErrorKind::CannotRecoverSecret)? + } else { + let mut res = + wrapped_secrets::recover_secret(&shares, verify_signatures).chain_err(|| ErrorKind::CannotRecoverSecret)?; + + debug!("Version: {:?}", res.get_version()); + + if res.get_mime_type() != "" { + debug!("MIME-Type: {}", res.get_mime_type()); + } + + res.take_secret() + }; + + match output_path { + Some(output_path) => { + let mut output_file = File::create(output_path) + .chain_err(|| ErrorKind::CannotCreateSecretFile(format!("{}", output_path.display())))?; + output_file + .write_all(&secret) + .chain_err(|| ErrorKind::CannotWriteSecretToFile(format!("{}", output_path.display())))?; + } + None => { + // See https://github.com/romac/rustysecrets-cli/issues/9 + // let secret_str = String::from_utf8(secret) + // .chain_err(|| "Could not parse secret as UTF-8, consider outputting it to a file instead")?; + + io::stdout() + .write_all(&secret) + .chain_err(|| ErrorKind::CannotWriteSecretToStdout)?; + } + } + + Ok(()) +} diff --git a/src/cmds/split.rs b/src/cmds/split.rs new file mode 100644 index 0000000..b8ba168 --- /dev/null +++ b/src/cmds/split.rs @@ -0,0 +1,66 @@ +use mime::Mime; +use rusty_secrets::{sss, wrapped_secrets}; + +use errors::*; +use input::Input; + +use std::path::Path; +use std::fs::File; +use std::io::{Read, Write}; + +#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] +pub fn split( + mut secret_input: Input, + output_path: &Path, + k: u8, + n: u8, + mime_type: Option, + sign_shares: bool, + raw: bool, + share_tmpl: &str, +) -> Result<()> { + if k > n { + bail!(ErrorKind::KMustBeSmallerThanN(k, n)) + } + + if raw && mime_type.is_some() { + bail!(ErrorKind::RawMimeConflict); + } + + debug!("Reading secret..."); + + let mut secret = Vec::new(); + let size = secret_input + .read_to_end(&mut secret) + .chain_err(|| ErrorKind::CannotReadSecret(secret_input))?; + + debug!("Read {} bytes.", size); + + debug!("Generating shares..."); + + let shares = if raw { + sss::split_secret(k, n, &secret, sign_shares) + } else { + let mime_type = mime_type.map(|m| m.as_ref().to_string()); + wrapped_secrets::split_secret(k, n, &secret, mime_type, sign_shares) + }.chain_err(|| "Could not generate shares")?; + + for (num, share) in shares.iter().enumerate() { + let mut path_buf = output_path.to_path_buf(); + path_buf.push(share_tmpl.replace("{{num}}", &format!("{}", num))); + let share_path = path_buf.as_path(); + + debug!("Writing share #{} to '{}'...", num, share_path.display()); + + let mut share_file = File::create(share_path) + .chain_err(|| ErrorKind::CannotCreateShareFile(format!("{}", share_path.display())))?; + + share_file + .write_all(share.as_bytes()) + .chain_err(|| ErrorKind::CannotWriteShareDataToFile(format!("{}", share_path.display())))?; + } + + info!("Wrote {} shares to '{}'", n, output_path.display()); + + Ok(()) +} diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..a748153 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,68 @@ +#![cfg_attr(feature = "cargo-clippy", allow(unused_doc_comment))] +#![allow(unknown_lints)] + +use input::Input; + +// Create the Error, ErrorKind, ResultExt, and Result types +error_chain! { + + errors { + KMustBeSmallerThanN(k: u8, n: u8) { + description("k must be smaller than or equal to n") + display("k must be smaller than or equal to n, got: k = {}, n = {}", k, n) + } + CannotReadSecret(input: Input) { + description("Cannot read secret") + display("Cannot read secret from '{}'", input) + } + CannotOpenSecretFile(path: String) { + description("cannot open secret file") + display("cannot open secret file '{}'", path) + } + CannotCreateShareFile(path: String) { + description("Cannot create share file") + display("Cannot create share file '{}'", path) + } + CannotWriteShareDataToFile(path: String) { + description("Cannot write share data to file") + display("Cannot write share data to '{}'", path) + } + ShareDoesNotExists(path: String) { + description("Share does not exists") + display("Share does not exists: '{}'", path) + } + ShareIsNotAFile(path: String) { + description("Given share is not a file") + display("Share is not a file: '{}'", path) + } + CannotOpenShare(path: String) { + description("Cannot open share") + display("Cannot open share at '{}'", path) + } + CannotReadShare(path: String) { + description("Cannot read share") + display("Cannot read share at '{}'", path) + } + CannotRecoverSecret { + description("Cannot recover secret") + display("Cannot recover secret") + } + CannotCreateSecretFile(path: String) { + description("Cannot write share data to file") + display("Cannot create secret file '{}'", path) + } + CannotWriteSecretToFile(path: String) { + description("Cannot write secret to file") + display("Cannot write secret to '{}'", path) + } + CannotWriteSecretToStdout { + description("Cannot write secret to stdout") + display("Cannot write secret to stdout") + } + RawMimeConflict { + description("Cannot set a MIME type with raw shares") + display("Cannot set a MIME type with raw shares") + } + } + +} diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..b6a35dd --- /dev/null +++ b/src/input.rs @@ -0,0 +1,38 @@ +// Adapted from +// https://gist.github.com/ayosec/2ee0993247e003b42c5c + +use std::{fmt, fs, io}; + +#[derive(Debug)] +pub enum Input { + Standard(io::Stdin), + File(fs::File, String), +} + +impl Input { + pub fn stdin() -> Input { + Input::Standard(io::stdin()) + } + + pub fn file(path: String) -> io::Result { + Ok(Input::File(try!(fs::File::open(path.clone())), path)) + } +} + +impl io::Read for Input { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match *self { + Input::Standard(ref mut s) => s.read(buf), + Input::File(ref mut f, _) => f.read(buf), + } + } +} + +impl fmt::Display for Input { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Input::Standard(_) => write!(f, ""), + Input::File(_, ref path) => write!(f, "{}", path), + } + } +} diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..a6aad2c --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,45 @@ +use log::{Level, Log, Metadata, Record}; +use colored::*; + +pub struct ColoredTermLogger { + level: Level, + #[allow(dead_code)] + colored: bool, +} + +impl ColoredTermLogger { + pub fn new(level: Level, colored: bool) -> Self { + ColoredTermLogger { level, colored } + } + + pub fn with_level(level: Level) -> Self { + Self::new(level, !cfg!(windows)) + } +} + +impl Default for ColoredTermLogger { + fn default() -> Self { + Self::with_level(Level::Warn) + } +} + +impl Log for ColoredTermLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= self.level + } + + // TODO: Disable colors if colored == false + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + match record.level() { + Level::Trace => eprintln!("{} {}", "debug:".white().bold(), record.args()), + Level::Debug => eprintln!("{} {}", "info:".blue().bold(), record.args()), + Level::Info => eprintln!("{} {}", "success:".green().bold(), record.args()), + Level::Warn => eprintln!("{} {}", "warn:".yellow().bold(), record.args()), + Level::Error => eprintln!("{} {}", "error:".red().bold(), record.args()), + } + } + } + + fn flush(&self) {} +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..46e2d69 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,107 @@ +// `error_chain` recursion adjustment +#![recursion_limit = "1024"] +// Make rustc's built-in lints more strict +#![warn(warnings)] + +extern crate colored; +use colored::*; + +extern crate clap; + +#[macro_use] +extern crate error_chain; + +#[macro_use] +extern crate log; +extern crate mime; +extern crate rusty_secrets; + +mod errors; +use errors::*; + +mod input; +use input::Input; + +mod cli; +mod cmds; +mod version; +mod logger; +use logger::ColoredTermLogger; + +use log::{Level, LevelFilter}; +use std::path::Path; + +fn main() { + if let Err(ref e) = run() { + error!("{}", e); + + for e in e.iter().skip(1) { + error!("{} {}", "reason:".yellow().bold(), e); + } + + if let Some(backtrace) = e.backtrace() { + error!("{} {:?}", "backtrace:".blue().bold(), backtrace); + } + + ::std::process::exit(1); + } +} + +fn run() -> Result<()> { + let app = cli::build_cli().version(version::get()); + let matches = app.get_matches(); + + let verbose = matches + .subcommand_matches("split") + .or_else(|| matches.subcommand_matches("recover")) + .map(|matches| matches.is_present("verbose")) + .unwrap_or(false); + + let level = if verbose { Level::Debug } else { Level::Info }; + let logger = ColoredTermLogger::with_level(level); + + log::set_max_level(LevelFilter::Debug); + log::set_boxed_logger(Box::new(logger)).unwrap(); + + if let Some(matches) = matches.subcommand_matches("split") { + let secret_arg = matches.value_of("INPUT").unwrap(); + let secret_input = if secret_arg == "-" { + Input::stdin() + } else { + Input::file(secret_arg.to_string()).chain_err(|| ErrorKind::CannotOpenSecretFile(secret_arg.to_string()))? + }; + + let output_path = Path::new(matches.value_of("DIR").unwrap()); + let k = matches.value_of("k").unwrap().parse::().unwrap(); + let n = matches.value_of("n").unwrap().parse::().unwrap(); + let mime_type = matches.value_of("MIME").map(|v| v.parse().unwrap()); + let sign_shares = matches.is_present("sign"); + let raw = matches.is_present("raw"); + let share_tmpl = matches.value_of("share-tmpl").unwrap_or("share_{{num}}"); + + cmds::split( + secret_input, + output_path, + k, + n, + mime_type, + sign_shares, + raw, + share_tmpl, + )? + } else if let Some(matches) = matches.subcommand_matches("recover") { + let shares = matches + .values_of("SHARES") + .unwrap() + .map(Path::new) + .collect(); + + let output_path = matches.value_of("FILE").map(Path::new); + let verify_signatures = matches.is_present("verify"); + let raw = matches.is_present("raw"); + + cmds::recover(shares, output_path, verify_signatures, raw)? + } + + Ok(()) +} diff --git a/src/version.rs b/src/version.rs new file mode 100644 index 0000000..ecf0b7f --- /dev/null +++ b/src/version.rs @@ -0,0 +1,5 @@ +include!(concat!(env!("OUT_DIR"), "/version.rs")); + +pub(crate) fn get() -> &'static str { + VERSION +} diff --git a/tests/resources/secret.txt b/tests/resources/secret.txt new file mode 100644 index 0000000..c17b2ef --- /dev/null +++ b/tests/resources/secret.txt @@ -0,0 +1,2 @@ +These programs were never about terrorism: they’re about economic spying, +social control, and diplomatic manipulation. They’re about power. diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..15a50e1 --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,65 @@ +extern crate colored; +use colored::*; + +extern crate tempdir; +use tempdir::TempDir; + +use std::str; +use std::process::Command; + +#[test] +fn raw() { + run(&["--raw"]); +} + +#[test] +fn wrapped() { + run(&[]); +} + +fn run(raw: &[&str]) { + let secret_path = "tests/resources/secret.txt"; + let secret = include_str!("resources/secret.txt"); + let n = 10; + let k = 7; + + let tmp = TempDir::new("rustysecrets").unwrap(); + + let output_path = tmp.path().to_string_lossy().as_ref().to_string(); + + let split_out = Command::new("target/debug/rustysecrets") + .arg("split") + .arg(secret_path) + .args(raw) + .args(&["-o", &output_path]) + .args(&["-k", &k.to_string()]) + .args(&["-n", &n.to_string()]) + .output() + .unwrap(); + + assert_eq!(str::from_utf8(&split_out.stdout).unwrap(), ""); + + assert_eq!( + str::from_utf8(&split_out.stderr).unwrap(), + &format!( + "{} Wrote {} shares to '{}'\n", + "success:".green().bold(), + n, + output_path + ) + ); + + let shares = (0..7) + .map(|i| format!("{}/share_{}", output_path, i)) + .collect::>(); + + let recover_out = Command::new("target/debug/rustysecrets") + .arg("recover") + .args(raw) + .args(&shares) + .output() + .unwrap(); + + assert_eq!(str::from_utf8(&recover_out.stdout).unwrap(), secret); + assert_eq!(str::from_utf8(&recover_out.stderr).unwrap(), ""); +}