2013-01-29 04:07:54 +01:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* Author: Valient Gough <vgough@pobox.com>
|
|
|
|
*
|
|
|
|
*****************************************************************************
|
|
|
|
* Copyright (c) 2012 Valient Gough
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU Lesser General Public License as published by the Free
|
|
|
|
* Software Foundation, either version 3 of the License, or (at your option) any
|
2013-10-20 00:35:26 +02:00
|
|
|
* later version.
|
2013-01-29 04:07:54 +01:00
|
|
|
*
|
|
|
|
* 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 Lesser General Public License for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "fs/testing.h"
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <string>
|
|
|
|
|
2013-10-21 07:38:27 +02:00
|
|
|
#include <glog/logging.h>
|
2013-01-29 04:07:54 +01:00
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
2013-03-05 07:36:32 +01:00
|
|
|
#include "cipher/CipherV1.h"
|
2013-01-29 04:07:54 +01:00
|
|
|
#include "cipher/MemoryPool.h"
|
|
|
|
|
|
|
|
#include "fs/FSConfig.h"
|
2013-03-05 07:29:58 +01:00
|
|
|
#include "fs/fsconfig.pb.h"
|
|
|
|
#include "fs/FileUtils.h"
|
2013-01-29 04:07:54 +01:00
|
|
|
#include "fs/MACFileIO.h"
|
2013-03-05 07:29:58 +01:00
|
|
|
#include "fs/MemFileIO.h"
|
2013-01-29 04:07:54 +01:00
|
|
|
|
2013-03-05 07:39:51 +01:00
|
|
|
using std::list;
|
|
|
|
using std::string;
|
2013-01-29 04:07:54 +01:00
|
|
|
|
2013-03-05 07:29:58 +01:00
|
|
|
namespace encfs {
|
|
|
|
|
2013-03-05 07:36:32 +01:00
|
|
|
FSConfigPtr makeConfig(const shared_ptr<CipherV1>& cipher, int blockSize) {
|
2013-01-29 04:07:54 +01:00
|
|
|
FSConfigPtr cfg = FSConfigPtr(new FSConfig);
|
|
|
|
cfg->cipher = cipher;
|
|
|
|
cfg->key = cipher->newRandomKey();
|
2013-03-05 07:36:32 +01:00
|
|
|
cfg->cipher->setKey(cfg->key);
|
2013-01-29 04:07:54 +01:00
|
|
|
cfg->config.reset(new EncfsConfig);
|
|
|
|
cfg->config->set_block_size(blockSize);
|
|
|
|
cfg->opts.reset(new EncFS_Opts);
|
|
|
|
|
|
|
|
return cfg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void runWithCipher(const string& cipherName, int blockSize,
|
|
|
|
void (*func)(FSConfigPtr& config)) {
|
2013-03-05 07:36:32 +01:00
|
|
|
shared_ptr<CipherV1> cipher = CipherV1::New(cipherName);
|
2013-01-29 04:07:54 +01:00
|
|
|
ASSERT_TRUE(cipher.get() != NULL);
|
|
|
|
|
|
|
|
FSConfigPtr cfg = makeConfig(cipher, blockSize);
|
|
|
|
ASSERT_NO_FATAL_FAILURE(func(cfg));
|
|
|
|
}
|
|
|
|
|
|
|
|
void runWithAllCiphers(void (*func)(FSConfigPtr& config)) {
|
2013-03-05 07:36:32 +01:00
|
|
|
list<CipherV1::CipherAlgorithm> algorithms = CipherV1::GetAlgorithmList();
|
|
|
|
list<CipherV1::CipherAlgorithm>::const_iterator it;
|
2013-01-29 04:07:54 +01:00
|
|
|
for (it = algorithms.begin(); it != algorithms.end(); ++it) {
|
|
|
|
int blockSize = it->blockSize.closest(512);
|
|
|
|
int keyLength = it->keyLength.closest(128);
|
2013-10-20 00:35:26 +02:00
|
|
|
SCOPED_TRACE(testing::Message() << "Testng with cipher " << it->name
|
|
|
|
<< ", blocksize " << blockSize
|
|
|
|
<< ", keyLength " << keyLength);
|
2013-03-05 07:36:32 +01:00
|
|
|
shared_ptr<CipherV1> cipher = CipherV1::New(it->iface, keyLength);
|
2013-01-29 04:07:54 +01:00
|
|
|
ASSERT_TRUE(cipher.get() != NULL);
|
|
|
|
|
|
|
|
FSConfigPtr cfg = makeConfig(cipher, blockSize);
|
|
|
|
ASSERT_NO_FATAL_FAILURE(func(cfg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void truncate(FileIO* a, FileIO* b, int len) {
|
|
|
|
SCOPED_TRACE(testing::Message() << "Truncate from " << a->getSize()
|
2013-10-20 00:35:26 +02:00
|
|
|
<< " to len " << len);
|
2013-01-29 04:07:54 +01:00
|
|
|
a->truncate(len);
|
|
|
|
ASSERT_EQ(len, a->getSize());
|
|
|
|
|
|
|
|
b->truncate(len);
|
|
|
|
ASSERT_EQ(len, b->getSize());
|
|
|
|
|
|
|
|
compare(a, b, 0, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) {
|
|
|
|
SCOPED_TRACE(testing::Message() << "Write random " << offset << ", " << len);
|
|
|
|
|
2013-03-05 07:39:51 +01:00
|
|
|
if (a->getSize() < offset + len) {
|
2013-01-29 04:07:54 +01:00
|
|
|
a->truncate(offset + len);
|
2013-03-05 07:39:51 +01:00
|
|
|
}
|
2013-01-29 04:07:54 +01:00
|
|
|
|
2013-03-05 07:39:51 +01:00
|
|
|
if (b->getSize() < offset + len) {
|
|
|
|
b->truncate(offset + len);
|
|
|
|
}
|
2013-10-20 00:35:26 +02:00
|
|
|
|
|
|
|
unsigned char* buf = new unsigned char[len];
|
2013-03-05 07:36:32 +01:00
|
|
|
ASSERT_TRUE(cfg->cipher->pseudoRandomize(buf, len));
|
2013-01-29 04:07:54 +01:00
|
|
|
|
|
|
|
IORequest req;
|
|
|
|
req.data = new unsigned char[len];
|
|
|
|
req.dataLen = len;
|
2013-03-05 07:39:51 +01:00
|
|
|
|
2013-01-29 04:07:54 +01:00
|
|
|
memcpy(req.data, buf, len);
|
|
|
|
req.offset = offset;
|
|
|
|
ASSERT_TRUE(a->write(req));
|
2013-03-05 07:39:51 +01:00
|
|
|
|
|
|
|
// Check that write succeeded.
|
|
|
|
req.offset = offset;
|
|
|
|
req.dataLen = len;
|
|
|
|
ASSERT_EQ(len, a->read(req));
|
|
|
|
ASSERT_TRUE(memcmp(req.data, buf, len) == 0);
|
2013-10-20 00:35:26 +02:00
|
|
|
|
2013-01-29 04:07:54 +01:00
|
|
|
memcpy(req.data, buf, len);
|
|
|
|
req.offset = offset;
|
2013-03-05 07:39:51 +01:00
|
|
|
req.dataLen = len;
|
2013-01-29 04:07:54 +01:00
|
|
|
ASSERT_TRUE(b->write(req));
|
|
|
|
|
2013-03-05 07:39:51 +01:00
|
|
|
// Check that write succeeded.
|
|
|
|
req.offset = offset;
|
|
|
|
req.dataLen = len;
|
|
|
|
ASSERT_EQ(len, b->read(req));
|
|
|
|
ASSERT_TRUE(memcmp(req.data, buf, len) == 0);
|
|
|
|
|
2013-01-29 04:07:54 +01:00
|
|
|
compare(a, b, offset, len);
|
|
|
|
|
|
|
|
delete[] buf;
|
2013-03-05 07:39:51 +01:00
|
|
|
delete[] req.data;
|
2013-01-29 04:07:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void compare(FileIO* a, FileIO* b, int offset, int len) {
|
|
|
|
SCOPED_TRACE(testing::Message() << "compare " << offset << ", " << len
|
2013-10-20 00:35:26 +02:00
|
|
|
<< " from file length " << a->getSize());
|
|
|
|
unsigned char* buf1 = new unsigned char[len];
|
|
|
|
unsigned char* buf2 = new unsigned char[len];
|
2013-01-29 04:07:54 +01:00
|
|
|
memset(buf1, 0, len);
|
|
|
|
memset(buf2, 0, len);
|
|
|
|
|
|
|
|
IORequest req;
|
|
|
|
req.offset = offset;
|
|
|
|
req.data = buf1;
|
|
|
|
req.dataLen = len;
|
|
|
|
ssize_t size1 = a->read(req);
|
|
|
|
|
|
|
|
req.offset = offset;
|
|
|
|
req.data = buf2;
|
|
|
|
req.dataLen = len;
|
|
|
|
ssize_t size2 = b->read(req);
|
|
|
|
|
|
|
|
ASSERT_EQ(size1, size2);
|
2013-10-20 00:35:26 +02:00
|
|
|
for (int i = 0; i < len; i++) {
|
2013-01-29 04:07:54 +01:00
|
|
|
bool match = (buf1[i] == buf2[i]);
|
2013-03-05 07:39:51 +01:00
|
|
|
ASSERT_TRUE(match) << "mismatched data at offset " << i << " of " << len
|
2013-10-20 00:35:26 +02:00
|
|
|
<< ", got " << int(buf1[i]) << " and " << int(buf2[i]);
|
|
|
|
if (!match) {
|
|
|
|
break;
|
2013-01-29 04:07:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] buf1;
|
|
|
|
delete[] buf2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) {
|
2013-10-20 00:35:26 +02:00
|
|
|
const int size = 2 * 1024;
|
2013-01-29 04:07:54 +01:00
|
|
|
writeRandom(cfg, a, b, 0, size);
|
|
|
|
if (testing::Test::HasFatalFailure()) return;
|
|
|
|
|
|
|
|
for (int i = 0; i < 10000; i++) {
|
|
|
|
SCOPED_TRACE(testing::Message() << "Test Loop " << i);
|
2013-03-05 07:39:51 +01:00
|
|
|
int len = 128 + random() % 512;
|
2013-10-20 00:35:26 +02:00
|
|
|
int offset = (len == a->getSize()) ? 0 : random() % (a->getSize() - len);
|
2013-01-29 04:07:54 +01:00
|
|
|
writeRandom(cfg, a, b, offset, len);
|
|
|
|
if (testing::Test::HasFatalFailure()) return;
|
|
|
|
ASSERT_EQ(a->getSize(), b->getSize());
|
|
|
|
}
|
|
|
|
|
|
|
|
SCOPED_TRACE("Final Compare");
|
|
|
|
compare(a, b, 0, a->getSize());
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
int main(int argc, char** argv) {
|
2013-01-29 04:07:54 +01:00
|
|
|
::testing::InitGoogleTest(&argc, argv);
|
2013-10-21 07:38:27 +02:00
|
|
|
google::InitGoogleLogging(argv[0]);
|
|
|
|
|
2013-01-29 04:07:54 +01:00
|
|
|
return RUN_ALL_TESTS();
|
|
|
|
}
|
|
|
|
|
2013-03-05 07:29:58 +01:00
|
|
|
} // namespace encfs
|