Passwordfile library 5.0.11
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<size_t>(buffstr.tellp());
493
494 // write the data to a buffer
495 buffstr.seekg(0);
496 vector<char> decryptedData(size, 0);
497 buffstr.read(decryptedData.data(), static_cast<streamoff>(size));
498 vector<char> encryptedData;
499
500 // compress data
502 uLongf compressedSize = compressBound(size);
503 encryptedData.resize(8 + compressedSize);
504 LE::getBytes(static_cast<std::uint64_t>(size), encryptedData.data());
505 switch (
506 compress(reinterpret_cast<Bytef *>(encryptedData.data() + 8), &compressedSize, reinterpret_cast<Bytef *>(decryptedData.data()), size)) {
507 case Z_MEM_ERROR:
508 throw runtime_error("Compressing failed. The source buffer was too small.");
509 case Z_BUF_ERROR:
510 throw runtime_error("Compressing failed. The destination buffer was too small.");
511 case Z_OK:
512 encryptedData.swap(decryptedData); // compression successful
513 size = 8 + compressedSize;
514 }
515 }
516
517 if (size > numeric_limits<int>::max()) {
518 throw CryptoException("size exceeds limit");
519 }
520
521 // write data without encryption
522 if (!(options & PasswordFileSaveFlags::Encryption)) {
523 // write data to file
524 m_file.write(decryptedData.data(), static_cast<streamsize>(size));
525 m_file.flush();
526 return;
527 }
528
529 // prepare password
531 const uint32_t hashCount = (options & PasswordFileSaveFlags::PasswordHashing) ? Util::OpenSsl::generateRandomNumber(1, 100) : 0u;
532 if (hashCount) {
533 // hash password a few times
534 password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
535 for (uint32_t i = 1; i < hashCount; ++i) {
537 }
538 } else {
539 m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
540 }
541
542 // initiate ctx, encrypt data
543 EVP_CIPHER_CTX *ctx = nullptr;
544 unsigned char iv[aes256cbcIvSize];
545 int outlen1, outlen2;
546 encryptedData.resize(size + aes256additionalBufferSize);
547 if (RAND_bytes(iv, aes256cbcIvSize) != 1 || (ctx = EVP_CIPHER_CTX_new()) == nullptr
548 || EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
549 || EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()), &outlen1,
550 reinterpret_cast<unsigned char *>(decryptedData.data()), static_cast<int>(size))
551 != 1
552 || EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()) + outlen1, &outlen2) != 1) {
553 // handle encryption error
554 if (ctx) {
555 EVP_CIPHER_CTX_free(ctx);
556 }
557 string msg;
558 auto errorCode = ERR_get_error();
559 while (errorCode) {
560 if (!msg.empty()) {
561 msg += "\n";
562 }
563 msg += ERR_error_string(errorCode, nullptr);
564 errorCode = ERR_get_error();
565 }
566 throw CryptoException(std::move(msg));
567 }
568
569 if (ctx) {
570 EVP_CIPHER_CTX_free(ctx);
571 }
572
573 // write encrypted data to file
574 if (version >= 0x6U) {
575 m_fwriter.writeUInt32BE(hashCount);
576 }
577 m_file.write(reinterpret_cast<char *>(iv), aes256cbcIvSize);
578 m_file.write(encryptedData.data(), static_cast<streamsize>(outlen1 + outlen2));
579 m_file.flush();
580}
581
586{
587 m_rootEntry.reset();
588}
589
594{
595 close();
596 clearPath();
598 clearEntries();
599 m_openOptions = PasswordFileOpenFlags::None;
600 m_extendedHeader.clear();
601 m_encryptedExtendedHeader.clear();
602}
603
609void PasswordFile::exportToTextfile(const string &targetPath) const
610{
611 if (!m_rootEntry) {
612 throw runtime_error("Root entry has not been created.");
613 }
614 NativeFileStream output;
615 output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
616 output.open(targetPath, std::ios_base::out);
617 const auto printIndention = [&output](int level) {
618 for (int i = 0; i < level; ++i) {
619 output << " ";
620 }
621 };
622 function<void(const Entry *entry, int level)> printNode;
623 printNode = [&output, &printNode, &printIndention](const Entry *entry, int level) {
624 printIndention(level);
625 output << " - " << entry->label() << endl;
626 switch (entry->type()) {
627 case EntryType::Node:
628 for (const Entry *child : static_cast<const NodeEntry *>(entry)->children()) {
629 printNode(child, level + 1);
630 }
631 break;
633 for (const Field &field : static_cast<const AccountEntry *>(entry)->fields()) {
634 printIndention(level);
635 output << " " << field.name();
636 for (auto i = field.name().length(); i < 15; ++i) {
637 output << ' ';
638 }
639 output << field.value() << endl;
640 }
641 }
642 };
643 printNode(m_rootEntry.get(), 0);
644 output.close();
645}
646
652{
653 if (!isOpen()) {
654 open();
655 }
656
657 // skip if the current file is empty anyways
658 if (!size()) {
659 return;
660 }
661
662 m_file.seekg(0);
663 fstream backupFile(m_path + ".backup", ios::out | ios::trunc | ios::binary);
664 backupFile.exceptions(ios_base::failbit | ios_base::badbit);
665 backupFile << m_file.rdbuf();
666 backupFile.close();
667}
668
675{
676 return m_rootEntry != nullptr;
677}
678
683{
684 return m_rootEntry.get();
685}
686
691{
692 return m_rootEntry.get();
693}
694
699{
700 if (m_file.is_open()) {
701 m_file.close();
702 }
703 m_file.clear();
704}
705
709void PasswordFile::setPath(const string &value)
710{
711 close();
712 m_path = value;
713
714 // support "file://" protocol
715 if (startsWith(m_path, "file:")) {
716 m_path = m_path.substr(5);
717 }
718}
719
726{
727 if (!isOpen()) {
728 return false;
729 }
730 m_file.seekg(0);
731
732 // check magic number
733 if (m_freader.readUInt32LE() != 0x7770616DU) {
734 return false;
735 }
736
737 // check version
738 const auto version = m_freader.readUInt32LE();
739 if (version == 0x1U || version == 0x2U) {
740 return true;
741 } else if (version >= 0x3U) {
742 return m_freader.readByte() & 0x80;
743 } else {
744 return false;
745 }
746}
747
752{
753 if (!isOpen()) {
754 return 0;
755 }
756 m_file.seekg(0, ios::end);
757 return static_cast<size_t>(m_file.tellg());
758}
759
764{
765 string result = "<table>";
766 if (!m_path.empty()) {
767 result += argsToString("<tr><td>Path:</td><td>", m_path, "</td></tr>");
768 }
769 result += argsToString("<tr><td>Version:</td><td>", m_version, "</td></tr>");
770 const auto minVersion = mininumVersion(saveOptions);
771 if (m_version != minVersion) {
772 result += argsToString("<tr><td></td><td>(on disk, after saving: ", minVersion, ")</td></tr>");
773 }
774 result += argsToString("<tr><td>Features:</td><td>", flagsToString(m_saveOptions), "</td></tr>");
775 if (m_saveOptions != saveOptions) {
776 result += argsToString("<tr><td></td><td>(on disk, after saving: ", flagsToString(saveOptions), ")</td></tr>");
777 }
778 const auto stats = m_rootEntry ? m_rootEntry->computeStatistics() : EntryStatistics();
779 result += argsToString("<tr><td>Number of categories:</td><td>", stats.nodeCount, "</td></tr><tr><td>Number of accounts:</td><td>",
780 stats.accountCount, "</td></tr><tr><td>Number of fields:</td><td>", stats.fieldCount, "</td></tr></table>");
781 return result;
782}
783
788{
789 vector<string> options;
791 options.emplace_back("read-only");
792 }
793 if (options.empty()) {
794 options.emplace_back("none");
795 }
796 return joinStrings(options, ", ");
797}
798
803{
804 vector<string> options;
805 options.reserve(3);
807 options.emplace_back("encryption");
808 }
810 options.emplace_back("compression");
811 }
813 options.emplace_back("password hashing");
814 }
815 if (options.empty()) {
816 options.emplace_back("none");
817 }
818 return joinStrings(options, ", ");
819}
820
821} // 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
virtual EntryType type() const =0
Returns the type of the entry.
const std::string & label() const
Returns the label.
Definition entry.h:70
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