|
@@ -1,41 +1,143 @@
|
|
#include "../include/fileman.h"
|
|
#include "../include/fileman.h"
|
|
#include "../include/base64.h"
|
|
#include "../include/base64.h"
|
|
|
|
|
|
-FileMan::FileMan() { islisting = false; }
|
|
|
|
|
|
+#include <cstdio>
|
|
|
|
+#include <cstring>
|
|
|
|
+#include <iostream>
|
|
|
|
+
|
|
|
|
+using std::string;
|
|
|
|
+using std::vector;
|
|
|
|
+
|
|
|
|
+FileMan::FileMan() {
|
|
|
|
+ isputting = false;
|
|
|
|
+ islisting = false;
|
|
|
|
+ keyenabled = false;
|
|
|
|
+ cryptoreadye = false;
|
|
|
|
+ cryptoreadyd = false;
|
|
|
|
+ ERR_load_crypto_strings();
|
|
|
|
+}
|
|
|
|
|
|
FileMan::~FileMan() {
|
|
FileMan::~FileMan() {
|
|
cancelGet();
|
|
cancelGet();
|
|
cancelPut();
|
|
cancelPut();
|
|
cancelList();
|
|
cancelList();
|
|
|
|
+ if (keyenabled)
|
|
|
|
+ closeKey();
|
|
|
|
+ ERR_free_strings();
|
|
}
|
|
}
|
|
|
|
|
|
bool FileMan::isGetting() { return getfile.is_open(); }
|
|
bool FileMan::isGetting() { return getfile.is_open(); }
|
|
|
|
|
|
-bool FileMan::isPutting() { return putfile.is_open(); }
|
|
|
|
|
|
+bool FileMan::isPutting() { return isputting; }
|
|
|
|
|
|
bool FileMan::isListing() { return islisting; }
|
|
bool FileMan::isListing() { return islisting; }
|
|
|
|
|
|
-bool FileMan::openPut(const std::string &path) {
|
|
|
|
|
|
+bool FileMan::isEncrypted() { return keyenabled; }
|
|
|
|
+
|
|
|
|
+vector<vector<char>> FileMan::chunkify(char *data, unsigned int size) {
|
|
|
|
+ vector<vector<char>> ret;
|
|
|
|
+ vector<char> chunk;
|
|
|
|
+ unsigned int i;
|
|
|
|
+ for (i = 0; (i + max_read_len) < size; i += max_read_len) {
|
|
|
|
+ chunk = vector<char>(data + i, data + i + max_read_len);
|
|
|
|
+ ret.push_back(chunk);
|
|
|
|
+ }
|
|
|
|
+ chunk = vector<char>(data + i, data + size);
|
|
|
|
+ ret.push_back(chunk);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool FileMan::openPut(const string &path) {
|
|
|
|
+ std::ifstream putfile;
|
|
|
|
+ std::fstream keyfile;
|
|
putpath = path;
|
|
putpath = path;
|
|
putname = pathToFilename(path);
|
|
putname = pathToFilename(path);
|
|
putfile.open(path, std::ios::ate | std::ios::binary);
|
|
putfile.open(path, std::ios::ate | std::ios::binary);
|
|
if (putfile.is_open()) {
|
|
if (putfile.is_open()) {
|
|
size_t size = putfile.tellg();
|
|
size_t size = putfile.tellg();
|
|
|
|
+ //~ putsize = size;
|
|
|
|
+ // increment by one for CCATs signature in its own chunk
|
|
|
|
+ //~ putchunks = 1 + (size / max_read_len + ((size % max_read_len) ? 1 : 0));
|
|
|
|
+ if (keyenabled) {
|
|
|
|
+ // fill IV for file
|
|
|
|
+ keyfile.open("/dev/urandom", std::ios::binary | std::ios::in);
|
|
|
|
+ keyfile.read((char *)iv, sizeof(iv));
|
|
|
|
+ keyfile.close();
|
|
|
|
+ }
|
|
|
|
+ putfile.seekg(0);
|
|
|
|
+
|
|
|
|
+ // read into memory and chunkify
|
|
|
|
+
|
|
|
|
+ char *temp = new char[size + sizeof(signature)];
|
|
|
|
+ memcpy(temp, signature, sizeof(signature));
|
|
|
|
+ putfile.read(temp + sizeof(signature), size);
|
|
|
|
+
|
|
|
|
+ size += sizeof(signature);
|
|
|
|
+
|
|
|
|
+ // have all file in memory prepended with signature
|
|
|
|
+ // if crypto enabled, encrypt now
|
|
|
|
+ if (keyenabled) {
|
|
|
|
+ if (!initCryptoE()) {
|
|
|
|
+ // failed to init crypto, do not continue
|
|
|
|
+ delete[] temp;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ // resize buffer to also fit IV and tag
|
|
|
|
+ size_t additionalsize = sizeof(iv) + sizeof(tag);
|
|
|
|
+ unsigned char *cipher = new unsigned char[size];
|
|
|
|
+ int cipherlen;
|
|
|
|
+
|
|
|
|
+ if (!EVP_EncryptUpdate(cryptctxe, cipher, &cipherlen, (unsigned char *)temp, size)) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " failed to update " << getOpensslError() << std::endl;
|
|
|
|
+ }
|
|
|
|
+ if (!EVP_EncryptFinal_ex(cryptctxe, cipher + cipherlen, &cipherlen)) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " failed to finalize " << getOpensslError() << std::endl;
|
|
|
|
+ }
|
|
|
|
+ // obtain tag
|
|
|
|
+ if (!EVP_CIPHER_CTX_ctrl(cryptctxe, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " failed to get tag " << getOpensslError() << std::endl;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ delete[] temp;
|
|
|
|
+ temp = new char[size + additionalsize];
|
|
|
|
+
|
|
|
|
+ // prepend IV and tag
|
|
|
|
+ memcpy(temp, iv, sizeof(iv));
|
|
|
|
+ memcpy(temp + sizeof(iv), tag, sizeof(tag));
|
|
|
|
+ memcpy(temp + additionalsize, cipher, size);
|
|
|
|
+
|
|
|
|
+ delete[] cipher;
|
|
|
|
+
|
|
|
|
+ // increase size to also include IV and tag
|
|
|
|
+ size += sizeof(iv) + sizeof(tag);
|
|
|
|
+ deinitCryptoE();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // chunkify
|
|
|
|
+ putdata = chunkify(temp, size);
|
|
putsize = size;
|
|
putsize = size;
|
|
- putchunks = size / max_read_len + ((size % max_read_len) ? 1 : 0);
|
|
|
|
- putchunksRemaining = putchunks;
|
|
|
|
- putfile.seekg(std::ios::beg);
|
|
|
|
|
|
+ putchunksRemaining = putchunks = putdata.size();
|
|
|
|
+
|
|
|
|
+ delete[] temp;
|
|
|
|
+
|
|
|
|
+ // end read into memory and chunkify
|
|
|
|
+
|
|
|
|
+ isputting = true;
|
|
|
|
+
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
-bool FileMan::openGet(const std::string &path) {
|
|
|
|
|
|
+bool FileMan::openGet(const string &path) {
|
|
getpath = path;
|
|
getpath = path;
|
|
getname = pathToFilename(path);
|
|
getname = pathToFilename(path);
|
|
getchunks = 0;
|
|
getchunks = 0;
|
|
getchunksRemaining = 0;
|
|
getchunksRemaining = 0;
|
|
- getfile.open(path, std::ios::app | std::ios::binary);
|
|
|
|
|
|
+ getfile.open(path, std::ios::app | std::ios::binary | std::ios::out);
|
|
if (getfile.tellp() != std::ios::beg) {
|
|
if (getfile.tellp() != std::ios::beg) {
|
|
closeGet();
|
|
closeGet();
|
|
return false;
|
|
return false;
|
|
@@ -47,17 +149,59 @@ bool FileMan::openList() {
|
|
if (isListing()) {
|
|
if (isListing()) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
- listdata = std::vector<std::string>();
|
|
|
|
|
|
+ listdata = vector<string>();
|
|
islisting = true;
|
|
islisting = true;
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-void FileMan::closePut() { putfile.close(); }
|
|
|
|
|
|
+bool FileMan::openKey(const string &path) {
|
|
|
|
+ std::ifstream keyfile;
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " begin" << std::endl;
|
|
|
|
+ if (isPutting() || isGetting())
|
|
|
|
+ return false; // do not enable key mid-operation
|
|
|
|
+ if (keyenabled)
|
|
|
|
+ closeKey();
|
|
|
|
+ keyfile.open(path, std::ios::ate | std::ios::binary);
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " open keyfile" << std::endl;
|
|
|
|
+ if (keyfile.is_open()) {
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " keyfile open " << keyfile.tellg() << " " << sizeof(key) << std::endl;
|
|
|
|
+ if (keyfile.tellg() == sizeof(key)) {
|
|
|
|
+ keyfile.seekg(0);
|
|
|
|
+ std::cerr << "keyfile is at " << keyfile.tellg() << std::endl;
|
|
|
|
+ keyfile.read((char *)key, sizeof(key));
|
|
|
|
+ keyfile.close();
|
|
|
|
+ keyenabled = true;
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileMan::closePut() {
|
|
|
|
+ putdata = vector<vector<char>>();
|
|
|
|
+ isputting = false;
|
|
|
|
+ memset(iv, 0, sizeof(iv));
|
|
|
|
+ memset(tag, 0, sizeof(tag));
|
|
|
|
+}
|
|
|
|
|
|
-void FileMan::closeGet() { getfile.close(); }
|
|
|
|
|
|
+void FileMan::closeGet() {
|
|
|
|
+ getfile.close();
|
|
|
|
+ memset(iv, 0, sizeof(iv));
|
|
|
|
+ memset(tag, 0, sizeof(tag));
|
|
|
|
+}
|
|
|
|
|
|
void FileMan::closeList() { islisting = false; }
|
|
void FileMan::closeList() { islisting = false; }
|
|
|
|
|
|
|
|
+bool FileMan::closeKey() {
|
|
|
|
+ if (isPutting() || isGetting())
|
|
|
|
+ return false;
|
|
|
|
+ if (keyenabled) {
|
|
|
|
+ memset(key, 0, sizeof(key));
|
|
|
|
+ keyenabled = false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
void FileMan::cancelPut() {
|
|
void FileMan::cancelPut() {
|
|
if (isPutting()) {
|
|
if (isPutting()) {
|
|
closePut();
|
|
closePut();
|
|
@@ -77,19 +221,33 @@ void FileMan::cancelList() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-void FileMan::writeGet(const std::vector<char> data) {
|
|
|
|
- getfile.write(data.data(), data.size());
|
|
|
|
|
|
+void FileMan::writeGet(const vector<char> data) {
|
|
|
|
+ if (getchunksRemaining == getchunks - 1 && !keyenabled) {
|
|
|
|
+ // check if signature matches
|
|
|
|
+ if (memcmp(data.data(), signature, 4)) {
|
|
|
|
+ // mismatch, encrypted file without enabled key, write as is
|
|
|
|
+ getfile.write(data.data(), data.size());
|
|
|
|
+ } else {
|
|
|
|
+ // skip signature for unencrypted files
|
|
|
|
+ getfile.write(data.data() + 4, data.size() - 4);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ getfile.write(data.data(), data.size());
|
|
|
|
+ }
|
|
getchunksRemaining--;
|
|
getchunksRemaining--;
|
|
}
|
|
}
|
|
|
|
|
|
-void FileMan::writeBase64(std::string data) { writeGet(base64::decodeVector(data)); }
|
|
|
|
|
|
+void FileMan::writeBase64(string data) {
|
|
|
|
+ vector<char> decode = base64::decodeVector(data);
|
|
|
|
+ keyenabled ? writeEnc(decode) : writeGet(decode);
|
|
|
|
+}
|
|
|
|
|
|
-void FileMan::putListData(std::vector<std::string> names) {
|
|
|
|
|
|
+void FileMan::putListData(vector<string> names) {
|
|
listdata.insert(listdata.end(), names.begin(), names.end());
|
|
listdata.insert(listdata.end(), names.begin(), names.end());
|
|
listchunksRemaining--;
|
|
listchunksRemaining--;
|
|
}
|
|
}
|
|
|
|
|
|
-std::vector<std::string> FileMan::getListData() { return listdata; }
|
|
|
|
|
|
+vector<string> FileMan::getListData() { return listdata; }
|
|
|
|
|
|
int FileMan::getGetChunks() { return getchunks; }
|
|
int FileMan::getGetChunks() { return getchunks; }
|
|
|
|
|
|
@@ -105,28 +263,17 @@ void FileMan::setListChunks(int chunks) {
|
|
listchunksRemaining = chunks - 1;
|
|
listchunksRemaining = chunks - 1;
|
|
}
|
|
}
|
|
|
|
|
|
-std::vector<char> FileMan::readPut() {
|
|
|
|
- char buf[max_read_len];
|
|
|
|
- std::vector<char> data;
|
|
|
|
-
|
|
|
|
- std::streamoff read = this->putfile.tellg();
|
|
|
|
- if (read + max_read_len > this->putsize) {
|
|
|
|
- read = this->putsize % max_read_len;
|
|
|
|
- } else {
|
|
|
|
- read = max_read_len;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- putfile.read(buf, read);
|
|
|
|
- data.assign(buf, buf + read);
|
|
|
|
|
|
+vector<char> FileMan::readPut() {
|
|
|
|
+ vector<char> data = putdata[putchunks - putchunksRemaining];
|
|
putchunksRemaining--;
|
|
putchunksRemaining--;
|
|
return data;
|
|
return data;
|
|
}
|
|
}
|
|
|
|
|
|
-std::string FileMan::readBase64() { return base64::encodeVector(readPut()); }
|
|
|
|
|
|
+string FileMan::readBase64() { return base64::encodeVector(readPut()); }
|
|
|
|
|
|
-std::string FileMan::getPutName() { return putname; }
|
|
|
|
|
|
+string FileMan::getPutName() { return putname; }
|
|
|
|
|
|
-std::string FileMan::getGetName() { return getname; }
|
|
|
|
|
|
+string FileMan::getGetName() { return getname; }
|
|
|
|
|
|
int FileMan::getPutChunks() { return putchunks; }
|
|
int FileMan::getPutChunks() { return putchunks; }
|
|
|
|
|
|
@@ -138,11 +285,11 @@ int FileMan::getListRemainingChunks() { return listchunksRemaining; }
|
|
|
|
|
|
int FileMan::getListChunks() { return listchunks; }
|
|
int FileMan::getListChunks() { return listchunks; }
|
|
|
|
|
|
-std::string FileMan::pathToFilename(std::string path) {
|
|
|
|
|
|
+string FileMan::pathToFilename(string path) {
|
|
|
|
|
|
int lastFoundIndex = -1;
|
|
int lastFoundIndex = -1;
|
|
|
|
|
|
- for (int currentIndex = path.find("/"); currentIndex != std::string::npos; currentIndex = path.find("/", currentIndex + 1)) {
|
|
|
|
|
|
+ for (int currentIndex = path.find("/"); currentIndex != string::npos; currentIndex = path.find("/", currentIndex + 1)) {
|
|
|
|
|
|
// check if the "/" was escaped
|
|
// check if the "/" was escaped
|
|
if (currentIndex > 0 && path[currentIndex - 1] == '\\')
|
|
if (currentIndex > 0 && path[currentIndex - 1] == '\\')
|
|
@@ -162,3 +309,122 @@ std::string FileMan::pathToFilename(std::string path) {
|
|
|
|
|
|
return path.substr(lastFoundIndex + 1);
|
|
return path.substr(lastFoundIndex + 1);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+string FileMan::getOpensslError() {
|
|
|
|
+ pendingerr = false;
|
|
|
|
+ return opensslerr;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileMan::setOpensslError() {
|
|
|
|
+ opensslerr = ERR_error_string(ERR_get_error(), NULL);
|
|
|
|
+ pendingerr = true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool FileMan::initCryptoE() {
|
|
|
|
+ // try to initialize crypto context
|
|
|
|
+ if (!cryptoreadye) {
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " init crypto" << std::endl;
|
|
|
|
+ if (!(cryptctxe = EVP_CIPHER_CTX_new())) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (!EVP_EncryptInit_ex(cryptctxe, EVP_aes_256_gcm(), NULL, key, iv)) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ cryptoreadye = true;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool FileMan::initCryptoD() {
|
|
|
|
+ // try to initialize crypto context
|
|
|
|
+ if (!cryptoreadyd) {
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " init crypto" << std::endl;
|
|
|
|
+ if (!(cryptctxd = EVP_CIPHER_CTX_new())) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (!EVP_DecryptInit_ex(cryptctxd, EVP_aes_256_gcm(), NULL, key, iv)) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ cryptoreadyd = true;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileMan::deinitCryptoE() {
|
|
|
|
+ if (cryptoreadye) {
|
|
|
|
+ EVP_CIPHER_CTX_free(cryptctxe);
|
|
|
|
+ cryptctxe = NULL;
|
|
|
|
+ cryptoreadye = false;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileMan::deinitCryptoD() {
|
|
|
|
+ if (cryptoreadyd) {
|
|
|
|
+ EVP_CIPHER_CTX_free(cryptctxd);
|
|
|
|
+ cryptctxd = NULL;
|
|
|
|
+ cryptoreadyd = false;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FileMan::writeEnc(const vector<char> data) {
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " begin" << std::endl;
|
|
|
|
+ writeGet(data);
|
|
|
|
+ if (getchunksRemaining < 0) {
|
|
|
|
+ // loaded everything, try to decrypt
|
|
|
|
+ unsigned char *cipher, *plain;
|
|
|
|
+ int plainlen = 0, finallen = 0;
|
|
|
|
+ getfile.close();
|
|
|
|
+ getfile.open(getpath, std::ios::binary | std::ios::in | std::ios::ate);
|
|
|
|
+ size_t size = getfile.tellg();
|
|
|
|
+ if (size < (sizeof(iv) + sizeof(tag))) {
|
|
|
|
+ // avoid underflow with files that are too small
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ size -= (sizeof(iv) + sizeof(tag));
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " size is " << size << std::endl;
|
|
|
|
+ cipher = new unsigned char[size];
|
|
|
|
+ plain = new unsigned char[size];
|
|
|
|
+ getfile.seekg(0);
|
|
|
|
+ getfile.read((char *)iv, sizeof(iv));
|
|
|
|
+ getfile.read((char *)tag, sizeof(tag));
|
|
|
|
+ getfile.read((char *)cipher, size);
|
|
|
|
+ getfile.close();
|
|
|
|
+
|
|
|
|
+ if (initCryptoD()) {
|
|
|
|
+ if (!EVP_DecryptUpdate(cryptctxd, plain, &plainlen, cipher, size)) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " failed to update " << getOpensslError() << std::endl;
|
|
|
|
+ }
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " decrypted" << std::endl;
|
|
|
|
+ if (!EVP_CIPHER_CTX_ctrl(cryptctxd, EVP_CTRL_GCM_SET_TAG, 16, tag)) {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " failed to finalize " << getOpensslError() << std::endl;
|
|
|
|
+ }
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " set tag" << std::endl;
|
|
|
|
+ if (0 < EVP_DecryptFinal_ex(cryptctxd, plain + plainlen, &finallen)) {
|
|
|
|
+ plainlen += finallen;
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " finalized with len " << plainlen << std::endl;
|
|
|
|
+ getfile.close();
|
|
|
|
+ // check signature
|
|
|
|
+ if (memcmp(plain, signature, 4)) {
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " signature mismatch" << std::endl;
|
|
|
|
+ } else {
|
|
|
|
+ // signatur matches, skip it and dump the rest to disk
|
|
|
|
+ getfile.open(getpath, std::ios::binary | std::ios::out | std::ios::trunc);
|
|
|
|
+ getfile.write((char *)(plain + sizeof(signature)), plainlen - sizeof(signature));
|
|
|
|
+ getfile.close();
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ setOpensslError();
|
|
|
|
+ std::cerr << __PRETTY_FUNCTION__ << " failed to finalize " << getOpensslError() << std::endl;
|
|
|
|
+ }
|
|
|
|
+ deinitCryptoD();
|
|
|
|
+ }
|
|
|
|
+ delete[] cipher;
|
|
|
|
+ delete[] plain;
|
|
|
|
+ }
|
|
|
|
+}
|