mirror of
https://github.com/vgough/encfs.git
synced 2025-08-19 10:02:28 +02:00
break out cipher primitives, add unit tests
git-svn-id: http://encfs.googlecode.com/svn/trunk@94 db9cf616-1c43-0410-9cb8-a902689de0d6
This commit is contained in:
29
cipher/BlockCipher.cpp
Normal file
29
cipher/BlockCipher.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "cipher/BlockCipher.h"
|
||||
|
||||
// TODO: add ifdef when OpenSSL becomes optional.
|
||||
#include "cipher/openssl.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
Registry<BlockCipher>& BlockCipher::GetRegistry()
|
||||
{
|
||||
static Registry<BlockCipher> registry;
|
||||
static bool first = true;
|
||||
if (first)
|
||||
{
|
||||
OpenSSL::registerCiphers();
|
||||
first = false;
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
|
||||
BlockCipher::BlockCipher()
|
||||
{
|
||||
}
|
||||
|
||||
BlockCipher::~BlockCipher()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
28
cipher/BlockCipher.h
Normal file
28
cipher/BlockCipher.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef BLOCKCIPHER_H
|
||||
#define BLOCKCIPHER_H
|
||||
|
||||
#include "base/Interface.h"
|
||||
#include "base/Range.h"
|
||||
#include "base/Registry.h"
|
||||
#include "base/shared_ptr.h"
|
||||
#include "base/types.h"
|
||||
#include "cipher/StreamCipher.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
// BlockCipher is a StreamCipher with a block size.
|
||||
// Encryption and decryption must be in multiples of the block size.
|
||||
class BlockCipher : public StreamCipher
|
||||
{
|
||||
public:
|
||||
static Registry<BlockCipher>& GetRegistry();
|
||||
|
||||
BlockCipher();
|
||||
virtual ~BlockCipher();
|
||||
|
||||
virtual int blockSize() const =0;
|
||||
};
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
#endif // BLOCKCIPHER_H
|
95
cipher/BlockCipher_test.cpp
Normal file
95
cipher/BlockCipher_test.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
|
||||
/*****************************************************************************
|
||||
* 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
|
||||
* 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 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 <list>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "base/shared_ptr.h"
|
||||
#include "cipher/BlockCipher.h"
|
||||
#include "cipher/MemoryPool.h"
|
||||
|
||||
using namespace encfs;
|
||||
using std::list;
|
||||
using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
void compare(const byte *a, const byte *b, int size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
bool match = (a[i] == b[i]);
|
||||
ASSERT_TRUE(match) << "mismatched data at offset " << i
|
||||
<< " of " << size;
|
||||
if (!match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BlockEncryptionTest, BlockCipher) {
|
||||
Registry<BlockCipher> registry = BlockCipher::GetRegistry();
|
||||
list<string> ciphers = registry.GetAll();
|
||||
for (const string &name : ciphers) {
|
||||
const BlockCipher::Properties *properties = registry.GetProperties(name.c_str());
|
||||
SCOPED_TRACE(testing::Message() << "Cipher " << name);
|
||||
|
||||
for (int keySize = properties->keySize.min();
|
||||
keySize <= properties->keySize.max();
|
||||
keySize += properties->keySize.inc()) {
|
||||
SCOPED_TRACE(testing::Message() << "Key size " << keySize);
|
||||
|
||||
shared_ptr<BlockCipher> cipher (registry.Create(name.c_str()));
|
||||
|
||||
ASSERT_TRUE(cipher->randomKey(keySize / 8));
|
||||
|
||||
// Create some data to encrypt.
|
||||
int blockSize = cipher->blockSize();
|
||||
MemBlock mb;
|
||||
mb.allocate(16 * blockSize);
|
||||
|
||||
for (int i = 0; i < 16 * blockSize; i++) {
|
||||
mb.data[i] = i % 256;
|
||||
}
|
||||
|
||||
MemBlock iv;
|
||||
iv.allocate(blockSize);
|
||||
for (int i = 0; i < blockSize; i++) {
|
||||
iv.data[i] = i;
|
||||
}
|
||||
|
||||
// Encrypt.
|
||||
MemBlock encrypted;
|
||||
encrypted.allocate(16 * blockSize);
|
||||
|
||||
ASSERT_TRUE(cipher->encrypt(iv.data, mb.data,
|
||||
encrypted.data, 16 * blockSize));
|
||||
|
||||
// Decrypt.
|
||||
MemBlock decrypted;
|
||||
decrypted.allocate(16 * blockSize);
|
||||
ASSERT_TRUE(cipher->decrypt(iv.data, encrypted.data,
|
||||
decrypted.data, 16 * blockSize));
|
||||
|
||||
compare(mb.data, decrypted.data, 16 * blockSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
@@ -2,41 +2,42 @@ include_directories (${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
link_directories (${Encfs_BINARY_DIR}/base)
|
||||
|
||||
enable_testing ()
|
||||
find_package (GTest REQUIRED)
|
||||
|
||||
add_library (encfs-cipher
|
||||
readpassphrase.cpp
|
||||
BlockCipher.cpp
|
||||
Cipher.cpp
|
||||
CipherKey.cpp
|
||||
MAC.cpp
|
||||
MemoryPool.cpp
|
||||
NullCipher.cpp
|
||||
openssl.cpp
|
||||
PBKDF.cpp
|
||||
readpassphrase.cpp
|
||||
SSL_Cipher.cpp
|
||||
StreamCipher.cpp
|
||||
)
|
||||
|
||||
target_link_libraries (encfs-cipher
|
||||
${OPENSSL_LIBRARIES}
|
||||
)
|
||||
|
||||
#include_directories (${GTEST_INCLUDE_DIR})
|
||||
#add_executable (unittests
|
||||
#MemBlockFileIO.cpp
|
||||
#MemFileIO.cpp
|
||||
#testing.cpp
|
||||
#test_IO.cpp
|
||||
#test_BlockIO.cpp
|
||||
#)
|
||||
if (GTEST_FOUND)
|
||||
link_directories (${PROJECT_BINARY_DIR}/base)
|
||||
include_directories (${GTEST_INCLUDE_DIR})
|
||||
|
||||
#target_link_libraries (unittests
|
||||
#${GTEST_BOTH_LIBRARIES}
|
||||
#encfs-fs
|
||||
#encfs-base
|
||||
#${GLOG_LIBRARIES}
|
||||
#)
|
||||
file (GLOB TEST_FILES "*_test.cpp")
|
||||
|
||||
#add_test (UnitTests unittests)
|
||||
#GTEST_ADD_TESTS (unittests "${UnitTestArgs}" test_IO.cpp test_BlockIO.cpp)
|
||||
#add_custom_target (test COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests)
|
||||
add_executable (cipher-tests
|
||||
testing.cpp
|
||||
${TEST_FILES}
|
||||
)
|
||||
|
||||
target_link_libraries (cipher-tests
|
||||
${GTEST_BOTH_LIBRARIES}
|
||||
encfs-cipher
|
||||
encfs-base
|
||||
${GLOG_LIBRARIES}
|
||||
)
|
||||
|
||||
add_test (CipherTests cipher-tests)
|
||||
GTEST_ADD_TESTS (cipher-tests "${CipherTestArgs}" ${TEST_FILES})
|
||||
endif (GTEST_FOUND)
|
||||
|
16
cipher/MAC.cpp
Normal file
16
cipher/MAC.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "cipher/MAC.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
DEFINE_REGISTERABLE_TYPE(MessageAuthenticationCode)
|
||||
|
||||
MessageAuthenticationCode::MessageAuthenticationCode()
|
||||
{
|
||||
}
|
||||
|
||||
MessageAuthenticationCode::~MessageAuthenticationCode()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
43
cipher/MAC.h
Normal file
43
cipher/MAC.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef ENCFS_MAC_H
|
||||
#define ENCFS_MAC_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/Registry.h"
|
||||
#include "base/types.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
// MessageAuthenticationCode provides keyed MAC algorithms, eg HMAC.
|
||||
class MessageAuthenticationCode
|
||||
{
|
||||
public:
|
||||
DECLARE_REGISTERABLE_TYPE(MessageAuthenticationCode);
|
||||
|
||||
struct Properties {
|
||||
int blockSize; // Block length of hash function.
|
||||
std::string hashFunction;
|
||||
std::string mode;
|
||||
std::string library;
|
||||
|
||||
std::string toString() const {
|
||||
return hashFunction + "/" + mode;
|
||||
}
|
||||
};
|
||||
|
||||
MessageAuthenticationCode();
|
||||
virtual ~MessageAuthenticationCode();
|
||||
|
||||
virtual int outputSize() const =0;
|
||||
|
||||
virtual bool setKey(const byte *key, int keyLength) =0;
|
||||
virtual bool randomKey(int keyLength) =0;
|
||||
|
||||
virtual void reset() =0;
|
||||
virtual bool update(const byte *in, int length) =0;
|
||||
virtual bool write(byte *out) =0;
|
||||
};
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
#endif // ENCFS_MAC_H
|
88
cipher/MAC_test.cpp
Normal file
88
cipher/MAC_test.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
/*****************************************************************************
|
||||
* 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
|
||||
* 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 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 <string.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "base/shared_ptr.h"
|
||||
#include "cipher/MAC.h"
|
||||
#include "cipher/testing.h"
|
||||
|
||||
using namespace encfs;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(HMacSha1Test, MessageAuthenticationCode) {
|
||||
Registry<MessageAuthenticationCode> registry =
|
||||
MessageAuthenticationCode::GetRegistry();
|
||||
shared_ptr<MessageAuthenticationCode> hmac(
|
||||
registry.CreateForMatch( "SHA-1/HMAC" ));
|
||||
ASSERT_FALSE(!hmac);
|
||||
|
||||
// Test cases from rfc2202
|
||||
// Test case 1
|
||||
byte key[20];
|
||||
byte out[20];
|
||||
for (int i = 0; i < 20; ++i)
|
||||
key[i] = 0x0b;
|
||||
hmac->setKey(key, 20);
|
||||
hmac->reset();
|
||||
hmac->update((byte *)"Hi There", 8);
|
||||
hmac->write(out);
|
||||
ASSERT_EQ("b617318655057264e28bc0b6fb378c8ef146be00", stringToHex(out, 20));
|
||||
|
||||
// Test case 2
|
||||
strcpy((char *)key, "Jefe");
|
||||
hmac->setKey(key, 4);
|
||||
hmac->reset();
|
||||
hmac->update((byte *)"what do ya want for nothing?", 28);
|
||||
hmac->write(out);
|
||||
ASSERT_EQ("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", stringToHex(out, 20));
|
||||
|
||||
// Test case 3
|
||||
for (int i = 0; i < 20; ++i)
|
||||
key[i] = 0xaa;
|
||||
hmac->setKey(key, 20);
|
||||
hmac->reset();
|
||||
{
|
||||
byte data[50];
|
||||
memset(data, 0xdd, 50);
|
||||
hmac->update(data, 50);
|
||||
}
|
||||
hmac->write(out);
|
||||
ASSERT_EQ("125d7342b9ac11cd91a39af48aa17b4f63f175d3", stringToHex(out, 20));
|
||||
|
||||
// Test #7
|
||||
byte longKey[80];
|
||||
memset(longKey, 0xaa, 80);
|
||||
hmac->setKey(longKey, 80);
|
||||
hmac->reset();
|
||||
hmac->update((byte *)"Test Using Larger Than Block-Size Key and Larger "
|
||||
"Than One Block-Size Data", 73);
|
||||
hmac->write(out);
|
||||
ASSERT_EQ("e8e99d0f45237d786d6bbaa7965c7808bbff1a91", stringToHex(out, 20));
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
@@ -134,7 +134,7 @@ void MemoryPool::destroyAll()
|
||||
SecureMem::SecureMem(int len)
|
||||
{
|
||||
rAssert(len > 0);
|
||||
data = (char *)OPENSSL_malloc(len);
|
||||
data = (byte *)OPENSSL_malloc(len);
|
||||
if (data)
|
||||
{
|
||||
size = len;
|
||||
|
@@ -29,7 +29,8 @@ namespace encfs {
|
||||
Memory Pool for fixed sized objects.
|
||||
|
||||
Usage:
|
||||
MemBlock mb( size );
|
||||
MemBlock mb;
|
||||
mb.allocate( size );
|
||||
// do things with storage in mb.data
|
||||
byte *buffer = mb.data;
|
||||
|
||||
@@ -59,7 +60,7 @@ namespace MemoryPool
|
||||
struct SecureMem
|
||||
{
|
||||
int size;
|
||||
char *data;
|
||||
byte *data;
|
||||
|
||||
SecureMem(int len);
|
||||
~SecureMem();
|
||||
|
16
cipher/PBKDF.cpp
Normal file
16
cipher/PBKDF.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "cipher/PBKDF.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
DEFINE_REGISTERABLE_TYPE(PBKDF)
|
||||
|
||||
PBKDF::PBKDF()
|
||||
{
|
||||
}
|
||||
|
||||
PBKDF::~PBKDF()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
35
cipher/PBKDF.h
Normal file
35
cipher/PBKDF.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef ENCFS_PBKDF_H
|
||||
#define ENCFS_PBKDF_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/Registry.h"
|
||||
#include "base/types.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
// Password Based Key Derivation Function.
|
||||
class PBKDF
|
||||
{
|
||||
public:
|
||||
DECLARE_REGISTERABLE_TYPE(PBKDF);
|
||||
|
||||
struct Properties {
|
||||
std::string mode;
|
||||
std::string library;
|
||||
|
||||
std::string toString() const { return mode; }
|
||||
};
|
||||
|
||||
PBKDF();
|
||||
virtual ~PBKDF();
|
||||
|
||||
virtual bool makeKey(const char *password, int passwordLength,
|
||||
const byte *salt, int saltLength,
|
||||
int numIterations,
|
||||
byte *outKey, int keyLength) const = 0;
|
||||
};
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
#endif // ENCFS_PBKDF_H
|
78
cipher/PBKDF_test.cpp
Normal file
78
cipher/PBKDF_test.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
/*****************************************************************************
|
||||
* 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
|
||||
* 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 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 <string.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "base/shared_ptr.h"
|
||||
#include "cipher/PBKDF.h"
|
||||
#include "cipher/testing.h"
|
||||
|
||||
using namespace encfs;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) {
|
||||
Registry<PBKDF> registry = PBKDF::GetRegistry();
|
||||
shared_ptr<PBKDF> impl( registry.CreateForMatch( "PKCS5_PBKDF2_HMAC_SHA1" ));
|
||||
ASSERT_FALSE(!impl);
|
||||
|
||||
// Test cases from rfc6070
|
||||
// Test case 1
|
||||
{
|
||||
byte key[20];
|
||||
bool ok = impl->makeKey("password", 8,
|
||||
(byte*)"salt", 4,
|
||||
1,
|
||||
key, sizeof(key));
|
||||
ASSERT_TRUE(ok);
|
||||
ASSERT_EQ("0c60c80f961f0e71f3a9b524af6012062fe037a6",
|
||||
stringToHex(key, sizeof(key)));
|
||||
}
|
||||
|
||||
{
|
||||
byte key[25];
|
||||
bool ok = impl->makeKey("passwordPASSWORDpassword", 24,
|
||||
(byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
|
||||
4096,
|
||||
key, sizeof(key));
|
||||
ASSERT_TRUE(ok);
|
||||
ASSERT_EQ("3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038",
|
||||
stringToHex(key, sizeof(key)));
|
||||
}
|
||||
|
||||
{
|
||||
byte key[16];
|
||||
bool ok = impl->makeKey("pass\0word", 9,
|
||||
(byte*)"sa\0lt", 5,
|
||||
4096,
|
||||
key, sizeof(key));
|
||||
ASSERT_TRUE(ok);
|
||||
ASSERT_EQ("56fa6aa75548099dcc37d7f03425e0c3",
|
||||
stringToHex(key, sizeof(key)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "cipher/SSL_Cipher.h"
|
||||
#include "cipher/MemoryPool.h"
|
||||
#include "cipher/BlockCipher.h"
|
||||
#include "base/Error.h"
|
||||
#include "base/Mutex.h"
|
||||
#include "base/Range.h"
|
||||
@@ -65,13 +66,13 @@ inline int MIN(int a, int b)
|
||||
|
||||
DEPRECATED: this is here for backward compatibilty only. Use PBKDF
|
||||
*/
|
||||
int BytesToKey( int keyLen, int ivLen, const EVP_MD *md,
|
||||
int BytesToKey(int keyLen, int ivLen, const EVP_MD *md,
|
||||
const byte *data, int dataLen,
|
||||
unsigned int rounds, byte *key, byte *iv)
|
||||
{
|
||||
if( data == NULL || dataLen == 0 )
|
||||
return 0; // OpenSSL returns nkey here, but why? It is a failure..
|
||||
|
||||
|
||||
byte mdBuf[ EVP_MAX_MD_SIZE ];
|
||||
unsigned int mds=0;
|
||||
int addmd =0;
|
||||
@@ -110,7 +111,7 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md,
|
||||
{
|
||||
memcpy( iv, mdBuf+offset, toCopy );
|
||||
iv += toCopy;
|
||||
niv -= toCopy;
|
||||
niv -= toCopy;
|
||||
offset += toCopy;
|
||||
}
|
||||
if((nkey == 0) && (niv == 0)) break;
|
||||
@@ -128,9 +129,9 @@ long time_diff(const timeval &end, const timeval &start)
|
||||
}
|
||||
|
||||
int SSL_Cipher::TimedPBKDF2(const char *pass, int passlen,
|
||||
const byte *salt, int saltlen,
|
||||
int keylen, byte *out,
|
||||
long desiredPDFTime)
|
||||
const byte *salt, int saltlen,
|
||||
int keylen, byte *out,
|
||||
long desiredPDFTime)
|
||||
{
|
||||
int iter = 1000;
|
||||
timeval start, end;
|
||||
@@ -188,8 +189,9 @@ static shared_ptr<Cipher> NewBFCipher( const Interface &iface, int keyLen )
|
||||
const EVP_CIPHER *blockCipher = EVP_bf_cbc();
|
||||
const EVP_CIPHER *streamCipher = EVP_bf_cfb();
|
||||
|
||||
return shared_ptr<Cipher>( new SSL_Cipher(iface, BlowfishInterface,
|
||||
blockCipher, streamCipher, keyLen / 8) );
|
||||
return shared_ptr<Cipher>(
|
||||
new SSL_Cipher(iface, BlowfishInterface,
|
||||
blockCipher, streamCipher, keyLen / 8) );
|
||||
}
|
||||
|
||||
static bool BF_Cipher_registered = Cipher::Register(
|
||||
@@ -239,8 +241,8 @@ static shared_ptr<Cipher> NewAESCipher( const Interface &iface, int keyLen )
|
||||
}
|
||||
|
||||
static bool AES_Cipher_registered = Cipher::Register(
|
||||
"AES", "16 byte block cipher",
|
||||
AESInterface, AESKeyRange, AESBlockRange, NewAESCipher, true);
|
||||
"AES", "16 byte block cipher",
|
||||
AESInterface, AESKeyRange, AESBlockRange, NewAESCipher, true);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_EVP_AES_XTS)
|
||||
@@ -276,35 +278,35 @@ static shared_ptr<Cipher> NewAesXtsCipher( const Interface &iface, int keyLen )
|
||||
}
|
||||
|
||||
static bool AES_XTS_Cipher_registered = Cipher::Register(
|
||||
"AES_XTS", "Tweakable wide-block cipher",
|
||||
AesXtsInterface, AesXtsKeyRange, AesXtsBlockRange, NewAesXtsCipher, false);
|
||||
"AES_XTS", "Tweakable wide-block cipher",
|
||||
AesXtsInterface, AesXtsKeyRange, AesXtsBlockRange, NewAesXtsCipher, false);
|
||||
#endif
|
||||
|
||||
class SSLKey : public AbstractCipherKey
|
||||
{
|
||||
public:
|
||||
pthread_mutex_t mutex;
|
||||
public:
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
unsigned int keySize; // in bytes
|
||||
unsigned int ivLength;
|
||||
unsigned int keySize; // in bytes
|
||||
unsigned int ivLength;
|
||||
|
||||
// key data is first _keySize bytes,
|
||||
// followed by iv of _ivLength bytes,
|
||||
SecureMem buf;
|
||||
// key data is first _keySize bytes,
|
||||
// followed by iv of _ivLength bytes,
|
||||
SecureMem buf;
|
||||
|
||||
EVP_CIPHER_CTX block_enc;
|
||||
EVP_CIPHER_CTX block_dec;
|
||||
EVP_CIPHER_CTX stream_enc;
|
||||
EVP_CIPHER_CTX stream_dec;
|
||||
EVP_CIPHER_CTX block_enc;
|
||||
EVP_CIPHER_CTX block_dec;
|
||||
EVP_CIPHER_CTX stream_enc;
|
||||
EVP_CIPHER_CTX stream_dec;
|
||||
|
||||
HMAC_CTX mac_ctx;
|
||||
HMAC_CTX mac_ctx;
|
||||
|
||||
SSLKey(int keySize, int ivLength);
|
||||
~SSLKey();
|
||||
SSLKey(int keySize, int ivLength);
|
||||
~SSLKey();
|
||||
};
|
||||
|
||||
SSLKey::SSLKey(int keySize_, int ivLength_)
|
||||
: buf(keySize_ + ivLength_)
|
||||
: buf(keySize_ + ivLength_)
|
||||
{
|
||||
rAssert(keySize_ >= 8);
|
||||
rAssert(ivLength_ >= 8);
|
||||
@@ -341,7 +343,7 @@ inline byte* IVData( const shared_ptr<SSLKey> &key )
|
||||
}
|
||||
|
||||
void initKey(const shared_ptr<SSLKey> &key, const EVP_CIPHER *_blockCipher,
|
||||
const EVP_CIPHER *_streamCipher, int _keySize)
|
||||
const EVP_CIPHER *_streamCipher, int _keySize)
|
||||
{
|
||||
Lock lock( key->mutex );
|
||||
// initialize the cipher context once so that we don't have to do it for
|
||||
@@ -377,10 +379,10 @@ void initKey(const shared_ptr<SSLKey> &key, const EVP_CIPHER *_blockCipher,
|
||||
|
||||
|
||||
SSL_Cipher::SSL_Cipher(const Interface &iface_,
|
||||
const Interface &realIface_,
|
||||
const EVP_CIPHER *blockCipher,
|
||||
const EVP_CIPHER *streamCipher,
|
||||
int keySize_)
|
||||
const Interface &realIface_,
|
||||
const EVP_CIPHER *blockCipher,
|
||||
const EVP_CIPHER *streamCipher,
|
||||
int keySize_)
|
||||
{
|
||||
this->iface = iface_;
|
||||
this->realIface = realIface_;
|
||||
@@ -393,8 +395,8 @@ SSL_Cipher::SSL_Cipher(const Interface &iface_,
|
||||
rAssert(_ivLength <= _keySize);
|
||||
|
||||
VLOG(1) << "allocated cipher " << iface.name()
|
||||
<< ", keySize " << _keySize
|
||||
<< ", ivlength " << _ivLength;
|
||||
<< ", keySize " << _keySize
|
||||
<< ", ivlength " << _ivLength;
|
||||
|
||||
// EVP_CIPHER_key_length isn't useful for variable-length ciphers like
|
||||
// Blowfish. Version 1 relied upon it incorrectly.
|
||||
@@ -402,8 +404,8 @@ SSL_Cipher::SSL_Cipher(const Interface &iface_,
|
||||
&& iface.major() == 1)
|
||||
{
|
||||
LOG(WARNING) << "Running in backward compatibilty mode for 1.0 - \n"
|
||||
<< "key is really " << EVP_CIPHER_key_length( _blockCipher ) * 8
|
||||
<< " bits, not " << _keySize * 8;
|
||||
<< "key is really " << EVP_CIPHER_key_length( _blockCipher ) * 8
|
||||
<< " bits, not " << _keySize * 8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,10 +424,10 @@ Interface SSL_Cipher::interface() const
|
||||
|
||||
This algorithm must remain constant for backward compatibility, as this key
|
||||
is used to encipher/decipher the master key.
|
||||
*/
|
||||
*/
|
||||
CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
|
||||
int &iterationCount, long desiredDuration,
|
||||
const byte *salt, int saltLen)
|
||||
int &iterationCount, long desiredDuration,
|
||||
const byte *salt, int saltLen)
|
||||
{
|
||||
shared_ptr<SSLKey> key( new SSLKey( _keySize, _ivLength) );
|
||||
|
||||
@@ -477,7 +479,7 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength)
|
||||
if(bytes != (int)_keySize)
|
||||
{
|
||||
LOG(WARNING) << "newKey: BytesToKey returned " << bytes
|
||||
<< ", expecting " << _keySize << " key bytes";
|
||||
<< ", expecting " << _keySize << " key bytes";
|
||||
}
|
||||
} else
|
||||
{
|
||||
@@ -499,7 +501,7 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength)
|
||||
|
||||
This algorithm can change at any time without affecting backward
|
||||
compatibility.
|
||||
*/
|
||||
*/
|
||||
CipherKey SSL_Cipher::newRandomKey()
|
||||
{
|
||||
const int bufLen = MAX_KEYLENGTH;
|
||||
@@ -531,11 +533,11 @@ CipherKey SSL_Cipher::newRandomKey()
|
||||
|
||||
/*
|
||||
Compute a 64-bit check value for the data using HMAC.
|
||||
*/
|
||||
*/
|
||||
static uint64_t _checksum_64(SSLKey *key,
|
||||
const byte *data,
|
||||
int dataLen,
|
||||
uint64_t *chainedIV)
|
||||
const byte *data,
|
||||
int dataLen,
|
||||
uint64_t *chainedIV)
|
||||
{
|
||||
rAssert( dataLen > 0 );
|
||||
Lock lock( key->mutex );
|
||||
@@ -576,7 +578,7 @@ static uint64_t _checksum_64(SSLKey *key,
|
||||
}
|
||||
|
||||
bool SSL_Cipher::randomize( byte *buf, int len,
|
||||
bool strongRandom ) const
|
||||
bool strongRandom ) const
|
||||
{
|
||||
// to avoid warnings of uninitialized data from valgrind
|
||||
memset(buf, 0, len);
|
||||
@@ -599,7 +601,7 @@ bool SSL_Cipher::randomize( byte *buf, int len,
|
||||
}
|
||||
|
||||
uint64_t SSL_Cipher::MAC_64( const byte *data, int len,
|
||||
const CipherKey &key, uint64_t *chainedIV ) const
|
||||
const CipherKey &key, uint64_t *chainedIV ) const
|
||||
{
|
||||
shared_ptr<SSLKey> mk = dynamic_pointer_cast<SSLKey>(key);
|
||||
uint64_t tmp = _checksum_64( mk.get(), data, len, chainedIV );
|
||||
@@ -611,7 +613,7 @@ uint64_t SSL_Cipher::MAC_64( const byte *data, int len,
|
||||
}
|
||||
|
||||
CipherKey SSL_Cipher::readKey(const byte *data,
|
||||
const CipherKey &masterKey, bool checkKey)
|
||||
const CipherKey &masterKey, bool checkKey)
|
||||
{
|
||||
shared_ptr<SSLKey> mk = dynamic_pointer_cast<SSLKey>(masterKey);
|
||||
rAssert(mk->keySize == _keySize);
|
||||
@@ -638,8 +640,8 @@ CipherKey SSL_Cipher::readKey(const byte *data,
|
||||
if(checksum2 != checksum && checkKey)
|
||||
{
|
||||
VLOG(1) << "checksum mismatch: expected " << checksum
|
||||
<< ", got " << checksum2
|
||||
<< "on decode of " << _keySize + _ivLength << " bytes";
|
||||
<< ", got " << checksum2
|
||||
<< "on decode of " << _keySize + _ivLength << " bytes";
|
||||
OPENSSL_cleanse(tmpBuf, sizeof(tmpBuf));
|
||||
return CipherKey();
|
||||
}
|
||||
@@ -656,7 +658,7 @@ CipherKey SSL_Cipher::readKey(const byte *data,
|
||||
}
|
||||
|
||||
void SSL_Cipher::writeKey(const CipherKey &ckey, byte *data,
|
||||
const CipherKey &masterKey)
|
||||
const CipherKey &masterKey)
|
||||
{
|
||||
shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey);
|
||||
rAssert(key->keySize == _keySize);
|
||||
@@ -771,7 +773,7 @@ void SSL_Cipher::setIVec_old(byte *ivec,
|
||||
{
|
||||
unsigned int var1 = 0x060a4011 * seed;
|
||||
unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C);
|
||||
|
||||
|
||||
memcpy( ivec, IVData(key), _ivLength );
|
||||
|
||||
ivec[0] ^= (var1 >> 24) & 0xff;
|
||||
@@ -861,7 +863,7 @@ bool SSL_Cipher::streamEncode(byte *buf, int size,
|
||||
|
||||
dstLen += tmpLen;
|
||||
LOG_IF(ERROR, dstLen != size) << "encoding " << size
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -897,7 +899,7 @@ bool SSL_Cipher::streamDecode(byte *buf, int size,
|
||||
|
||||
dstLen += tmpLen;
|
||||
LOG_IF(ERROR, dstLen != size) << "encoding " << size
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -928,7 +930,7 @@ bool SSL_Cipher::blockEncode(byte *buf, int size,
|
||||
dstLen += tmpLen;
|
||||
|
||||
LOG_IF(ERROR, dstLen != size) << "encoding " << size
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -958,7 +960,7 @@ bool SSL_Cipher::blockDecode(byte *buf, int size,
|
||||
dstLen += tmpLen;
|
||||
|
||||
LOG_IF(ERROR, dstLen != size) << "decoding " << size
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
20
cipher/StreamCipher.cpp
Normal file
20
cipher/StreamCipher.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "cipher/StreamCipher.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
Registry<StreamCipher>& StreamCipher::GetRegistry()
|
||||
{
|
||||
static Registry<StreamCipher> registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
StreamCipher::StreamCipher()
|
||||
{
|
||||
}
|
||||
|
||||
StreamCipher::~StreamCipher()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
60
cipher/StreamCipher.h
Normal file
60
cipher/StreamCipher.h
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
/*****************************************************************************
|
||||
* 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
|
||||
* 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 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _STREAMCIPHER_incl_
|
||||
#define _STREAMCIPHER_incl_
|
||||
|
||||
#include "base/Range.h"
|
||||
#include "base/Registry.h"
|
||||
#include "base/shared_ptr.h"
|
||||
#include "base/types.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
class StreamCipher
|
||||
{
|
||||
public:
|
||||
static Registry<StreamCipher>& GetRegistry();
|
||||
|
||||
struct Properties {
|
||||
Range keySize;
|
||||
std::string cipher;
|
||||
std::string mode;
|
||||
std::string library;
|
||||
};
|
||||
|
||||
StreamCipher();
|
||||
virtual ~StreamCipher();
|
||||
|
||||
virtual bool setKey(const byte *key, int keyLength) =0;
|
||||
virtual bool randomKey(int keyLength) =0;
|
||||
|
||||
virtual bool encrypt(const byte *iv, const byte *in,
|
||||
byte *out, int numBytes) =0;
|
||||
virtual bool decrypt(const byte *iv, const byte *in,
|
||||
byte *out, int numBytes) =0;
|
||||
};
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* Author: Valient Gough <vgough@pobox.com>
|
||||
*
|
||||
*****************************************************************************
|
||||
* Copyright (c) 2007, Valient Gough
|
||||
* Copyright (c) 2007-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
|
||||
@@ -20,10 +20,16 @@
|
||||
|
||||
#include "cipher/openssl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "base/config.h"
|
||||
|
||||
#define NO_DES
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
@@ -31,8 +37,345 @@
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/blowfish.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "base/Error.h"
|
||||
#include "base/i18n.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"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace encfs {
|
||||
|
||||
const int MAX_KEYLENGTH = 64; // in bytes (256 bit)
|
||||
const int MAX_IVLENGTH = 16;
|
||||
const int KEY_CHECKSUM_BYTES = 4;
|
||||
|
||||
#ifndef MIN
|
||||
inline int MIN(int a, int b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Base for {Block,Stream}Cipher implementation.
|
||||
class OpenSSLCipher : public BlockCipher {
|
||||
public:
|
||||
OpenSSLCipher() {
|
||||
}
|
||||
|
||||
virtual ~OpenSSLCipher() {
|
||||
EVP_CIPHER_CTX_cleanup( &enc );
|
||||
EVP_CIPHER_CTX_cleanup( &dec );
|
||||
}
|
||||
|
||||
bool rekey(const EVP_CIPHER *cipher, const byte *key, int length) {
|
||||
EVP_CIPHER_CTX_init( &enc );
|
||||
EVP_EncryptInit_ex( &enc, cipher, NULL, NULL, NULL);
|
||||
EVP_CIPHER_CTX_set_key_length( &enc, length );
|
||||
EVP_CIPHER_CTX_set_padding( &enc, 0 );
|
||||
EVP_EncryptInit_ex( &enc, NULL, NULL, key, NULL);
|
||||
|
||||
EVP_CIPHER_CTX_init( &dec );
|
||||
EVP_DecryptInit_ex( &dec, cipher, NULL, NULL, NULL);
|
||||
EVP_CIPHER_CTX_set_key_length( &dec, length );
|
||||
EVP_CIPHER_CTX_set_padding( &dec, 0 );
|
||||
EVP_DecryptInit_ex( &dec, NULL, NULL, key, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool randomize(byte *out, int len) {
|
||||
int result = RAND_bytes( out, len );
|
||||
if(result != 1)
|
||||
{
|
||||
char errStr[120]; // specs require string at least 120 bytes long..
|
||||
unsigned long errVal = 0;
|
||||
if((errVal = ERR_get_error()) != 0)
|
||||
LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr );
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rekey with random key.
|
||||
bool rekey(const EVP_CIPHER *cipher, int keyLength) {
|
||||
SecureMem key(keyLength);
|
||||
|
||||
if (!randomize(key.data, key.size))
|
||||
return false;
|
||||
|
||||
return rekey(cipher, key.data, key.size);
|
||||
}
|
||||
|
||||
virtual int blockSize() const {
|
||||
return EVP_CIPHER_CTX_block_size(&enc);
|
||||
}
|
||||
|
||||
virtual bool encrypt(const byte *ivec, const byte *in,
|
||||
byte *out, int size) {
|
||||
int dstLen = 0, tmpLen = 0;
|
||||
EVP_EncryptInit_ex( &enc, NULL, NULL, NULL, ivec);
|
||||
EVP_EncryptUpdate( &enc, out, &dstLen, in, size);
|
||||
EVP_EncryptFinal_ex( &enc, out+dstLen, &tmpLen );
|
||||
dstLen += tmpLen;
|
||||
|
||||
if (dstLen != size) {
|
||||
LOG(ERROR) << "encoding " << size
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool decrypt(const byte *ivec, const byte *in,
|
||||
byte *out, int size) {
|
||||
int dstLen = 0, tmpLen = 0;
|
||||
EVP_DecryptInit_ex( &dec, NULL, NULL, NULL, ivec);
|
||||
EVP_DecryptUpdate( &dec, out, &dstLen, in, size );
|
||||
EVP_DecryptFinal_ex( &dec, out+dstLen, &tmpLen );
|
||||
dstLen += tmpLen;
|
||||
|
||||
if (dstLen != size) {
|
||||
LOG(ERROR) << "decoding " << size
|
||||
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
EVP_CIPHER_CTX enc;
|
||||
EVP_CIPHER_CTX dec;
|
||||
};
|
||||
|
||||
|
||||
#if defined(HAVE_EVP_BF)
|
||||
static Range BfKeyRange(128,256,32);
|
||||
class BfCbcBlockCipher : public OpenSSLCipher {
|
||||
public:
|
||||
BfCbcBlockCipher() {}
|
||||
virtual ~BfCbcBlockCipher() {}
|
||||
|
||||
virtual bool setKey(const byte *key, int length) {
|
||||
if (BfKeyRange.allowed(length * 8))
|
||||
return rekey(EVP_bf_cbc(), key, length);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool randomKey(int length) {
|
||||
return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cbc(), length);
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
Properties props;
|
||||
props.keySize = BfKeyRange;
|
||||
props.cipher = "Blowfish";
|
||||
props.mode = "CBC";
|
||||
props.library = "OpenSSL";
|
||||
return props;
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(BfCbcBlockCipher, BlockCipher);
|
||||
|
||||
class BfCfbStreamCipher : public OpenSSLCipher {
|
||||
public:
|
||||
BfCfbStreamCipher() {}
|
||||
virtual ~BfCfbStreamCipher() {}
|
||||
|
||||
virtual bool setKey(const byte *key, int length) {
|
||||
return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cfb(), key, length);
|
||||
}
|
||||
|
||||
virtual bool randomKey(int length) {
|
||||
return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cfb(), length);
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
Properties props;
|
||||
props.keySize = BfKeyRange;
|
||||
props.cipher = "Blowfish";
|
||||
props.mode = "CFB";
|
||||
props.library = "OpenSSL";
|
||||
return props;
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(BfCfbStreamCipher, StreamCipher);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAVE_EVP_AES)
|
||||
static Range AesKeyRange(128,256,64);
|
||||
class AesCbcBlockCipher : public OpenSSLCipher {
|
||||
public:
|
||||
AesCbcBlockCipher() {}
|
||||
virtual ~AesCbcBlockCipher() {}
|
||||
|
||||
virtual bool setKey(const byte *key, int length) {
|
||||
const EVP_CIPHER *cipher = getCipher(length);
|
||||
return (cipher != NULL) && rekey(cipher, key, length);
|
||||
}
|
||||
|
||||
virtual bool randomKey(int length) {
|
||||
const EVP_CIPHER *cipher = getCipher(length);
|
||||
return (cipher != NULL) && rekey(cipher, length);
|
||||
}
|
||||
|
||||
static const EVP_CIPHER *getCipher(int keyLength) {
|
||||
switch(keyLength * 8)
|
||||
{
|
||||
case 128: return EVP_aes_128_cbc();
|
||||
case 192: return EVP_aes_192_cbc();
|
||||
case 256: return EVP_aes_256_cbc();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
Properties props;
|
||||
props.keySize = AesKeyRange;
|
||||
props.cipher = "AES";
|
||||
props.mode = "CBC";
|
||||
props.library = "OpenSSL";
|
||||
return props;
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(AesCbcBlockCipher, BlockCipher);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_EVP_AES_XTS)
|
||||
static Range AesXtsKeyRange(128,256,128);
|
||||
class AesXtsBlockCipher : public OpenSSLCipher {
|
||||
public:
|
||||
AesXtsBlockCipher() {}
|
||||
virtual ~AesXtsBlockCipher() {}
|
||||
|
||||
virtual bool setKey(const byte *key, int length) {
|
||||
const EVP_CIPHER *cipher = getCipher(length);
|
||||
return (cipher != NULL) && rekey(cipher, key, length);
|
||||
}
|
||||
|
||||
virtual bool randomKey(int length) {
|
||||
const EVP_CIPHER *cipher = getCipher(length);
|
||||
return (cipher != NULL) && rekey(cipher, length);
|
||||
}
|
||||
|
||||
static const EVP_CIPHER *getCipher(int keyLength) {
|
||||
switch(keyLength * 8)
|
||||
{
|
||||
case 128: return EVP_aes_128_xts();
|
||||
case 256: return EVP_aes_256_xts();
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
Properties props;
|
||||
props.keySize = AesXtsKeyRange;
|
||||
props.cipher = "AES";
|
||||
props.mode = "XTS";
|
||||
props.library = "OpenSSL";
|
||||
return props;
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(AesXtsBlockCipher, BlockCipher);
|
||||
#endif
|
||||
|
||||
class Sha1HMac : public MessageAuthenticationCode {
|
||||
public:
|
||||
Sha1HMac() {}
|
||||
virtual ~Sha1HMac() {
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
}
|
||||
|
||||
virtual int outputSize() const {
|
||||
return 20; // 160 bit.
|
||||
}
|
||||
|
||||
virtual bool setKey(const byte *key, int keyLength) {
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init_ex(&ctx, key, keyLength, EVP_sha1(), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool randomKey(int keyLength) {
|
||||
SecureMem key(keyLength);
|
||||
|
||||
return OpenSSLCipher::randomize(key.data, key.size)
|
||||
&& setKey(key.data, key.size);
|
||||
}
|
||||
|
||||
virtual void reset() {
|
||||
HMAC_Init_ex(&ctx, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
virtual bool update(const byte *in, int length) {
|
||||
HMAC_Update(&ctx, in, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool write(byte *out) {
|
||||
unsigned int outSize = 0;
|
||||
HMAC_Final(&ctx, (unsigned char *)out, &outSize);
|
||||
CHECK_EQ(outputSize(), outSize) << "Invalid HMAC output size";
|
||||
return true;
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
Properties props;
|
||||
props.blockSize = 20;
|
||||
props.hashFunction = "SHA-1";
|
||||
props.mode = "HMAC";
|
||||
props.library = "OpenSSL";
|
||||
return props;
|
||||
}
|
||||
private:
|
||||
HMAC_CTX ctx;
|
||||
};
|
||||
REGISTER_CLASS(Sha1HMac, MessageAuthenticationCode);
|
||||
|
||||
|
||||
class PbkdfPkcs5HmacSha1 : public PBKDF {
|
||||
public:
|
||||
PbkdfPkcs5HmacSha1() {}
|
||||
virtual ~PbkdfPkcs5HmacSha1() {}
|
||||
|
||||
virtual bool makeKey(const char *password, int passwordLength,
|
||||
const byte *salt, int saltLength,
|
||||
int numIterations,
|
||||
byte *outKey, int keyLength) const {
|
||||
return PKCS5_PBKDF2_HMAC_SHA1(
|
||||
password, passwordLength,
|
||||
const_cast<byte *>(salt), saltLength,
|
||||
numIterations, keyLength, outKey) == 1;
|
||||
}
|
||||
|
||||
static Properties GetProperties() {
|
||||
Properties props;
|
||||
props.mode = "PKCS5_PBKDF2_HMAC_SHA1";
|
||||
props.library = "OpenSSL";
|
||||
return props;
|
||||
}
|
||||
};
|
||||
REGISTER_CLASS(PbkdfPkcs5HmacSha1, PBKDF);
|
||||
|
||||
|
||||
unsigned long pthreads_thread_id()
|
||||
{
|
||||
return (unsigned long)pthread_self();
|
||||
@@ -73,7 +416,7 @@ void pthreads_locking_cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
void openssl_init(bool threaded)
|
||||
void OpenSSL::init(bool threaded)
|
||||
{
|
||||
// initialize the SSL library
|
||||
SSL_load_error_strings();
|
||||
@@ -99,7 +442,7 @@ void openssl_init(bool threaded)
|
||||
}
|
||||
}
|
||||
|
||||
void openssl_shutdown(bool threaded)
|
||||
void OpenSSL::shutdown(bool threaded)
|
||||
{
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE_cleanup();
|
||||
@@ -109,4 +452,10 @@ void openssl_shutdown(bool threaded)
|
||||
pthreads_locking_cleanup();
|
||||
}
|
||||
|
||||
void OpenSSL::registerCiphers()
|
||||
{
|
||||
// Nothing required.. Just need to reference this code block to get static
|
||||
// initializers.
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
@@ -21,10 +21,17 @@
|
||||
#ifndef _openssl_incl_
|
||||
#define _openssl_incl_
|
||||
|
||||
#include "base/Registry.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
void openssl_init(bool isThreaded);
|
||||
void openssl_shutdown(bool isThreaded);
|
||||
class OpenSSL {
|
||||
public:
|
||||
static void init(bool isThreaded);
|
||||
static void shutdown(bool isThreaded);
|
||||
|
||||
static void registerCiphers();
|
||||
};
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
|
30
cipher/testing.cpp
Normal file
30
cipher/testing.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "cipher/testing.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
std::string stringToHex(const byte *data, int len) {
|
||||
static const char lookup[] = "0123456789abcdef";
|
||||
|
||||
std::string out;
|
||||
out.reserve(2 * len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
unsigned int c = (unsigned int)data[i] & 0xff;
|
||||
int first = (unsigned int)c >> 4;
|
||||
int second = (unsigned int)c & 15;
|
||||
|
||||
out.push_back(lookup[first]);
|
||||
out.push_back(lookup[second]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
36
cipher/testing.h
Normal file
36
cipher/testing.h
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
/*****************************************************************************
|
||||
* 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
|
||||
* 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 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _CIPHER_TESTING_incl_
|
||||
#define _CIPHER_TESTING_incl_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/types.h"
|
||||
|
||||
namespace encfs {
|
||||
|
||||
std::string stringToHex(const byte *data, int len);
|
||||
|
||||
} // namespace encfs
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user