2013-03-06 09:02:23 +01:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* Author: Valient Gough <vgough@pobox.com>
|
|
|
|
*
|
|
|
|
*****************************************************************************
|
|
|
|
* Copyright (c) 2013 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-03-06 09:02:23 +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 "cipher/botan.h"
|
|
|
|
#include "base/config.h"
|
2013-06-17 05:11:46 +02:00
|
|
|
#include "base/shared_ptr.h"
|
2013-03-06 09:02:23 +01:00
|
|
|
|
|
|
|
#include <glog/logging.h>
|
|
|
|
#include <botan/botan.h>
|
|
|
|
|
|
|
|
#include "base/Error.h"
|
|
|
|
#include "base/Mutex.h"
|
|
|
|
#include "base/Range.h"
|
|
|
|
|
|
|
|
#include "cipher/BlockCipher.h"
|
|
|
|
#include "cipher/MAC.h"
|
|
|
|
#include "cipher/MemoryPool.h"
|
|
|
|
#include "cipher/PBKDF.h"
|
|
|
|
#include "cipher/StreamCipher.h"
|
|
|
|
|
2013-06-17 05:11:46 +02:00
|
|
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
|
|
|
#include <valgrind/memcheck.h>
|
|
|
|
#endif
|
|
|
|
|
2013-03-06 09:02:23 +01:00
|
|
|
#include <string>
|
2013-10-03 07:10:01 +02:00
|
|
|
#include <sstream>
|
2013-03-06 09:02:23 +01:00
|
|
|
|
|
|
|
using namespace Botan;
|
2013-06-17 05:11:46 +02:00
|
|
|
using std::string;
|
2013-03-06 09:02:23 +01:00
|
|
|
|
|
|
|
namespace encfs {
|
|
|
|
namespace botan {
|
|
|
|
|
|
|
|
class PbkdfPkcs5Hmac : public PBKDF {
|
|
|
|
Botan::PBKDF* pbkdf_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
PbkdfPkcs5Hmac(Botan::PBKDF* pbkdf) : pbkdf_(pbkdf) {}
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual ~PbkdfPkcs5Hmac() { delete pbkdf_; }
|
2013-03-06 09:02:23 +01:00
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual bool makeKey(const char* password, int passwordLength,
|
|
|
|
const byte* salt, int saltLength, int numIterations,
|
|
|
|
CipherKey* outKey) {
|
2013-03-06 09:02:23 +01:00
|
|
|
if (pbkdf_ == NULL) {
|
|
|
|
// TODO: error message
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string pass;
|
|
|
|
pass.assign(password, passwordLength);
|
2013-10-20 00:35:26 +02:00
|
|
|
OctetString key = pbkdf_->derive_key(outKey->size(), pass, salt, saltLength,
|
|
|
|
numIterations);
|
2013-03-06 09:02:23 +01:00
|
|
|
memcpy(outKey->data(), key.begin(), outKey->size());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual CipherKey randomKey(int length) {
|
|
|
|
CipherKey key(length);
|
|
|
|
rng.randomize(key.data(), key.size());
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual bool pseudoRandom(byte* out, int length) {
|
2013-03-06 09:02:23 +01:00
|
|
|
rng.randomize(out, length);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
AutoSeeded_RNG rng;
|
|
|
|
};
|
2013-10-20 00:35:26 +02:00
|
|
|
|
2013-03-06 09:02:23 +01:00
|
|
|
class PbkdfPkcs5HmacSha1 : public PbkdfPkcs5Hmac {
|
|
|
|
public:
|
2013-10-20 00:35:26 +02:00
|
|
|
PbkdfPkcs5HmacSha1() : PbkdfPkcs5Hmac(get_pbkdf("PBKDF2(SHA-1)")) {}
|
|
|
|
~PbkdfPkcs5HmacSha1() {}
|
2013-03-06 09:02:23 +01:00
|
|
|
|
|
|
|
static Properties GetProperties() {
|
|
|
|
Properties props;
|
|
|
|
props.mode = NAME_PBKDF2_HMAC_SHA1;
|
|
|
|
props.library = "Botan";
|
|
|
|
return props;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_CLASS(PbkdfPkcs5HmacSha1, PBKDF);
|
|
|
|
|
|
|
|
class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac {
|
|
|
|
public:
|
2013-10-20 00:35:26 +02:00
|
|
|
PbkdfPkcs5HmacSha256() : PbkdfPkcs5Hmac(get_pbkdf("PBKDF2(SHA-256)")) {}
|
|
|
|
~PbkdfPkcs5HmacSha256() {}
|
2013-03-06 09:02:23 +01:00
|
|
|
|
|
|
|
static Properties GetProperties() {
|
|
|
|
Properties props;
|
|
|
|
props.mode = NAME_PBKDF2_HMAC_SHA256;
|
|
|
|
props.library = "Botan";
|
|
|
|
return props;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF);
|
|
|
|
|
2013-06-17 05:11:46 +02:00
|
|
|
class BotanBlockCipher : public BlockCipher {
|
2013-10-20 00:35:26 +02:00
|
|
|
Keyed_Filter* encryption; // Not owned.
|
|
|
|
Keyed_Filter* decryption; // Not owned.
|
2013-06-17 05:11:46 +02:00
|
|
|
shared_ptr<Pipe> encryptor;
|
|
|
|
shared_ptr<Pipe> decryptor;
|
2013-10-20 00:35:26 +02:00
|
|
|
|
2013-06-17 05:11:46 +02:00
|
|
|
public:
|
2013-10-21 07:38:54 +02:00
|
|
|
BotanBlockCipher() : encryption(nullptr), decryption(nullptr) {}
|
2013-06-17 05:11:46 +02:00
|
|
|
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 ||
|
2013-10-20 00:35:26 +02:00
|
|
|
VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0 ||
|
2013-06-17 05:11:46 +02:00
|
|
|
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
|
2013-10-20 00:35:26 +02:00
|
|
|
<< ", got " << written;
|
|
|
|
LOG_IF(ERROR, encryptor->remaining() > 0)
|
|
|
|
<< "unread bytes in pipe: " << encryptor->remaining();
|
2013-06-17 05:11:46 +02:00
|
|
|
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
|
2013-10-20 00:35:26 +02:00
|
|
|
<< ", got " << written;
|
|
|
|
LOG_IF(ERROR, decryptor->remaining() > 0)
|
|
|
|
<< "unread bytes in pipe: " << decryptor->remaining();
|
2013-06-17 05:11:46 +02:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual int blockSize() const { return 128 >> 3; }
|
2013-06-17 05:11:46 +02:00
|
|
|
|
|
|
|
static Properties GetProperties() {
|
2013-10-20 00:35:26 +02:00
|
|
|
return Properties(Range(128, 256, 64), "AES", "CBC", "Botan");
|
2013-06-17 05:11:46 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual int blockSize() const { return 128 >> 3; }
|
2013-06-17 05:11:46 +02:00
|
|
|
|
|
|
|
static Properties GetProperties() {
|
2013-10-20 00:35:26 +02:00
|
|
|
return Properties(Range(128, 256, 64), "AES", "CFB", "Botan");
|
2013-06-17 05:11:46 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_CLASS(BotanAesCfb, StreamCipher);
|
|
|
|
|
|
|
|
class BotanBlowfishCbc : public BotanBlockCipher {
|
|
|
|
public:
|
|
|
|
BotanBlowfishCbc() {}
|
|
|
|
virtual ~BotanBlowfishCbc() {}
|
|
|
|
|
|
|
|
virtual bool setKey(const CipherKey& key) {
|
|
|
|
std::ostringstream ss;
|
2013-10-20 00:35:26 +02:00
|
|
|
ss << "Blowfish"
|
|
|
|
<< "/CBC/NoPadding";
|
2013-06-17 05:11:46 +02:00
|
|
|
return rekey(key, ss.str());
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual int blockSize() const { return 64 >> 3; }
|
2013-06-17 05:11:46 +02:00
|
|
|
|
|
|
|
static Properties GetProperties() {
|
2013-10-20 00:35:26 +02:00
|
|
|
return Properties(Range(128, 256, 32), "Blowfish", "CBC", "Botan");
|
2013-06-17 05:11:46 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_CLASS(BotanBlowfishCbc, BlockCipher);
|
|
|
|
|
|
|
|
class BotanBlowfishCfb : public BotanBlockCipher {
|
|
|
|
public:
|
|
|
|
BotanBlowfishCfb() {}
|
|
|
|
virtual ~BotanBlowfishCfb() {}
|
|
|
|
|
|
|
|
virtual bool setKey(const CipherKey& key) {
|
|
|
|
std::ostringstream ss;
|
2013-10-20 00:35:26 +02:00
|
|
|
ss << "Blowfish"
|
|
|
|
<< "/CFB";
|
2013-06-17 05:11:46 +02:00
|
|
|
return rekey(key, ss.str());
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual int blockSize() const { return 64 >> 3; }
|
2013-06-17 05:11:46 +02:00
|
|
|
|
|
|
|
static Properties GetProperties() {
|
2013-10-20 00:35:26 +02:00
|
|
|
return Properties(Range(128, 256, 32), "Blowfish", "CFB", "Botan");
|
2013-06-17 05:11:46 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_CLASS(BotanBlowfishCfb, StreamCipher);
|
|
|
|
|
|
|
|
class Sha1HMac : public MAC {
|
2013-10-20 00:35:26 +02:00
|
|
|
MessageAuthenticationCode* mac;
|
2013-06-17 05:11:46 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
Sha1HMac() : mac(Botan::get_mac("HMAC(SHA-1)")) {}
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual ~Sha1HMac() { delete mac; }
|
2013-06-17 05:11:46 +02:00
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual int outputSize() const { return mac->output_length(); }
|
2013-06-17 05:11:46 +02:00
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual bool setKey(const CipherKey& key) {
|
2013-06-17 05:11:46 +02:00
|
|
|
SymmetricKey bkey(key.data(), key.size());
|
|
|
|
mac->set_key(bkey);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual void init() {}
|
2013-06-17 05:11:46 +02:00
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual bool update(const byte* in, int length) {
|
2013-06-17 05:11:46 +02:00
|
|
|
mac->update(in, length);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:35:26 +02:00
|
|
|
virtual bool write(byte* out) {
|
2013-06-17 05:11:46 +02:00
|
|
|
#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);
|
2013-03-06 09:02:23 +01:00
|
|
|
|
|
|
|
} // namespace botan
|
|
|
|
|
|
|
|
static Botan::LibraryInitializer* initializer;
|
|
|
|
|
|
|
|
void Botan_init(bool threaded) {
|
|
|
|
if (threaded) {
|
|
|
|
initializer = new Botan::LibraryInitializer("thread_safe=true");
|
|
|
|
} else {
|
|
|
|
initializer = new Botan::LibraryInitializer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Botan_shutdown() {
|
|
|
|
delete initializer;
|
|
|
|
initializer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Botan_registerCiphers() {
|
|
|
|
// Just a reference to ensure static initializers are linked.
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace encfs
|