Passwordfile library  5.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 
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  return;
511  }
512 
513  // prepare password
515  const uint32_t hashCount = (options & PasswordFileSaveFlags::PasswordHashing) ? Util::OpenSsl::generateRandomNumber(1, 100) : 0u;
516  if (hashCount) {
517  // hash password a few times
518  password = Util::OpenSsl::computeSha256Sum(reinterpret_cast<unsigned const char *>(m_password.data()), m_password.size());
519  for (uint32_t i = 1; i < hashCount; ++i) {
521  }
522  } else {
523  m_password.copy(reinterpret_cast<char *>(password.data), Util::OpenSsl::Sha256Sum::size);
524  }
525 
526  // initiate ctx, encrypt data
527  EVP_CIPHER_CTX *ctx = nullptr;
528  unsigned char iv[aes256cbcIvSize];
529  int outlen1, outlen2;
530  encryptedData.resize(size + 32);
531  if (RAND_bytes(iv, aes256cbcIvSize) != 1 || (ctx = EVP_CIPHER_CTX_new()) == nullptr
532  || EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, password.data, iv) != 1
533  || EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()), &outlen1,
534  reinterpret_cast<unsigned char *>(decryptedData.data()), static_cast<int>(size))
535  != 1
536  || EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()) + outlen1, &outlen2) != 1) {
537  // handle encryption error
538  if (ctx) {
539  EVP_CIPHER_CTX_free(ctx);
540  }
541  string msg;
542  auto errorCode = ERR_get_error();
543  while (errorCode) {
544  if (!msg.empty()) {
545  msg += "\n";
546  }
547  msg += ERR_error_string(errorCode, nullptr);
548  errorCode = ERR_get_error();
549  }
550  throw CryptoException(move(msg));
551  }
552 
553  if (ctx) {
554  EVP_CIPHER_CTX_free(ctx);
555  }
556 
557  // write encrypted data to file
558  if (version >= 0x6U) {
559  m_fwriter.writeUInt32BE(hashCount);
560  }
561  m_file.write(reinterpret_cast<char *>(iv), aes256cbcIvSize);
562  m_file.write(encryptedData.data(), static_cast<streamsize>(outlen1 + outlen2));
563 }
564 
569 {
570  m_rootEntry.reset();
571 }
572 
577 {
578  close();
579  clearPath();
580  clearPassword();
581  clearEntries();
582  m_openOptions = PasswordFileOpenFlags::None;
583  m_extendedHeader.clear();
584  m_encryptedExtendedHeader.clear();
585 }
586 
593 void PasswordFile::exportToTextfile(const string &targetPath) const
594 {
595  if (!m_rootEntry) {
596  throw runtime_error("Root entry has not been created.");
597  }
598  fstream output(targetPath.c_str(), ios_base::out);
599  const auto printIndention = [&output](int level) {
600  for (int i = 0; i < level; ++i) {
601  output << " ";
602  }
603  };
604  function<void(const Entry *entry, int level)> printNode;
605  printNode = [&output, &printNode, &printIndention](const Entry *entry, int level) {
606  printIndention(level);
607  output << " - " << entry->label() << endl;
608  switch (entry->type()) {
609  case EntryType::Node:
610  for (const Entry *child : static_cast<const NodeEntry *>(entry)->children()) {
611  printNode(child, level + 1);
612  }
613  break;
614  case EntryType::Account:
615  for (const Field &field : static_cast<const AccountEntry *>(entry)->fields()) {
616  printIndention(level);
617  output << " " << field.name();
618  for (auto i = field.name().length(); i < 15; ++i) {
619  output << ' ';
620  }
621  output << field.value() << endl;
622  }
623  }
624  };
625  printNode(m_rootEntry.get(), 0);
626  output.close();
627 }
628 
634 {
635  if (!isOpen()) {
636  open();
637  }
638 
639  // skip if the current file is empty anyways
640  if (!size()) {
641  return;
642  }
643 
644  m_file.seekg(0);
645  fstream backupFile(m_path + ".backup", ios::out | ios::trunc | ios::binary);
646  backupFile.exceptions(ios_base::failbit | ios_base::badbit);
647  backupFile << m_file.rdbuf();
648  backupFile.close();
649 }
650 
657 {
658  return m_rootEntry != nullptr;
659 }
660 
665 {
666  return m_rootEntry.get();
667 }
668 
673 {
674  return m_rootEntry.get();
675 }
676 
681 {
682  if (m_file.is_open()) {
683  m_file.close();
684  }
685  m_file.clear();
686 }
687 
691 void PasswordFile::setPath(const string &value)
692 {
693  close();
694  m_path = value;
695 
696  // support "file://" protocol
697  if (startsWith(m_path, "file:")) {
698  m_path = m_path.substr(5);
699  }
700 }
701 
708 {
709  if (!isOpen()) {
710  return false;
711  }
712  m_file.seekg(0);
713 
714  // check magic number
715  if (m_freader.readUInt32LE() != 0x7770616DU) {
716  return false;
717  }
718 
719  // check version
720  const auto version = m_freader.readUInt32LE();
721  if (version == 0x1U || version == 0x2U) {
722  return true;
723  } else if (version >= 0x3U) {
724  return m_freader.readByte() & 0x80;
725  } else {
726  return false;
727  }
728 }
729 
734 {
735  if (!isOpen()) {
736  return 0;
737  }
738  m_file.seekg(0, ios::end);
739  return static_cast<size_t>(m_file.tellg());
740 }
741 
746 {
747  string result = "<table>";
748  if (!m_path.empty()) {
749  result += argsToString("<tr><td>Path:</td><td>", m_path, "</td></tr>");
750  }
751  result += argsToString("<tr><td>Version:</td><td>", m_version, "</td></tr>");
752  const auto minVersion = mininumVersion(saveOptions);
753  if (m_version != minVersion) {
754  result += argsToString("<tr><td></td><td>(on disk, after saving: ", minVersion, ")</td></tr>");
755  }
756  result += argsToString("<tr><td>Features:</td><td>", flagsToString(m_saveOptions), "</td></tr>");
757  if (m_saveOptions != saveOptions) {
758  result += argsToString("<tr><td></td><td>(on disk, after saving: ", flagsToString(saveOptions), ")</td></tr>");
759  }
760  const auto stats = m_rootEntry ? m_rootEntry->computeStatistics() : EntryStatistics();
761  result += argsToString("<tr><td>Number of categories:</td><td>", stats.nodeCount, "</td></tr><tr><td>Number of accounts:</td><td>",
762  stats.accountCount, "</td></tr><tr><td>Number of fields:</td><td>", stats.fieldCount, "</td></tr></table>");
763  return result;
764 }
765 
770 {
771  vector<string> options;
772  if (flags & PasswordFileOpenFlags::ReadOnly) {
773  options.emplace_back("read-only");
774  }
775  if (options.empty()) {
776  options.emplace_back("none");
777  }
778  return joinStrings(options, ", ");
779 }
780 
785 {
786  vector<string> options;
787  options.reserve(3);
788  if (flags & PasswordFileSaveFlags::Encryption) {
789  options.emplace_back("encryption");
790  }
792  options.emplace_back("compression");
793  }
795  options.emplace_back("password hashing");
796  }
797  if (options.empty()) {
798  options.emplace_back("none");
799  }
800  return joinStrings(options, ", ");
801 }
802 
803 } // 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
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
PasswordFileSaveFlags
Definition: passwordfile.h:29
Io::PasswordFile::clear
void clear()
Closes the file if opened.
Definition: passwordfile.cpp:576
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:593
Io::PasswordFile::clearPath
void clearPath()
Clears the current path.
Definition: passwordfile.h:116
Io::PasswordFile::rootEntry
const NodeEntry * rootEntry() const
Returns the root entry if present or nullptr otherwise.
Definition: passwordfile.cpp:664
Io::Entry
Instances of the Entry class form a hierarchic data strucutre used to store account information.
Definition: entry.h:30
Io::PasswordFileSaveFlags::PasswordHashing
Io::PasswordFile::load
void load()
Reads the contents of the file.
Definition: passwordfile.cpp:173
Io::PasswordFileOpenFlags::ReadOnly
Io::aes256cbcIvSize
const unsigned int aes256cbcIvSize
Definition: passwordfile.cpp:31
Io::EntryType::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:680
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:691
cryptoexception.h
Io
Contains all IO related classes.
Definition: cryptoexception.h:9
Util::OpenSsl::computeSha256Sum
Sha256Sum PASSWORD_FILE_EXPORT 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:733
Io::PasswordFile::doBackup
void doBackup()
Creates a backup of the file.
Definition: passwordfile.cpp:633
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
Io::PasswordFile::clearEntries
void clearEntries()
Removes the root element if one is present.
Definition: passwordfile.cpp:568
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:745
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:656
Io::flagsToString
std::string PASSWORD_FILE_EXPORT flagsToString(PasswordFileOpenFlags flags)
Returns a comma-separated string for the specified flags.
Definition: passwordfile.cpp:769
Io::PasswordFile::isEncryptionUsed
bool isEncryptionUsed()
Returns an indication whether encryption is used and the file is open; returns always false otherwise...
Definition: passwordfile.cpp:707
Util::OpenSsl::generateRandomNumber
std::uint32_t PASSWORD_FILE_EXPORT generateRandomNumber(std::uint32_t min, std::uint32_t max)
Io::PasswordFileSaveFlags::Compression
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
Io::PasswordFileSaveFlags::AllowToCreateNewFile