mirror of
https://github.com/vgough/encfs.git
synced 2025-02-16 09:49:46 +01:00
Implement more Botan support.
git-svn-id: http://encfs.googlecode.com/svn/trunk@99 db9cf616-1c43-0410-9cb8-a902689de0d6
This commit is contained in:
parent
95750d4539
commit
bd182db260
@ -91,6 +91,7 @@ find_program (POD2MAN pod2man)
|
||||
|
||||
find_package (GTest)
|
||||
if (GTEST_FOUND)
|
||||
include_directories(${GTEST_INCLUDE_DIR})
|
||||
enable_testing()
|
||||
endif (GTEST_FOUND)
|
||||
|
||||
|
@ -31,10 +31,6 @@
|
||||
|
||||
#include <tinyxml.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/buffer.h>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "base/base64.h"
|
||||
#include "base/Interface.h"
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "base/config.h"
|
||||
#include "base/shared_ptr.h"
|
||||
#include "cipher/BlockCipher.h"
|
||||
#include "cipher/CipherV1.h"
|
||||
#include "cipher/MemoryPool.h"
|
||||
#include "cipher/PBKDF.h"
|
||||
#include "cipher/testing.h"
|
||||
@ -40,6 +41,13 @@ using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
class BlockCipherTest : public testing::Test {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
CipherV1::init(false);
|
||||
}
|
||||
};
|
||||
|
||||
void compare(const byte *a, const byte *b, int size) {
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
ASSERT_EQ(0, VALGRIND_CHECK_MEM_IS_DEFINED(a, size));
|
||||
@ -54,7 +62,7 @@ void compare(const byte *a, const byte *b, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RequiredBlockCiphers, BlockCipher) {
|
||||
TEST_F(BlockCipherTest, RequiredBlockCiphers) {
|
||||
auto aes_cbc = BlockCipher::GetRegistry().CreateForMatch(NAME_AES_CBC);
|
||||
ASSERT_TRUE(aes_cbc != NULL);
|
||||
|
||||
@ -62,7 +70,7 @@ TEST(RequiredBlockCiphers, BlockCipher) {
|
||||
ASSERT_TRUE(bf_cbc != NULL);
|
||||
}
|
||||
|
||||
TEST(RequiredStreamCiphers, StreamCipher) {
|
||||
TEST_F(BlockCipherTest, RequiredStreamCiphers) {
|
||||
auto aes_cfb = StreamCipher::GetRegistry().CreateForMatch(NAME_AES_CFB);
|
||||
ASSERT_TRUE(aes_cfb != NULL);
|
||||
|
||||
@ -84,6 +92,7 @@ void checkTestVector(const char *cipherName,
|
||||
|
||||
CipherKey key(strlen(hexKey)/2);
|
||||
setDataFromHex(key.data(), key.size(), hexKey);
|
||||
|
||||
ASSERT_TRUE(cipher->setKey(key));
|
||||
|
||||
byte iv[strlen(hexIv)/2];
|
||||
@ -93,19 +102,23 @@ void checkTestVector(const char *cipherName,
|
||||
setDataFromHex(plaintext, sizeof(plaintext), hexPlaintext);
|
||||
|
||||
byte ciphertext[sizeof(plaintext)];
|
||||
ASSERT_TRUE(cipher->encrypt(iv, plaintext, ciphertext, sizeof(ciphertext)));
|
||||
|
||||
ASSERT_EQ(hexCipher, stringToHex(ciphertext, sizeof(ciphertext)));
|
||||
// Run test in a loop with the same cipher, since that's how we use it later.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ASSERT_TRUE(cipher->encrypt(iv, plaintext, ciphertext, sizeof(ciphertext)));
|
||||
|
||||
byte decypered[sizeof(plaintext)];
|
||||
ASSERT_TRUE(cipher->decrypt(iv, ciphertext, decypered, sizeof(ciphertext)));
|
||||
ASSERT_EQ(hexCipher, stringToHex(ciphertext, sizeof(ciphertext)));
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(plaintext); ++i) {
|
||||
ASSERT_EQ(plaintext[i], decypered[i]);
|
||||
byte decypered[sizeof(plaintext)];
|
||||
ASSERT_TRUE(cipher->decrypt(iv, ciphertext, decypered, sizeof(ciphertext)));
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(plaintext); ++i) {
|
||||
ASSERT_EQ(plaintext[i], decypered[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestVectors, BlockCipher) {
|
||||
TEST_F(BlockCipherTest, TestVectors) {
|
||||
// BF128 CBC
|
||||
checkTestVector<BlockCipher>(NAME_BLOWFISH_CBC,
|
||||
"0123456789abcdeff0e1d2c3b4a59687",
|
||||
@ -149,7 +162,7 @@ TEST(TestVectors, BlockCipher) {
|
||||
"dc7e84bfda79164b7ecd8486985d3860");
|
||||
}
|
||||
|
||||
TEST(BlockEncryptionTest, BlockCipher) {
|
||||
TEST_F(BlockCipherTest, BlockEncryptionTest) {
|
||||
Registry<BlockCipher> registry = BlockCipher::GetRegistry();
|
||||
|
||||
shared_ptr<PBKDF> pbkdf(
|
||||
|
@ -15,6 +15,7 @@ elseif (WITH_BOTAN)
|
||||
find_package (Botan REQUIRED)
|
||||
set (EXTRA_LIBS ${BOTAN_LIBRARIES})
|
||||
set (EXTRA_SOURCE botan.cpp)
|
||||
include_directories (${BOTAN_INCLUDE_DIR})
|
||||
endif (WITH_COMMON_CRYPTO)
|
||||
|
||||
add_library (encfs-cipher
|
||||
|
@ -19,9 +19,17 @@ using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(CipherKey, ReadWrite) {
|
||||
class CipherKeyTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
CipherV1::init(false);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CipherKeyTest, ReadWrite) {
|
||||
for (auto alg : CipherV1::GetAlgorithmList()) {
|
||||
auto cipher = CipherV1::New(alg.iface);
|
||||
ASSERT_FALSE(!cipher);
|
||||
|
||||
CipherKey masterKey = cipher->newRandomKey();
|
||||
CipherKey volumeKey = cipher->newRandomKey();
|
||||
|
@ -297,6 +297,8 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface,
|
||||
else
|
||||
_keySize = keyRange.closest(keyLength) / 8;
|
||||
|
||||
LOG_IF(ERROR, _keySize == 0) << "invalid key size";
|
||||
|
||||
_pbkdf.reset(PBKDF::GetRegistry().CreateForMatch(
|
||||
NAME_PBKDF2_HMAC_SHA1));
|
||||
if (!_pbkdf) {
|
||||
@ -405,6 +407,9 @@ bool CipherV1::pseudoRandomize( byte *buf, int len )
|
||||
bool CipherV1::setKey(const CipherKey &keyIv) {
|
||||
Lock l(_hmacMutex);
|
||||
|
||||
LOG_IF(ERROR, _keySize != keyIv.size()) << "Mismatched key size: passed "
|
||||
<< keyIv.size() << ", expecting " << _keySize;
|
||||
|
||||
// Key is actually key plus iv, so extract the different parts.
|
||||
CipherKey key(_keySize);
|
||||
memcpy(key.data(), keyIv.data(), _keySize);
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
#ifdef WITH_BOTAN
|
||||
# include <botan/botan.h>
|
||||
# include <botan/version.h>
|
||||
#endif
|
||||
|
||||
namespace encfs {
|
||||
@ -104,13 +105,33 @@ MemBlock::~MemBlock()
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
SecureMem::SecureMem(int len)
|
||||
#ifdef WITH_BOTAN
|
||||
: data_(len)
|
||||
#endif
|
||||
SecureMem::SecureMem(int len)
|
||||
: data_(new Botan::SecureVector<unsigned char>(len))
|
||||
{
|
||||
rAssert(len > 0);
|
||||
}
|
||||
|
||||
SecureMem::~SecureMem()
|
||||
{
|
||||
# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
|
||||
data_->destroy();
|
||||
# endif
|
||||
delete data_;
|
||||
}
|
||||
|
||||
byte* SecureMem::data() const {
|
||||
return const_cast<byte*>(data_->begin());
|
||||
}
|
||||
|
||||
int SecureMem::size() const {
|
||||
return data_->size();
|
||||
}
|
||||
|
||||
#else
|
||||
SecureMem::SecureMem(int len)
|
||||
{
|
||||
rAssert(len > 0);
|
||||
#ifndef WITH_BOTAN
|
||||
data_ = allocBlock(len);
|
||||
if (data_)
|
||||
{
|
||||
@ -120,14 +141,10 @@ SecureMem::SecureMem(int len)
|
||||
{
|
||||
size_ = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SecureMem::~SecureMem()
|
||||
{
|
||||
#ifdef WITH_BOTAN
|
||||
data_.destroy();
|
||||
#else
|
||||
if (size_)
|
||||
{
|
||||
cleanBlock(data_, size_);
|
||||
@ -137,8 +154,8 @@ SecureMem::~SecureMem()
|
||||
data_ = NULL;
|
||||
size_ = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
bool operator == (const SecureMem &a, const SecureMem &b) {
|
||||
return (a.size() == b.size()) &&
|
||||
|
@ -25,7 +25,9 @@
|
||||
#include "base/types.h"
|
||||
|
||||
#ifdef WITH_BOTAN
|
||||
#include <botan/secmem.h>
|
||||
namespace Botan {
|
||||
template <typename T> class SecureVector;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace encfs {
|
||||
@ -69,21 +71,14 @@ class SecureMem
|
||||
|
||||
private:
|
||||
#ifdef WITH_BOTAN
|
||||
Botan::SecureVector<Botan::byte> data_;
|
||||
Botan::SecureVector<unsigned char> *data_;
|
||||
#else
|
||||
byte *data_;
|
||||
int size_;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef WITH_BOTAN
|
||||
inline byte* SecureMem::data() const {
|
||||
return const_cast<byte*>(data_.begin());
|
||||
}
|
||||
inline int SecureMem::size() const {
|
||||
return data_.size();
|
||||
}
|
||||
#else
|
||||
#ifndef WITH_BOTAN
|
||||
inline byte* SecureMem::data() const {
|
||||
return data_;
|
||||
}
|
||||
|
197
cipher/botan.cpp
197
cipher/botan.cpp
@ -21,6 +21,7 @@
|
||||
|
||||
#include "cipher/botan.h"
|
||||
#include "base/config.h"
|
||||
#include "base/shared_ptr.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <botan/botan.h>
|
||||
@ -35,9 +36,14 @@
|
||||
#include "cipher/PBKDF.h"
|
||||
#include "cipher/StreamCipher.h"
|
||||
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
#include <valgrind/memcheck.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace Botan;
|
||||
using std::string;
|
||||
|
||||
namespace encfs {
|
||||
namespace botan {
|
||||
@ -115,6 +121,197 @@ class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac {
|
||||
REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF);
|
||||
|
||||
|
||||
class BotanBlockCipher : public BlockCipher {
|
||||
Keyed_Filter *encryption; // Not owned.
|
||||
Keyed_Filter *decryption; // Not owned.
|
||||
shared_ptr<Pipe> encryptor;
|
||||
shared_ptr<Pipe> decryptor;
|
||||
public:
|
||||
BotanBlockCipher() {}
|
||||
virtual ~BotanBlockCipher() {}
|
||||
|
||||
bool rekey(const CipherKey& key, const string& cipherMode) {
|
||||
SymmetricKey bkey(key.data(), key.size());
|
||||
OctetString iv;
|
||||
encryption = Botan::get_cipher(cipherMode, bkey, iv, Botan::ENCRYPTION);
|
||||
decryption = Botan::get_cipher(cipherMode, bkey, iv, Botan::DECRYPTION);
|
||||
if (encryption == nullptr || decryption == nullptr) {
|
||||
return false;
|
||||
}
|
||||
encryptor.reset(new Pipe(encryption));
|
||||
decryptor.reset(new Pipe(decryption));
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool encrypt(const byte* iv, const byte* in, byte* out, int size) {
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(in, size) != 0 ||
|
||||
VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0 ||
|
||||
VALGRIND_CHECK_MEM_IS_ADDRESSABLE(iv, blockSize())) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
encryption->set_iv(OctetString(iv, blockSize()));
|
||||
encryptor->process_msg(in, size);
|
||||
auto written = encryptor->read(out, size, Pipe::LAST_MESSAGE);
|
||||
LOG_IF(ERROR, (int)written != size) << "expected output size " << size
|
||||
<< ", got " << written;
|
||||
LOG_IF(ERROR, encryptor->remaining() > 0) << "unread bytes in pipe: "
|
||||
<< encryptor->remaining();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool decrypt(const byte* iv, const byte* in, byte* out, int size) {
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(in, size) != 0 ||
|
||||
VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0 ||
|
||||
VALGRIND_CHECK_MEM_IS_ADDRESSABLE(iv, blockSize())) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
decryption->set_iv(OctetString(iv, blockSize()));
|
||||
decryptor->process_msg(in, size);
|
||||
auto written = decryptor->read(out, size, Pipe::LAST_MESSAGE);
|
||||
LOG_IF(ERROR, (int)written != size) << "expected output size " << size
|
||||
<< ", got " << written;
|
||||
LOG_IF(ERROR, encryptor->remaining() > 0) << "unread bytes in pipe: "
|
||||
<< encryptor->remaining();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class BotanAesCbc : public BotanBlockCipher {
|
||||
public:
|
||||
BotanAesCbc() {}
|
||||
virtual ~BotanAesCbc() {}
|
||||
|
||||
virtual bool setKey(const CipherKey& key) {
|
||||
std::ostringstream ss;
|
||||
ss << "AES-" << (key.size() * 8) << "/CBC/NoPadding";
|
||||
return rekey(key, ss.str());
|
||||
}
|
||||
|
||||
virtual int blockSize() const {
|
||||
return 128 >> 3;
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
return Properties(Range(128,256,64), "AES", "CBC", "Botan");
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(BotanAesCbc, BlockCipher);
|
||||
|
||||
class BotanAesCfb : public BotanBlockCipher {
|
||||
public:
|
||||
BotanAesCfb() {}
|
||||
virtual ~BotanAesCfb() {}
|
||||
|
||||
virtual bool setKey(const CipherKey& key) {
|
||||
std::ostringstream ss;
|
||||
ss << "AES-" << (key.size() * 8) << "/CFB";
|
||||
return rekey(key, ss.str());
|
||||
}
|
||||
|
||||
virtual int blockSize() const {
|
||||
return 128 >> 3;
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
return Properties(Range(128,256,64), "AES", "CFB", "Botan");
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(BotanAesCfb, StreamCipher);
|
||||
|
||||
class BotanBlowfishCbc : public BotanBlockCipher {
|
||||
public:
|
||||
BotanBlowfishCbc() {}
|
||||
virtual ~BotanBlowfishCbc() {}
|
||||
|
||||
virtual bool setKey(const CipherKey& key) {
|
||||
std::ostringstream ss;
|
||||
ss << "Blowfish" << "/CBC/NoPadding";
|
||||
return rekey(key, ss.str());
|
||||
}
|
||||
|
||||
virtual int blockSize() const {
|
||||
return 64 >> 3;
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
return Properties(Range(128,256,32), "Blowfish", "CBC", "Botan");
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(BotanBlowfishCbc, BlockCipher);
|
||||
|
||||
class BotanBlowfishCfb : public BotanBlockCipher {
|
||||
public:
|
||||
BotanBlowfishCfb() {}
|
||||
virtual ~BotanBlowfishCfb() {}
|
||||
|
||||
virtual bool setKey(const CipherKey& key) {
|
||||
std::ostringstream ss;
|
||||
ss << "Blowfish" << "/CFB";
|
||||
return rekey(key, ss.str());
|
||||
}
|
||||
|
||||
virtual int blockSize() const {
|
||||
return 64 >> 3;
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
return Properties(Range(128,256,32), "Blowfish", "CFB", "Botan");
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(BotanBlowfishCfb, StreamCipher);
|
||||
|
||||
|
||||
class Sha1HMac : public MAC {
|
||||
MessageAuthenticationCode *mac;
|
||||
|
||||
public:
|
||||
Sha1HMac() : mac(Botan::get_mac("HMAC(SHA-1)")) {}
|
||||
virtual ~Sha1HMac() {
|
||||
delete mac;
|
||||
}
|
||||
|
||||
virtual int outputSize() const {
|
||||
return mac->output_length();
|
||||
}
|
||||
|
||||
virtual bool setKey(const CipherKey &key) {
|
||||
SymmetricKey bkey(key.data(), key.size());
|
||||
mac->set_key(bkey);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void init() {
|
||||
}
|
||||
|
||||
virtual bool update(const byte *in, int length) {
|
||||
mac->update(in, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool write(byte *out) {
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, outputSize()) != 0) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
mac->final(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
Properties props;
|
||||
props.blockSize = 160 >> 3;
|
||||
props.hashFunction = "SHA-1";
|
||||
props.mode = "HMAC";
|
||||
props.library = "Botan";
|
||||
return props;
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(Sha1HMac, MAC);
|
||||
|
||||
} // namespace botan
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user