Cipherpack v1.2.0-dirty
A Cryprographic Stream Processor
crypto0.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021 Gothel Software e.K.
4 * Copyright (c) 2021 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
27
28#ifdef USE_LIBCURL
29 #include <curl/curl.h>
30#endif
31
32#include <jau/cpuid.hpp>
33#include <jau/os/os_support.hpp>
34
35#include <jau/debug.hpp>
36
37namespace Botan {
38 class CPUID final {
39 public:
40 static bool has_simd_32();
41
42 /**
43 * Return a possibly empty string containing list of known CPU
44 * extensions. Each name will be seperated by a space, and the ordering
45 * will be arbitrary. This list only contains values that are useful to
46 * Botan (for example FMA instructions are not checked).
47 *
48 * Example outputs "sse2 ssse3 rdtsc", "neon arm_aes", "altivec"
49 */
50 static std::string to_string();
51 };
52}
53
54using namespace cipherpack;
55
56static std::string cp_query_hash_provider(const std::string& algo) noexcept {
57 std::unique_ptr<Botan::HashFunction> hash_func = Botan::HashFunction::create(algo);
58 if( nullptr == hash_func ) {
59 return "";
60 }
61 return hash_func->provider();
62}
63
64static void cp_print_hash_provider(const std::string& algo) noexcept {
65 std::string p = cp_query_hash_provider(algo);
66 if( p.empty() ) {
67 jau::fprintf_td(stderr, "hash '%s': Not available, provider {", algo.c_str());
68 } else {
69 jau::fprintf_td(stderr, "hash '%s': provider '%s' of {", algo.c_str(), p.c_str());
70 }
71 std::vector<std::string> hash_provider = Botan::HashFunction::providers(algo);
72 for(const std::string& pi : hash_provider) {
73 ::fprintf(stderr, "'%s', ", pi.c_str());
74 }
75 ::fprintf(stderr, "}\n");
76}
77
78environment::environment() noexcept {
79 jau::environment::get("cipherpack");
80
81#ifdef USE_LIBCURL
82 curl_global_init(CURL_GLOBAL_ALL);
83#endif
84}
85
86
87void environment::print_info() noexcept {
88 jau::fprintf_td(stderr, "%s\n", jau::os::get_platform_info().c_str());
89
90 jau::fprintf_td(stderr, "Botan cpuid: '%s'\n", Botan::CPUID::to_string().c_str());
91 jau::fprintf_td(stderr, "Botan cpuid: has_simd32 %d\n", (int)Botan::CPUID::has_simd_32());
92
93 cp_print_hash_provider("SHA-256");
94 cp_print_hash_provider("SHA-512");
95 cp_print_hash_provider("BLAKE2b(512)");
96}
97
98const std::string Constants::package_magic = "CIPHERPACK_0004";
99
100static const std::string default_pk_type = "RSA";
101static const std::string default_pk_fingerprt_hash_algo = "SHA-256";
102static const std::string default_pk_enc_padding_algo = "OAEP"; // or "EME1"
103static const std::string default_pk_enc_hash_algo = "SHA-256";
104static const std::string default_pk_sign_algo = "EMSA1(SHA-256)";
105
106static const std::string default_sym_enc_mac_algo = "ChaCha20Poly1305"; // or "AES-256/GCM"
107
108static const std::string default_hash_algo_ = "BLAKE2b(512)";
109
110std::string_view cipherpack::default_hash_algo() noexcept {
111 return default_hash_algo_;
112}
113
114/**
115 * Symmetric Encryption nonce size in bytes.
116 *
117 * We only process one message per 'encrypted_key', hence medium nonce size of 96 bit.
118 *
119 * ChaCha Nonce Sizes are usually: 64-bit classic, 96-bit IETF, 192-bit big
120 */
121static constexpr const size_t ChaCha_Nonce_BitSize = 96;
122
124 return CryptoConfig (
128 );
129}
130
131bool CryptoConfig::valid() const noexcept {
132 return !pk_type.empty() &&
133 !pk_fingerprt_hash_algo.empty() &&
134 !pk_enc_padding_algo.empty() &&
135 !pk_enc_hash_algo.empty() &&
136 !pk_sign_algo.empty() &&
137 !sym_enc_algo.empty() &&
139}
140
141std::string CryptoConfig::to_string() const noexcept {
142 return "CCfg[pk[type '"+pk_type+"', fingerprt_hash '"+pk_fingerprt_hash_algo+"', enc_padding '"+pk_enc_padding_algo+
143 "', enc_hash '"+pk_enc_hash_algo+"', sign '"+pk_sign_algo+
144 "'], sym['"+sym_enc_algo+"', nonce "+std::to_string(sym_enc_nonce_bytes)+" bytes]]";
145}
146
147std::string PackHeader::to_string(const bool show_crypto_algos, const bool force_all_fingerprints) const noexcept {
148 const std::string crypto_str = show_crypto_algos ? ", "+crypto_cfg_.to_string() : "";
149
150 std::string recevr_fingerprint_str;
151 {
152 if( 0 <= used_recevr_key_idx_ ) {
153 recevr_fingerprint_str += "dec '"+jau::bytesHexString(recevr_fingerprints_.at(used_recevr_key_idx_), true /* lsbFirst */)+"', ";
154 }
155 if( force_all_fingerprints || 0 > used_recevr_key_idx_ ) {
156 recevr_fingerprint_str += "enc[";
157 int i = 0;
158 for(const std::vector<uint8_t>& tkf : recevr_fingerprints_) {
159 if( 0 < i ) {
160 recevr_fingerprint_str += ", ";
161 }
162 recevr_fingerprint_str.append("'").append(jau::bytesHexString(tkf, true /* lsbFirst */)).append("'");
163 ++i;
164 }
165 recevr_fingerprint_str += "]";
166 }
167 }
168
169 std::string res = "Header[";
170 res += "valid "+std::to_string( isValid() )+
171 ", file[target_path '"+target_path_+"', plaintext_size "+jau::to_decstring(plaintext_size_).c_str()+
172 "], creation "+ts_creation_.to_iso8601_string()+" UTC, subject '"+subject_+"', "+
173 " version['"+plaintext_version_+
174 "', parent '"+plaintext_version_parent_+"']"+crypto_str+
175 ", fingerprints[sender '"+jau::bytesHexString(sender_fingerprint_, true /* lsbFirst */)+
176 "', recevr["+recevr_fingerprint_str+
177 "]], phash['"+plaintext_hash_algo_+"', sz "+std::to_string(plaintext_hash_.size())+"]]";
178 return res;
179}
180
181std::shared_ptr<Botan::Public_Key> cipherpack::load_public_key(const std::string& pubkey_fname) {
182 jau::io::ByteInStream_File key_data_(pubkey_fname);
183 WrappingDataSource key_data(key_data_);
184 std::shared_ptr<Botan::Public_Key> key(Botan::X509::load_key(key_data));
185 if( !key ) {
186 ERR_PRINT("Couldn't load Key %s", pubkey_fname.c_str());
187 return std::shared_ptr<Botan::Public_Key>();
188 }
189 if( key->algo_name() != "RSA" ) {
190 ERR_PRINT("Key doesn't support RSA %s", pubkey_fname.c_str());
191 return std::shared_ptr<Botan::Public_Key>();
192 }
193 return key;
194}
195
196/**
197 * Get info from an EncryptedPrivateKeyInfo
198 *
199 * Copied from Botan, allowing to only pass passphrase by const reference
200 * for later secure erasure not leaving a copy in memory.
201 */
203 Botan::AlgorithmIdentifier& pbe_alg_id)
204{
206
207 Botan::BER_Decoder(source)
208 .start_sequence()
209 .decode(pbe_alg_id)
210 .decode(key_data, Botan::ASN1_Type::OctetString)
211 .verify_end();
212
213 return key_data;
214}
215
216#if defined(BOTAN_HAS_PKCS5_PBES2)
217namespace Botan {
218 /**
219 * Decrypt a PKCS #5 v2.0 encrypted stream
220 * @param key_bits the input
221 * @param passphrase the passphrase to use for decryption
222 * @param params the PBES2 parameters
223 */
225 pbes2_decrypt(const secure_vector<uint8_t>& key_bits,
226 const std::string& passphrase,
227 const std::vector<uint8_t>& params);
228}
229#endif
230
231/**
232 * PEM decode and/or decrypt a private key
233 *
234 * Copied from Botan, allowing to only pass passphrase by const reference
235 * for later secure erasure not leaving a copy in memory.
236 */
238 const std::string& passphrase,
239 Botan::AlgorithmIdentifier& pk_alg_id,
240 bool is_encrypted)
241{
242 Botan::AlgorithmIdentifier pbe_alg_id;
244
245 try {
246 if(Botan::ASN1::maybe_BER(source) && !Botan::PEM_Code::matches(source)) {
247 if(is_encrypted) {
248 key_data = jau_PKCS8_extract(source, pbe_alg_id);
249 } else {
250 // todo read more efficiently
251 while(!source.end_of_data()) {
252 uint8_t b;
253 size_t read = source.read_byte(b);
254 if(read) {
255 key_data.push_back(b);
256 }
257 }
258 }
259 } else {
260 std::string label;
261 key_data = Botan::PEM_Code::decode(source, label);
262
263 // todo remove autodetect for pem as well?
264 if(label == "PRIVATE KEY") {
265 is_encrypted = false;
266 } else if(label == "ENCRYPTED PRIVATE KEY") {
267 Botan::DataSource_Memory key_source(key_data);
268 key_data = jau_PKCS8_extract(key_source, pbe_alg_id);
269 } else {
270 throw Botan::PKCS8_Exception("Unknown PEM label " + label);
271 }
272 }
273
274 if(key_data.empty()) {
275 throw Botan::PKCS8_Exception("No key data found");
276 }
277 } catch(Botan::Decoding_Error& e) {
278 throw Botan::Decoding_Error("PKCS #8 private key decoding", e);
279 }
280
281 try {
282 if(is_encrypted) {
283 if(Botan::OIDS::oid2str_or_throw(pbe_alg_id.get_oid()) != "PBE-PKCS5v20") {
284 throw Botan::PKCS8_Exception("Unknown PBE type " + pbe_alg_id.get_oid().to_string());
285 }
286#if defined(BOTAN_HAS_PKCS5_PBES2)
287 key = Botan::pbes2_decrypt(key_data, passphrase, pbe_alg_id.get_parameters()); // pass passphrase by const reference, OK
288#else
289 #error Private key is encrypted but PBES2 was disabled in build
290 BOTAN_UNUSED(passphrase);
291 throw Botan::Decoding_Error("Private key is encrypted but PBES2 was disabled in build");
292#endif
293 } else {
294 key = key_data;
295 }
296
297 Botan::BER_Decoder(key)
298 .start_sequence()
299 .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
300 .decode(pk_alg_id)
301 .decode(key, Botan::ASN1_Type::OctetString)
302 .discard_remaining()
303 .end_cons();
304 } catch(std::exception& e) {
305 throw Botan::Decoding_Error("PKCS #8 private key decoding", e);
306 }
307 return key;
308}
309
310std::shared_ptr<Botan::Private_Key> cipherpack::load_private_key(const std::string& privatekey_fname, const jau::io::secure_string& passphrase) {
311 jau::io::ByteInStream_File key_data_(privatekey_fname);
312 WrappingDataSource key_data(key_data_);
313 std::shared_ptr<Botan::Private_Key> key;
314 if( passphrase.empty() ) {
315 key = Botan::PKCS8::load_key(key_data);
316 } else {
317 /**
318 * We drop Botan::PKCS8::load_key(), since it copies the std::string passphrase via
319 * `const std::function<std::string ()>& get_pass`
320 * and hence leaves an intact copy of the passphrase in memory.
321 *
322 * Hence we replace it by our own 'jau_PKCS8_decode()' handing down only a const reference w/o copy.
323 *
324 * `key = Botan::PKCS8::load_key(key_data, passphrase);`
325 */
326 std::string insec_passphrase_copy(passphrase);
327 Botan::AlgorithmIdentifier alg_id;
328 cipherpack::secure_vector<uint8_t> pkcs8_key = jau_PKCS8_decode(key_data, insec_passphrase_copy, alg_id, true /* is_encrypted */);
329
330 const std::string alg_name = Botan::OIDS::oid2str_or_empty(alg_id.get_oid());
331 if( alg_name.empty() ) {
332 throw Botan::PKCS8_Exception("Unknown algorithm OID: " + alg_id.get_oid().to_string());
333 }
334 key = Botan::load_private_key(alg_id, pkcs8_key);
335 ::explicit_bzero(insec_passphrase_copy.data(), insec_passphrase_copy.size());
336 }
337 if( !key ) {
338 ERR_PRINT("Couldn't load Key %s", privatekey_fname.c_str());
339 return std::shared_ptr<Botan::Private_Key>();
340 }
341 if( key->algo_name() != "RSA" ) {
342 ERR_PRINT("Key doesn't support RSA %s", privatekey_fname.c_str());
343 return std::shared_ptr<Botan::Private_Key>();
344 }
345 return key;
346}
347
348std::string cipherpack::hash_util::file_suffix(const std::string& algo) noexcept {
349 std::string s = algo;
350 // lower-case
351 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
352 // remove '-'
353 auto it = std::remove( s.begin(), s.end(), '-');
354 s.erase(it, s.end());
355 return s;
356}
357
358bool cipherpack::hash_util::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 {
359 const std::string hash_str = jau::bytesHexString(hash_value.data(), 0, hash_value.size(), true /* lsbFirst */, true /* lowerCase */);
360
361 jau::io::ByteOutStream_File out(out_file);
362 if( !out.good() ) {
363 return false;
364 }
365 if( hash_algo.size() != out.write(hash_algo.data(), hash_algo.size()) ) {
366 return false;
367 }
368 if( 1 != out.write(" ", 1) ) {
369 return false;
370 }
371 if( hash_str.size() != out.write(hash_str.data(), hash_str.size()) ) {
372 return false;
373 }
374 if( 2 != out.write(" *", 2) ) {
375 return false;
376 }
377 if( hashed_file.size() != out.write(hashed_file.data(), hashed_file.size()) ) {
378 return false;
379 }
380 if( 1 != out.write("\n", 1) ) {
381 return false;
382 }
383 return out.good();
384}
385
386std::unique_ptr<std::vector<uint8_t>> cipherpack::hash_util::calc(const std::string_view& algo, jau::io::ByteInStream& source) noexcept {
387 const std::string algo_s(algo);
388 std::unique_ptr<Botan::HashFunction> hash_func = Botan::HashFunction::create(algo_s);
389 if( nullptr == hash_func ) {
390 ERR_PRINT2("Hash failed: Algo %s not available", algo_s.c_str());
391 return nullptr;
392 }
393 jau::io::StreamConsumerFunc consume_data = [&](jau::io::secure_vector<uint8_t>& data, bool is_final) -> bool {
394 (void) is_final;
395 hash_func->update(data.data(), data.size());
396 return true;
397 };
398 jau::io::secure_vector<uint8_t> io_buffer;
399 io_buffer.reserve(Constants::buffer_size);
400 const uint64_t in_bytes_total = jau::io::read_stream(source, io_buffer, consume_data);
401 source.close();
402 if( source.has_content_size() && in_bytes_total != source.content_size() ) {
403 ERR_PRINT2("Hash failed: Only read %" PRIu64 " bytes of %s", in_bytes_total, source.to_string().c_str());
404 return nullptr;
405 }
406 std::unique_ptr<std::vector<uint8_t>> res = std::make_unique<std::vector<uint8_t>>(hash_func->output_length());
407 hash_func->final(res->data());
408 return res;
409}
410
411std::unique_ptr<std::vector<uint8_t>> cipherpack::hash_util::calc(const std::string_view& algo, const std::string& path_or_uri, uint64_t& bytes_hashed, jau::fraction_i64 timeout) noexcept {
412 bytes_hashed = 0;
413
414 if( !jau::io::uri_tk::is_local_file_protocol(path_or_uri) &&
415 jau::io::uri_tk::protocol_supported(path_or_uri) )
416 {
417 jau::io::ByteInStream_URL in(path_or_uri, timeout);
418 if( !in.fail() ) {
419 return calc(algo, in);
420 }
421 }
422 std::unique_ptr<jau::fs::file_stats> stats;
423 if( jau::io::uri_tk::is_local_file_protocol(path_or_uri) ) {
424 // cut of leading `file://`
425 std::string path2 = path_or_uri.substr(7);
426 stats = std::make_unique<jau::fs::file_stats>(path2);
427 } else {
428 stats = std::make_unique<jau::fs::file_stats>(path_or_uri);
429 }
430 if( !stats->is_dir() ) {
431 if( stats->has_fd() ) {
432 jau::io::ByteInStream_File in(stats->fd());
433 if( in.fail() ) {
434 return nullptr;
435 }
436 return calc(algo, in);
437 } else {
438 jau::io::ByteInStream_File in(stats->path());
439 if( in.fail() ) {
440 return nullptr;
441 }
442 return calc(algo, in);
443 }
444 }
445 //
446 // directory handling
447 //
448 struct context_t {
449 std::vector<int> dirfds;
450 std::unique_ptr<Botan::HashFunction> hash_func;
451 jau::io::secure_vector<uint8_t> io_buffer;
452 jau::io::StreamConsumerFunc consume_data;
453 uint64_t bytes_hashed;
454 };
455 context_t ctx { std::vector<int>(), nullptr, jau::io::secure_vector<uint8_t>(), nullptr, 0 };
456 {
457 const std::string algo_s(algo);
458 ctx.hash_func = Botan::HashFunction::create(algo_s);
459 if( nullptr == ctx.hash_func ) {
460 ERR_PRINT2("Hash failed: Algo %s not available", algo_s.c_str());
461 return nullptr;
462 }
463 }
464 ctx.consume_data = [&](jau::io::secure_vector<uint8_t>& data, bool is_final) -> bool {
465 (void) is_final;
466 ctx.hash_func->update(data.data(), data.size());
467 return true;
468 };
469 ctx.io_buffer.reserve(Constants::buffer_size);
470
471 const jau::fs::path_visitor pv = jau::bind_capref<bool, context_t, jau::fs::traverse_event, const jau::fs::file_stats&, size_t>(&ctx,
472 ( bool(*)(context_t*, jau::fs::traverse_event, const jau::fs::file_stats&, size_t) ) /* help template type deduction of function-ptr */
473 ( [](context_t* ctx_ptr, jau::fs::traverse_event tevt, const jau::fs::file_stats& element_stats, size_t depth) -> bool {
474 (void)depth;
475 if( is_set(tevt, jau::fs::traverse_event::file) && !is_set(tevt, jau::fs::traverse_event::symlink) ) {
476 jau::io::ByteInStream_File in(ctx_ptr->dirfds.back(), element_stats.item().basename());
477 if( in.fail() ) {
478 return false;
479 }
480 const uint64_t in_bytes_total = jau::io::read_stream(in, ctx_ptr->io_buffer, ctx_ptr->consume_data);
481 in.close();
482 if( in.has_content_size() && in_bytes_total != in.content_size() ) {
483 ERR_PRINT2("Hash failed: Only read %" PRIu64 " bytes of %s", in_bytes_total, in.to_string().c_str());
484 return false;
485 }
486 ctx_ptr->bytes_hashed += in_bytes_total;
487 }
488 return true;
489 } ) );
490 const jau::fs::traverse_options topts = jau::fs::traverse_options::recursive | jau::fs::traverse_options::lexicographical_order;
491 if( jau::fs::visit(*stats, topts, pv, &ctx.dirfds) ) {
492 std::unique_ptr<std::vector<uint8_t>> res = std::make_unique<std::vector<uint8_t>>(ctx.hash_func->output_length());
493 ctx.hash_func->final(res->data());
494 bytes_hashed = ctx.bytes_hashed;
495 return res;
496 }
497 return nullptr;
498}
static std::string to_string()
Return a possibly empty string containing list of known CPU extensions.
static bool has_simd_32()
static const std::string package_magic
Package magic CIPHERPACK_0004.
Definition: cipherpack.hpp:266
static constexpr const size_t buffer_size
Intermediate copy buffer size of 16384 bytes, usually the 4 x 4096 bytes page-size.
Definition: cipherpack.hpp:261
std::string to_string(const bool show_crypto_algos=false, const bool force_all_fingerprints=false) const noexcept
Return a string representation.
Definition: crypto0.cpp:147
This class represents an abstract data source object.
Definition: cipherpack.hpp:172
void print_info() noexcept
Definition: crypto0.cpp:87
static const std::string default_pk_sign_algo
Definition: crypto0.cpp:104
static constexpr const size_t ChaCha_Nonce_BitSize
Symmetric Encryption nonce size in bytes.
Definition: crypto0.cpp:121
static const std::string default_pk_type
Definition: crypto0.cpp:100
static std::string cp_query_hash_provider(const std::string &algo) noexcept
Definition: crypto0.cpp:56
static const std::string default_sym_enc_mac_algo
Definition: crypto0.cpp:106
static void cp_print_hash_provider(const std::string &algo) noexcept
Definition: crypto0.cpp:64
static const std::string default_pk_fingerprt_hash_algo
Definition: crypto0.cpp:101
static cipherpack::secure_vector< uint8_t > jau_PKCS8_extract(Botan::DataSource &source, Botan::AlgorithmIdentifier &pbe_alg_id)
Get info from an EncryptedPrivateKeyInfo.
Definition: crypto0.cpp:202
static const std::string default_pk_enc_padding_algo
Definition: crypto0.cpp:102
static cipherpack::secure_vector< uint8_t > jau_PKCS8_decode(Botan::DataSource &source, const std::string &passphrase, Botan::AlgorithmIdentifier &pk_alg_id, bool is_encrypted)
PEM decode and/or decrypt a private key.
Definition: crypto0.cpp:237
static const std::string default_hash_algo_
Definition: crypto0.cpp:108
static const std::string default_pk_enc_hash_algo
Definition: crypto0.cpp:103
static std::string to_string(const std::vector< uint8_t > &v)
Definition: crypto1.cpp:72
std::shared_ptr< Botan::Public_Key > load_public_key(const std::string &pubkey_fname)
Definition: crypto0.cpp:181
std::shared_ptr< Botan::Private_Key > load_private_key(const std::string &privatekey_fname, const jau::io::secure_string &passphrase)
Definition: crypto0.cpp:310
std::vector< T, Botan::secure_allocator< T > > secure_vector
Definition: cipherpack.hpp:166
std::string_view default_hash_algo() noexcept
Name of default hash algo for the plaintext message, e.g.
Definition: crypto0.cpp:110
std::string file_suffix(const std::string &algo) noexcept
Return a lower-case file suffix used to store a sha256sum compatible hash signature w/o dot and w/o d...
Definition: crypto0.cpp:348
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.
Definition: crypto0.cpp:386
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.
Definition: crypto0.cpp:358
CryptoConfig, contains crypto algorithms settings given at encryption wired via the Cipherpack Data S...
Definition: cipherpack.hpp:205
bool valid() const noexcept
Definition: crypto0.cpp:131
static CryptoConfig getDefault() noexcept
Returns default CryptoConfig.
Definition: crypto0.cpp:123
std::string pk_enc_padding_algo
Definition: cipherpack.hpp:208
std::string pk_fingerprt_hash_algo
Definition: cipherpack.hpp:207
std::string pk_enc_hash_algo
Definition: cipherpack.hpp:209
std::string to_string() const noexcept
Definition: crypto0.cpp:141