14#include <jau/debug.hpp>
20using namespace jau::fractions_i64_literals;
41 jau::PLAIN_PRINT(
true,
"CL::Error[%d]: %s, %s",
count_error.load(), msg.c_str(), header.to_string(
true,
true).c_str());
49 jau::PLAIN_PRINT(
true,
"CL::Header[%d]: %s",
count_header.load(), header.to_string(
true,
true).c_str());
54 bool notifyProgress(
const bool decrypt_mode,
const uint64_t plaintext_size,
const uint64_t bytes_processed)
noexcept override {
58 (void)bytes_processed;
67 jau::PLAIN_PRINT(
true,
"CL::End[%d]: %s",
count_end.load(), header.to_string(
true,
true).c_str());
84 std::string
toString() const noexcept
override {
100 std::string bname = jau::fs::basename(progname);
101 fprintf(stderr,
"Usage %s pack [-epk <enc-pub-key>]+ -ssk <sign-sec-key> [-sskp <sign-sec-key-passphrase>]? "
102 "[-target_path <target-path-filename>]? [-subject <string>]? [-version <file-version-str>]? [-version_parent <file-version-parent-str>]? "
103 "[-hash <plaintext-hash-algo>]? [-hashout <plaintext-hash-outfile>]? [-verbose]? [-out <output-filename>]? [<input-source>]?\n", bname.c_str());
104 fprintf(stderr,
"Usage %s unpack [-spk <sign-pub-key>]+ -dsk <dec-sec-key> [-dskp <dec-sec-key-passphrase>]? "
105 "[-hash <plaintext-hash-algo>]? [-hashout <plaintext-hash-outfile>]? [-verbose]? [-out <output-filename>]? [<input-source>]?\n", bname.c_str());
106 fprintf(stderr,
"Usage %s hash [-hash <hash-algo>]? [-verbose]? [-out <output-filename>]? [<input-source>]?\n", bname.c_str());
107 fprintf(stderr,
"Usage %s hashcheck [-verbose]? [<input-hash-signatures-file>]?\n", bname.c_str());
129int main(
int argc,
char *argv[])
133 fprintf(stderr,
"Called '%s' with %d arguments:\n", (argc>0?argv[0]:
"exe"), argc-1);
134 for(
int i=1; i<argc; i++) {
135 fprintf(stderr,
"[%d] '%s'\n", i, argv[i]);
137 fprintf(stderr,
"\n");
145 const std::string command = argv[argi++];
147 if( command ==
"pack") {
148 std::vector<std::string> enc_pub_keys;
149 std::string sign_sec_key_fname;
150 jau::io::secure_string sign_sec_key_passphrase;
151 std::string target_path;
153 std::string plaintext_version =
"0";
154 std::string plaintext_version_parent =
"0";
156 std::string plaintext_fname_output;
157 bool verbose =
false;
158 std::string fname_output = jau::fs::to_named_fd(1);
159 std::string fname_input = jau::fs::to_named_fd(0);
160 for(; argi < argc; ++argi) {
161 if( 0 == strcmp(
"-epk", argv[argi]) && argi + 1 < argc ) {
162 enc_pub_keys.emplace_back(argv[++argi] );
163 }
else if( 0 == strcmp(
"-ssk", argv[argi]) && argi + 1 < argc ) {
164 sign_sec_key_fname = argv[++argi];
165 }
else if( 0 == strcmp(
"-sskp", argv[argi]) && argi + 1 < argc ) {
166 char* argv_pp = argv[++argi];
167 size_t pp_len = strlen(argv_pp);
168 sign_sec_key_passphrase = jau::io::secure_string(argv_pp, pp_len);
169 ::explicit_bzero(argv_pp, pp_len);
170 }
else if( 0 == strcmp(
"-target_path", argv[argi]) && argi + 1 < argc ) {
171 target_path = argv[++argi];
172 }
else if( 0 == strcmp(
"-subject", argv[argi]) && argi + 1 < argc ) {
173 subject = argv[++argi];
174 }
else if( 0 == strcmp(
"-version", argv[argi]) && argi + 1 < argc ) {
175 plaintext_version = argv[++argi];
176 }
else if( 0 == strcmp(
"-version_parent", argv[argi]) && argi + 1 < argc ) {
177 plaintext_version_parent = argv[++argi];
178 }
else if( 0 == strcmp(
"-hash", argv[argi]) && argi + 1 < argc ) {
179 plaintext_hash_algo = argv[++argi];
180 }
else if( 0 == strcmp(
"-hashout", argv[argi]) && argi + 1 < argc ) {
181 plaintext_fname_output = argv[++argi];
182 }
else if( 0 == strcmp(
"-out", argv[argi]) && argi + 1 < argc ) {
183 fname_output = argv[++argi];
184 }
else if( 0 == strcmp(
"-verbose", argv[argi]) ) {
187 }
else if( argi == argc - 1 ) {
188 fname_input = argv[argi];
191 if( target_path.empty() ) {
192 target_path = fname_input;
194 if( 0 == enc_pub_keys.size() ||
195 sign_sec_key_fname.empty() )
197 jau::PLAIN_PRINT(
true,
"Pack: Error: Arguments incomplete");
202 std::unique_ptr<jau::io::ByteInStream> input = jau::io::to_ByteInStream(fname_input);
203 if(
nullptr == input ) {
204 jau::PLAIN_PRINT(
true,
"Pack: Error: source '%s' failed to open", fname_input.c_str());
209 enc_pub_keys, sign_sec_key_fname, sign_sec_key_passphrase,
210 *input, target_path, subject,
211 plaintext_version, plaintext_version_parent,
213 plaintext_hash_algo, fname_output);
214 if( !plaintext_fname_output.empty() ) {
218 jau::PLAIN_PRINT(
true,
"Pack: Encrypted %s to %s", fname_input.c_str(), fname_output.c_str());
219 jau::PLAIN_PRINT(
true,
"Pack: %s", ph.
to_string(
true,
true).c_str());
220 jau::PLAIN_PRINT(
true,
"Pack: %s", cpl->toString().c_str());
224 if( command ==
"unpack") {
225 std::vector<std::string> sign_pub_keys;
226 std::string dec_sec_key_fname;
227 jau::io::secure_string dec_sec_key_passphrase;
229 std::string plaintext_fname_output;
230 bool verbose =
false;
231 std::string fname_output = jau::fs::to_named_fd(1);
232 std::string fname_input = jau::fs::to_named_fd(0);
233 for(; argi < argc; ++argi) {
234 if( 0 == strcmp(
"-spk", argv[argi]) && argi + 1 < argc ) {
235 sign_pub_keys.emplace_back(argv[++argi] );
236 }
else if( 0 == strcmp(
"-dsk", argv[argi]) && argi + 1 < argc ) {
237 dec_sec_key_fname = argv[++argi];
238 }
else if( 0 == strcmp(
"-dskp", argv[argi]) && argi + 1 < argc ) {
239 char* argv_pp = argv[++argi];
240 size_t pp_len = strlen(argv_pp);
241 dec_sec_key_passphrase = jau::io::secure_string(argv_pp, pp_len);
242 ::explicit_bzero(argv_pp, pp_len);
243 }
else if( 0 == strcmp(
"-hash", argv[argi]) && argi + 1 < argc ) {
244 plaintext_hash_algo = argv[++argi];
245 }
else if( 0 == strcmp(
"-hashout", argv[argi]) && argi + 1 < argc ) {
246 plaintext_fname_output = argv[++argi];
247 }
else if( 0 == strcmp(
"-out", argv[argi]) && argi + 1 < argc ) {
248 fname_output = argv[++argi];
249 }
else if( 0 == strcmp(
"-verbose", argv[argi]) ) {
252 }
else if( argi == argc - 1 ) {
253 fname_input = argv[argi];
256 if( 0 == sign_pub_keys.size() ||
257 dec_sec_key_fname.empty() )
259 jau::PLAIN_PRINT(
true,
"Unpack: Error: Arguments incomplete");
264 std::unique_ptr<jau::io::ByteInStream> input = jau::io::to_ByteInStream(fname_input);
265 if(
nullptr == input ) {
266 jau::PLAIN_PRINT(
true,
"Unpack: Error: source '%s' failed to open", fname_input.c_str());
273 plaintext_hash_algo, fname_output);
274 if( !plaintext_fname_output.empty() ) {
279 jau::PLAIN_PRINT(
true,
"Unpack: Decypted %s to %s", fname_input.c_str(), fname_output.c_str());
280 jau::PLAIN_PRINT(
true,
"Unpack: %s", ph.
to_string(
true,
true).c_str());
281 jau::PLAIN_PRINT(
true,
"Unpack: %s", cpl->toString().c_str());
285 if( command ==
"hash") {
287 bool verbose =
false;
288 std::string fname_output = jau::fs::to_named_fd(1);
289 std::string fname_input = jau::fs::to_named_fd(0);
290 for(; argi < argc; ++argi) {
291 if( 0 == strcmp(
"-hash", argv[argi]) && argi + 1 < argc ) {
292 hash_algo = argv[++argi];
293 }
else if( 0 == strcmp(
"-out", argv[argi]) && argi + 1 < argc ) {
294 fname_output = argv[++argi];
295 }
else if( 0 == strcmp(
"-verbose", argv[argi]) ) {
298 }
else if( argi == argc - 1 ) {
299 fname_input = argv[argi];
302 uint64_t bytes_hashed = 0;
304 if(
nullptr != hash ) {
305 std::string hash_str = jau::bytesHexString(hash->data(), 0, hash->size(),
true ,
true );
308 jau::PLAIN_PRINT(
true,
"Hash: algo '%s', bytes %s, '%s' of '%s'", hash_algo.c_str(), jau::to_decstring(bytes_hashed).c_str(),
309 hash_str.c_str(), fname_input.c_str());
315 if( command ==
"hashcheck") {
316 bool verbose =
false;
317 std::string fname_input =
"/dev/stdin";
318 for(; argi < argc; ++argi) {
319 if( 0 == strcmp(
"-verbose", argv[argi]) ) {
322 }
else if( argi == argc - 1 ) {
323 fname_input = argv[argi];
326 std::ifstream in(fname_input, std::ios::in | std::ios::binary);
328 jau::PLAIN_PRINT(
true,
"HashCheck: Error: Couldn't open file '%s'", fname_input.c_str());
332 std::string hash_line0;
333 while( std::getline(in, hash_line0) ) {
335 std::string hash_algo;
336 std::string hash_value1;
337 std::string hashed_file;
338 char* haystack =
const_cast<char*
>( hash_line0.data() );
340 char* p = std::strstr(haystack,
" ");
342 jau::PLAIN_PRINT(
true,
"HashCheck: Error: %s:%d: No separator to hash value found", fname_input.c_str(), line_no);
346 hash_algo = std::string(haystack);
350 char* p = std::strstr(haystack,
" *");
352 jau::PLAIN_PRINT(
true,
"HashCheck: Error: %s:%d: No separator to hashed file found", fname_input.c_str(), line_no);
356 hash_value1 = std::string(haystack);
359 hashed_file = std::string(haystack);
361 jau::fs::file_stats hashed_file_stats(hashed_file);
362 if( hashed_file_stats.has_fd() ) {
363 jau::PLAIN_PRINT(
true,
"HashCheck: Ignored: %s:%d: Named file descriptor: %s",
364 fname_input.c_str(), line_no, hashed_file_stats.to_string().c_str());
368 const std::string hash_line1 = hash_algo+
" "+hash_value1+
" *"+hashed_file;
369 uint64_t bytes_hashed = 0;
371 if(
nullptr == hash2 ) {
372 jau::PLAIN_PRINT(
true,
"HashCheck: Error: %s:%d: Bad format: %s", fname_input.c_str(), line_no, hash_line1.c_str());
375 const std::string hash_value2 = jau::bytesHexString(hash2->data(), 0, hash2->size(),
true ,
true );
376 if( hash_value2 != hash_value1 ) {
377 const std::string hash_line2 = hash_algo+
" "+hash_value2+
" *"+hashed_file;
378 jau::PLAIN_PRINT(
true,
"HashCheck: Error: %s:%d: Hash value mismatch", fname_input.c_str(), line_no);
379 jau::PLAIN_PRINT(
true,
"- expected: %s", hash_line1.c_str());
380 jau::PLAIN_PRINT(
true,
"- produced: %s", hash_line2.c_str());
382 }
else if( verbose ) {
383 jau::PLAIN_PRINT(
true,
"HashCheck: OK: %s:%d: %s", fname_input.c_str(), line_no, hash_line1.c_str());
388 fprintf(stderr,
"Unknown command\n");
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.