Passwordfile library 5.0.12
C++ library to read/write passwords from/to encrypted files
Loading...
Searching...
No Matches
passwordfile.cpp
Go to the documentation of this file.
1#include "./passwordfile.h"
2#include "./cryptoexception.h"
3#include "./entry.h"
5
6#include "../util/openssl.h"
8
9#include <c++utilities/conversion/stringbuilder.h>
10#include <c++utilities/conversion/stringconversion.h>
11#include <c++utilities/io/path.h>
12
13#include <openssl/conf.h>
14#include <openssl/err.h>
15#include <openssl/evp.h>
16#include <openssl/rand.h>
17
18#include <zlib.h>
19
20#include <cstring>
21#include <filesystem>
22#include <functional>
23#include <limits>
24#include <memory>
25#include <sstream>
26#include <streambuf>
27
28using namespace std;
29using namespace CppUtilities;
30
31namespace Io {
32
33constexpr unsigned int aes256cbcIvSize = 16U;
34constexpr unsigned int aes256blockSize = 32U;
35constexpr unsigned int aes256additionalBufferSize = aes256blockSize * 2;
36
47 : m_freader(BinaryReader(&m_file))
48 , m_fwriter(BinaryWriter(&m_file))
49 , m_version(0)
50 , m_openOptions(PasswordFileOpenFlags::None)
51 , m_saveOptions(PasswordFileSaveFlags::None)
52{
53 m_file.exceptions(ios_base::failbit | ios_base::badbit);
55}
56
60PasswordFile::PasswordFile(const string &path, const string &password)
61 : m_freader(BinaryReader(&m_file))
62 , m_fwriter(BinaryWriter(&m_file))
63 , m_version(0)
64 , m_openOptions(PasswordFileOpenFlags::None)
65 , m_saveOptions(PasswordFileSaveFlags::None)
66{
67 m_file.exceptions(ios_base::failbit | ios_base::badbit);
70}
71
76 : m_path(other.m_path)
77 , m_password(other.m_password)
78 , m_rootEntry(other.m_rootEntry ? make_unique<NodeEntry>(*other.m_rootEntry) : nullptr)
79 , m_extendedHeader(other.m_extendedHeader)
80 , m_encryptedExtendedHeader(other.m_encryptedExtendedHeader)
81 , m_freader(BinaryReader(&m_file))
82 , m_fwriter(BinaryWriter(&m_file))
83 , m_version(other.m_version)
84 , m_openOptions(other.m_openOptions)
85 , m_saveOptions(other.m_saveOptions)
86{
87 m_file.exceptions(ios_base::failbit | ios_base::badbit);
88}
89
94 : m_path(std::move(other.m_path))
95 , m_password(std::move(other.m_password))
96 , m_rootEntry(std::move(other.m_rootEntry))
97 , m_extendedHeader(std::move(other.m_extendedHeader))
98 , m_encryptedExtendedHeader(std::move(other.m_encryptedExtendedHeader))
99 , m_file(std::move(other.m_file))
100 , m_freader(BinaryReader(&m_file))
101 , m_fwriter(BinaryWriter(&m_file))
102 , m_version(other.m_version)
103 , m_openOptions(other.m_openOptions)
104 , m_saveOptions(other.m_saveOptions)
105{
106}
107
114
120{
121 close();
122 if (m_path.empty()) {
123 throw std::ios_base::failure("Unable to open file because path is empty.");
124 }
125 m_file.open(
126 m_path, options & PasswordFileOpenFlags::ReadOnly ? ios_base::in | ios_base::binary : ios_base::in | ios_base::out | ios_base::binary);
127 m_openOptions = options;
128 opened();
129}
130
137{
138 m_file.seekg(0, ios_base::end);
139 if (m_file.tellg() == 0) {
140 throw std::ios_base::failure("File is empty.");
141 } else {
142 m_file.seekg(0);
143 }
144}
145
150{
151 if (!m_rootEntry) {
152 m_rootEntry.reset(new NodeEntry("accounts"));
153 }
154}
155
161{
162 close();
163 if (m_path.empty()) {
164 throw std::ios_base::failure("Unable to create file because path is empty.");
165 }
166 m_file.open(m_path, fstream::out | fstream::trunc | fstream::binary);
167}
168
178{
179 if (!m_file.is_open()) {
180 open();
181 }
182 m_file.seekg(0);
183 m_version = 0;
184 m_saveOptions = PasswordFileSaveFlags::None;
185
186 // check magic number
187 if (m_freader.readUInt32LE() != 0x7770616DU) {
188 throw ParsingException("Signature not present.");
189 }
190
191 // check version and flags (used in version 0x3 only)
192 m_version = m_freader.readUInt32LE();
193 if (m_version > 0x6U) {
194 throw ParsingException(argsToString("Version \"", m_version, "\" is unknown. Only versions 0 to 6 are supported."));
195 }
196 if (m_version >= 0x6U) {
198 }
199 bool decrypterUsed, ivUsed, compressionUsed;
200 if (m_version >= 0x3U) {
201 const auto flags = m_freader.readByte();
202 if ((decrypterUsed = flags & 0x80)) {
203 m_saveOptions |= PasswordFileSaveFlags::Encryption;
204 }
205 if ((compressionUsed = flags & 0x20)) {
206 m_saveOptions |= PasswordFileSaveFlags::Compression;
207 }
208 ivUsed = flags & 0x40;
209 } else {
210 if ((decrypterUsed = m_version >= 0x1U)) {
211 m_saveOptions |= PasswordFileSaveFlags::Encryption;
212 }
213 compressionUsed = false;
214 ivUsed = m_version == 0x2U;
215 }
216
217 // skip extended header
218 // (the extended header might be used in further versions to
219 // add additional information without breaking compatibility)
220 if (m_version >= 0x4U) {
221 std::uint16_t extendedHeaderSize = m_freader.readUInt16BE();
222 m_extendedHeader = m_freader.readString(extendedHeaderSize);
223 } else {
224 m_extendedHeader.clear();
225 }
226
227 // get length
228 const auto headerSize = static_cast<size_t>(m_file.tellg());
229 m_file.seekg(0, ios_base::end);
230 auto remainingSize = static_cast<size_t>(m_file.tellg()) - headerSize;
231 m_file.seekg(static_cast<streamoff>(headerSize), ios_base::beg);
232
233 // read hash count
234 uint32_t hashCount = 0U;
235 if ((m_saveOptions & PasswordFileSaveFlags::PasswordHashing) && decrypterUsed) {
236 if (remainingSize < 4) {
237 throw ParsingException("Hash count truncated.");
238 }
239 hashCount = m_freader.readUInt32BE();
240 remainingSize -= 4;
241 }
242
243 // read IV
244 unsigned char iv[aes256cbcIvSize] = { 0 };
245 if (decrypterUsed && ivUsed) {
246 if (remainingSize < aes256cbcIvSize) {
247 throw ParsingException("Initiation vector is truncated.");
248 }
249 m_file.read(reinterpret_cast<char *>(iv), aes256cbcIvSize);
250 remainingSize -= aes256cbcIvSize;
251 }
252 if (!remainingSize) {
253 throw ParsingException("No contents found.");
254 }
255
256 // decrypt contents
257 vector<char> rawData;
258 m_freader.read(rawData, static_cast<streamoff>(remainingSize));
259 vector<char> decryptedData;
260 if (decrypterUsed) {
261 if (remainingSize > numeric_limits<int>::max()) {
262 throw CryptoException("Size exceeds limit.");
263 }
264
265 // prepare password
267 if (hashCount) {
268 // hash the password as often as it has been hashed when writing the file
269 password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
270 for (uint32_t i = 1; i < hashCount; ++i) {
272 }
273 } else {
274 m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
275 }
276
277 // initiate ctx, decrypt data
278 EVP_CIPHER_CTX *ctx = nullptr;
279 decryptedData.resize(remainingSize + aes256additionalBufferSize);
280 int outlen1, outlen2;
281 if ((ctx = EVP_CIPHER_CTX_new()) == nullptr || EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
282 || EVP_DecryptUpdate(ctx, reinterpret_cast<unsigned char *>(decryptedData.data()), &outlen1,
283 reinterpret_cast<unsigned char *>(rawData.data()), static_cast<int>(remainingSize))
284 != 1
285 || EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(decryptedData.data()) + outlen1, &outlen2) != 1) {
286 // handle decryption error
287 if (ctx) {
288 EVP_CIPHER_CTX_free(ctx);
289 }
290 string msg;
291 auto errorCode = ERR_get_error();
292 while (errorCode) {
293 if (!msg.empty()) {
294 msg += "\n";
295 }
296 msg += ERR_error_string(errorCode, nullptr);
297 errorCode = ERR_get_error();
298 }
299 throw CryptoException(std::move(msg));
300 }
301
302 if (ctx) {
303 EVP_CIPHER_CTX_free(ctx);
304 }
305 const auto decryptedSize = outlen1 + outlen2;
306 if (decryptedSize < 0) {
307 throw CryptoException("Decrypted size is negative.");
308 }
309 remainingSize = static_cast<size_t>(decryptedSize);
310 if (!remainingSize) {
311 throw ParsingException("Decrypted buffer is empty.");
312 }
313
314 } else {
315 // use raw data directly if not encrypted
316 decryptedData.swap(rawData);
317 }
318
319 // decompress
320 if (compressionUsed) {
321 if (remainingSize < 8) {
322 throw ParsingException("File is truncated (decompressed size expected).");
323 }
324 if (remainingSize > numeric_limits<uLongf>::max()) {
325 throw CryptoException("Size exceeds limit.");
326 }
327 const auto rawDecompressedSize = LE::toUInt64(decryptedData.data());
328 if (rawDecompressedSize > numeric_limits<uLongf>::max()) {
329 throw ParsingException("Decompressed size exceeds limit.");
330 }
331 auto decompressedSize = static_cast<uLongf>(rawDecompressedSize);
332 rawData.resize(decompressedSize);
333 switch (uncompress(reinterpret_cast<Bytef *>(rawData.data()), &decompressedSize, reinterpret_cast<Bytef *>(decryptedData.data() + 8),
334 static_cast<uLongf>(remainingSize - 8))) {
335 case Z_MEM_ERROR:
336 throw ParsingException("Decompressing failed. The source buffer was too small.");
337 case Z_BUF_ERROR:
338 throw ParsingException("Decompressing failed. The destination buffer was too small.");
339 case Z_DATA_ERROR:
340 throw ParsingException("Decompressing failed. The input data was corrupted or incomplete.");
341 case Z_OK:
342 decryptedData.swap(rawData);
343 remainingSize = decompressedSize;
344 }
345 }
346 if (!remainingSize) {
347 throw ParsingException("Decompressed buffer is empty.");
348 }
349
350 // parse contents
351 stringstream decryptedStream(stringstream::in | stringstream::out | stringstream::binary);
352 decryptedStream.exceptions(ios_base::failbit | ios_base::badbit);
353 try {
354#if defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
355 decryptedStream.rdbuf()->pubsetbuf(decryptedData.data(), static_cast<streamsize>(remainingSize));
356#else
357 decryptedStream.write(decryptedData.data(), static_cast<streamsize>(remainingSize));
358#endif
359 if (m_version >= 0x5u) {
360 BinaryReader reader(&decryptedStream);
361 const auto extendedHeaderSize = reader.readUInt16BE();
362 m_encryptedExtendedHeader = reader.readString(extendedHeaderSize);
363 } else {
364 m_encryptedExtendedHeader.clear();
365 }
366 m_rootEntry.reset(new NodeEntry(decryptedStream));
367 } catch (const std::ios_base::failure &failure) {
368 if (decryptedStream.eof()) {
369 throw ParsingException("The file seems to be truncated.");
370 }
371 throw ParsingException(argsToString("An IO error occurred when reading internal buffer: ", failure.what()));
372 }
373}
374
380{
382 return 0x6U; // password hashing requires at least version 6
383 } else if (!m_encryptedExtendedHeader.empty()) {
384 return 0x5U; // encrypted extended header requires at least version 5
385 } else if (!m_extendedHeader.empty()) {
386 return 0x4U; // regular extended header requires at least version 4
387 }
388 return 0x3U; // lowest supported version by the serializer
389}
390
400{
401 if (!m_rootEntry) {
402 throw runtime_error("Root entry has not been created.");
403 }
404
405 // use already opened and writable file; otherwise re-open the file
406 auto fileSize = std::size_t();
407 if (m_file.good() && m_file.is_open() && !(m_openOptions & PasswordFileOpenFlags::ReadOnly)) {
408 fileSize = size();
409 m_file.seekp(0);
410 } else {
411 m_file.clear();
412 if (m_file.is_open()) {
413 m_file.close();
414 }
415 try {
416 m_file.open(m_path, ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary);
417 } catch (const ios_base::failure &) {
418 // try to create a new file if configured via \a options
420 throw;
421 }
422 m_file.open(m_path, ios_base::out | ios_base::trunc | ios_base::binary);
423 }
424 }
425
426 // write entries
427 write(options);
428 m_file.flush();
429
430 // truncate file if it became smaller
431 const auto newSize = static_cast<std::size_t>(m_file.tellp());
432 if (fileSize && newSize < fileSize) {
433 m_file.close();
434 std::filesystem::resize_file(makeNativePath(m_path), newSize);
435 }
436}
437
446{
447 if (!m_rootEntry) {
448 throw runtime_error("Root entry has not been created.");
449 }
450
451 // write magic number
452 m_fwriter.writeUInt32LE(0x7770616DU);
453
454 // write version
455 const auto version = mininumVersion(options);
456 m_fwriter.writeUInt32LE(version);
457
458 // write flags
459 std::uint8_t flags = 0x00;
460 if (options & PasswordFileSaveFlags::Encryption) {
461 flags |= 0x80 | 0x40;
462 }
464 flags |= 0x20;
465 }
466 m_fwriter.writeByte(flags);
467
468 // write extended header
469 if (version >= 0x4U) {
470 if (m_extendedHeader.size() > numeric_limits<std::uint16_t>::max()) {
471 throw runtime_error("Extended header exceeds maximum size.");
472 }
473 m_fwriter.writeUInt16BE(static_cast<std::uint16_t>(m_extendedHeader.size()));
474 m_fwriter.writeString(m_extendedHeader);
475 }
476
477 // serialize root entry and descendants
478 stringstream buffstr(stringstream::in | stringstream::out | stringstream::binary);
479 buffstr.exceptions(ios_base::failbit | ios_base::badbit);
480
481 // write encrypted extended header
482 if (version >= 0x5U) {
483 if (m_encryptedExtendedHeader.size() > numeric_limits<std::uint16_t>::max()) {
484 throw runtime_error("Encrypted extended header exceeds maximum size.");
485 }
486 BinaryWriter buffstrWriter(&buffstr);
487 buffstrWriter.writeUInt16BE(static_cast<std::uint16_t>(m_encryptedExtendedHeader.size()));
488 buffstrWriter.writeString(m_encryptedExtendedHeader);
489 }
490 m_rootEntry->make(buffstr);
491 buffstr.seekp(0, ios_base::end);
492 auto size = static_cast<std::size_t>(buffstr.tellp());
493 if (size > std::numeric_limits<uLong>::max()) {
494 throw std::runtime_error("File size exceeds maximum size.");
495 }
496
497 // write the data to a buffer
498 buffstr.seekg(0);
499 vector<char> decryptedData(size, 0);
500 buffstr.read(decryptedData.data(), static_cast<streamoff>(size));
501 vector<char> encryptedData;
502
503 // compress data
505 auto compressedSize = static_cast<uLongf>(compressBound(static_cast<uLong>(size)));
506 encryptedData.resize(8 + compressedSize);
507 LE::getBytes(static_cast<std::uint64_t>(size), encryptedData.data());
508 switch (compress(reinterpret_cast<Bytef *>(encryptedData.data() + 8), &compressedSize, reinterpret_cast<Bytef *>(decryptedData.data()),
509 static_cast<uLong>(size))) {
510 case Z_MEM_ERROR:
511 throw runtime_error("Compressing failed. The source buffer was too small.");
512 case Z_BUF_ERROR:
513 throw runtime_error("Compressing failed. The destination buffer was too small.");
514 case Z_OK:
515 encryptedData.swap(decryptedData); // compression successful
516 size = 8 + compressedSize;
517 }
518 }
519
520 if (size > numeric_limits<int>::max()) {
521 throw CryptoException("size exceeds limit");
522 }
523
524 // write data without encryption
525 if (!(options & PasswordFileSaveFlags::Encryption)) {
526 // write data to file
527 m_file.write(decryptedData.data(), static_cast<streamsize>(size));
528 m_file.flush();
529 return;
530 }
531
532 // prepare password
534 const uint32_t hashCount = (options & PasswordFileSaveFlags::PasswordHashing) ? Util::OpenSsl::generateRandomNumber(1, 100) : 0u;
535 if (hashCount) {
536 // hash password a few times
537 password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
538 for (uint32_t i = 1; i < hashCount; ++i) {
540 }
541 } else {
542 m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
543 }
544
545 // initiate ctx, encrypt data
546 EVP_CIPHER_CTX *ctx = nullptr;
547 unsigned char iv[aes256cbcIvSize];
548 int outlen1, outlen2;
549 encryptedData.resize(size + aes256additionalBufferSize);
550 if (RAND_bytes(iv, aes256cbcIvSize) != 1 || (ctx = EVP_CIPHER_CTX_new()) == nullptr
551 || EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
552 || EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()), &outlen1,
553 reinterpret_cast<unsigned char *>(decryptedData.data()), static_cast<int>(size))
554 != 1
555 || EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()) + outlen1, &outlen2) != 1) {
556 // handle encryption error
557 if (ctx) {
558 EVP_CIPHER_CTX_free(ctx);
559 }
560 string msg;
561 auto errorCode = ERR_get_error();
562 while (errorCode) {
563 if (!msg.empty()) {
564 msg += "\n";
565 }
566 msg += ERR_error_string(errorCode, nullptr);
567 errorCode = ERR_get_error();
568 }
569 throw CryptoException(std::move(msg));
570 }
571
572 if (ctx) {
573 EVP_CIPHER_CTX_free(ctx);
574 }
575
576 // write encrypted data to file
577 if (version >= 0x6U) {
578 m_fwriter.writeUInt32BE(hashCount);
579 }
580 m_file.write(reinterpret_cast<char *>(iv), aes256cbcIvSize);
581 m_file.write(encryptedData.data(), static_cast<streamsize>(outlen1 + outlen2));
582 m_file.flush();
583}
584
589{
590 m_rootEntry.reset();
591}
592
597{
598 close();
599 clearPath();
601 clearEntries();
602 m_openOptions = PasswordFileOpenFlags::None;
603 m_extendedHeader.clear();
604 m_encryptedExtendedHeader.clear();
605}
606
612void PasswordFile::exportToTextfile(const string &targetPath) const
613{
614 if (!m_rootEntry) {
615 throw runtime_error("Root entry has not been created.");
616 }
617 NativeFileStream output;
618 output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
619 output.open(targetPath, std::ios_base::out);
620 const auto printIndention = [&output](int level) {
621 for (int i = 0; i < level; ++i) {
622 output << " ";
623 }
624 };
625 function<void(const Entry *entry, int level)> printNode;
626 printNode = [&output, &printNode, &printIndention](const Entry *entry, int level) {
627 printIndention(level);
628 output << " - " << entry->label() << endl;
629 switch (entry->type()) {
630 case EntryType::Node:
631 for (const Entry *child : static_cast<const NodeEntry *>(entry)->children()) {
632 printNode(child, level + 1);
633 }
634 break;
636 for (const Field &field : static_cast<const AccountEntry *>(entry)->fields()) {
637 printIndention(level);
638 output << " " << field.name();
639 for (auto i = field.name().length(); i < 15; ++i) {
640 output << ' ';
641 }
642 output << field.value() << endl;
643 }
644 }
645 };
646 printNode(m_rootEntry.get(), 0);
647 output.close();
648}
649
655{
656 if (!isOpen()) {
657 open();
658 }
659
660 // skip if the current file is empty anyways
661 if (!size()) {
662 return;
663 }
664
665 m_file.seekg(0);
666 fstream backupFile(m_path + ".backup", ios::out | ios::trunc | ios::binary);
667 backupFile.exceptions(ios_base::failbit | ios_base::badbit);
668 backupFile << m_file.rdbuf();
669 backupFile.close();
670}
671
678{
679 return m_rootEntry != nullptr;
680}
681
686{
687 return m_rootEntry.get();
688}
689
694{
695 return m_rootEntry.get();
696}
697
702{
703 if (m_file.is_open()) {
704 m_file.close();
705 }
706 m_file.clear();
707}
708
712void PasswordFile::setPath(const string &value)
713{
714 close();
715 m_path = value;
716
717 // support "file://" protocol
718 if (startsWith(m_path, "file:")) {
719 m_path = m_path.substr(5);
720 }
721}
722
729{
730 if (!isOpen()) {
731 return false;
732 }
733 m_file.seekg(0);
734
735 // check magic number
736 if (m_freader.readUInt32LE() != 0x7770616DU) {
737 return false;
738 }
739
740 // check version
741 const auto version = m_freader.readUInt32LE();
742 if (version == 0x1U || version == 0x2U) {
743 return true;
744 } else if (version >= 0x3U) {
745 return m_freader.readByte() & 0x80;
746 } else {
747 return false;
748 }
749}
750
755{
756 if (!isOpen()) {
757 return 0;
758 }
759 m_file.seekg(0, ios::end);
760 return static_cast<size_t>(m_file.tellg());
761}
762
767{
768 string result = "<table>";
769 if (!m_path.empty()) {
770 result += argsToString("<tr><td>Path:</td><td>", m_path, "</td></tr>");
771 }
772 result += argsToString("<tr><td>Version:</td><td>", m_version, "</td></tr>");
773 const auto minVersion = mininumVersion(saveOptions);
774 if (m_version != minVersion) {
775 result += argsToString("<tr><td></td><td>(on disk, after saving: ", minVersion, ")</td></tr>");
776 }
777 result += argsToString("<tr><td>Features:</td><td>", flagsToString(m_saveOptions), "</td></tr>");
778 if (m_saveOptions != saveOptions) {
779 result += argsToString("<tr><td></td><td>(on disk, after saving: ", flagsToString(saveOptions), ")</td></tr>");
780 }
781 const auto stats = m_rootEntry ? m_rootEntry->computeStatistics() : EntryStatistics();
782 result += argsToString("<tr><td>Number of categories:</td><td>", stats.nodeCount, "</td></tr><tr><td>Number of accounts:</td><td>",
783 stats.accountCount, "</td></tr><tr><td>Number of fields:</td><td>", stats.fieldCount, "</td></tr></table>");
784 return result;
785}
786
791{
792 vector<string> options;
794 options.emplace_back("read-only");
795 }
796 if (options.empty()) {
797 options.emplace_back("none");
798 }
799 return joinStrings(options, ", ");
800}
801
806{
807 vector<string> options;
808 options.reserve(3);
810 options.emplace_back("encryption");
811 }
813 options.emplace_back("compression");
814 }
816 options.emplace_back("password hashing");
817 }
818 if (options.empty()) {
819 options.emplace_back("none");
820 }
821 return joinStrings(options, ", ");
822}
823
824} // namespace Io
The exception that is thrown when a parsing error occurs.
Definition entry.h:170
The exception that is thrown when an encryption/decryption error occurs.
Instances of the Entry class form a hierarchic data structure used to store account information.
Definition entry.h:30
const std::string & label() const
Returns the label.
Definition entry.h:70
virtual EntryType type() const =0
Returns the type of the entry.
The Field class holds field information which consists of a name and a value and is able to serialize...
Definition field.h:15
The NodeEntry class acts as parent for other entries.
Definition entry.h:114
The exception that is thrown when a parsing error occurs.
The PasswordFile class holds account information in the form of Entry and Field instances and provide...
const NodeEntry * rootEntry() const
Returns the root entry if present or nullptr otherwise.
bool isOpen() const
Returns an indication whether the file is open.
void clear()
Closes the file if opened.
void opened()
Handles the file being opened.
void clearEntries()
Removes the root element if one is present.
void open(PasswordFileOpenFlags options=PasswordFileOpenFlags::Default)
Opens the file.
bool hasRootEntry() const
Returns an indication whether a root entry is present.
void create()
Creates the file.
void exportToTextfile(const std::string &targetPath) const
Writes the current root entry to a plain text file.
void load()
Reads the contents of the file.
void close()
Closes the file if currently opened.
std::uint32_t version() const
Returns the file version used the last time when saving the file (the version of the file as it is on...
void clearPassword()
Clears the current password.
std::string summary(PasswordFileSaveFlags saveOptions) const
Returns a summary about the file (version, used features, statistics).
PasswordFile()
Constructs a new password file.
const std::string & password() const
Returns the current password.
void setPassword(const std::string &password)
Sets the current password.
const std::string & path() const
Returns the current file path.
bool isEncryptionUsed()
Returns an indication whether encryption is used and the file is open; returns always false otherwise...
std::size_t size()
Returns the size of the file if the file is open; otherwise returns zero.
~PasswordFile()
Closes the file if still opened and destroys the instance.
void save(PasswordFileSaveFlags options=PasswordFileSaveFlags::Default)
Writes the current root entry to the file under path() replacing its previous contents.
void setPath(const std::string &value)
Sets the current file path.
std::uint32_t mininumVersion(PasswordFileSaveFlags options) const
Returns the minimum file version required to write the current instance with the specified options.
void write(PasswordFileSaveFlags options=PasswordFileSaveFlags::Default)
Writes the current root entry to the file which is assumed to be opened and writeable.
void generateRootEntry()
Generates a new root entry for the file.
void clearPath()
Clears the current path.
void doBackup()
Creates a backup of the file.
PasswordFileSaveFlags saveOptions() const
Returns the save options used the last time when saving the file.
Contains all IO related classes.
PASSWORD_FILE_EXPORT std::string flagsToString(PasswordFileOpenFlags flags)
Returns a comma-separated string for the specified flags.
constexpr unsigned int aes256additionalBufferSize
constexpr unsigned int aes256cbcIvSize
PasswordFileSaveFlags
constexpr unsigned int aes256blockSize
PasswordFileOpenFlags
PASSWORD_FILE_EXPORT std::uint32_t generateRandomNumber(std::uint32_t min, std::uint32_t max)
PASSWORD_FILE_EXPORT Sha256Sum computeSha256Sum(const unsigned char *buffer, std::size_t size)
Computes a SHA-256 sum using OpenSSL.
Definition openssl.cpp:50
static constexpr std::size_t size
Definition openssl.h:14