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