mirror of
https://github.com/vgough/encfs.git
synced 2024-11-28 19:03:42 +01:00
begin adding Botan support.
implement pbkdf-hmac-sha256 module for Botan and CommonCrypto. git-svn-id: http://encfs.googlecode.com/svn/trunk@98 db9cf616-1c43-0410-9cb8-a902689de0d6
This commit is contained in:
parent
63c2d1c539
commit
95750d4539
@ -7,12 +7,16 @@ set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}")
|
|||||||
|
|
||||||
option (BUILD_SHARED_LIBS "Build dynamic link libraries" OFF)
|
option (BUILD_SHARED_LIBS "Build dynamic link libraries" OFF)
|
||||||
|
|
||||||
option (WITH_OPENSSL "WithOpenSSL" ON)
|
option (WITH_OPENSSL "WithOpenSSL" OFF)
|
||||||
option (WITH_COMMON_CRYPTO "WithCommonCrypto" OFF)
|
option (WITH_COMMON_CRYPTO "WithCommonCrypto" OFF)
|
||||||
|
option (WITH_BOTAN "WithBotan" ON)
|
||||||
|
|
||||||
if (WITH_COMMON_CRYPTO)
|
if (WITH_BOTAN)
|
||||||
|
set (WITH_COMMON_CRYPTO OFF)
|
||||||
set (WITH_OPENSSL OFF)
|
set (WITH_OPENSSL OFF)
|
||||||
endif (WITH_COMMON_CRYPTO)
|
elseif (WITH_COMMON_CRYPTO)
|
||||||
|
set (WITH_OPENSSL OFF)
|
||||||
|
endif (WITH_BOTAN)
|
||||||
|
|
||||||
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
|
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
|
||||||
"${CMAKE_SOURCE_DIR}/CMakeModules/")
|
"${CMAKE_SOURCE_DIR}/CMakeModules/")
|
||||||
@ -61,15 +65,8 @@ check_include_file_cxx (tr1/tuple HAVE_TR1_TUPLE)
|
|||||||
check_include_file_cxx (valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
|
check_include_file_cxx (valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
|
||||||
check_include_file_cxx (valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H)
|
check_include_file_cxx (valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H)
|
||||||
|
|
||||||
if (WITH_COMMON_CRYPTO)
|
# Used with CommonCrypto
|
||||||
check_include_file_cxx (Security/SecRandom.h HAVE_SEC_RANDOM_H)
|
check_include_file_cxx (Security/SecRandom.h HAVE_SEC_RANDOM_H)
|
||||||
endif (WITH_COMMON_CRYPTO)
|
|
||||||
|
|
||||||
if (WITH_OPENSSL)
|
|
||||||
# TODO: move this to cipher directory.
|
|
||||||
find_package (OpenSSL REQUIRED)
|
|
||||||
include (OpenSSLTests)
|
|
||||||
endif (WITH_OPENSSL)
|
|
||||||
|
|
||||||
# Check if xattr functions take extra argument.
|
# Check if xattr functions take extra argument.
|
||||||
include (CheckCXXSourceCompiles)
|
include (CheckCXXSourceCompiles)
|
||||||
|
46
CMakeModules/FindBotan.cmake
Normal file
46
CMakeModules/FindBotan.cmake
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# - Try to find the Botan library
|
||||||
|
#
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# BOTAN_FOUND - System has Botan
|
||||||
|
# BOTAN_INCLUDE_DIR - The Botan include directory
|
||||||
|
# BOTAN_LIBRARIES - The libraries needed to use Botan
|
||||||
|
# BOTAN_DEFINITIONS - Compiler switches required for using Botan
|
||||||
|
|
||||||
|
IF (BOTAN_INCLUDE_DIR AND BOTAN_LIBRARY)
|
||||||
|
# in cache already
|
||||||
|
SET(Botan_FIND_QUIETLY TRUE)
|
||||||
|
ENDIF (BOTAN_INCLUDE_DIR AND BOTAN_LIBRARY)
|
||||||
|
|
||||||
|
IF (NOT WIN32)
|
||||||
|
# try using pkg-config to get the directories and then use these values
|
||||||
|
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||||
|
# also fills in BOTAN_DEFINITIONS, although that isn't normally useful
|
||||||
|
FIND_PACKAGE(PkgConfig)
|
||||||
|
PKG_SEARCH_MODULE(PC_BOTAN botan-1.10 botan-1.9 botan-1.8 botan)
|
||||||
|
SET(BOTAN_DEFINITIONS ${PC_BOTAN_CFLAGS})
|
||||||
|
ENDIF (NOT WIN32)
|
||||||
|
|
||||||
|
FIND_PATH(BOTAN_INCLUDE_DIR botan/botan.h
|
||||||
|
HINTS
|
||||||
|
${PC_BOTAN_INCLUDEDIR}
|
||||||
|
${PC_BOTAN_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(BOTAN_LIBRARY NAMES ${PC_BOTAN_LIBRARIES}
|
||||||
|
HINTS
|
||||||
|
${PC_BOTAN_LIBDIR}
|
||||||
|
${PC_BOTAN_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(BOTAN_INCLUDE_DIR BOTAN_LIBRARY)
|
||||||
|
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set BOTAN_FOUND to TRUE if
|
||||||
|
# all listed variables are TRUE
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Botan DEFAULT_MSG BOTAN_LIBRARY BOTAN_INCLUDE_DIR)
|
||||||
|
|
||||||
|
IF(BOTAN_FOUND)
|
||||||
|
SET(BOTAN_LIBRARIES ${BOTAN_LIBRARY})
|
||||||
|
SET(BOTAN_INCLUDE_DIRS ${BOTAN_INCLUDE_DIR})
|
||||||
|
ENDIF()
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#cmakedefine WITH_OPENSSL
|
#cmakedefine WITH_OPENSSL
|
||||||
#cmakedefine WITH_COMMON_CRYPTO
|
#cmakedefine WITH_COMMON_CRYPTO
|
||||||
|
#cmakedefine WITH_BOTAN
|
||||||
#cmakedefine HAVE_SEC_RANDOM_H
|
#cmakedefine HAVE_SEC_RANDOM_H
|
||||||
|
|
||||||
#cmakedefine HAVE_EVP_BF
|
#cmakedefine HAVE_EVP_BF
|
||||||
|
@ -153,7 +153,7 @@ TEST(BlockEncryptionTest, BlockCipher) {
|
|||||||
Registry<BlockCipher> registry = BlockCipher::GetRegistry();
|
Registry<BlockCipher> registry = BlockCipher::GetRegistry();
|
||||||
|
|
||||||
shared_ptr<PBKDF> pbkdf(
|
shared_ptr<PBKDF> pbkdf(
|
||||||
PBKDF::GetRegistry().CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1));
|
PBKDF::GetRegistry().CreateForMatch(NAME_PBKDF2_HMAC_SHA1));
|
||||||
|
|
||||||
list<string> ciphers = registry.GetAll();
|
list<string> ciphers = registry.GetAll();
|
||||||
for (const string &name : ciphers) {
|
for (const string &name : ciphers) {
|
||||||
|
@ -6,9 +6,15 @@ if (WITH_COMMON_CRYPTO)
|
|||||||
set (EXTRA_LIBS ${SECURITY_FRAMEWORK})
|
set (EXTRA_LIBS ${SECURITY_FRAMEWORK})
|
||||||
set (EXTRA_SOURCE CommonCrypto.cpp)
|
set (EXTRA_SOURCE CommonCrypto.cpp)
|
||||||
elseif (WITH_OPENSSL)
|
elseif (WITH_OPENSSL)
|
||||||
|
find_package (OpenSSL REQUIRED)
|
||||||
|
include (OpenSSLTests)
|
||||||
include_directories (${OPENSSL_INCLUDE_DIR})
|
include_directories (${OPENSSL_INCLUDE_DIR})
|
||||||
set (EXTRA_LIBS ${OPENSSL_LIBRARIES})
|
set (EXTRA_LIBS ${OPENSSL_LIBRARIES})
|
||||||
set (EXTRA_SOURCE openssl.cpp)
|
set (EXTRA_SOURCE openssl.cpp)
|
||||||
|
elseif (WITH_BOTAN)
|
||||||
|
find_package (Botan REQUIRED)
|
||||||
|
set (EXTRA_LIBS ${BOTAN_LIBRARIES})
|
||||||
|
set (EXTRA_SOURCE botan.cpp)
|
||||||
endif (WITH_COMMON_CRYPTO)
|
endif (WITH_COMMON_CRYPTO)
|
||||||
|
|
||||||
add_library (encfs-cipher
|
add_library (encfs-cipher
|
||||||
|
@ -43,7 +43,7 @@ CipherKey::CipherKey(const byte *data, int length)
|
|||||||
: _valid(true)
|
: _valid(true)
|
||||||
{
|
{
|
||||||
_mem.reset(new SecureMem(length));
|
_mem.reset(new SecureMem(length));
|
||||||
memcpy(_mem->data, data, length);
|
memcpy(_mem->data(), data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
CipherKey::CipherKey(const CipherKey& src)
|
CipherKey::CipherKey(const CipherKey& src)
|
||||||
@ -64,12 +64,12 @@ void CipherKey::operator = (const CipherKey& src)
|
|||||||
|
|
||||||
byte *CipherKey::data() const
|
byte *CipherKey::data() const
|
||||||
{
|
{
|
||||||
return !_mem ? NULL : _mem->data;
|
return !_mem ? NULL : _mem->data();
|
||||||
}
|
}
|
||||||
|
|
||||||
int CipherKey::size() const
|
int CipherKey::size() const
|
||||||
{
|
{
|
||||||
return !_mem ? 0 : _mem->size;
|
return !_mem ? 0 : _mem->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CipherKey::reset()
|
void CipherKey::reset()
|
||||||
|
@ -49,6 +49,10 @@
|
|||||||
#include "cipher/openssl.h"
|
#include "cipher/openssl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_BOTAN
|
||||||
|
#include "cipher/botan.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using std::list;
|
using std::list;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
@ -70,6 +74,9 @@ void CipherV1::init(bool threaded) {
|
|||||||
#ifdef WITH_OPENSSL
|
#ifdef WITH_OPENSSL
|
||||||
OpenSSL::init(threaded);
|
OpenSSL::init(threaded);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef WITH_BOTAN
|
||||||
|
Botan_init(threaded);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CipherV1::shutdown(bool threaded) {
|
void CipherV1::shutdown(bool threaded) {
|
||||||
@ -103,22 +110,22 @@ bool BytesToKey(const byte *data, int dataLen,
|
|||||||
{
|
{
|
||||||
sha1->init();
|
sha1->init();
|
||||||
if( addmd++ )
|
if( addmd++ )
|
||||||
sha1->update(mdBuf.data, mdBuf.size);
|
sha1->update(mdBuf.data(), mdBuf.size());
|
||||||
sha1->update(data, dataLen);
|
sha1->update(data, dataLen);
|
||||||
sha1->write(mdBuf.data);
|
sha1->write(mdBuf.data());
|
||||||
|
|
||||||
for(unsigned int i=1; i < rounds; ++i)
|
for(unsigned int i=1; i < rounds; ++i)
|
||||||
{
|
{
|
||||||
sha1->init();
|
sha1->init();
|
||||||
sha1->update(mdBuf.data, mdBuf.size);
|
sha1->update(mdBuf.data(), mdBuf.size());
|
||||||
sha1->write(mdBuf.data);
|
sha1->write(mdBuf.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int toCopy = MIN( remaining, (int)mdBuf.size - offset );
|
int toCopy = MIN( remaining, mdBuf.size() - offset );
|
||||||
if( toCopy )
|
if( toCopy )
|
||||||
{
|
{
|
||||||
memcpy( key->data(), mdBuf.data+offset, toCopy );
|
memcpy( key->data(), mdBuf.data()+offset, toCopy );
|
||||||
key += toCopy;
|
key += toCopy;
|
||||||
remaining -= toCopy;
|
remaining -= toCopy;
|
||||||
offset += toCopy;
|
offset += toCopy;
|
||||||
@ -144,7 +151,7 @@ int CipherV1::TimedPBKDF2(const char *pass, int passlen,
|
|||||||
VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltlen);
|
VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltlen);
|
||||||
#endif
|
#endif
|
||||||
Registry<PBKDF> registry = PBKDF::GetRegistry();
|
Registry<PBKDF> registry = PBKDF::GetRegistry();
|
||||||
shared_ptr<PBKDF> impl(registry.CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1));
|
shared_ptr<PBKDF> impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1));
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -291,7 +298,7 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface,
|
|||||||
_keySize = keyRange.closest(keyLength) / 8;
|
_keySize = keyRange.closest(keyLength) / 8;
|
||||||
|
|
||||||
_pbkdf.reset(PBKDF::GetRegistry().CreateForMatch(
|
_pbkdf.reset(PBKDF::GetRegistry().CreateForMatch(
|
||||||
NAME_PKCS5_PBKDF2_HMAC_SHA1));
|
NAME_PBKDF2_HMAC_SHA1));
|
||||||
if (!_pbkdf) {
|
if (!_pbkdf) {
|
||||||
LOG(ERROR) << "PBKDF missing";
|
LOG(ERROR) << "PBKDF missing";
|
||||||
return false;
|
return false;
|
||||||
@ -401,7 +408,7 @@ bool CipherV1::setKey(const CipherKey &keyIv) {
|
|||||||
// Key is actually key plus iv, so extract the different parts.
|
// Key is actually key plus iv, so extract the different parts.
|
||||||
CipherKey key(_keySize);
|
CipherKey key(_keySize);
|
||||||
memcpy(key.data(), keyIv.data(), _keySize);
|
memcpy(key.data(), keyIv.data(), _keySize);
|
||||||
memcpy(_iv->data, keyIv.data() + _keySize, _ivLength);
|
memcpy(_iv->data(), keyIv.data() + _keySize, _ivLength);
|
||||||
|
|
||||||
if (_blockCipher->setKey(key)
|
if (_blockCipher->setKey(key)
|
||||||
&& _streamCipher->setKey(key)
|
&& _streamCipher->setKey(key)
|
||||||
@ -518,11 +525,11 @@ void CipherV1::writeKey(const CipherKey &ckey, byte *out)
|
|||||||
rAssert( _keySet );
|
rAssert( _keySet );
|
||||||
|
|
||||||
SecureMem tmpBuf(ckey.size());
|
SecureMem tmpBuf(ckey.size());
|
||||||
memcpy(tmpBuf.data, ckey.data(), tmpBuf.size);
|
memcpy(tmpBuf.data(), ckey.data(), tmpBuf.size());
|
||||||
|
|
||||||
unsigned int checksum = reduceMac32(
|
unsigned int checksum = reduceMac32(
|
||||||
MAC_64(tmpBuf.data, tmpBuf.size, NULL));
|
MAC_64(tmpBuf.data(), tmpBuf.size(), NULL));
|
||||||
streamEncode(tmpBuf.data, tmpBuf.size, checksum);
|
streamEncode(tmpBuf.data(), tmpBuf.size(), checksum);
|
||||||
|
|
||||||
// first N bytes contain HMAC derived checksum..
|
// first N bytes contain HMAC derived checksum..
|
||||||
for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i)
|
for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i)
|
||||||
@ -531,7 +538,7 @@ void CipherV1::writeKey(const CipherKey &ckey, byte *out)
|
|||||||
checksum >>= 8;
|
checksum >>= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy( out+KEY_CHECKSUM_BYTES, tmpBuf.data, tmpBuf.size );
|
memcpy( out+KEY_CHECKSUM_BYTES, tmpBuf.data(), tmpBuf.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CipherV1::encodeAsString(const CipherKey &key)
|
std::string CipherV1::encodeAsString(const CipherKey &key)
|
||||||
@ -602,7 +609,7 @@ static void setIVec_old(byte *ivec, int ivLen, unsigned int seed)
|
|||||||
void CipherV1::setIVec(byte *ivec, uint64_t seed) const
|
void CipherV1::setIVec(byte *ivec, uint64_t seed) const
|
||||||
{
|
{
|
||||||
rAssert( _keySet );
|
rAssert( _keySet );
|
||||||
memcpy( ivec, _iv->data, _ivLength );
|
memcpy( ivec, _iv->data(), _ivLength );
|
||||||
if (iface.major() < 3)
|
if (iface.major() < 3)
|
||||||
{
|
{
|
||||||
// Backward compatible mode.
|
// Backward compatible mode.
|
||||||
|
@ -40,17 +40,19 @@
|
|||||||
namespace encfs {
|
namespace encfs {
|
||||||
namespace commoncrypto {
|
namespace commoncrypto {
|
||||||
|
|
||||||
class PbkdfPkcs5HmacSha1CC : public PBKDF {
|
class PbkdfPkcs5Hmac : public PBKDF {
|
||||||
|
CCPseudoRandomAlgorithm prf_;
|
||||||
public:
|
public:
|
||||||
PbkdfPkcs5HmacSha1CC() {}
|
PbkdfPkcs5Hmac(CCPseudoRandomAlgorithm prf)
|
||||||
virtual ~PbkdfPkcs5HmacSha1CC() {}
|
: prf_(prf) {}
|
||||||
|
virtual ~PbkdfPkcs5Hmac() {}
|
||||||
|
|
||||||
virtual bool makeKey(const char *password, int passwordLength,
|
virtual bool makeKey(const char *password, int passwordLength,
|
||||||
const byte *salt, int saltLength,
|
const byte *salt, int saltLength,
|
||||||
int numIterations,
|
int numIterations,
|
||||||
CipherKey *outKey) {
|
CipherKey *outKey) {
|
||||||
int ret = CCKeyDerivationPBKDF(kCCPBKDF2, password, passwordLength,
|
int ret = CCKeyDerivationPBKDF(kCCPBKDF2, password, passwordLength,
|
||||||
salt, saltLength, kCCPRFHmacAlgSHA1,
|
salt, saltLength, prf_,
|
||||||
numIterations,
|
numIterations,
|
||||||
outKey->data(), outKey->size());
|
outKey->data(), outKey->size());
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@ -86,16 +88,37 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PbkdfPkcs5HmacSha1CC : public PbkdfPkcs5Hmac {
|
||||||
|
public:
|
||||||
|
PbkdfPkcs5HmacSha1CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA1) {}
|
||||||
|
~PbkdfPkcs5HmacSha1CC() {}
|
||||||
|
|
||||||
static Properties GetProperties() {
|
static Properties GetProperties() {
|
||||||
Properties props;
|
Properties props;
|
||||||
props.mode = NAME_PKCS5_PBKDF2_HMAC_SHA1;
|
props.mode = NAME_PBKDF2_HMAC_SHA1;
|
||||||
props.library = "CommonCrypto";
|
props.library = "CommonCrypto";
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
REGISTER_CLASS(PbkdfPkcs5HmacSha1CC, PBKDF);
|
REGISTER_CLASS(PbkdfPkcs5HmacSha1CC, PBKDF);
|
||||||
|
|
||||||
|
class PbkdfPkcs5HmacSha256CC : public PbkdfPkcs5Hmac {
|
||||||
|
public:
|
||||||
|
PbkdfPkcs5HmacSha256CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA256) {}
|
||||||
|
~PbkdfPkcs5HmacSha256CC() {}
|
||||||
|
|
||||||
|
static Properties GetProperties() {
|
||||||
|
Properties props;
|
||||||
|
props.mode = NAME_PBKDF2_HMAC_SHA256;
|
||||||
|
props.library = "CommonCrypto";
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
REGISTER_CLASS(PbkdfPkcs5HmacSha256CC, PBKDF);
|
||||||
|
|
||||||
class CCCipher : public BlockCipher {
|
class CCCipher : public BlockCipher {
|
||||||
CipherKey key;
|
CipherKey key;
|
||||||
CCAlgorithm algorithm;
|
CCAlgorithm algorithm;
|
||||||
|
@ -47,6 +47,10 @@
|
|||||||
# include <openssl/buffer.h>
|
# include <openssl/buffer.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_BOTAN
|
||||||
|
# include <botan/botan.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
#ifdef WITH_OPENSSL
|
#ifdef WITH_OPENSSL
|
||||||
@ -61,14 +65,16 @@ static void freeBlock( byte *block, int size )
|
|||||||
OPENSSL_cleanse(block, size);
|
OPENSSL_cleanse(block, size);
|
||||||
OPENSSL_free(block);
|
OPENSSL_free(block);
|
||||||
}
|
}
|
||||||
#elif defined(WITH_COMMON_CRYPTO)
|
|
||||||
|
#else
|
||||||
|
|
||||||
static byte *allocBlock(int size) {
|
static byte *allocBlock(int size) {
|
||||||
byte *block = new byte[size];
|
byte *block = new byte[size];
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char cleanse_ctr = 0;
|
unsigned char cleanse_ctr = 0;
|
||||||
static void freeBlock(byte *data, int len) {
|
static void cleanBlock(byte *data, int len) {
|
||||||
byte *p = data;
|
byte *p = data;
|
||||||
size_t loop = len, ctr = cleanse_ctr;
|
size_t loop = len, ctr = cleanse_ctr;
|
||||||
while(loop--)
|
while(loop--)
|
||||||
@ -81,8 +87,8 @@ static void freeBlock(byte *data, int len) {
|
|||||||
if(p)
|
if(p)
|
||||||
ctr += (63 + (size_t)p);
|
ctr += (63 + (size_t)p);
|
||||||
cleanse_ctr = (unsigned char)ctr;
|
cleanse_ctr = (unsigned char)ctr;
|
||||||
delete[] data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void MemBlock::allocate(int size)
|
void MemBlock::allocate(int size)
|
||||||
@ -94,38 +100,49 @@ void MemBlock::allocate(int size)
|
|||||||
|
|
||||||
MemBlock::~MemBlock()
|
MemBlock::~MemBlock()
|
||||||
{
|
{
|
||||||
freeBlock(data, size);
|
cleanBlock(data, size);
|
||||||
|
delete[] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
SecureMem::SecureMem(int len)
|
SecureMem::SecureMem(int len)
|
||||||
|
#ifdef WITH_BOTAN
|
||||||
|
: data_(len)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
rAssert(len > 0);
|
rAssert(len > 0);
|
||||||
data = allocBlock(len);
|
#ifndef WITH_BOTAN
|
||||||
if (data)
|
data_ = allocBlock(len);
|
||||||
|
if (data_)
|
||||||
{
|
{
|
||||||
size = len;
|
size_ = len;
|
||||||
mlock(data, size);
|
mlock(data_, size_);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
size = 0;
|
size_ = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SecureMem::~SecureMem()
|
SecureMem::~SecureMem()
|
||||||
{
|
{
|
||||||
if (size)
|
#ifdef WITH_BOTAN
|
||||||
|
data_.destroy();
|
||||||
|
#else
|
||||||
|
if (size_)
|
||||||
{
|
{
|
||||||
freeBlock(data, size);
|
cleanBlock(data_, size_);
|
||||||
munlock(data, size);
|
delete[] data_;
|
||||||
|
munlock(data_, size_);
|
||||||
|
|
||||||
data = NULL;
|
data_ = NULL;
|
||||||
size = 0;
|
size_ = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator == (const SecureMem &a, const SecureMem &b) {
|
bool operator == (const SecureMem &a, const SecureMem &b) {
|
||||||
return (a.size == b.size) &&
|
return (a.size() == b.size()) &&
|
||||||
(memcmp(a.data, b.data, a.size) == 0);
|
(memcmp(a.data(), b.data(), a.size()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
@ -21,12 +21,18 @@
|
|||||||
#ifndef _MemoryPool_incl_
|
#ifndef _MemoryPool_incl_
|
||||||
#define _MemoryPool_incl_
|
#define _MemoryPool_incl_
|
||||||
|
|
||||||
|
#include "base/config.h"
|
||||||
#include "base/types.h"
|
#include "base/types.h"
|
||||||
|
|
||||||
|
#ifdef WITH_BOTAN
|
||||||
|
#include <botan/secmem.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Memory Pool for fixed sized objects.
|
Memory Pool for fixed sized objects.
|
||||||
|
Use SecureMem if storing sensitive information.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
MemBlock mb;
|
MemBlock mb;
|
||||||
@ -55,13 +61,37 @@ inline MemBlock::MemBlock()
|
|||||||
class SecureMem
|
class SecureMem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int size;
|
byte* data() const;
|
||||||
byte *data;
|
int size() const;
|
||||||
|
|
||||||
explicit SecureMem(int len);
|
explicit SecureMem(int len);
|
||||||
~SecureMem();
|
~SecureMem();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef WITH_BOTAN
|
||||||
|
Botan::SecureVector<Botan::byte> 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
|
||||||
|
inline byte* SecureMem::data() const {
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
inline int SecureMem::size() const {
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool operator == (const SecureMem &a, const SecureMem &b);
|
bool operator == (const SecureMem &a, const SecureMem &b);
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
// Well-known algorithms.
|
// Well-known algorithms.
|
||||||
static const char NAME_PKCS5_PBKDF2_HMAC_SHA1[] = "PKCS5_PBKDF2_HMAC_SHA1";
|
static const char NAME_PBKDF2_HMAC_SHA1[] = "PBKDF2_HMAC_SHA1";
|
||||||
|
static const char NAME_PBKDF2_HMAC_SHA256[] = "PBKDF2_HMAC_SHA256";
|
||||||
|
|
||||||
// Password Based Key Derivation Function.
|
// Password Based Key Derivation Function.
|
||||||
class PBKDF
|
class PBKDF
|
||||||
|
@ -34,7 +34,7 @@ namespace {
|
|||||||
|
|
||||||
TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) {
|
TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) {
|
||||||
Registry<PBKDF> registry = PBKDF::GetRegistry();
|
Registry<PBKDF> registry = PBKDF::GetRegistry();
|
||||||
shared_ptr<PBKDF> impl( registry.CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1));
|
shared_ptr<PBKDF> impl( registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1));
|
||||||
ASSERT_FALSE(!impl);
|
ASSERT_FALSE(!impl);
|
||||||
|
|
||||||
// Test cases from rfc6070
|
// Test cases from rfc6070
|
||||||
@ -68,6 +68,50 @@ TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PKCS5_PBKDF2_HMAC_SHA256, PBKDF) {
|
||||||
|
Registry<PBKDF> registry = PBKDF::GetRegistry();
|
||||||
|
shared_ptr<PBKDF> impl(
|
||||||
|
registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA256));
|
||||||
|
ASSERT_FALSE(!impl);
|
||||||
|
|
||||||
|
// Test case 1
|
||||||
|
{
|
||||||
|
CipherKey key(32);
|
||||||
|
bool ok = impl->makeKey("password", 8,
|
||||||
|
(byte*)"salt", 4,
|
||||||
|
1, &key);
|
||||||
|
ASSERT_TRUE(ok);
|
||||||
|
ASSERT_EQ("120fb6cffcf8b32c"
|
||||||
|
"43e7225256c4f837"
|
||||||
|
"a86548c92ccc3548"
|
||||||
|
"0805987cb70be17b", stringToHex(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case 2
|
||||||
|
{
|
||||||
|
CipherKey key(40);
|
||||||
|
bool ok = impl->makeKey("passwordPASSWORDpassword", 24,
|
||||||
|
(byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
|
||||||
|
4096, &key);
|
||||||
|
ASSERT_TRUE(ok);
|
||||||
|
ASSERT_EQ("348c89dbcbd32b2f"
|
||||||
|
"32d814b8116e84cf"
|
||||||
|
"2b17347ebc180018"
|
||||||
|
"1c4e2a1fb8dd53e1"
|
||||||
|
"c635518c7dac47e9",
|
||||||
|
stringToHex(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case 3
|
||||||
|
{
|
||||||
|
CipherKey key(16);
|
||||||
|
bool ok = impl->makeKey("pass\0word", 9,
|
||||||
|
(byte*)"sa\0lt", 5,
|
||||||
|
4096, &key);
|
||||||
|
ASSERT_TRUE(ok);
|
||||||
|
ASSERT_EQ("89b69d0516f829893c696226650a8687", stringToHex(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
141
cipher/botan.cpp
Normal file
141
cipher/botan.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* 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 "cipher/botan.h"
|
||||||
|
#include "base/config.h"
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace Botan;
|
||||||
|
|
||||||
|
namespace encfs {
|
||||||
|
namespace botan {
|
||||||
|
|
||||||
|
class PbkdfPkcs5Hmac : public PBKDF {
|
||||||
|
Botan::PBKDF* pbkdf_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PbkdfPkcs5Hmac(Botan::PBKDF* pbkdf) : pbkdf_(pbkdf) {}
|
||||||
|
virtual ~PbkdfPkcs5Hmac() {
|
||||||
|
delete pbkdf_;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool makeKey(const char *password, int passwordLength,
|
||||||
|
const byte *salt, int saltLength,
|
||||||
|
int numIterations,
|
||||||
|
CipherKey *outKey) {
|
||||||
|
if (pbkdf_ == NULL) {
|
||||||
|
// TODO: error message
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string pass;
|
||||||
|
pass.assign(password, passwordLength);
|
||||||
|
OctetString key = pbkdf_->derive_key(outKey->size(),
|
||||||
|
pass,
|
||||||
|
salt, saltLength,
|
||||||
|
numIterations);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool pseudoRandom(byte *out, int length) {
|
||||||
|
rng.randomize(out, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoSeeded_RNG rng;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PbkdfPkcs5HmacSha1 : public PbkdfPkcs5Hmac {
|
||||||
|
public:
|
||||||
|
PbkdfPkcs5HmacSha1()
|
||||||
|
: PbkdfPkcs5Hmac( get_pbkdf("PBKDF2(SHA-1)")) { }
|
||||||
|
~PbkdfPkcs5HmacSha1() {}
|
||||||
|
|
||||||
|
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:
|
||||||
|
PbkdfPkcs5HmacSha256()
|
||||||
|
: PbkdfPkcs5Hmac( get_pbkdf("PBKDF2(SHA-256)")) { }
|
||||||
|
~PbkdfPkcs5HmacSha256() {}
|
||||||
|
|
||||||
|
static Properties GetProperties() {
|
||||||
|
Properties props;
|
||||||
|
props.mode = NAME_PBKDF2_HMAC_SHA256;
|
||||||
|
props.library = "Botan";
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // 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
|
||||||
|
|
36
cipher/botan.h
Normal file
36
cipher/botan.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_BOTAN_incl_
|
||||||
|
#define _CIPHER_BOTAN_incl_
|
||||||
|
|
||||||
|
#include "base/Registry.h"
|
||||||
|
|
||||||
|
namespace encfs {
|
||||||
|
|
||||||
|
extern void Botan_init(bool threaded);
|
||||||
|
extern void Botan_shutdown();
|
||||||
|
extern void Botan_registerCiphers();
|
||||||
|
|
||||||
|
} // namespace encfs
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -33,8 +33,6 @@
|
|||||||
#include <valgrind/memcheck.h>
|
#include <valgrind/memcheck.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "base/config.h"
|
|
||||||
|
|
||||||
#define NO_DES
|
#define NO_DES
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
@ -449,7 +447,7 @@ class PbkdfPkcs5HmacSha1 : public PBKDF {
|
|||||||
|
|
||||||
static Properties GetProperties() {
|
static Properties GetProperties() {
|
||||||
Properties props;
|
Properties props;
|
||||||
props.mode = NAME_PKCS5_PBKDF2_HMAC_SHA1;
|
props.mode = NAME_PBKDF2_HMAC_SHA1;
|
||||||
props.library = "OpenSSL";
|
props.library = "OpenSSL";
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
@ -1350,11 +1350,11 @@ std::string readPassword( int FD )
|
|||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
ssize_t rdSize = recv(FD, buf->data, buf->size, 0);
|
ssize_t rdSize = recv(FD, buf->data(), buf->size(), 0);
|
||||||
|
|
||||||
if(rdSize > 0)
|
if(rdSize > 0)
|
||||||
{
|
{
|
||||||
result.append( (char*)buf->data, rdSize );
|
result.append( (char*)buf->data(), rdSize );
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1441,7 +1441,7 @@ SecureMem *passwordFromProgram(const std::string &passProg,
|
|||||||
|
|
||||||
SecureMem *result = new SecureMem(password.length()+1);
|
SecureMem *result = new SecureMem(password.length()+1);
|
||||||
if (result)
|
if (result)
|
||||||
strncpy((char *)result->data, password.c_str(), result->size);
|
strncpy((char *)result->data(), password.c_str(), result->size());
|
||||||
password.assign(password.length(), '\0');
|
password.assign(password.length(), '\0');
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -1451,13 +1451,13 @@ SecureMem *passwordFromStdin()
|
|||||||
{
|
{
|
||||||
SecureMem *buf = new SecureMem(MaxPassBuf);
|
SecureMem *buf = new SecureMem(MaxPassBuf);
|
||||||
|
|
||||||
char *res = fgets( (char *)buf->data, buf->size, stdin );
|
char *res = fgets( (char *)buf->data(), buf->size(), stdin );
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
// Kill the trailing newline.
|
// Kill the trailing newline.
|
||||||
int last = strnlen((char *)buf->data, buf->size);
|
int last = strnlen((char *)buf->data(), buf->size());
|
||||||
if (last > 0 && buf->data[last-1] == '\n')
|
if (last > 0 && buf->data()[last-1] == '\n')
|
||||||
buf->data[ last-1 ] = '\0';
|
buf->data()[ last-1 ] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
@ -1469,7 +1469,7 @@ SecureMem *passwordFromPrompt()
|
|||||||
|
|
||||||
// xgroup(common)
|
// xgroup(common)
|
||||||
char *res = readpassphrase( _("EncFS Password: "),
|
char *res = readpassphrase( _("EncFS Password: "),
|
||||||
(char *)buf->data, buf->size-1, RPP_ECHO_OFF );
|
(char *)buf->data(), buf->size()-1, RPP_ECHO_OFF );
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
delete buf;
|
delete buf;
|
||||||
@ -1488,13 +1488,13 @@ SecureMem *passwordFromPrompts()
|
|||||||
{
|
{
|
||||||
// xgroup(common)
|
// xgroup(common)
|
||||||
char *res1 = readpassphrase(_("New Encfs Password: "),
|
char *res1 = readpassphrase(_("New Encfs Password: "),
|
||||||
(char *)buf->data, buf->size-1, RPP_ECHO_OFF);
|
(char *)buf->data(), buf->size()-1, RPP_ECHO_OFF);
|
||||||
// xgroup(common)
|
// xgroup(common)
|
||||||
char *res2 = readpassphrase(_("Verify Encfs Password: "),
|
char *res2 = readpassphrase(_("Verify Encfs Password: "),
|
||||||
(char *)buf2->data, buf2->size-1, RPP_ECHO_OFF);
|
(char *)buf2->data(), buf2->size()-1, RPP_ECHO_OFF);
|
||||||
|
|
||||||
if(res1 && res2
|
if(res1 && res2
|
||||||
&& !strncmp((char*)buf->data, (char*)buf2->data, MaxPassBuf))
|
&& !strncmp((char*)buf->data(), (char*)buf2->data(), MaxPassBuf))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
} else
|
} else
|
||||||
@ -1520,8 +1520,8 @@ CipherKey getUserKey(const EncfsConfig &config, bool useStdin)
|
|||||||
|
|
||||||
if (password)
|
if (password)
|
||||||
{
|
{
|
||||||
userKey = decryptKey(config, (char*)password->data,
|
userKey = decryptKey(config, (char*)password->data(),
|
||||||
strlen((char*)password->data));
|
strlen((char*)password->data()));
|
||||||
delete password;
|
delete password;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1536,8 +1536,8 @@ CipherKey getUserKey( const EncfsConfig &config, const std::string &passProg,
|
|||||||
|
|
||||||
if (password)
|
if (password)
|
||||||
{
|
{
|
||||||
result = decryptKey(config, (char*)password->data,
|
result = decryptKey(config, (char*)password->data(),
|
||||||
strlen((char*)password->data));
|
strlen((char*)password->data()));
|
||||||
delete password;
|
delete password;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1560,8 +1560,8 @@ CipherKey getNewUserKey(EncfsConfig &config,
|
|||||||
|
|
||||||
if (password)
|
if (password)
|
||||||
{
|
{
|
||||||
result = makeNewKey(config, (char*)password->data,
|
result = makeNewKey(config, (char*)password->data(),
|
||||||
strlen((char*)password->data));
|
strlen((char*)password->data()));
|
||||||
delete password;
|
delete password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user