Passwordfile library  4.0.0
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"
4 #include "./parsingexception.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 #include <c++utilities/io/catchiofailure.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 <functional>
22 #include <limits>
23 #include <memory>
24 #include <sstream>
25 #include <streambuf>
26 
27 using namespace std;
28 using namespace ConversionUtilities;
29 using namespace IoUtilities;
30 
31 namespace Io {
32 
33 const unsigned int aes256cbcIvSize = 16U;
34 
44 PasswordFile::PasswordFile()
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);
52  clearPassword();
53 }
54 
58 PasswordFile::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);
66  setPath(path);
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  throwIoFailure("Unable to open file because path is emtpy.");
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  throwIoFailure("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  throwIoFailure("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  uint16 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 + 32);
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 = ConversionUtilities::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 (...) {
366  const char *const what = catchIoFailure();
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: ", 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  if (m_file.good() && m_file.is_open() && (m_file.flags() & ios_base::out)) {
405  m_file.seekp(0);
406  } else {
407  m_file.close();
408  m_file.clear();
409  m_file.open(m_path, ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary);
410  }
411 
412  write(options);
413  m_file.flush();
414 }
415 
424 {
425  if (!m_rootEntry) {
426  throw runtime_error("Root entry has not been created.");
427  }
428 
429  // write magic number
430  m_fwriter.writeUInt32LE(0x7770616DU);
431 
432  // write version
433  const auto version = mininumVersion(options);
434  m_fwriter.writeUInt32LE(version);
435 
436  // write flags
437  byte flags = 0x00;
438  if (options & PasswordFileSaveFlags::Encryption) {
439  flags |= 0x80 | 0x40;
440  }
441  if (options & PasswordFileSaveFlags::Compression) {
442  flags |= 0x20;
443  }
444  m_fwriter.writeByte(flags);
445 
446  // write extened header
447  if (version >= 0x4U) {
448  if (m_extendedHeader.size() > numeric_limits<uint16>::max()) {
449  throw runtime_error("Extended header exceeds maximum size.");
450  }
451  m_fwriter.writeUInt16BE(static_cast<uint16>(m_extendedHeader.size()));
452  m_fwriter.writeString(m_extendedHeader);
453  }
454 
455  // serialize root entry and descendants
456  stringstream buffstr(stringstream::in | stringstream::out | stringstream::binary);
457  buffstr.exceptions(ios_base::failbit | ios_base::badbit);
458 
459  // write encrypted extened header
460  if (version >= 0x5U) {
461  if (m_encryptedExtendedHeader.size() > numeric_limits<uint16>::max()) {
462  throw runtime_error("Encrypted extended header exceeds maximum size.");
463  }
464  BinaryWriter buffstrWriter(&buffstr);
465  buffstrWriter.writeUInt16BE(static_cast<uint16>(m_encryptedExtendedHeader.size()));
466  buffstrWriter.writeString(m_encryptedExtendedHeader);
467  }
468  m_rootEntry->make(buffstr);
469  buffstr.seekp(0, ios_base::end);
470  auto size = static_cast<size_t>(buffstr.tellp());
471 
472  // write the data to a buffer
473  buffstr.seekg(0);
474  vector<char> decryptedData(size, 0);
475  buffstr.read(decryptedData.data(), static_cast<streamoff>(size));
476  vector<char> encryptedData;
477 
478  // compress data
479  if (options & PasswordFileSaveFlags::Compression) {
480  uLongf compressedSize = compressBound(size);
481  encryptedData.resize(8 + compressedSize);
482  ConversionUtilities::LE::getBytes(static_cast<uint64>(size), encryptedData.data());
483  switch (
484  compress(reinterpret_cast<Bytef *>(encryptedData.data() + 8), &compressedSize, reinterpret_cast<Bytef *>(decryptedData.data()), size)) {
485  case Z_MEM_ERROR:
486  throw runtime_error("Compressing failed. The source buffer was too small.");
487  case Z_BUF_ERROR:
488  throw runtime_error("Compressing failed. The destination buffer was too small.");
489  case Z_OK:
490  encryptedData.swap(decryptedData); // decompression successful
491  size = 8 + compressedSize;
492  }
493  }
494 
495  if (size > numeric_limits<int>::max()) {
496  throw CryptoException("size exceeds limit");
497  }
498 
499  // write data without encryption
500  if (!(options & PasswordFileSaveFlags::Encryption)) {
501  // write data to file
502  m_file.write(decryptedData.data(), static_cast<streamsize>(size));
503  return;
504  }
505 
506  // prepare password
508  const uint32_t hashCount = (options & PasswordFileSaveFlags::PasswordHashing) ? Util::OpenSsl::generateRandomNumber(1, 100) : 0u;
509  if (hashCount) {
510  // hash password a few times
511  password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
512  for (uint32_t i = 1; i < hashCount; ++i) {
514  }
515  } else {
516  m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
517  }
518 
519  // initiate ctx, encrypt data
520  EVP_CIPHER_CTX *ctx = nullptr;
521  unsigned char iv[aes256cbcIvSize];
522  int outlen1, outlen2;
523  encryptedData.resize(size + 32);
524  if (RAND_bytes(iv, aes256cbcIvSize) != 1 || (ctx = EVP_CIPHER_CTX_new()) == nullptr
525  || EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
526  || EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()), &outlen1,
527  reinterpret_cast<unsigned char *>(decryptedData.data()), static_cast<int>(size))
528  != 1
529  || EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()) + outlen1, &outlen2) != 1) {
530  // handle encryption error
531  if (ctx) {
532  EVP_CIPHER_CTX_free(ctx);
533  }
534  string msg;
535  auto errorCode = ERR_get_error();
536  while (errorCode) {
537  if (!msg.empty()) {
538  msg += "\n";
539  }
540  msg += ERR_error_string(errorCode, nullptr);
541  errorCode = ERR_get_error();
542  }
543  throw CryptoException(move(msg));
544  }
545 
546  if (ctx) {
547  EVP_CIPHER_CTX_free(ctx);
548  }
549 
550  // write encrypted data to file
551  if (version >= 0x6U) {
552  m_fwriter.writeUInt32BE(hashCount);
553  }
554  m_file.write(reinterpret_cast<char *>(iv), aes256cbcIvSize);
555  m_file.write(encryptedData.data(), static_cast<streamsize>(outlen1 + outlen2));
556 }
557 
562 {
563  m_rootEntry.reset();
564 }
565 
570 {
571  close();
572  clearPath();
573  clearPassword();
574  clearEntries();
575  m_openOptions = PasswordFileOpenFlags::None;
576  m_extendedHeader.clear();
577  m_encryptedExtendedHeader.clear();
578 }
579 
586 void PasswordFile::exportToTextfile(const string &targetPath) const
587 {
588  if (!m_rootEntry) {
589  throw runtime_error("Root entry has not been created.");
590  }
591  fstream output(targetPath.c_str(), ios_base::out);
592  const auto printIndention = [&output](int level) {
593  for (int i = 0; i < level; ++i) {
594  output << " ";
595  }
596  };
597  function<void(const Entry *entry, int level)> printNode;
598  printNode = [&output, &printNode, &printIndention](const Entry *entry, int level) {
599  printIndention(level);
600  output << " - " << entry->label() << endl;
601  switch (entry->type()) {
602  case EntryType::Node:
603  for (const Entry *child : static_cast<const NodeEntry *>(entry)->children()) {
604  printNode(child, level + 1);
605  }
606  break;
607  case EntryType::Account:
608  for (const Field &field : static_cast<const AccountEntry *>(entry)->fields()) {
609  printIndention(level);
610  output << " " << field.name();
611  for (auto i = field.name().length(); i < 15; ++i) {
612  output << ' ';
613  }
614  output << field.value() << endl;
615  }
616  }
617  };
618  printNode(m_rootEntry.get(), 0);
619  output.close();
620 }
621 
627 {
628  if (!isOpen()) {
629  open();
630  }
631 
632  // skip if the current file is empty anyways
633  if (!size()) {
634  return;
635  }
636 
637  m_file.seekg(0);
638  fstream backupFile(m_path + ".backup", ios::out | ios::trunc | ios::binary);
639  backupFile.exceptions(ios_base::failbit | ios_base::badbit);
640  backupFile << m_file.rdbuf();
641  backupFile.close();
642 }
643 
650 {
651  return m_rootEntry != nullptr;
652 }
653 
658 {
659  return m_rootEntry.get();
660 }
661 
666 {
667  return m_rootEntry.get();
668 }
669 
674 {
675  if (m_file.is_open()) {
676  m_file.close();
677  }
678  m_file.clear();
679 }
680 
684 void PasswordFile::setPath(const string &value)
685 {
686  close();
687  m_path = value;
688 
689  // support "file://" protocol
690  if (ConversionUtilities::startsWith(m_path, "file:")) {
691  m_path = m_path.substr(5);
692  }
693 }
694 
701 {
702  if (!isOpen()) {
703  return false;
704  }
705  m_file.seekg(0);
706 
707  // check magic number
708  if (m_freader.readUInt32LE() != 0x7770616DU) {
709  return false;
710  }
711 
712  // check version
713  const auto version = m_freader.readUInt32LE();
714  if (version == 0x1U || version == 0x2U) {
715  return true;
716  } else if (version >= 0x3U) {
717  return m_freader.readByte() & 0x80;
718  } else {
719  return false;
720  }
721 }
722 
727 {
728  if (!isOpen()) {
729  return 0;
730  }
731  m_file.seekg(0, ios::end);
732  return static_cast<size_t>(m_file.tellg());
733 }
734 
739 {
740  string result = "<table>";
741  if (!m_path.empty()) {
742  result += argsToString("<tr><td>Path:</td><td>", m_path, "</td></tr>");
743  }
744  result += argsToString("<tr><td>Version:</td><td>", m_version, "</td></tr>");
745  const auto minVersion = mininumVersion(saveOptions);
746  if (m_version != minVersion) {
747  result += argsToString("<tr><td></td><td>(on disk, after saving: ", minVersion, ")</td></tr>");
748  }
749  result += argsToString("<tr><td>Features:</td><td>", flagsToString(m_saveOptions), "</td></tr>");
750  if (m_saveOptions != saveOptions) {
751  result += argsToString("<tr><td></td><td>(on disk, after saving: ", flagsToString(saveOptions), ")</td></tr>");
752  }
753  const auto stats = m_rootEntry ? m_rootEntry->computeStatistics() : EntryStatistics();
754  result += argsToString("<tr><td>Number of categories:</td><td>", stats.nodeCount, "</td></tr><tr><td>Number of accounts:</td><td>",
755  stats.accountCount, "</td></tr><tr><td>Number of fields:</td><td>", stats.fieldCount, "</td></tr></table>");
756  return result;
757 }
758 
763 {
764  vector<string> options;
765  if (flags & PasswordFileOpenFlags::ReadOnly) {
766  options.emplace_back("read-only");
767  }
768  if (options.empty()) {
769  options.emplace_back("none");
770  }
771  return joinStrings(options, ", ");
772 }
773 
778 {
779  vector<string> options;
780  options.reserve(3);
781  if (flags & PasswordFileSaveFlags::Encryption) {
782  options.emplace_back("encryption");
783  }
785  options.emplace_back("compression");
786  }
788  options.emplace_back("password hashing");
789  }
790  if (options.empty()) {
791  options.emplace_back("none");
792  }
793  return joinStrings(options, ", ");
794 }
795 
796 } // namespace Io
PasswordFile()
Constructs a new password file.
uint32 mininumVersion(PasswordFileSaveFlags options) const
Returns the minimum file version required to write the current instance with the specified options...
bool hasRootEntry() const
Returns an indication whether a root entry is present.
void clear()
Closes the file if opened.
The NodeEntry class acts as parent for other entries.
Definition: entry.h:115
The PasswordFile class holds account information in the form of Entry and Field instances and provide...
Definition: passwordfile.h:73
void load()
Reads the contents of the file.
static constexpr std::size_t size
Definition: openssl.h:14
STL namespace.
std::string PASSWORD_FILE_EXPORT flagsToString(PasswordFileOpenFlags flags)
Returns a comma-separated string for the specified flags.
void close()
Closes the file if currently opened.
void doBackup()
Creates a backup of the file.
Contains all IO related classes.
const NodeEntry * rootEntry() const
Returns the root entry if present or nullptr otherwise.
std::string summary(PasswordFileSaveFlags saveOptions) const
Returns a summary about the file (version, used features, statistics).
void open(PasswordFileOpenFlags options=PasswordFileOpenFlags::Default)
Opens the file.
PasswordFileOpenFlags
Definition: passwordfile.h:19
Sha256Sum PASSWORD_FILE_EXPORT computeSha256Sum(const unsigned char *buffer, std::size_t size)
Computes a SHA-256 sum using OpenSSL.
Definition: openssl.cpp:50
void exportToTextfile(const std::string &targetPath) const
Writes the current root entry to a plain text file.
bool isOpen() const
Returns an indication whether the file is open.
Definition: passwordfile.h:190
The Field class holds field information which consists of a name and a value and is able to serialize...
Definition: field.h:15
void clearPath()
Clears the current path.
Definition: passwordfile.h:149
bool isEncryptionUsed()
Returns an indication whether encryption is used and the file is open; returns always false otherwise...
const unsigned int aes256cbcIvSize
~PasswordFile()
Closes the file if still opened and destroys the instance.
const std::string & path() const
Returns the current file path.
Definition: passwordfile.h:141
PasswordFileSaveFlags
Definition: passwordfile.h:45
void setPassword(const std::string &password)
Sets the current password.
Definition: passwordfile.h:166
void setPath(const std::string &value)
Sets the current file path.
std::uint32_t PASSWORD_FILE_EXPORT generateRandomNumber(std::uint32_t min, std::uint32_t max)
void create()
Creates the file.
std::size_t size()
Returns the size of the file if the file is open; otherwise returns zero.
void generateRootEntry()
Generates a new root entry for the file.
void write(PasswordFileSaveFlags options=PasswordFileSaveFlags::Default)
Writes the current root entry to the file which is assumed to be opened and writeable.
const std::string & password() const
Returns the current password.
Definition: passwordfile.h:158
The exception that is thrown when an encryption/decryption error occurs.
uint32 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:231
void opened()
Handles the file being opened.
The exception that is thrown when a parsing error occurs.
void save(PasswordFileSaveFlags options=PasswordFileSaveFlags::Default)
Writes the current root entry to the file under path() replacing its previous contents.
void clearPassword()
Clears the current password.
Definition: passwordfile.h:182
void clearEntries()
Removes the root element if one is present.
Instances of the Entry class form a hierarchic data strucutre used to store account information...
Definition: entry.h:31
PasswordFileSaveFlags saveOptions() const
Returns the save options used the last time when saving the file.
Definition: passwordfile.h:247