cipherpack command line tool.
#include <iostream>
#include <fstream>
#include <cassert>
#include <cinttypes>
#include <cstring>
#include <jau/debug.hpp>
extern "C" {
#include <unistd.h>
}
using namespace jau::fractions_i64_literals;
private:
bool verbose;
public:
: verbose(verbose_),
{}
(void)decrypt_mode;
jau::PLAIN_PRINT(
true,
"CL::Error[%d]: %s, %s",
count_error.load(), msg.c_str(), header.to_string(
true,
true).c_str());
}
(void)decrypt_mode;
(void)header;
if( verbose ) {
jau::PLAIN_PRINT(
true,
"CL::Header[%d]: %s",
count_header.load(), header.to_string(
true,
true).c_str());
}
return true;
}
bool notifyProgress(
const bool decrypt_mode,
const uint64_t plaintext_size,
const uint64_t bytes_processed)
noexcept override {
(void)decrypt_mode;
(void)plaintext_size;
(void)bytes_processed;
return true;
}
(void)decrypt_mode;
(void)header;
if( verbose ) {
jau::PLAIN_PRINT(
true,
"CL::End[%d]: %s",
count_end.load(), header.to_string(
true,
true).c_str());
}
}
bool getSendContent(
const bool decrypt_mode)
const noexcept override {
(void)decrypt_mode;
return false;
}
(void)decrypt_mode;
(void)ctype;
(void)data;
(void)is_final;
return true;
}
std::string
toString() const noexcept
override {
}
};
}
std::string bname = jau::fs::basename(progname);
fprintf(stderr, "Usage %s pack [-epk <enc-pub-key>]+ -ssk <sign-sec-key> [-sskp <sign-sec-key-passphrase>]? "
"[-target_path <target-path-filename>]? [-subject <string>]? [-version <file-version-str>]? [-version_parent <file-version-parent-str>]? "
"[-hash <plaintext-hash-algo>]? [-hashout <plaintext-hash-outfile>]? [-verbose]? [-out <output-filename>]? [<input-source>]?\n", bname.c_str());
fprintf(stderr, "Usage %s unpack [-spk <sign-pub-key>]+ -dsk <dec-sec-key> [-dskp <dec-sec-key-passphrase>]? "
"[-hash <plaintext-hash-algo>]? [-hashout <plaintext-hash-outfile>]? [-verbose]? [-out <output-filename>]? [<input-source>]?\n", bname.c_str());
fprintf(stderr, "Usage %s hash [-hash <hash-algo>]? [-verbose]? [-out <output-filename>]? [<input-source>]?\n", bname.c_str());
fprintf(stderr, "Usage %s hashcheck [-verbose]? [<input-hash-signatures-file>]?\n", bname.c_str());
}
int main(
int argc,
char *argv[])
{
#if 0
fprintf(stderr, "Called '%s' with %d arguments:\n", (argc>0?argv[0]:"exe"), argc-1);
for(int i=1; i<argc; i++) {
fprintf(stderr, "[%d] '%s'\n", i, argv[i]);
}
fprintf(stderr, "\n");
#endif
int argi = 1;
if( argi >= argc ) {
return -1;
}
const std::string command = argv[argi++];
if( command == "pack") {
std::vector<std::string> enc_pub_keys;
std::string sign_sec_key_fname;
jau::io::secure_string sign_sec_key_passphrase;
std::string target_path;
std::string subject;
std::string plaintext_version = "0";
std::string plaintext_version_parent = "0";
std::string plaintext_fname_output;
bool verbose = false;
std::string fname_output = jau::fs::to_named_fd(1);
std::string fname_input = jau::fs::to_named_fd(0);
for(; argi < argc; ++argi) {
if( 0 == strcmp("-epk", argv[argi]) && argi + 1 < argc ) {
enc_pub_keys.emplace_back(argv[++argi] );
} else if( 0 == strcmp("-ssk", argv[argi]) && argi + 1 < argc ) {
sign_sec_key_fname = argv[++argi];
} else if( 0 == strcmp("-sskp", argv[argi]) && argi + 1 < argc ) {
char* argv_pp = argv[++argi];
size_t pp_len = strlen(argv_pp);
sign_sec_key_passphrase = jau::io::secure_string(argv_pp, pp_len);
::explicit_bzero(argv_pp, pp_len);
} else if( 0 == strcmp("-target_path", argv[argi]) && argi + 1 < argc ) {
target_path = argv[++argi];
} else if( 0 == strcmp("-subject", argv[argi]) && argi + 1 < argc ) {
subject = argv[++argi];
} else if( 0 == strcmp("-version", argv[argi]) && argi + 1 < argc ) {
plaintext_version = argv[++argi];
} else if( 0 == strcmp("-version_parent", argv[argi]) && argi + 1 < argc ) {
plaintext_version_parent = argv[++argi];
} else if( 0 == strcmp("-hash", argv[argi]) && argi + 1 < argc ) {
plaintext_hash_algo = argv[++argi];
} else if( 0 == strcmp("-hashout", argv[argi]) && argi + 1 < argc ) {
plaintext_fname_output = argv[++argi];
} else if( 0 == strcmp("-out", argv[argi]) && argi + 1 < argc ) {
fname_output = argv[++argi];
} else if( 0 == strcmp("-verbose", argv[argi]) ) {
verbose = true;
} else if( argi == argc - 1 ) {
fname_input = argv[argi];
}
}
if( target_path.empty() ) {
target_path = fname_input;
}
if( 0 == enc_pub_keys.size() ||
sign_sec_key_fname.empty() )
{
jau::PLAIN_PRINT(true, "Pack: Error: Arguments incomplete");
return -1;
}
std::unique_ptr<jau::io::ByteInStream> input = jau::io::to_ByteInStream(fname_input);
if( nullptr == input ) {
jau::PLAIN_PRINT(true, "Pack: Error: source '%s' failed to open", fname_input.c_str());
return -1;
}
enc_pub_keys, sign_sec_key_fname, sign_sec_key_passphrase,
*input, target_path, subject,
plaintext_version, plaintext_version_parent,
cpl,
plaintext_hash_algo, fname_output);
if( !plaintext_fname_output.empty() ) {
}
if( verbose ) {
jau::PLAIN_PRINT(true, "Pack: Encrypted %s to %s", fname_input.c_str(), fname_output.c_str());
jau::PLAIN_PRINT(
true,
"Pack: %s", ph.
to_string(
true,
true).c_str());
jau::PLAIN_PRINT(true, "Pack: %s", cpl->toString().c_str());
}
}
if( command == "unpack") {
std::vector<std::string> sign_pub_keys;
std::string dec_sec_key_fname;
jau::io::secure_string dec_sec_key_passphrase;
std::string plaintext_fname_output;
bool verbose = false;
std::string fname_output = jau::fs::to_named_fd(1);
std::string fname_input = jau::fs::to_named_fd(0);
for(; argi < argc; ++argi) {
if( 0 == strcmp("-spk", argv[argi]) && argi + 1 < argc ) {
sign_pub_keys.emplace_back(argv[++argi] );
} else if( 0 == strcmp("-dsk", argv[argi]) && argi + 1 < argc ) {
dec_sec_key_fname = argv[++argi];
} else if( 0 == strcmp("-dskp", argv[argi]) && argi + 1 < argc ) {
char* argv_pp = argv[++argi];
size_t pp_len = strlen(argv_pp);
dec_sec_key_passphrase = jau::io::secure_string(argv_pp, pp_len);
::explicit_bzero(argv_pp, pp_len);
} else if( 0 == strcmp("-hash", argv[argi]) && argi + 1 < argc ) {
plaintext_hash_algo = argv[++argi];
} else if( 0 == strcmp("-hashout", argv[argi]) && argi + 1 < argc ) {
plaintext_fname_output = argv[++argi];
} else if( 0 == strcmp("-out", argv[argi]) && argi + 1 < argc ) {
fname_output = argv[++argi];
} else if( 0 == strcmp("-verbose", argv[argi]) ) {
verbose = true;
} else if( argi == argc - 1 ) {
fname_input = argv[argi];
}
}
if( 0 == sign_pub_keys.size() ||
dec_sec_key_fname.empty() )
{
jau::PLAIN_PRINT(true, "Unpack: Error: Arguments incomplete");
return -1;
}
std::unique_ptr<jau::io::ByteInStream> input = jau::io::to_ByteInStream(fname_input);
if( nullptr == input ) {
jau::PLAIN_PRINT(true, "Unpack: Error: source '%s' failed to open", fname_input.c_str());
return -1;
}
*input,
cpl,
plaintext_hash_algo, fname_output);
if( !plaintext_fname_output.empty() ) {
}
if( verbose ) {
jau::PLAIN_PRINT(true, "Unpack: Decypted %s to %s", fname_input.c_str(), fname_output.c_str());
jau::PLAIN_PRINT(
true,
"Unpack: %s", ph.
to_string(
true,
true).c_str());
jau::PLAIN_PRINT(true, "Unpack: %s", cpl->toString().c_str());
}
}
if( command == "hash") {
bool verbose = false;
std::string fname_output = jau::fs::to_named_fd(1);
std::string fname_input = jau::fs::to_named_fd(0);
for(; argi < argc; ++argi) {
if( 0 == strcmp("-hash", argv[argi]) && argi + 1 < argc ) {
hash_algo = argv[++argi];
} else if( 0 == strcmp("-out", argv[argi]) && argi + 1 < argc ) {
fname_output = argv[++argi];
} else if( 0 == strcmp("-verbose", argv[argi]) ) {
verbose = true;
} else if( argi == argc - 1 ) {
fname_input = argv[argi];
}
}
uint64_t bytes_hashed = 0;
if( nullptr != hash ) {
std::string hash_str = jau::bytesHexString(hash->data(), 0, hash->size(), true , true );
if( verbose ) {
jau::PLAIN_PRINT(true, "Hash: algo '%s', bytes %s, '%s' of '%s'", hash_algo.c_str(), jau::to_decstring(bytes_hashed).c_str(),
hash_str.c_str(), fname_input.c_str());
}
return 0;
}
return -1;
}
if( command == "hashcheck") {
bool verbose = false;
std::string fname_input = "/dev/stdin";
for(; argi < argc; ++argi) {
if( 0 == strcmp("-verbose", argv[argi]) ) {
verbose = true;
} else if( argi == argc - 1 ) {
fname_input = argv[argi];
}
}
std::ifstream in(fname_input, std::ios::in | std::ios::binary);
if( in.bad() ) {
jau::PLAIN_PRINT(true, "HashCheck: Error: Couldn't open file '%s'", fname_input.c_str());
return -1;
}
int line_no = 0;
std::string hash_line0;
while( std::getline(in, hash_line0) ) {
++line_no;
std::string hash_algo;
std::string hash_value1;
std::string hashed_file;
char* haystack = const_cast<char*>( hash_line0.data() );
{
char* p = std::strstr(haystack, " ");
if( nullptr == p ) {
jau::PLAIN_PRINT(true, "HashCheck: Error: %s:%d: No separator to hash value found", fname_input.c_str(), line_no);
return -1;
}
*p = 0;
hash_algo = std::string(haystack);
haystack = p + 1;
}
{
char* p = std::strstr(haystack, " *");
if( nullptr == p ) {
jau::PLAIN_PRINT(true, "HashCheck: Error: %s:%d: No separator to hashed file found", fname_input.c_str(), line_no);
return -1;
}
*p = 0;
hash_value1 = std::string(haystack);
haystack = p + 2;
}
hashed_file = std::string(haystack);
{
jau::fs::file_stats hashed_file_stats(hashed_file);
if( hashed_file_stats.has_fd() ) {
jau::PLAIN_PRINT(true, "HashCheck: Ignored: %s:%d: Named file descriptor: %s",
fname_input.c_str(), line_no, hashed_file_stats.to_string().c_str());
continue;
}
}
const std::string hash_line1 = hash_algo+" "+hash_value1+" *"+hashed_file;
uint64_t bytes_hashed = 0;
if( nullptr == hash2 ) {
jau::PLAIN_PRINT(true, "HashCheck: Error: %s:%d: Bad format: %s", fname_input.c_str(), line_no, hash_line1.c_str());
return -1;
}
const std::string hash_value2 = jau::bytesHexString(hash2->data(), 0, hash2->size(), true , true );
if( hash_value2 != hash_value1 ) {
const std::string hash_line2 = hash_algo+" "+hash_value2+" *"+hashed_file;
jau::PLAIN_PRINT(true, "HashCheck: Error: %s:%d: Hash value mismatch", fname_input.c_str(), line_no);
jau::PLAIN_PRINT(true,"- expected: %s", hash_line1.c_str());
jau::PLAIN_PRINT(true,"- produced: %s", hash_line2.c_str());
return -1;
} else if( verbose ) {
jau::PLAIN_PRINT(true, "HashCheck: OK: %s:%d: %s", fname_input.c_str(), line_no, hash_line1.c_str());
}
}
return 0;
}
fprintf(stderr, "Unknown command\n");
return -1;
}
void notifyError(const bool decrypt_mode, const cipherpack::PackHeader &header, const std::string &msg) noexcept override
User notification about an error via text message and preliminary PackHeader.
bool notifyHeader(const bool decrypt_mode, const cipherpack::PackHeader &header) noexcept override
User notification of preliminary PackHeader w/o optional hash of the plaintext message.
std::string toString() const noexcept override
jau::relaxed_atomic_int count_header
jau::relaxed_atomic_int count_progress
jau::relaxed_atomic_int count_end
bool notifyProgress(const bool decrypt_mode, const uint64_t plaintext_size, const uint64_t bytes_processed) noexcept override
User notification about content streaming progress.
jau::relaxed_atomic_int count_error
void notifyEnd(const bool decrypt_mode, const cipherpack::PackHeader &header) noexcept override
User notification of successful completion.
LoggingCipherpackListener(const bool verbose_) noexcept
jau::relaxed_atomic_uint64 count_content
bool contentProcessed(const bool decrypt_mode, const content_type ctype, cipherpack::secure_vector< uint8_t > &data, const bool is_final) noexcept override
User callback to receive the actual processed content, either the generated cipherpack or plaintext c...
bool getSendContent(const bool decrypt_mode) const noexcept override
User provided information whether process shall send the processed content via contentProcessed() or ...
Listener for events occurring while processing a cipherpack message via encryptThenSign() and checkSi...
static environment & get() noexcept
int main(int argc, char *argv[])
cipherpack command line tool.
std::shared_ptr< LoggingCipherpackListener > LoggingCipherpackListenerRef
static void print_version()
static void print_usage(const char *progname)
static std::string to_string(const std::vector< uint8_t > &v)
std::vector< T, Botan::secure_allocator< T > > secure_vector
PackHeader encryptThenSign(const CryptoConfig &crypto_cfg, const std::vector< std::string > &enc_pub_keys, const std::string &sign_sec_key_fname, const jau::io::secure_string &passphrase, jau::io::ByteInStream &source, const std::string &target_path, const std::string &subject, const std::string &plaintext_version, const std::string &plaintext_version_parent, CipherpackListenerRef listener, const std::string_view &plaintext_hash_algo, const std::string destination_fname="")
Encrypt then sign the source producing a cipherpack stream passed to the CipherpackListener if opt-in...
std::string_view default_hash_algo() noexcept
Name of default hash algo for the plaintext message, e.g.
PackHeader checkSignThenDecrypt(const std::vector< std::string > &sign_pub_keys, const std::string &dec_sec_key_fname, const jau::io::secure_string &passphrase, jau::io::ByteInStream &source, CipherpackListenerRef listener, const std::string_view &plaintext_hash_algo, const std::string destination_fname="")
Verify signature then decrypt the source passing to the CipherpackListener if opt-in and also optiona...
std::unique_ptr< std::vector< uint8_t > > calc(const std::string_view &algo, jau::io::ByteInStream &source) noexcept
Return the calculated hash value using given algo name and byte input stream.
bool append_to_file(const std::string &out_file, const std::string &hashed_file, const std::string_view &hash_algo, const std::vector< uint8_t > &hash_value) noexcept
Append the hash signature to the text file out_file.
static CryptoConfig getDefault() noexcept
Returns default CryptoConfig.