Passwordfile library  5.0.3
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 
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 
26 using namespace std;
27 using namespace CppUtilities;
28 
29 namespace Io {
30 
31 const unsigned int aes256cbcIvSize = 16U;
32 
42 PasswordFile::PasswordFile()
43  : m_freader(BinaryReader(&m_file))
44  , m_fwriter(BinaryWriter(&m_file))
45  , m_version(0)
46  , m_openOptions(PasswordFileOpenFlags::None)
47  , m_saveOptions(PasswordFileSaveFlags::None)
48 {
49  m_file.exceptions(ios_base::failbit | ios_base::badbit);
50  clearPassword();
51 }
52 
56 PasswordFile::PasswordFile(const string &path, const string &password)
57  : m_freader(BinaryReader(&m_file))
58  , m_fwriter(BinaryWriter(&m_file))
59  , m_version(0)
60  , m_openOptions(PasswordFileOpenFlags::None)
61  , m_saveOptions(PasswordFileSaveFlags::None)
62 {
63  m_file.exceptions(ios_base::failbit | ios_base::badbit);
64  setPath(path);
66 }
67 
72  : m_path(other.m_path)
73  , m_password(other.m_password)
74  , m_rootEntry(other.m_rootEntry ? make_unique<NodeEntry>(*other.m_rootEntry) : nullptr)
75  , m_extendedHeader(other.m_extendedHeader)
76  , m_encryptedExtendedHeader(other.m_encryptedExtendedHeader)
77  , m_freader(BinaryReader(&m_file))
78  , m_fwriter(BinaryWriter(&m_file))
79  , m_version(other.m_version)
80  , m_openOptions(other.m_openOptions)
81  , m_saveOptions(other.m_saveOptions)
82 {
83  m_file.exceptions(ios_base::failbit | ios_base::badbit);
84 }
85 
90  : m_path(move(other.m_path))
91  , m_password(move(other.m_password))
92  , m_rootEntry(move(other.m_rootEntry))
93  , m_extendedHeader(move(other.m_extendedHeader))
94  , m_encryptedExtendedHeader(move(other.m_encryptedExtendedHeader))
95  , m_file(move(other.m_file))
96  , m_freader(BinaryReader(&m_file))
97  , m_fwriter(BinaryWriter(&m_file))
98  , m_version(other.m_version)
99  , m_openOptions(other.m_openOptions)
100  , m_saveOptions(other.m_saveOptions)
101 {
102 }
103 
108 {
109 }
110 
116 {
117  close();
118  if (m_path.empty()) {
119  throw std::ios_base::failure("Unable to open file because path is emtpy.");
120  }
121  m_file.open(
122  m_path, options & PasswordFileOpenFlags::ReadOnly ? ios_base::in | ios_base::binary : ios_base::in | ios_base::out | ios_base::binary);
123  m_openOptions = options;
124  opened();
125 }
126 
133 {
134  m_file.seekg(0, ios_base::end);
135  if (m_file.tellg() == 0) {
136  throw std::ios_base::failure("File is empty.");
137  } else {
138  m_file.seekg(0);
139  }
140 }
141 
146 {
147  if (!m_rootEntry) {
148  m_rootEntry.reset(new NodeEntry("accounts"));
149  }
150 }
151 
157 {
158  close();
159  if (m_path.empty()) {
160  throw std::ios_base::failure("Unable to create file because path is empty.");
161  }
162  m_file.open(m_path, fstream::out | fstream::trunc | fstream::binary);
163 }
164 
174 {
175  if (!m_file.is_open()) {
176  open();
177  }
178  m_file.seekg(0);
179  m_version = 0;
180  m_saveOptions = PasswordFileSaveFlags::None;
181 
182  // check magic number
183  if (m_freader.readUInt32LE() != 0x7770616DU) {
184  throw ParsingException("Signature not present.");
185  }
186 
187  // check version and flags (used in version 0x3 only)
188  m_version = m_freader.readUInt32LE();
189  if (m_version > 0x6U) {
190  throw ParsingException(argsToString("Version \"", m_version, "\" is unknown. Only versions 0 to 6 are supported."));
191  }
192  if (m_version >= 0x6U) {
194  }
195  bool decrypterUsed, ivUsed, compressionUsed;
196  if (m_version >= 0x3U) {
197  const auto flags = m_freader.readByte();
198  if ((decrypterUsed = flags & 0x80)) {
199  m_saveOptions |= PasswordFileSaveFlags::Encryption;
200  }
201  if ((compressionUsed = flags & 0x20)) {
202  m_saveOptions |= PasswordFileSaveFlags::Compression;
203  }
204  ivUsed = flags & 0x40;
205  } else {
206  if ((decrypterUsed = m_version >= 0x1U)) {
207  m_saveOptions |= PasswordFileSaveFlags::Encryption;
208  }
209  compressionUsed = false;
210  ivUsed = m_version == 0x2U;
211  }
212 
213  // skip extended header
214  // (the extended header might be used in further versions to
215  // add additional information without breaking compatibility)
216  if (m_version >= 0x4U) {
217  std::uint16_t extendedHeaderSize = m_freader.readUInt16BE();
218  m_extendedHeader = m_freader.readString(extendedHeaderSize);
219  } else {
220  m_extendedHeader.clear();
221  }
222 
223  // get length
224  const auto headerSize = static_cast<size_t>(m_file.tellg());
225  m_file.seekg(0, ios_base::end);
226  auto remainingSize = static_cast<size_t>(m_file.tellg()) - headerSize;
227  m_file.seekg(static_cast<streamoff>(headerSize), ios_base::beg);
228 
229  // read hash count
230  uint32_t hashCount = 0U;
231  if ((m_saveOptions & PasswordFileSaveFlags::PasswordHashing) && decrypterUsed) {
232  if (remainingSize < 4) {
233  throw ParsingException("Hash count truncated.");
234  }
235  hashCount = m_freader.readUInt32BE();
236  remainingSize -= 4;
237  }
238 
239  // read IV
240  unsigned char iv[aes256cbcIvSize] = { 0 };
241  if (decrypterUsed && ivUsed) {
242  if (remainingSize < aes256cbcIvSize) {
243  throw ParsingException("Initiation vector is truncated.");
244  }
245  m_file.read(reinterpret_cast<char *>(iv), aes256cbcIvSize);
246  remainingSize -= aes256cbcIvSize;
247  }
248  if (!remainingSize) {
249  throw ParsingException("No contents found.");
250  }
251 
252  // decrypt contents
253  vector<char> rawData;
254  m_freader.read(rawData, static_cast<streamoff>(remainingSize));
255  vector<char> decryptedData;
256  if (decrypterUsed) {
257  if (remainingSize > numeric_limits<int>::max()) {
258  throw CryptoException("Size exceeds limit.");
259  }
260 
261  // prepare password
263  if (hashCount) {
264  // hash the password as often as it has been hashed when writing the file
265  password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
266  for (uint32_t i = 1; i < hashCount; ++i) {
268  }
269  } else {
270  m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
271  }
272 
273  // initiate ctx, decrypt data
274  EVP_CIPHER_CTX *ctx = nullptr;
275  decryptedData.resize(remainingSize + 32);
276  int outlen1, outlen2;
277  if ((ctx = EVP_CIPHER_CTX_new()) == nullptr || EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
278  || EVP_DecryptUpdate(ctx, reinterpret_cast<unsigned char *>(decryptedData.data()), &outlen1,
279  reinterpret_cast<unsigned char *>(rawData.data()), static_cast<int>(remainingSize))
280  != 1
281  || EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(decryptedData.data()) + outlen1, &outlen2) != 1) {
282  // handle decryption error
283  if (ctx) {
284  EVP_CIPHER_CTX_free(ctx);
285  }
286  string msg;
287  auto errorCode = ERR_get_error();
288  while (errorCode) {
289  if (!msg.empty()) {
290  msg += "\n";
291  }
292  msg += ERR_error_string(errorCode, nullptr);
293  errorCode = ERR_get_error();
294  }
295  throw CryptoException(move(msg));
296  }
297 
298  if (ctx) {
299  EVP_CIPHER_CTX_free(ctx);
300  }
301  const auto decryptedSize = outlen1 + outlen2;
302  if (decryptedSize < 0) {
303  throw CryptoException("Decrypted size is negative.");
304  }
305  remainingSize = static_cast<size_t>(decryptedSize);
306  if (!remainingSize) {
307  throw ParsingException("Decrypted buffer is empty.");
308  }
309 
310  } else {
311  // use raw data directly if not encrypted
312  decryptedData.swap(rawData);
313  }
314 
315  // decompress
316  if (compressionUsed) {
317  if (remainingSize < 8) {
318  throw ParsingException("File is truncated (decompressed size expected).");
319  }
320  if (remainingSize > numeric_limits<uLongf>::max()) {
321  throw CryptoException("Size exceeds limit.");
322  }
323  const auto rawDecompressedSize = LE::toUInt64(decryptedData.data());
324  if (rawDecompressedSize > numeric_limits<uLongf>::max()) {
325  throw ParsingException("Decompressed size exceeds limit.");
326  }
327  auto decompressedSize = static_cast<uLongf>(rawDecompressedSize);
328  rawData.resize(decompressedSize);
329  switch (uncompress(reinterpret_cast<Bytef *>(rawData.data()), &decompressedSize, reinterpret_cast<Bytef *>(decryptedData.data() + 8),
330  static_cast<uLongf>(remainingSize - 8))) {
331  case Z_MEM_ERROR:
332  throw ParsingException("Decompressing failed. The source buffer was too small.");
333  case Z_BUF_ERROR:
334  throw ParsingException("Decompressing failed. The destination buffer was too small.");
335  case Z_DATA_ERROR:
336  throw ParsingException("Decompressing failed. The input data was corrupted or incomplete.");
337  case Z_OK:
338  decryptedData.swap(rawData);
339  remainingSize = decompressedSize;
340  }
341  }
342  if (!remainingSize) {
343  throw ParsingException("Decompressed buffer is empty.");
344  }
345 
346  // parse contents
347  stringstream decryptedStream(stringstream::in | stringstream::out | stringstream::binary);
348  decryptedStream.exceptions(ios_base::failbit | ios_base::badbit);
349  try {
350 #ifdef _LIBCPP_VERSION
351  decryptedStream.write(decryptedData.data(), static_cast<streamsize>(remainingSize));
352 #else
353  decryptedStream.rdbuf()->pubsetbuf(decryptedData.data(), static_cast<streamsize>(remainingSize));
354 #endif
355  if (m_version >= 0x5u) {
356  BinaryReader reader(&decryptedStream);
357  const auto extendedHeaderSize = reader.readUInt16BE();
358  m_encryptedExtendedHeader = reader.readString(extendedHeaderSize);
359  } else {
360  m_encryptedExtendedHeader.clear();
361  }
362  m_rootEntry.reset(new NodeEntry(decryptedStream));
363  } catch (const std::ios_base::failure &failure) {
364  if (decryptedStream.eof()) {
365  throw ParsingException("The file seems to be truncated.");
366  }
367  throw ParsingException(argsToString("An IO error occurred when reading internal buffer: ", failure.what()));
368  }
369 }
370 
376 {
378  return 0x6U; // password hashing requires at least version 6
379  } else if (!m_encryptedExtendedHeader.empty()) {
380  return 0x5U; // encrypted extended header requires at least version 5
381  } else if (!m_extendedHeader.empty()) {
382  return 0x4U; // regular extended header requires at least version 4
383  }
384  return 0x3U; // lowest supported version by the serializer
385 }
386 
395 {
396  if (!m_rootEntry) {
397  throw runtime_error("Root entry has not been created.");
398  }
399 
400  // use already opened and writable file; otherwise re-open the file
401  if (m_file.good() && m_file.is_open() && (m_file.flags() & ios_base::out)) {
402  m_file.seekp(0);
403  } else {
404  m_file.clear();
405  if (m_file.is_open()) {
406  m_file.close();
407  }
408  try {
409  m_file.open(m_path, ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary);
410  } catch (const ios_base::failure &) {
411  // try to create a new file if configured via \a options
413  throw;
414  }
415  m_file.open(m_path, ios_base::out | ios_base::trunc | ios_base::binary);
416  }
417  }
418 
419  write(options);
420  m_file.flush();
421 }
422 
431 {
432  if (!m_rootEntry) {
433  throw runtime_error("Root entry has not been created.");
434  }
435 
436  // write magic number
437  m_fwriter.writeUInt32LE(0x7770616DU);
438 
439  // write version
440  const auto version = mininumVersion(options);
441  m_fwriter.writeUInt32LE(version);
442 
443  // write flags
444  std::uint8_t flags = 0x00;
445  if (options & PasswordFileSaveFlags::Encryption) {
446  flags |= 0x80 | 0x40;
447  }
448  if (options & PasswordFileSaveFlags::Compression) {
449  flags |= 0x20;
450  }
451  m_fwriter.writeByte(flags);
452 
453  // write extened header
454  if (version >= 0x4U) {
455  if (m_extendedHeader.size() > numeric_limits<std::uint16_t>::max()) {
456  throw runtime_error("Extended header exceeds maximum size.");
457  }
458  m_fwriter.writeUInt16BE(static_cast<std::uint16_t>(m_extendedHeader.size()));
459  m_fwriter.writeString(m_extendedHeader);
460  }
461 
462  // serialize root entry and descendants
463  stringstream buffstr(stringstream::in | stringstream::out | stringstream::binary);
464  buffstr.exceptions(ios_base::failbit | ios_base::badbit);
465 
466  // write encrypted extened header
467  if (version >= 0x5U) {
468  if (m_encryptedExtendedHeader.size() > numeric_limits<std::uint16_t>::max()) {
469  throw runtime_error("Encrypted extended header exceeds maximum size.");
470  }
471  BinaryWriter buffstrWriter(&buffstr);
472  buffstrWriter.writeUInt16BE(static_cast<std::uint16_t>(m_encryptedExtendedHeader.size()));
473  buffstrWriter.writeString(m_encryptedExtendedHeader);
474  }
475  m_rootEntry->make(buffstr);
476  buffstr.seekp(0, ios_base::end);
477  auto size = static_cast<size_t>(buffstr.tellp());
478 
479  // write the data to a buffer
480  buffstr.seekg(0);
481  vector<char> decryptedData(size, 0);
482  buffstr.read(decryptedData.data(), static_cast<streamoff>(size));
483  vector<char> encryptedData;
484 
485  // compress data
486  if (options & PasswordFileSaveFlags::Compression) {
487  uLongf compressedSize = compressBound(size);
488  encryptedData.resize(8 + compressedSize);
489  LE::getBytes(static_cast<std::uint64_t>(size), encryptedData.data());
490  switch (
491  compress(reinterpret_cast<Bytef *>(encryptedData.data() + 8), &compressedSize, reinterpret_cast<Bytef *>(decryptedData.data()), size)) {
492  case Z_MEM_ERROR:
493  throw runtime_error("Compressing failed. The source buffer was too small.");
494  case Z_BUF_ERROR:
495  throw runtime_error("Compressing failed. The destination buffer was too small.");
496  case Z_OK:
497  encryptedData.swap(decryptedData); // decompression successful
498  size = 8 + compressedSize;
499  }
500  }
501 
502  if (size > numeric_limits<int>::max()) {
503  throw CryptoException("size exceeds limit");
504  }
505 
506  // write data without encryption
507  if (!(options & PasswordFileSaveFlags::Encryption)) {
508  // write data to file
509  m_file.write(decryptedData.data(), static_cast<streamsize>(size));
510  m_file.flush();
511  return;
512  }
513 
514  // prepare password
516  const uint32_t hashCount = (options & PasswordFileSaveFlags::PasswordHashing) ? Util::OpenSsl::generateRandomNumber(1, 100) : 0u;
517  if (hashCount) {
518  // hash password a few times
519  password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
520  for (uint32_t i = 1; i < hashCount; ++i) {
522  }
523  } else {
524  m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
525  }
526 
527  // initiate ctx, encrypt data
528  EVP_CIPHER_CTX *ctx = nullptr;
529  unsigned char iv[aes256cbcIvSize];
530  int outlen1, outlen2;
531  encryptedData.resize(size + 32);
532  if (RAND_bytes(iv, aes256cbcIvSize) != 1 || (ctx = EVP_CIPHER_CTX_new()) == nullptr
533  || EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
534  || EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()), &outlen1,
535  reinterpret_cast<unsigned char *>(decryptedData.data()), static_cast<int>(size))
536  != 1
537  || EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()) + outlen1, &outlen2) != 1) {
538  // handle encryption error
539  if (ctx) {
540  EVP_CIPHER_CTX_free(ctx);
541  }
542  string msg;
543  auto errorCode = ERR_get_error();
544  while (errorCode) {
545  if (!msg.empty()) {
546  msg += "\n";
547  }
548  msg += ERR_error_string(errorCode, nullptr);
549  errorCode = ERR_get_error();
550  }
551  throw CryptoException(move(msg));
552  }
553 
554  if (ctx) {
555  EVP_CIPHER_CTX_free(ctx);
556  }
557 
558  // write encrypted data to file
559  if (version >= 0x6U) {
560  m_fwriter.writeUInt32BE(hashCount);
561  }
562  m_file.write(reinterpret_cast<char *>(iv), aes256cbcIvSize);
563  m_file.write(encryptedData.data(), static_cast<streamsize>(outlen1 + outlen2));
564  m_file.flush();
565 }
566 
571 {
572  m_rootEntry.reset();
573 }
574 
579 {
580  close();
581  clearPath();
582  clearPassword();
583  clearEntries();
584  m_openOptions = PasswordFileOpenFlags::None;
585  m_extendedHeader.clear();
586  m_encryptedExtendedHeader.clear();
587 }
588 
595 void PasswordFile::exportToTextfile(const string &targetPath) const
596 {
597  if (!m_rootEntry) {
598  throw runtime_error("Root entry has not been created.");
599  }
600  fstream output(targetPath.c_str(), ios_base::out);
601  const auto printIndention = [&output](int level) {
602  for (int i = 0; i < level; ++i) {
603  output << " ";
604  }
605  };
606  function<void(const Entry *entry, int level)> printNode;
607  printNode = [&output, &printNode, &printIndention](const Entry *entry, int level) {
608  printIndention(level);
609  output << " - " << entry->label() << endl;
610  switch (entry->type()) {
611  case EntryType::Node:
612  for (const Entry *child : static_cast<const NodeEntry *>(entry)->children()) {
613  printNode(child, level + 1);
614  }
615  break;
616  case EntryType::Account:
617  for (const Field &field : static_cast<const AccountEntry *>(entry)->fields()) {
618  printIndention(level);
619  output << " " << field.name();
620  for (auto i = field.name().length(); i < 15; ++i) {
621  output << ' ';
622  }
623  output << field.value() << endl;
624  }
625  }
626  };
627  printNode(m_rootEntry.get(), 0);
628  output.close();
629 }
630 
636 {
637  if (!isOpen()) {
638  open();
639  }
640 
641  // skip if the current file is empty anyways
642  if (!size()) {
643  return;
644  }
645 
646  m_file.seekg(0);
647  fstream backupFile(m_path + ".backup", ios::out | ios::trunc | ios::binary);
648  backupFile.exceptions(ios_base::failbit | ios_base::badbit);
649  backupFile << m_file.rdbuf();
650  backupFile.close();
651 }
652 
659 {
660  return m_rootEntry != nullptr;
661 }
662 
667 {
668  return m_rootEntry.get();
669 }
670 
675 {
676  return m_rootEntry.get();
677 }
678 
683 {
684  if (m_file.is_open()) {
685  m_file.close();
686  }
687  m_file.clear();
688 }
689 
693 void PasswordFile::setPath(const string &value)
694 {
695  close();
696  m_path = value;
697 
698  // support "file://" protocol
699  if (startsWith(m_path, "file:")) {
700  m_path = m_path.substr(5);
701  }
702 }
703 
710 {
711  if (!isOpen()) {
712  return false;
713  }
714  m_file.seekg(0);
715 
716  // check magic number
717  if (m_freader.readUInt32LE() != 0x7770616DU) {
718  return false;
719  }
720 
721  // check version
722  const auto version = m_freader.readUInt32LE();
723  if (version == 0x1U || version == 0x2U) {
724  return true;
725  } else if (version >= 0x3U) {
726  return m_freader.readByte() & 0x80;
727  } else {
728  return false;
729  }
730 }
731 
736 {
737  if (!isOpen()) {
738  return 0;
739  }
740  m_file.seekg(0, ios::end);
741  return static_cast<size_t>(m_file.tellg());
742 }
743 
748 {
749  string result = "<table>";
750  if (!m_path.empty()) {
751  result += argsToString("<tr><td>Path:</td><td>", m_path, "</td></tr>");
752  }
753  result += argsToString("<tr><td>Version:</td><td>", m_version, "</td></tr>");
754  const auto minVersion = mininumVersion(saveOptions);
755  if (m_version != minVersion) {
756  result += argsToString("<tr><td></td><td>(on disk, after saving: ", minVersion, ")</td></tr>");
757  }
758  result += argsToString("<tr><td>Features:</td><td>", flagsToString(m_saveOptions), "</td></tr>");
759  if (m_saveOptions != saveOptions) {
760  result += argsToString("<tr><td></td><td>(on disk, after saving: ", flagsToString(saveOptions), ")</td></tr>");
761  }
762  const auto stats = m_rootEntry ? m_rootEntry->computeStatistics() : EntryStatistics();
763  result += argsToString("<tr><td>Number of categories:</td><td>", stats.nodeCount, "</td></tr><tr><td>Number of accounts:</td><td>",
764  stats.accountCount, "</td></tr><tr><td>Number of fields:</td><td>", stats.fieldCount, "</td></tr></table>");
765  return result;
766 }
767 
772 {
773  vector<string> options;
774  if (flags & PasswordFileOpenFlags::ReadOnly) {
775  options.emplace_back("read-only");
776  }
777  if (options.empty()) {
778  options.emplace_back("none");
779  }
780  return joinStrings(options, ", ");
781 }
782 
787 {
788  vector<string> options;
789  options.reserve(3);
790  if (flags & PasswordFileSaveFlags::Encryption) {
791  options.emplace_back("encryption");
792  }
794  options.emplace_back("compression");
795  }
797  options.emplace_back("password hashing");
798  }
799  if (options.empty()) {
800  options.emplace_back("none");
801  }
802  return joinStrings(options, ", ");
803 }
804 
805 } // namespace Io
Io::NodeEntry
The NodeEntry class acts as parent for other entries.
Definition: entry.h:114
Io::CryptoException
The exception that is thrown when an encryption/decryption error occurs.
Definition: cryptoexception.h:11
Io::PasswordFile::opened
void opened()
Handles the file being opened.
Definition: passwordfile.cpp:132
Io::ParsingException
The exception that is thrown when a parsing error occurs.
Definition: parsingexception.h:11
Io::PasswordFileSaveFlags::Encryption
@ Encryption
Io::PasswordFile
The PasswordFile class holds account information in the form of Entry and Field instances and provide...
Definition: passwordfile.h:40
Io::PasswordFileOpenFlags
PasswordFileOpenFlags
Definition: passwordfile.h:21
Io::PasswordFile::password
const std::string & password() const
Returns the current password.
Definition: passwordfile.h:125
Util::OpenSsl::Sha256Sum
Definition: openssl.h:13
Io::PasswordFile::saveOptions
PasswordFileSaveFlags saveOptions() const
Returns the save options used the last time when saving the file.
Definition: passwordfile.h:214
parsingexception.h
Io::PasswordFile::save
void save(PasswordFileSaveFlags options=PasswordFileSaveFlags::Default)
Writes the current root entry to the file under path() replacing its previous contents.
Definition: passwordfile.cpp:394
Io::PasswordFileSaveFlags::None
@ None
Io::PasswordFileSaveFlags
PasswordFileSaveFlags
Definition: passwordfile.h:29
Io::PasswordFile::clear
void clear()
Closes the file if opened.
Definition: passwordfile.cpp:578
Util::OpenSsl::Sha256Sum::size
static constexpr std::size_t size
Definition: openssl.h:14
Io::PasswordFile::exportToTextfile
void exportToTextfile(const std::string &targetPath) const
Writes the current root entry to a plain text file.
Definition: passwordfile.cpp:595
Io::PasswordFile::clearPath
void clearPath()
Clears the current path.
Definition: passwordfile.h:116
Io::Entry
Instances of the Entry class form a hierarchic data strucutre used to store account information.
Definition: entry.h:30
Io::PasswordFileSaveFlags::PasswordHashing
@ PasswordHashing
Io::PasswordFile::rootEntry
const NodeEntry * rootEntry() const
Returns the root entry if present or nullptr otherwise.
Definition: passwordfile.cpp:666
Io::PasswordFile::load
void load()
Reads the contents of the file.
Definition: passwordfile.cpp:173
Io::PasswordFileOpenFlags::ReadOnly
@ ReadOnly
Io::aes256cbcIvSize
const unsigned int aes256cbcIvSize
Definition: passwordfile.cpp:31
Io::EntryType::Node
@ Node
Io::PasswordFile::create
void create()
Creates the file.
Definition: passwordfile.cpp:156
entry.h
Io::PasswordFile::isOpen
bool isOpen() const
Returns an indication whether the file is open.
Definition: passwordfile.h:157
Io::PasswordFile::mininumVersion
std::uint32_t mininumVersion(PasswordFileSaveFlags options) const
Returns the minimum file version required to write the current instance with the specified options.
Definition: passwordfile.cpp:375
Io::PasswordFile::~PasswordFile
~PasswordFile()
Closes the file if still opened and destroys the instance.
Definition: passwordfile.cpp:107
Io::PasswordFile::setPassword
void setPassword(const std::string &password)
Sets the current password.
Definition: passwordfile.h:133
Io::PasswordFile::close
void close()
Closes the file if currently opened.
Definition: passwordfile.cpp:682
passwordfile.h
Io::PasswordFile::generateRootEntry
void generateRootEntry()
Generates a new root entry for the file.
Definition: passwordfile.cpp:145
Io::PasswordFile::setPath
void setPath(const std::string &value)
Sets the current file path.
Definition: passwordfile.cpp:693
cryptoexception.h
Io
Contains all IO related classes.
Definition: cryptoexception.h:9
Util::OpenSsl::computeSha256Sum
PASSWORD_FILE_EXPORT Sha256Sum computeSha256Sum(const unsigned char *buffer, std::size_t size)
Computes a SHA-256 sum using OpenSSL.
Definition: openssl.cpp:50
Io::PasswordFile::version
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
Io::EntryStatistics
Definition: entry.h:22
CppUtilities
Definition: utils.h:12
Io::PasswordFile::size
std::size_t size()
Returns the size of the file if the file is open; otherwise returns zero.
Definition: passwordfile.cpp:735
Io::PasswordFile::doBackup
void doBackup()
Creates a backup of the file.
Definition: passwordfile.cpp:635
Io::Field
The Field class holds field information which consists of a name and a value and is able to serialize...
Definition: field.h:15
Io::PasswordFile::open
void open(PasswordFileOpenFlags options=PasswordFileOpenFlags::Default)
Opens the file.
Definition: passwordfile.cpp:115
Io::PasswordFileOpenFlags::None
@ None
Io::PasswordFile::clearEntries
void clearEntries()
Removes the root element if one is present.
Definition: passwordfile.cpp:570
Io::PasswordFile::path
const std::string & path() const
Returns the current file path.
Definition: passwordfile.h:108
Io::PasswordFile::PasswordFile
PasswordFile()
Constructs a new password file.
Definition: passwordfile.cpp:42
Io::PasswordFile::summary
std::string summary(PasswordFileSaveFlags saveOptions) const
Returns a summary about the file (version, used features, statistics).
Definition: passwordfile.cpp:747
Io::PasswordFile::clearPassword
void clearPassword()
Clears the current password.
Definition: passwordfile.h:149
Io::PasswordFile::hasRootEntry
bool hasRootEntry() const
Returns an indication whether a root entry is present.
Definition: passwordfile.cpp:658
Io::flagsToString
PASSWORD_FILE_EXPORT std::string flagsToString(PasswordFileOpenFlags flags)
Returns a comma-separated string for the specified flags.
Definition: passwordfile.cpp:771
Io::PasswordFile::isEncryptionUsed
bool isEncryptionUsed()
Returns an indication whether encryption is used and the file is open; returns always false otherwise...
Definition: passwordfile.cpp:709
Io::PasswordFileSaveFlags::Compression
@ Compression
Io::AccountEntry
The exception that is thrown when a parsing error occurs.
Definition: entry.h:170
Io::PasswordFile::write
void write(PasswordFileSaveFlags options=PasswordFileSaveFlags::Default)
Writes the current root entry to the file which is assumed to be opened and writeable.
Definition: passwordfile.cpp:430
Io::EntryType::Account
@ Account
Io::PasswordFileSaveFlags::AllowToCreateNewFile
@ AllowToCreateNewFile
Util::OpenSsl::generateRandomNumber
PASSWORD_FILE_EXPORT std::uint32_t generateRandomNumber(std::uint32_t min, std::uint32_t max)