/*
* Copyright (c) 2016-2020 Belledonne Communications SARL.
*
* This file is part of bctoolbox.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef BCTBX_VFS_ENCRYPTED_HH
#define BCTBX_VFS_ENCRYPTED_HH
#include "bctoolbox/vfs.h"
#include "bctoolbox/exception.hh"
#include
#include
#include
#include "bctoolbox/port.h"
namespace bctoolbox {
/**
* @brief This dedicated exception inherits \ref BctoolboxException.
*
*/
class EvfsException : public BctbxException {
public:
EvfsException() = default;
EvfsException(const std::string &message): BctbxException(message) {}
EvfsException(const char *message): BctbxException(message) {}
virtual ~EvfsException() throw() {}
EvfsException(const EvfsException &other): BctbxException(other) {}
template EvfsException &operator<<(const T &val) {
BctbxException::operator<<(val);
return *this;
}
};
#define EVFS_EXCEPTION EvfsException() << " " << __FILE__ << ":" << __LINE__ << " "
/**
* Virtual File sytem provided
*/
extern BCTBX_PUBLIC bctbx_vfs_t bcEncryptedVfs;
/**
* Provided encryption suites
*/
enum class EncryptionSuite : uint16_t {
unset = 0,/**< no encryption suite selected */
dummy = 1, /**< a test suite, do not use other than for test */
aes256gcm128_sha256 = 2, /**< This module encrypts blocks with AES256GCM and authenticate header using HMAC-sha256 */
plain = 0xFFFF /**< no encryption activated, direct use of standard file system API */
};
/**
* Helper function returning a string holding the suite name
* @param[in] suite the encryption suite as a c++ enum
* @return the suite name in a readable string
*/
const std::string encryptionSuiteString(const EncryptionSuite suite) noexcept;
/* complete declaration follows, we need this one to define the callback type */
class VfsEncryption;
/**
* Define a function prototype to be called at each file opening.
* This function is a static class property, used to retrieve secretMaterial to encrypt/decrypt the file
*/
using EncryptedVfsOpenCb = std::function;
// forward declare this type, store all the encryption data and functions
class VfsEncryptionModule;
/** Store in the bctbx_vfs_file_t userData field an object specific to encryption */
class VfsEncryption {
/* Class properties and method */
private:
static EncryptedVfsOpenCb s_openCallback; /**< a class callback to get secret material at file opening. Implemented as static as it is called by constructor */
public:
/**
* at file opening a callback ask for crypto material, it is class property, set it using this class method
*/
static void openCallbackSet(EncryptedVfsOpenCb cb) noexcept;
static EncryptedVfsOpenCb openCallbackGet() noexcept;
/* Object properties and methods */
private:
uint16_t mVersionNumber; /**< version number of the encryption vfs */
size_t mChunkSize; /**< size of the file chunks payload in bytes : default is 4kB */
size_t rawChunkSizeGet() const noexcept; /** return the size of a chunk including its encryption header, as stored in the raw file */
std::shared_ptr m_module; /**< one of the available encryption module : if nullptr, assume we deal with regular plain file */
size_t mHeaderExtensionSize; /**< header extension size */
const std::string mFilename; /**< the filename as given to the open function */
uint64_t mFileSize; /**< size of the plaintext file */
uint64_t rawFileSizeGet() const noexcept; /**< return the size of the raw file */
uint32_t getChunkIndex(uint64_t offset) const noexcept; /**< return the chunk index where to find the given offset */
size_t getChunkOffset(uint32_t index) const noexcept; /**< return the offset in the actual file of the begining of the chunk */
std::vector r_header; /**< a cache of the header - without the encryption module data */
/** flags use to communicate during differents functions involved at file opening **/
bool mEncryptExistingPlainFile; /**< when opening a plain file, if the callback set an encryption suite and key material : migrate the file */
bool mIntegrityFullCheck; /**< if the file size given in the header metadata is incorrect, full check the file integrity and revrite header */
int mAccessMode; /**< the flags used to open the file, filtered on the access mode */
/**
* Parse the header of an encrypted file, check everything seems correct
* may perform integrity checking if the encryption module provides it
*
* @throw a EvfsException if something goes wrong
*/
void parseHeader();
/**
* Write the encrypted file header to the actual file
* Create the needed structures if the file is actually empty
* @param[in] fp if a file pointer is given write to this one, otherwise use the pFileStp property
*
* @throw a EvfsException if something goes wrong
**/
void writeHeader(bctbx_vfs_file_t *fp=nullptr);
public:
bctbx_vfs_file_t *pFileStd; /**< The encrypted vfs encapsulate a standard one */
VfsEncryption(bctbx_vfs_file_t *stdFp, const std::string &filename, int openFlags, int accessMode);
~VfsEncryption();
/***
* Plain version of the file related accessors
***/
/**
* @return the size of the plain text file
*/
int64_t fileSizeGet() const noexcept;
/* Read from file at given offset the requested size */
std::vector read(size_t offset, size_t count) const;
/* write to file at given offset the requested size */
size_t write(const std::vector &plainData, size_t offset);
/* Truncate the file to the given size, if given size is greater than current, pad with 0 */
void truncate(const uint64_t size);
/**
* Get the filename
* @return a string with the filename as given to the open function
*/
std::string filenameGet() const noexcept;
/***
* Encryption related API
***/
/**
* Set an encryption suite.
* When called at file creation, select the module to use for this file
* When called at the opening of an existing file, check it is the suite used at file creation, throw an exception if they differs
*/
void encryptionSuiteSet(const EncryptionSuite);
/**
* Set the secret Material in the encryption module
* This function cannot be called if a encryption suite was not set.
*/
void secretMaterialSet(const std::vector &secretMaterial);
/**
* Returns the encryption suite used for this file
* Can be return unset if the file is being created
*/
EncryptionSuite encryptionSuiteGet() const noexcept;
/**
* Returns the size of chunks in which the file is divided for encryption
*/
size_t chunkSizeGet() const noexcept;
/**
* Set the size, in bytes, of chunks in which the file is divided for encryption
* This size must be a multiple of 16, accepted values in range [16, (2^16-1)*16].
* If the size is set on an existing file and differs from previous setting, an exception is generated
* Default chunk size at file creation is 4kB.
* A file holds a maximum of 2^32-1 chunks. 16 bytes chunks - not recommended smallest admissible value - limit the file size to 64GB
*/
void chunkSizeSet(const size_t size);
/**
* Get raw header: encryption module might check integrity on header
* This function returns the raw header, without the encryption module part
*/
const std::vector& rawHeaderGet() const noexcept;
};
} // namespace bctoolbox
#endif /* BCTBX_VFS_STANDARD_HH */