Passwordfile library 5.0.9
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"
7#include "../util/opensslrandomdevice.h"
8
9#include <c++utilities/conversion/stringbuilder.h>
10#include <c++utilities/conversion/stringconversion.h>
11
12#include <openssl/conf.h>
13#include <openssl/err.h>
14#include <openssl/evp.h>
15#include <openssl/rand.h>
16
17#include <zlib.h>
18
19#include <cstring>
20#include <filesystem>
21#include <functional>
22#include <limits>
23#include <memory>
24#include <sstream>
25#include <streambuf>
26
27using namespace std;
28using namespace CppUtilities;
29
30namespace Io {
31
32constexpr unsigned int aes256cbcIvSize = 16U;
33constexpr unsigned int aes256blockSize = 32U;
34constexpr unsigned int aes256additionalBufferSize = aes256blockSize * 2;
35
46 : m_freader(BinaryReader(&m_file))
47 , m_fwriter(BinaryWriter(&m_file))
48 , m_version(0)
49 , m_openOptions(PasswordFileOpenFlags::None)
50 , m_saveOptions(PasswordFileSaveFlags::None)
51{
52 m_file.exceptions(ios_base::failbit | ios_base::badbit);
54}
55
59PasswordFile::PasswordFile(const string &path, const string &password)
60 : m_freader(BinaryReader(&m_file))
61 , m_fwriter(BinaryWriter(&m_file))
62 , m_version(0)
63 , m_openOptions(PasswordFileOpenFlags::None)
64 , m_saveOptions(PasswordFileSaveFlags::None)
65{
66 m_file.exceptions(ios_base::failbit | ios_base::badbit);
69}
70
75 : m_path(other.m_path)
76 , m_password(other.m_password)
77 , m_rootEntry(other.m_rootEntry ? make_unique<NodeEntry>(*other.m_rootEntry) : nullptr)
78 , m_extendedHeader(other.m_extendedHeader)
79 , m_encryptedExtendedHeader(other.m_encryptedExtendedHeader)
80 , m_freader(BinaryReader(&m_file))
81 , m_fwriter(BinaryWriter(&m_file))
82 , m_version(other.m_version)
83 , m_openOptions(other.m_openOptions)
84 , m_saveOptions(other.m_saveOptions)
85{
86 m_file.exceptions(ios_base::failbit | ios_base::badbit);
87}
88
93 : m_path(std::move(other.m_path))
94 , m_password(std::move(other.m_password))
95 , m_rootEntry(std::move(other.m_rootEntry))
96 , m_extendedHeader(std::move(other.m_extendedHeader))
97 , m_encryptedExtendedHeader(std::move(other.m_encryptedExtendedHeader))
98 , m_file(std::move(other.m_file))
99 , m_freader(BinaryReader(&m_file))
100 , m_fwriter(BinaryWriter(&m_file))
101 , m_version(other.m_version)
102 , m_openOptions(other.m_openOptions)
103 , m_saveOptions(other.m_saveOptions)
104{
105}
106
113
119{
120 close();
121 if (m_path.empty()) {
122 throw std::ios_base::failure("Unable to open file because path is empty.");
123 }
124 m_file.open(
125 m_path, options & PasswordFileOpenFlags::ReadOnly ? ios_base::in | ios_base::binary : ios_base::in | ios_base::out | ios_base::binary);
126 m_openOptions = options;
127 opened();
128}
129
136{
137 m_file.seekg(0, ios_base::end);
138 if (m_file.tellg() == 0) {
139 throw std::ios_base::failure("File is empty.");
140 } else {
141 m_file.seekg(0);
142 }
143}
144
149{
150 if (!m_rootEntry) {
151 m_rootEntry.reset(new NodeEntry("accounts"));
152 }
153}
154
160{
161 close();
162 if (m_path.empty()) {
163 throw std::ios_base::failure("Unable to create file because path is empty.");
164 }
165 m_file.open(m_path, fstream::out | fstream::trunc | fstream::binary);
166}
167
177{
178 if (!m_file.is_open()) {
179 open();
180 }
181 m_file.seekg(0);
182 m_version = 0;
183 m_saveOptions = PasswordFileSaveFlags::None;
184
185 // check magic number
186 if (m_freader.readUInt32LE() != 0x7770616DU) {
187 throw ParsingException("Signature not present.");
188 }
189
190 // check version and flags (used in version 0x3 only)
191 m_version = m_freader.readUInt32LE();
192 if (m_version > 0x6U) {
193 throw ParsingException(argsToString("Version \"", m_version, "\" is unknown. Only versions 0 to 6 are supported."));
194 }
195 if (m_version >= 0x6U) {
197 }
198 bool decrypterUsed, ivUsed, compressionUsed;
199 if (m_version >= 0x3U) {
200 const auto flags = m_freader.readByte();
201 if ((decrypterUsed = flags & 0x80)) {
202 m_saveOptions |= PasswordFileSaveFlags::Encryption;
203 }
204 if ((compressionUsed = flags & 0x20)) {
205 m_saveOptions |= PasswordFileSaveFlags::Compression;
206 }
207 ivUsed = flags & 0x40;
208 } else {
209 if ((decrypterUsed = m_version >= 0x1U)) {
210 m_saveOptions |= PasswordFileSaveFlags::Encryption;
211 }
212 compressionUsed = false;
213 ivUsed = m_version == 0x2U;
214 }
215
216 // skip extended header
217 // (the extended header might be used in further versions to
218 // add additional information without breaking compatibility)
219 if (m_version >= 0x4U) {
220 std::uint16_t extendedHeaderSize = m_freader.readUInt16BE();
221 m_extendedHeader = m_freader.readString(extendedHeaderSize);
222 } else {
223 m_extendedHeader.clear();
224 }
225
226 // get length
227 const auto headerSize = static_cast<size_t>(m_file.tellg());
228 m_file.seekg(0, ios_base::end);
229 auto remainingSize = static_cast<size_t>(m_file.tellg()) - headerSize;
230 m_file.seekg(static_cast<streamoff>(headerSize), ios_base::beg);
231
232 // read hash count
233 uint32_t hashCount = 0U;
234 if ((m_saveOptions & PasswordFileSaveFlags::PasswordHashing) && decrypterUsed) {
235 if (remainingSize < 4) {
236 throw ParsingException("Hash count truncated.");
237 }
238 hashCount = m_freader.readUInt32BE();
239 remainingSize -= 4;
240 }
241
242 // read IV
243 unsigned char iv[aes256cbcIvSize] = { 0 };
244 if (decrypterUsed && ivUsed) {
245 if (remainingSize < aes256cbcIvSize) {
246 throw ParsingException("Initiation vector is truncated.");
247 }
248 m_file.read(reinterpret_cast<char *>(iv), aes256cbcIvSize);
249 remainingSize -= aes256cbcIvSize;
250 }
251 if (!remainingSize) {
252 throw ParsingException("No contents found.");
253 }
254
255 // decrypt contents
256 vector<char> rawData;
257 m_freader.read(rawData, static_cast<streamoff>(remainingSize));
258 vector<char> decryptedData;
259 if (decrypterUsed) {
260 if (remainingSize > numeric_limits<int>::max()) {
261 throw CryptoException("Size exceeds limit.");
262 }
263
264 // prepare password
266 if (hashCount) {
267 // hash the password as often as it has been hashed when writing the file
268 password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
269 for (uint32_t i = 1; i < hashCount; ++i) {
271 }
272 } else {
273 m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
274 }
275
276 // initiate ctx, decrypt data
277 EVP_CIPHER_CTX *ctx = nullptr;
278 decryptedData.resize(remainingSize + aes256additionalBufferSize);
279 int outlen1, outlen2;
280 if ((ctx = EVP_CIPHER_CTX_new()) == nullptr || EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
281 || EVP_DecryptUpdate(ctx, reinterpret_cast<unsigned char *>(decryptedData.data()), &outlen1,
282 reinterpret_cast<unsigned char *>(rawData.data()), static_cast<int>(remainingSize))
283 != 1
284 || EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(decryptedData.data()) + outlen1, &outlen2) != 1) {
285 // handle decryption error
286 if (ctx) {
287 EVP_CIPHER_CTX_free(ctx);
288 }
289 string msg;
290 auto errorCode = ERR_get_error();
291 while (errorCode) {
292 if (!msg.empty()) {
293 msg += "\n";
294 }
295 msg += ERR_error_string(errorCode, nullptr);
296 errorCode = ERR_get_error();
297 }
298 throw CryptoException(std::move(msg));
299 }
300
301 if (ctx) {
302 EVP_CIPHER_CTX_free(ctx);
303 }
304 const auto decryptedSize = outlen1 + outlen2;
305 if (decryptedSize < 0) {
306 throw CryptoException("Decrypted size is negative.");
307 }
308 remainingSize = static_cast<size_t>(decryptedSize);
309 if (!remainingSize) {
310 throw ParsingException("Decrypted buffer is empty.");
311 }
312
313 } else {
314 // use raw data directly if not encrypted
315 decryptedData.swap(rawData);
316 }
317
318 // decompress
319 if (compressionUsed) {
320 if (remainingSize < 8) {
321 throw ParsingException("File is truncated (decompressed size expected).");
322 }
323 if (remainingSize > numeric_limits<uLongf>::max()) {
324 throw CryptoException("Size exceeds limit.");
325 }
326 const auto rawDecompressedSize = LE::toUInt64(decryptedData.data());
327 if (rawDecompressedSize > numeric_limits<uLongf>::max()) {
328 throw ParsingException("Decompressed size exceeds limit.");
329 }
330 auto decompressedSize = static_cast<uLongf>(rawDecompressedSize);
331 rawData.resize(decompressedSize);
332 switch (uncompress(reinterpret_cast<Bytef *>(rawData.data()), &decompressedSize, reinterpret_cast<Bytef *>(decryptedData.data() + 8),
333 static_cast<uLongf>(remainingSize - 8))) {
334 case Z_MEM_ERROR:
335 throw ParsingException("Decompressing failed. The source buffer was too small.");
336 case Z_BUF_ERROR:
337 throw ParsingException("Decompressing failed. The destination buffer was too small.");
338 case Z_DATA_ERROR:
339 throw ParsingException("Decompressing failed. The input data was corrupted or incomplete.");
340 case Z_OK:
341 decryptedData.swap(rawData);
342 remainingSize = decompressedSize;
343 }
344 }
345 if (!remainingSize) {
346 throw ParsingException("Decompressed buffer is empty.");
347 }
348
349 // parse contents
350 stringstream decryptedStream(stringstream::in | stringstream::out | stringstream::binary);
351 decryptedStream.exceptions(ios_base::failbit | ios_base::badbit);
352 try {
353#if defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
354 decryptedStream.rdbuf()->pubsetbuf(decryptedData.data(), static_cast<streamsize>(remainingSize));
355#else
356 decryptedStream.write(decryptedData.data(), static_cast<streamsize>(remainingSize));
357#endif
358 if (m_version >= 0x5u) {
359 BinaryReader reader(&decryptedStream);
360 const auto extendedHeaderSize = reader.readUInt16BE();
361 m_encryptedExtendedHeader = reader.readString(extendedHeaderSize);
362 } else {
363 m_encryptedExtendedHeader.clear();
364 }
365 m_rootEntry.reset(new NodeEntry(decryptedStream));
366 } catch (const std::ios_base::failure &failure) {
367 if (decryptedStream.eof()) {
368 throw ParsingException("The file seems to be truncated.");
369 }
370 throw ParsingException(argsToString("An IO error occurred when reading internal buffer: ", failure.what()));
371 }
372}
373
379{
381 return 0x6U; // password hashing requires at least version 6
382 } else if (!m_encryptedExtendedHeader.empty()) {
383 return 0x5U; // encrypted extended header requires at least version 5
384 } else if (!m_extendedHeader.empty()) {
385 return 0x4U; // regular extended header requires at least version 4
386 }
387 return 0x3U; // lowest supported version by the serializer
388}
389
398{
399 if (!m_rootEntry) {
400 throw runtime_error("Root entry has not been created.");
401 }
402
403 // use already opened and writable file; otherwise re-open the file
404 auto fileSize = std::size_t();
405 if (m_file.good() && m_file.is_open() && !(m_openOptions & PasswordFileOpenFlags::ReadOnly)) {
406 fileSize = size();
407 m_file.seekp(0);
408 } else {
409 m_file.clear();
410 if (m_file.is_open()) {
411 m_file.close();
412 }
413 try {
414 m_file.open(m_path, ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary);
415 } catch (const ios_base::failure &) {
416 // try to create a new file if configured via \a options
418 throw;
419 }
420 m_file.open(m_path, ios_base::out | ios_base::trunc | ios_base::binary);
421 }
422 }
423
424 // write entries
425 write(options);
426 m_file.flush();
427
428 // truncate file if it became smaller
429 const auto newSize = static_cast<std::size_t>(m_file.tellp());
430 if (fileSize && newSize < fileSize) {
431 m_file.close();
432 std::filesystem::resize_file(m_path, newSize);
433 }
434}
435
444{
445 if (!m_rootEntry) {
446 throw runtime_error("Root entry has not been created.");
447 }
448
449 // write magic number
450 m_fwriter.writeUInt32LE(0x7770616DU);
451
452 // write version
453 const auto version = mininumVersion(options);
454 m_fwriter.writeUInt32LE(version);
455
456 // write flags
457 std::uint8_t flags = 0x00;
458 if (options & PasswordFileSaveFlags::Encryption) {
459 flags |= 0x80 | 0x40;
460 }
462 flags |= 0x20;
463 }
464 m_fwriter.writeByte(flags);
465
466 // write extended header
467 if (version >= 0x4U) {
468 if (m_extendedHeader.size() > numeric_limits<std::uint16_t>::max()) {
469 throw runtime_error("Extended header exceeds maximum size.");
470 }
471 m_fwriter.writeUInt16BE(static_cast<std::uint16_t>(m_extendedHeader.size()));
472 m_fwriter.writeString(m_extendedHeader);
473 }
474
475 // serialize root entry and descendants
476 stringstream buffstr(stringstream::in | stringstream::out | stringstream::binary);
477 buffstr.exceptions(ios_base::failbit | ios_base::badbit);
478
479 // write encrypted extended header
480 if (version >= 0x5U) {
481 if (m_encryptedExtendedHeader.size() > numeric_limits<std::uint16_t>::max()) {
482 throw runtime_error("Encrypted extended header exceeds maximum size.");
483 }
484 BinaryWriter buffstrWriter(&buffstr);
485 buffstrWriter.writeUInt16BE(static_cast<std::uint16_t>(m_encryptedExtendedHeader.size()));
486 buffstrWriter.writeString(m_encryptedExtendedHeader);
487 }
488 m_rootEntry->make(buffstr);
489 buffstr.seekp(0, ios_base::end);
490 auto size = static_cast<size_t>(buffstr.tellp());
491
492 // write the data to a buffer
493 buffstr.seekg(0);
494 vector<char> decryptedData(size, 0);
495 buffstr.read(decryptedData.data(), static_cast<streamoff>(size));
496 vector<char> encryptedData;
497
498 // compress data
500 uLongf compressedSize = compressBound(size);
501 encryptedData.resize(8 + compressedSize);
502 LE::getBytes(static_cast<std::uint64_t>(size), encryptedData.data());
503 switch (
504 compress(reinterpret_cast<Bytef *>(encryptedData.data() + 8), &compressedSize, reinterpret_cast<Bytef *>(decryptedData.data()), size)) {
505 case Z_MEM_ERROR:
506 throw runtime_error("Compressing failed. The source buffer was too small.");
507 case Z_BUF_ERROR:
508 throw runtime_error("Compressing failed. The destination buffer was too small.");
509 case Z_OK:
510 encryptedData.swap(decryptedData); // compression successful
511 size = 8 + compressedSize;
512 }
513 }
514
515 if (size > numeric_limits<int>::max()) {
516 throw CryptoException("size exceeds limit");
517 }
518
519 // write data without encryption
520 if (!(options & PasswordFileSaveFlags::Encryption)) {
521 // write data to file
522 m_file.write(decryptedData.data(), static_cast<streamsize>(size));
523 m_file.flush();
524 return;
525 }
526
527 // prepare password
529 const uint32_t hashCount = (options & PasswordFileSaveFlags::PasswordHashing) ? Util::OpenSsl::generateRandomNumber(1, 100) : 0u;
530 if (hashCount) {
531 // hash password a few times
532 password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
533 for (uint32_t i = 1; i < hashCount; ++i) {
535 }
536 } else {
537 m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
538 }
539
540 // initiate ctx, encrypt data
541 EVP_CIPHER_CTX *ctx = nullptr;
542 unsigned char iv[aes256cbcIvSize];
543 int outlen1, outlen2;
544 encryptedData.resize(size + aes256additionalBufferSize);
545 if (RAND_bytes(iv, aes256cbcIvSize) != 1 || (ctx = EVP_CIPHER_CTX_new()) == nullptr
546 || EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
547 || EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()), &outlen1,
548 reinterpret_cast<unsigned char *>(decryptedData.data()), static_cast<int>(size))
549 != 1
550 || EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()) + outlen1, &outlen2) != 1) {
551 // handle encryption error
552 if (ctx) {
553 EVP_CIPHER_CTX_free(ctx);
554 }
555 string msg;
556 auto errorCode = ERR_get_error();
557 while (errorCode) {
558 if (!msg.empty()) {
559 msg += "\n";
560 }
561 msg += ERR_error_string(errorCode, nullptr);
562 errorCode = ERR_get_error();
563 }
564 throw CryptoException(std::move(msg));
565 }
566
567 if (ctx) {
568 EVP_CIPHER_CTX_free(ctx);
569 }
570
571 // write encrypted data to file
572 if (version >= 0x6U) {
573 m_fwriter.writeUInt32BE(hashCount);
574 }
575 m_file.write(reinterpret_cast<char *>(iv), aes256cbcIvSize);
576 m_file.write(encryptedData.data(), static_cast<streamsize>(outlen1 + outlen2));
577 m_file.flush();
578}
579
584{
585 m_rootEntry.reset();
586}
587
592{
593 close();
594 clearPath();
596 clearEntries();
597 m_openOptions = PasswordFileOpenFlags::None;
598 m_extendedHeader.clear();
599 m_encryptedExtendedHeader.clear();
600}
601
607void PasswordFile::exportToTextfile(const string &targetPath) const
608{
609 if (!m_rootEntry) {
610 throw runtime_error("Root entry has not been created.");
611 }
612 NativeFileStream output;
613 output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
614 output.open(targetPath, std::ios_base::out);
615 const auto printIndention = [&output](int level) {
616 for (int i = 0; i < level; ++i) {
617 output << " ";
618 }
619 };
620 function<void(const Entry *entry, int level)> printNode;
621 printNode = [&output, &printNode, &printIndention](const Entry *entry, int level) {
622 printIndention(level);
623 output << " - " << entry->label() << endl;
624 switch (entry->type()) {
625 case EntryType::Node:
626 for (const Entry *child : static_cast<const NodeEntry *>(entry)->children()) {
627 printNode(child, level + 1);
628 }
629 break;
631 for (const Field &field : static_cast<const AccountEntry *>(entry)->fields()) {
632 printIndention(level);
633 output << " " << field.name();
634 for (auto i = field.name().length(); i < 15; ++i) {
635 output << ' ';
636 }
637 output << field.value() << endl;
638 }
639 }
640 };
641 printNode(m_rootEntry.get(), 0);
642 output.close();
643}
644
650{
651 if (!isOpen()) {
652 open();
653 }
654
655 // skip if the current file is empty anyways
656 if (!size()) {
657 return;
658 }
659
660 m_file.seekg(0);
661 fstream backupFile(m_path + ".backup", ios::out | ios::trunc | ios::binary);
662 backupFile.exceptions(ios_base::failbit | ios_base::badbit);
663 backupFile << m_file.rdbuf();
664 backupFile.close();
665}
666
673{
674 return m_rootEntry != nullptr;
675}
676
681{
682 return m_rootEntry.get();
683}
684
689{
690 return m_rootEntry.get();
691}
692
697{
698 if (m_file.is_open()) {
699 m_file.close();
700 }
701 m_file.clear();
702}
703
707void PasswordFile::setPath(const string &value)
708{
709 close();
710 m_path = value;
711
712 // support "file://" protocol
713 if (startsWith(m_path, "file:")) {
714 m_path = m_path.substr(5);
715 }
716}
717
724{
725 if (!isOpen()) {
726 return false;
727 }
728 m_file.seekg(0);
729
730 // check magic number
731 if (m_freader.readUInt32LE() != 0x7770616DU) {
732 return false;
733 }
734
735 // check version
736 const auto version = m_freader.readUInt32LE();
737 if (version == 0x1U || version == 0x2U) {
738 return true;
739 } else if (version >= 0x3U) {
740 return m_freader.readByte() & 0x80;
741 } else {
742 return false;
743 }
744}
745
750{
751 if (!isOpen()) {
752 return 0;
753 }
754 m_file.seekg(0, ios::end);
755 return static_cast<size_t>(m_file.tellg());
756}
757
762{
763 string result = "<table>";
764 if (!m_path.empty()) {
765 result += argsToString("<tr><td>Path:</td><td>", m_path, "</td></tr>");
766 }
767 result += argsToString("<tr><td>Version:</td><td>", m_version, "</td></tr>");
768 const auto minVersion = mininumVersion(saveOptions);
769 if (m_version != minVersion) {
770 result += argsToString("<tr><td></td><td>(on disk, after saving: ", minVersion, ")</td></tr>");
771 }
772 result += argsToString("<tr><td>Features:</td><td>", flagsToString(m_saveOptions), "</td></tr>");
773 if (m_saveOptions != saveOptions) {
774 result += argsToString("<tr><td></td><td>(on disk, after saving: ", flagsToString(saveOptions), ")</td></tr>");
775 }
776 const auto stats = m_rootEntry ? m_rootEntry->computeStatistics() : EntryStatistics();
777 result += argsToString("<tr><td>Number of categories:</td><td>", stats.nodeCount, "</td></tr><tr><td>Number of accounts:</td><td>",
778 stats.accountCount, "</td></tr><tr><td>Number of fields:</td><td>", stats.fieldCount, "</td></tr></table>");
779 return result;
780}
781
786{
787 vector<string> options;
789 options.emplace_back("read-only");
790 }
791 if (options.empty()) {
792 options.emplace_back("none");
793 }
794 return joinStrings(options, ", ");
795}
796
801{
802 vector<string> options;
803 options.reserve(3);
805 options.emplace_back("encryption");
806 }
808 options.emplace_back("compression");
809 }
811 options.emplace_back("password hashing");
812 }
813 if (options.empty()) {
814 options.emplace_back("none");
815 }
816 return joinStrings(options, ", ");
817}
818
819} // 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