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