Improve coding style in PasswordFile

This commit is contained in:
Martchus 2018-09-08 19:38:15 +02:00
parent e6f66ce932
commit 51442d0b68
1 changed files with 70 additions and 61 deletions

View File

@ -15,10 +15,10 @@
#include <cstring> #include <cstring>
#include <functional> #include <functional>
#include <limits>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <streambuf> #include <streambuf>
#include <limits>
using namespace std; using namespace std;
using namespace IoUtilities; using namespace IoUtilities;
@ -159,20 +159,20 @@ void PasswordFile::load()
open(); open();
} }
m_file.seekg(0); m_file.seekg(0);
// check magic number // check magic number
if (m_freader.readUInt32LE() != 0x7770616DU) { if (m_freader.readUInt32LE() != 0x7770616DU) {
throw ParsingException("Signature not present."); throw ParsingException("Signature not present.");
} }
// check version and flags (used in version 0x3 only) // check version and flags (used in version 0x3 only)
uint32 version = m_freader.readUInt32LE(); const auto version = m_freader.readUInt32LE();
if (version != 0x0U && version != 0x1U && version != 0x2U && version != 0x3U && version != 0x4U && version != 0x5U) { if (version != 0x0U && version != 0x1U && version != 0x2U && version != 0x3U && version != 0x4U && version != 0x5U) {
throw ParsingException("Version is unknown."); throw ParsingException("Version is unknown.");
} }
bool decrypterUsed; bool decrypterUsed, ivUsed, compressionUsed;
bool ivUsed;
bool compressionUsed;
if (version == 0x3U) { if (version == 0x3U) {
byte flags = m_freader.readByte(); const auto flags = m_freader.readByte();
decrypterUsed = flags & 0x80; decrypterUsed = flags & 0x80;
ivUsed = flags & 0x40; ivUsed = flags & 0x40;
compressionUsed = flags & 0x20; compressionUsed = flags & 0x20;
@ -181,50 +181,54 @@ void PasswordFile::load()
ivUsed = version == 0x2U; ivUsed = version == 0x2U;
compressionUsed = false; compressionUsed = false;
} }
// skip extended header // skip extended header
// the extended header might be used in further versions to // (the extended header might be used in further versions to
// add additional information without breaking compatibility // add additional information without breaking compatibility)
if (version >= 0x4U) { if (version >= 0x4U) {
uint16 extendedHeaderSize = m_freader.readUInt16BE(); uint16 extendedHeaderSize = m_freader.readUInt16BE();
m_extendedHeader = m_freader.readString(extendedHeaderSize); m_extendedHeader = m_freader.readString(extendedHeaderSize);
} }
// get length // get length
auto headerSize = static_cast<size_t>(m_file.tellg()); const auto headerSize = static_cast<size_t>(m_file.tellg());
m_file.seekg(0, ios_base::end); m_file.seekg(0, ios_base::end);
auto size = static_cast<size_t>(m_file.tellg()); auto remainingSize = static_cast<size_t>(m_file.tellg()) - headerSize;
m_file.seekg(static_cast<streamoff>(headerSize), ios_base::beg); m_file.seekg(static_cast<streamoff>(headerSize), ios_base::beg);
size -= headerSize;
// read file // read file
unsigned char iv[aes256cbcIvSize] = { 0 }; unsigned char iv[aes256cbcIvSize] = { 0 };
if (decrypterUsed && ivUsed) { if (decrypterUsed && ivUsed) {
if (size < aes256cbcIvSize) { if (remainingSize < aes256cbcIvSize) {
throw ParsingException("Initiation vector not present."); throw ParsingException("Initiation vector is truncated.");
} }
m_file.read(reinterpret_cast<char *>(iv), aes256cbcIvSize); m_file.read(reinterpret_cast<char *>(iv), aes256cbcIvSize);
size -= aes256cbcIvSize; remainingSize -= aes256cbcIvSize;
} }
if (size <= 0) { if (!remainingSize) {
throw ParsingException("No contents found."); throw ParsingException("No contents found.");
} }
// decrypt contents // decrypt contents
vector<char> rawbuff; vector<char> rawData;
m_freader.read(rawbuff, static_cast<streamoff>(size)); m_freader.read(rawData, static_cast<streamoff>(remainingSize));
vector<char> decbuff; vector<char> decryptedData;
if (decrypterUsed) { if (decrypterUsed) {
if (size > numeric_limits<int>::max()) { if (remainingSize > numeric_limits<int>::max()) {
throw CryptoException("Size exceeds limit."); throw CryptoException("Size exceeds limit.");
} }
// initiate ctx // initiate ctx, decrypt data
EVP_CIPHER_CTX *ctx = nullptr; EVP_CIPHER_CTX *ctx = nullptr;
decbuff.resize(size + 32); decryptedData.resize(remainingSize + 32);
int outlen1, outlen2; int outlen1, outlen2;
if ((ctx = EVP_CIPHER_CTX_new()) == nullptr if ((ctx = EVP_CIPHER_CTX_new()) == nullptr
|| EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, reinterpret_cast<unsigned const char *>(m_password), iv) != 1 || EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, reinterpret_cast<unsigned const char *>(m_password), iv) != 1
|| EVP_DecryptUpdate( || EVP_DecryptUpdate(ctx, reinterpret_cast<unsigned char *>(decryptedData.data()), &outlen1,
ctx, reinterpret_cast<unsigned char *>(decbuff.data()), &outlen1, reinterpret_cast<unsigned char *>(rawbuff.data()), static_cast<int>(size)) reinterpret_cast<unsigned char *>(rawData.data()), static_cast<int>(remainingSize))
!= 1 != 1
|| EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(decbuff.data()) + outlen1, &outlen2) != 1) { || EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(decryptedData.data()) + outlen1, &outlen2) != 1) {
// handle decryption error
if (ctx) { if (ctx) {
EVP_CIPHER_CTX_free(ctx); EVP_CIPHER_CTX_free(ctx);
} }
@ -238,28 +242,31 @@ void PasswordFile::load()
errorCode = ERR_get_error(); errorCode = ERR_get_error();
} }
throw CryptoException(msg); throw CryptoException(msg);
} else { // decryption suceeded
if (ctx) {
EVP_CIPHER_CTX_free(ctx);
}
const auto decryptedSize = outlen1 + outlen2;
if (decryptedSize < 0) {
throw CryptoException("Decrypted size is negative.");
}
size = static_cast<size_t>(decryptedSize);
} }
} else { // file is not crypted
decbuff.swap(rawbuff); if (ctx) {
EVP_CIPHER_CTX_free(ctx);
}
const auto decryptedSize = outlen1 + outlen2;
if (decryptedSize < 0) {
throw CryptoException("Decrypted size is negative.");
}
remainingSize = static_cast<size_t>(decryptedSize);
} else {
// use raw data directly if not encrypted
decryptedData.swap(rawData);
} }
// decompress // decompress
if (compressionUsed) { if (compressionUsed) {
if (size < 8) { if (remainingSize < 8) {
throw ParsingException("File is truncated (decompressed size expected)."); throw ParsingException("File is truncated (decompressed size expected).");
} }
uLongf decompressedSize = ConversionUtilities::LE::toUInt64(decbuff.data()); uLongf decompressedSize = ConversionUtilities::LE::toUInt64(decryptedData.data());
rawbuff.resize(decompressedSize); rawData.resize(decompressedSize);
switch (uncompress(reinterpret_cast<Bytef *>(rawbuff.data()), &decompressedSize, reinterpret_cast<Bytef *>(decbuff.data() + 8), switch (uncompress(
size - 8)) { reinterpret_cast<Bytef *>(rawData.data()), &decompressedSize, reinterpret_cast<Bytef *>(decryptedData.data() + 8), remainingSize - 8)) {
case Z_MEM_ERROR: case Z_MEM_ERROR:
throw ParsingException("Decompressing failed. The source buffer was too small."); throw ParsingException("Decompressing failed. The source buffer was too small.");
case Z_BUF_ERROR: case Z_BUF_ERROR:
@ -267,20 +274,21 @@ void PasswordFile::load()
case Z_DATA_ERROR: case Z_DATA_ERROR:
throw ParsingException("Decompressing failed. The input data was corrupted or incomplete."); throw ParsingException("Decompressing failed. The input data was corrupted or incomplete.");
case Z_OK: case Z_OK:
decbuff.swap(rawbuff); // decompression successful decryptedData.swap(rawData);
size = decompressedSize; remainingSize = decompressedSize;
} }
} }
// parse contents // parse contents
stringstream buffstr(stringstream::in | stringstream::out | stringstream::binary); stringstream decryptedStream(stringstream::in | stringstream::out | stringstream::binary);
buffstr.write(decbuff.data(), static_cast<streamsize>(size)); decryptedStream.write(decryptedData.data(), static_cast<streamsize>(remainingSize));
decbuff.resize(0); decryptedData.resize(0);
buffstr.seekg(0, ios_base::beg); decryptedStream.seekg(0, ios_base::beg);
if (version >= 0x5u) { if (version >= 0x5u) {
uint16 extendedHeaderSize = m_freader.readUInt16BE(); const auto extendedHeaderSize = m_freader.readUInt16BE();
m_encryptedExtendedHeader = m_freader.readString(extendedHeaderSize); m_encryptedExtendedHeader = m_freader.readString(extendedHeaderSize);
} }
m_rootEntry.reset(new NodeEntry(buffstr)); m_rootEntry.reset(new NodeEntry(decryptedStream));
} }
/*! /*!
@ -359,22 +367,23 @@ void PasswordFile::write(bool useEncryption, bool useCompression)
// write the data to a buffer // write the data to a buffer
buffstr.seekg(0); buffstr.seekg(0);
vector<char> decbuff(size, 0); vector<char> decryptedData(size, 0);
buffstr.read(decbuff.data(), static_cast<streamoff>(size)); buffstr.read(decryptedData.data(), static_cast<streamoff>(size));
vector<char> encbuff; vector<char> encryptedData;
// compress data // compress data
if (useCompression) { if (useCompression) {
uLongf compressedSize = compressBound(size); uLongf compressedSize = compressBound(size);
encbuff.resize(8 + compressedSize); encryptedData.resize(8 + compressedSize);
ConversionUtilities::LE::getBytes(static_cast<uint64>(size), encbuff.data()); ConversionUtilities::LE::getBytes(static_cast<uint64>(size), encryptedData.data());
switch (compress(reinterpret_cast<Bytef *>(encbuff.data() + 8), &compressedSize, reinterpret_cast<Bytef *>(decbuff.data()), size)) { switch (
compress(reinterpret_cast<Bytef *>(encryptedData.data() + 8), &compressedSize, reinterpret_cast<Bytef *>(decryptedData.data()), size)) {
case Z_MEM_ERROR: case Z_MEM_ERROR:
throw runtime_error("Compressing failed. The source buffer was too small."); throw runtime_error("Compressing failed. The source buffer was too small.");
case Z_BUF_ERROR: case Z_BUF_ERROR:
throw runtime_error("Compressing failed. The destination buffer was too small."); throw runtime_error("Compressing failed. The destination buffer was too small.");
case Z_OK: case Z_OK:
encbuff.swap(decbuff); // decompression successful encryptedData.swap(decryptedData); // decompression successful
size = 8 + compressedSize; size = 8 + compressedSize;
} }
} }
@ -386,7 +395,7 @@ void PasswordFile::write(bool useEncryption, bool useCompression)
// write data without encryption // write data without encryption
if (!useEncryption) { if (!useEncryption) {
// write data to file // write data to file
m_file.write(decbuff.data(), static_cast<streamsize>(size)); m_file.write(decryptedData.data(), static_cast<streamsize>(size));
return; return;
} }
@ -394,13 +403,13 @@ void PasswordFile::write(bool useEncryption, bool useCompression)
EVP_CIPHER_CTX *ctx = nullptr; EVP_CIPHER_CTX *ctx = nullptr;
unsigned char iv[aes256cbcIvSize]; unsigned char iv[aes256cbcIvSize];
int outlen1, outlen2; int outlen1, outlen2;
encbuff.resize(size + 32); encryptedData.resize(size + 32);
if (RAND_bytes(iv, aes256cbcIvSize) != 1 || (ctx = EVP_CIPHER_CTX_new()) == nullptr if (RAND_bytes(iv, aes256cbcIvSize) != 1 || (ctx = EVP_CIPHER_CTX_new()) == nullptr
|| EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, reinterpret_cast<unsigned const char *>(m_password), iv) != 1 || EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, reinterpret_cast<unsigned const char *>(m_password), iv) != 1
|| EVP_EncryptUpdate( || EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()), &outlen1,
ctx, reinterpret_cast<unsigned char *>(encbuff.data()), &outlen1, reinterpret_cast<unsigned char *>(decbuff.data()), static_cast<int>(size)) reinterpret_cast<unsigned char *>(decryptedData.data()), static_cast<int>(size))
!= 1 != 1
|| EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(encbuff.data()) + outlen1, &outlen2) != 1) { || EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(encryptedData.data()) + outlen1, &outlen2) != 1) {
// handle encryption error // handle encryption error
if (ctx) { if (ctx) {
EVP_CIPHER_CTX_free(ctx); EVP_CIPHER_CTX_free(ctx);
@ -423,7 +432,7 @@ void PasswordFile::write(bool useEncryption, bool useCompression)
// write encrypted data to file // write encrypted data to file
m_file.write(reinterpret_cast<char *>(iv), aes256cbcIvSize); m_file.write(reinterpret_cast<char *>(iv), aes256cbcIvSize);
m_file.write(encbuff.data(), static_cast<streamsize>(outlen1 + outlen2)); m_file.write(encryptedData.data(), static_cast<streamsize>(outlen1 + outlen2));
} }
/*! /*!