mirror of
https://github.com/vgough/encfs.git
synced 2024-11-25 01:13:12 +01:00
use PBKDF2 for new keys with salt and variable iteration count
git-svn-id: http://encfs.googlecode.com/svn/trunk@35 db9cf616-1c43-0410-9cb8-a902689de0d6
This commit is contained in:
parent
ebd17ec8da
commit
921a361e1b
64
ChangeLog
64
ChangeLog
@ -1,13 +1,65 @@
|
|||||||
|
|
||||||
|
Sat Aug 16 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* use PBKDF2 for new keys with salt and variable iteration count.
|
||||||
|
When creating a new key, adjusts iteration count to take
|
||||||
|
approximatly 1/2 a second of CPU time to test key.
|
||||||
|
|
||||||
|
Tue Aug 5 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* bump version to 1.4.3
|
||||||
|
|
||||||
|
Fri Aug 1 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* fix xattr support for Mac
|
||||||
|
|
||||||
|
Tue Jul 1 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* add patch info to Changelog
|
||||||
|
* separate RenameOp definition from implementation to avoid gcc 4.3
|
||||||
|
errors
|
||||||
|
|
||||||
|
Sat Jun 28 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* remove logs in Context, which displayed plaintext names
|
||||||
|
|
||||||
|
Mon Jun 2 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* fix defaultYes/defaultNo functions
|
||||||
|
|
||||||
Tue Jul 1 2008 Valient Gough <vgough@pobox.com>
|
Tue Jul 1 2008 Valient Gough <vgough@pobox.com>
|
||||||
* patch to fix compile errors in w/ gcc 4.3 from Anthony Shipman.
|
* patch to fix compile errors in w/ gcc 4.3 from Anthony Shipman.
|
||||||
|
|
||||||
2008-05-22 gettextize <bug-gnu-gettext@gnu.org>
|
Thu May 22 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* use autoreconf in reconfig.sh
|
||||||
|
* update autoconf and gettext tools
|
||||||
|
* remove AM_MKINSTALLDIRS from configure.ac
|
||||||
|
|
||||||
* m4/gettext.m4: Upgrade to gettext-0.17.
|
Sun May 18 2008 Valient Gough <vgough@pobox.com>
|
||||||
* m4/iconv.m4: Upgrade to gettext-0.17.
|
* add makeKey program and showKey option to encfsctl
|
||||||
* m4/lib-link.m4: Upgrade to gettext-0.17.
|
* replace C header includes with C++ versions
|
||||||
* m4/po.m4: Upgrade to gettext-0.17.
|
|
||||||
* configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.17.
|
Sat May 17 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* fix EVP initialization
|
||||||
|
|
||||||
|
Thu May 15 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* include cstring in several files, patch by A.Klitzing
|
||||||
|
* improve return code check on RAND_bytes call
|
||||||
|
|
||||||
|
Wed May 14 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* include binary_object header in FuseUtils
|
||||||
|
|
||||||
|
Sat May 10 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* explicit namespace for make_binary_object calls
|
||||||
|
|
||||||
|
Wed May 7 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* add string.h to ConfigVar
|
||||||
|
|
||||||
|
Sun May 4 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* change boost requirement to 1.34+, to eliminate fs::native usage
|
||||||
|
requirement
|
||||||
|
* ensure boost::filesystem::path is created with native option"
|
||||||
|
|
||||||
|
Sat Apr 19 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* add direct-load method so that encfsctl cat can work with direct
|
||||||
|
cipher paths
|
||||||
|
|
||||||
|
Tue Apr 15 2008 Valient Gough <vgough@pobox.com>
|
||||||
|
* add boost filesystem lib check
|
||||||
|
|
||||||
Sun Apr 13 2008 Valient Gough <vgough@pobox.com>
|
Sun Apr 13 2008 Valient Gough <vgough@pobox.com>
|
||||||
* fix bug in export - wasn't able to export symlinks.
|
* fix bug in export - wasn't able to export symlinks.
|
||||||
|
@ -84,7 +84,10 @@ public:
|
|||||||
virtual rel::Interface interface() const =0;
|
virtual rel::Interface interface() const =0;
|
||||||
|
|
||||||
// create a new key based on a password
|
// create a new key based on a password
|
||||||
virtual CipherKey newKey(const char *password, int passwdLength) =0;
|
// if iterationCount == 0, then iteration count will be determined
|
||||||
|
// by newKey function and filled in.
|
||||||
|
virtual CipherKey newKey(const char *password, int passwdLength,
|
||||||
|
int &iterationCount, const unsigned char *salt, int saltLen) =0;
|
||||||
// create a new random key
|
// create a new random key
|
||||||
virtual CipherKey newRandomKey() =0;
|
virtual CipherKey newRandomKey() =0;
|
||||||
|
|
||||||
@ -109,7 +112,9 @@ public:
|
|||||||
// fill the supplied buffer with random data
|
// fill the supplied buffer with random data
|
||||||
// The data may be pseudo random and might not be suitable for key
|
// The data may be pseudo random and might not be suitable for key
|
||||||
// generation. For generating keys, uses newRandomKey() instead.
|
// generation. For generating keys, uses newRandomKey() instead.
|
||||||
virtual void randomize( unsigned char *buf, int len ) const =0;
|
// Returns true on success, false on failure.
|
||||||
|
virtual bool randomize( unsigned char *buf, int len,
|
||||||
|
bool strongRandom ) const =0;
|
||||||
|
|
||||||
// 64 bit MAC of the data with the given key
|
// 64 bit MAC of the data with the given key
|
||||||
virtual uint64_t MAC_64( const unsigned char *src, int len,
|
virtual uint64_t MAC_64( const unsigned char *src, int len,
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "MemoryPool.h"
|
#include "MemoryPool.h"
|
||||||
|
|
||||||
#include <rlog/rlog.h>
|
#include <rlog/rlog.h>
|
||||||
|
#include <rlog/Error.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
@ -206,7 +207,8 @@ void CipherFileIO::initHeader( )
|
|||||||
unsigned char buf[8] = {0};
|
unsigned char buf[8] = {0};
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
cipher->randomize( buf, 8 );
|
if(!cipher->randomize( buf, 8, false ))
|
||||||
|
throw ERROR("Unable to generate a random file IV");
|
||||||
|
|
||||||
fileIV = 0;
|
fileIV = 0;
|
||||||
for(int i=0; i<8; ++i)
|
for(int i=0; i<8; ++i)
|
||||||
|
@ -87,7 +87,9 @@ static const char ENCFS_ENV_STDERR[] = "encfs_stderr";
|
|||||||
static int V5SubVersion = 20040813; // fix MACFileIO block size issues
|
static int V5SubVersion = 20040813; // fix MACFileIO block size issues
|
||||||
static int V5SubVersionDefault = 0;
|
static int V5SubVersionDefault = 0;
|
||||||
|
|
||||||
const int V6SubVersion = 20080813; // switch to v6/XML, add allowHoles option
|
// 20080813 was really made on 20080413 -- typo on date..
|
||||||
|
//const int V6SubVersion = 20080813; // switch to v6/XML, add allowHoles option
|
||||||
|
const int V6SubVersion = 20080816; // add salt and iteration count
|
||||||
|
|
||||||
struct ConfigInfo
|
struct ConfigInfo
|
||||||
{
|
{
|
||||||
@ -118,6 +120,35 @@ namespace boost
|
|||||||
{
|
{
|
||||||
namespace serialization
|
namespace serialization
|
||||||
{
|
{
|
||||||
|
template<class Archive>
|
||||||
|
void encodeBinary(Archive &ar,
|
||||||
|
const char *id, const std::string &in)
|
||||||
|
{
|
||||||
|
int encodedSize = in.length();
|
||||||
|
std::string name = std::string("encoded") + id + "Size";
|
||||||
|
ar << make_nvp(name.c_str(), encodedSize);
|
||||||
|
|
||||||
|
char data[encodedSize];
|
||||||
|
memcpy(data, in.data(), encodedSize);
|
||||||
|
name = std::string("encoded") + id + "Data";
|
||||||
|
ar << make_nvp(name.c_str(),
|
||||||
|
serial::make_binary_object(data, encodedSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void decodeBinary(Archive &ar, const char *id, std::string &out)
|
||||||
|
{
|
||||||
|
int encodedSize;
|
||||||
|
std::string name = std::string("encoded") + id + "Size";
|
||||||
|
ar >> make_nvp(name.c_str(), encodedSize);
|
||||||
|
|
||||||
|
char data[encodedSize];
|
||||||
|
name = std::string("encoded") + id + "Data";
|
||||||
|
ar >> make_nvp(name.c_str(),
|
||||||
|
serial::make_binary_object(data, encodedSize));
|
||||||
|
out.assign( (char*)data, encodedSize );
|
||||||
|
}
|
||||||
|
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
void save(Archive &ar, const EncFSConfig &cfg,
|
void save(Archive &ar, const EncFSConfig &cfg,
|
||||||
unsigned int version)
|
unsigned int version)
|
||||||
@ -135,18 +166,18 @@ namespace boost
|
|||||||
ar << make_nvp("blockMACRandBytes", cfg.blockMACRandBytes);
|
ar << make_nvp("blockMACRandBytes", cfg.blockMACRandBytes);
|
||||||
ar << make_nvp("allowHoles", cfg.allowHoles);
|
ar << make_nvp("allowHoles", cfg.allowHoles);
|
||||||
|
|
||||||
int keyLen = cfg.keyData.length();
|
encodeBinary(ar, "Key", cfg.keyData);
|
||||||
ar << make_nvp("encodedKeySize", keyLen);
|
|
||||||
char key[keyLen];
|
// version 20080816
|
||||||
memcpy(key, cfg.keyData.data(), keyLen);
|
ar << make_nvp("saltSize", cfg.saltSize);
|
||||||
ar << make_nvp("encodedKeyData",
|
ar << make_nvp("saltData",
|
||||||
serial::make_binary_object(key, keyLen));
|
serial::make_binary_object(cfg.saltData, cfg.saltSize));
|
||||||
|
ar << make_nvp("kdfIterations", cfg.kdfIterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
void load(Archive &ar, EncFSConfig &cfg, unsigned int version)
|
void load(Archive &ar, EncFSConfig &cfg, unsigned int version)
|
||||||
{
|
{
|
||||||
(void)version;
|
|
||||||
cfg.subVersion = version;
|
cfg.subVersion = version;
|
||||||
ar >> make_nvp("creator", cfg.creator);
|
ar >> make_nvp("creator", cfg.creator);
|
||||||
ar >> make_nvp("cipherAlg", cfg.cipherIface);
|
ar >> make_nvp("cipherAlg", cfg.cipherIface);
|
||||||
@ -160,12 +191,21 @@ namespace boost
|
|||||||
ar >> make_nvp("blockMACRandBytes", cfg.blockMACRandBytes);
|
ar >> make_nvp("blockMACRandBytes", cfg.blockMACRandBytes);
|
||||||
ar >> make_nvp("allowHoles", cfg.allowHoles);
|
ar >> make_nvp("allowHoles", cfg.allowHoles);
|
||||||
|
|
||||||
int encodedKeySize;
|
decodeBinary(ar, "Key", cfg.keyData);
|
||||||
ar >> make_nvp("encodedKeySize", encodedKeySize);
|
|
||||||
char key[encodedKeySize];
|
if(version >= 20080816)
|
||||||
ar >> make_nvp("encodedKeyData",
|
{
|
||||||
serial::make_binary_object(key, encodedKeySize));
|
ar >> make_nvp("saltSize", cfg.saltSize);
|
||||||
cfg.keyData.assign( (char*)key, encodedKeySize );
|
cfg.saltData = new unsigned char[cfg.saltSize];
|
||||||
|
ar >> make_nvp("saltData",
|
||||||
|
serial::make_binary_object(cfg.saltData, cfg.saltSize));
|
||||||
|
ar >> make_nvp("kdfIterations", cfg.kdfIterations);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
cfg.saltSize = 0;
|
||||||
|
cfg.saltData = NULL;
|
||||||
|
cfg.kdfIterations = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
@ -1027,6 +1067,17 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
|
|||||||
config.externalIVChaining = externalIV;
|
config.externalIVChaining = externalIV;
|
||||||
config.allowHoles = allowHoles;
|
config.allowHoles = allowHoles;
|
||||||
|
|
||||||
|
config.saltSize = 20;
|
||||||
|
config.saltData = new unsigned char[config.saltSize];
|
||||||
|
config.kdfIterations = 0; // filled in by keying function
|
||||||
|
|
||||||
|
if(!cipher->randomize(config.saltData, config.saltSize, true))
|
||||||
|
{
|
||||||
|
cout << _("Unable to generate random data for key derivation\n");
|
||||||
|
return rootInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
cout << "\n";
|
cout << "\n";
|
||||||
// xgroup(setup)
|
// xgroup(setup)
|
||||||
cout << _("Configuration finished. The filesystem to be created has\n"
|
cout << _("Configuration finished. The filesystem to be created has\n"
|
||||||
@ -1063,11 +1114,17 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
|
|||||||
CipherKey userKey;
|
CipherKey userKey;
|
||||||
rDebug( "useStdin: %i", useStdin );
|
rDebug( "useStdin: %i", useStdin );
|
||||||
if(useStdin)
|
if(useStdin)
|
||||||
userKey = getUserKey( cipher, useStdin );
|
userKey = getUserKey( cipher, useStdin,
|
||||||
|
config.saltData, config.saltSize,
|
||||||
|
config.kdfIterations);
|
||||||
else if(passwordProgram.empty())
|
else if(passwordProgram.empty())
|
||||||
userKey = getNewUserKey( cipher );
|
userKey = getNewUserKey( cipher,
|
||||||
|
config.saltData, config.saltSize,
|
||||||
|
config.kdfIterations );
|
||||||
else
|
else
|
||||||
userKey = getUserKey( passwordProgram, cipher, rootDir );
|
userKey = getUserKey( passwordProgram, cipher, rootDir,
|
||||||
|
config.saltData, config.saltSize,
|
||||||
|
config.kdfIterations );
|
||||||
|
|
||||||
cipher->writeKey( volumeKey, encodedKey, userKey );
|
cipher->writeKey( volumeKey, encodedKey, userKey );
|
||||||
userKey.reset();
|
userKey.reset();
|
||||||
@ -1231,7 +1288,8 @@ void showFSInfo( const EncFSConfig &config )
|
|||||||
cout << "\n";
|
cout << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
CipherKey getUserKey( const shared_ptr<Cipher> &cipher, bool useStdin )
|
CipherKey getUserKey( const shared_ptr<Cipher> &cipher, bool useStdin,
|
||||||
|
const unsigned char *salt, int saltSize, int &iterations)
|
||||||
{
|
{
|
||||||
char passBuf[MaxPassBuf];
|
char passBuf[MaxPassBuf];
|
||||||
char *res;
|
char *res;
|
||||||
@ -1253,7 +1311,8 @@ CipherKey getUserKey( const shared_ptr<Cipher> &cipher, bool useStdin )
|
|||||||
if(!res)
|
if(!res)
|
||||||
cerr << _("Zero length password not allowed\n");
|
cerr << _("Zero length password not allowed\n");
|
||||||
else
|
else
|
||||||
userKey = cipher->newKey( passBuf, strlen(passBuf) );
|
userKey = cipher->newKey( passBuf, strlen(passBuf),
|
||||||
|
iterations, salt, saltSize);
|
||||||
|
|
||||||
memset( passBuf, 0, sizeof(passBuf) );
|
memset( passBuf, 0, sizeof(passBuf) );
|
||||||
|
|
||||||
@ -1287,7 +1346,8 @@ std::string readPassword( int FD )
|
|||||||
}
|
}
|
||||||
|
|
||||||
CipherKey getUserKey( const std::string &passProg,
|
CipherKey getUserKey( const std::string &passProg,
|
||||||
const shared_ptr<Cipher> &cipher, const std::string &rootDir )
|
const shared_ptr<Cipher> &cipher, const std::string &rootDir,
|
||||||
|
const unsigned char *salt, int saltSize, int &iterations)
|
||||||
{
|
{
|
||||||
// have a child process run the command and get the result back to us.
|
// have a child process run the command and get the result back to us.
|
||||||
int fds[2], pid;
|
int fds[2], pid;
|
||||||
@ -1358,7 +1418,8 @@ CipherKey getUserKey( const std::string &passProg,
|
|||||||
waitpid(pid, NULL, 0);
|
waitpid(pid, NULL, 0);
|
||||||
|
|
||||||
// convert to key..
|
// convert to key..
|
||||||
result = cipher->newKey( password.c_str(), password.length() );
|
result = cipher->newKey( password.c_str(), password.length(),
|
||||||
|
iterations, salt, saltSize );
|
||||||
|
|
||||||
// clear buffer..
|
// clear buffer..
|
||||||
password.assign( password.length(), '\0' );
|
password.assign( password.length(), '\0' );
|
||||||
@ -1366,7 +1427,8 @@ CipherKey getUserKey( const std::string &passProg,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CipherKey getNewUserKey( const shared_ptr<Cipher> &cipher )
|
CipherKey getNewUserKey( const shared_ptr<Cipher> &cipher,
|
||||||
|
const unsigned char *salt, int saltSize, int &iterations )
|
||||||
{
|
{
|
||||||
CipherKey userKey;
|
CipherKey userKey;
|
||||||
char passBuf[MaxPassBuf];
|
char passBuf[MaxPassBuf];
|
||||||
@ -1382,7 +1444,8 @@ CipherKey getNewUserKey( const shared_ptr<Cipher> &cipher )
|
|||||||
sizeof(passBuf2)-1, RPP_ECHO_OFF);
|
sizeof(passBuf2)-1, RPP_ECHO_OFF);
|
||||||
|
|
||||||
if(res1 && res2 && !strcmp(passBuf, passBuf2))
|
if(res1 && res2 && !strcmp(passBuf, passBuf2))
|
||||||
userKey = cipher->newKey( passBuf, strlen(passBuf) );
|
userKey = cipher->newKey( passBuf, strlen(passBuf),
|
||||||
|
iterations, salt, saltSize );
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// xgroup(common) -- probably not common, but group with the others
|
// xgroup(common) -- probably not common, but group with the others
|
||||||
@ -1433,10 +1496,12 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts )
|
|||||||
CipherKey userKey;
|
CipherKey userKey;
|
||||||
rDebug( "useStdin: %i", opts->useStdin );
|
rDebug( "useStdin: %i", opts->useStdin );
|
||||||
if(opts->passwordProgram.empty())
|
if(opts->passwordProgram.empty())
|
||||||
userKey = getUserKey( cipher, opts->useStdin );
|
userKey = getUserKey( cipher, opts->useStdin,
|
||||||
|
config.saltData, config.saltSize, config.kdfIterations);
|
||||||
else
|
else
|
||||||
userKey = getUserKey( opts->passwordProgram,
|
userKey = getUserKey( opts->passwordProgram,
|
||||||
cipher, opts->rootDir );
|
cipher, opts->rootDir,
|
||||||
|
config.saltData, config.saltSize, config.kdfIterations);
|
||||||
|
|
||||||
if(!userKey)
|
if(!userKey)
|
||||||
return rootInfo;
|
return rootInfo;
|
||||||
|
@ -51,6 +51,10 @@ struct EncFSConfig
|
|||||||
int blockSize; // reported in bytes
|
int blockSize; // reported in bytes
|
||||||
std::string keyData;
|
std::string keyData;
|
||||||
|
|
||||||
|
int saltSize; // in bytes
|
||||||
|
unsigned char *saltData;
|
||||||
|
int kdfIterations;
|
||||||
|
|
||||||
int blockMACBytes; // MAC headers on blocks..
|
int blockMACBytes; // MAC headers on blocks..
|
||||||
int blockMACRandBytes; // number of random bytes in the block header
|
int blockMACRandBytes; // number of random bytes in the block header
|
||||||
|
|
||||||
@ -69,6 +73,16 @@ struct EncFSConfig
|
|||||||
externalIVChaining = false;
|
externalIVChaining = false;
|
||||||
chainedNameIV = false;
|
chainedNameIV = false;
|
||||||
allowHoles = false;
|
allowHoles = false;
|
||||||
|
|
||||||
|
saltSize = 0;
|
||||||
|
saltData = NULL;
|
||||||
|
kdfIterations = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~EncFSConfig()
|
||||||
|
{
|
||||||
|
if(saltData != NULL)
|
||||||
|
delete[] saltData;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -165,10 +179,13 @@ bool writeV6Config( const char *configFile, EncFSConfig *config);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
CipherKey getUserKey(const boost::shared_ptr<Cipher> &cipher, bool useStdin);
|
CipherKey getUserKey(const boost::shared_ptr<Cipher> &cipher, bool useStdin,
|
||||||
|
const unsigned char *salt, int saltLen, int &iterations);
|
||||||
CipherKey getUserKey(const std::string &passwordProgram,
|
CipherKey getUserKey(const std::string &passwordProgram,
|
||||||
const boost::shared_ptr<Cipher> &cipher,
|
const boost::shared_ptr<Cipher> &cipher,
|
||||||
const std::string &rootDir );
|
const std::string &rootDir,
|
||||||
CipherKey getNewUserKey(const boost::shared_ptr<Cipher> &cipher);
|
const unsigned char *salt, int saltLen, int &iterations);
|
||||||
|
CipherKey getNewUserKey(const boost::shared_ptr<Cipher> &cipher,
|
||||||
|
const unsigned char *salt, int saltLen, int &iterations);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -259,7 +259,10 @@ bool MACFileIO::writeOneBlock( const IORequest &req )
|
|||||||
memset( newReq.data, 0, headerSize );
|
memset( newReq.data, 0, headerSize );
|
||||||
memcpy( newReq.data + headerSize, req.data, req.dataLen );
|
memcpy( newReq.data + headerSize, req.data, req.dataLen );
|
||||||
if(randBytes)
|
if(randBytes)
|
||||||
cipher->randomize( newReq.data+macBytes, randBytes );
|
{
|
||||||
|
if(!cipher->randomize( newReq.data+macBytes, randBytes, false ))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// compute the mac (which includes the random data) and fill it in
|
// compute the mac (which includes the random data) and fill it in
|
||||||
uint64_t mac = cipher->MAC_64( newReq.data+macBytes,
|
uint64_t mac = cipher->MAC_64( newReq.data+macBytes,
|
||||||
|
@ -83,7 +83,8 @@ Interface NullCipher::interface() const
|
|||||||
return iface;
|
return iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
CipherKey NullCipher::newKey(const char *, int )
|
CipherKey NullCipher::newKey(const char *, int,
|
||||||
|
int &, const unsigned char *, int )
|
||||||
{
|
{
|
||||||
return gNullKey;
|
return gNullKey;
|
||||||
}
|
}
|
||||||
@ -93,9 +94,10 @@ CipherKey NullCipher::newRandomKey()
|
|||||||
return gNullKey;
|
return gNullKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NullCipher::randomize( unsigned char *buf, int len ) const
|
bool NullCipher::randomize( unsigned char *buf, int len, bool ) const
|
||||||
{
|
{
|
||||||
memset( buf, 0, len );
|
memset( buf, 0, len );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t NullCipher::MAC_64(const unsigned char *, int ,
|
uint64_t NullCipher::MAC_64(const unsigned char *, int ,
|
||||||
|
@ -37,7 +37,8 @@ public:
|
|||||||
virtual rel::Interface interface() const;
|
virtual rel::Interface interface() const;
|
||||||
|
|
||||||
// create a new key based on a password
|
// create a new key based on a password
|
||||||
virtual CipherKey newKey(const char *password, int passwdLength);
|
virtual CipherKey newKey(const char *password, int passwdLength,
|
||||||
|
int &iterationCount, const unsigned char *salt, int saltLen);
|
||||||
// create a new random key
|
// create a new random key
|
||||||
virtual CipherKey newRandomKey();
|
virtual CipherKey newRandomKey();
|
||||||
|
|
||||||
@ -55,7 +56,8 @@ public:
|
|||||||
virtual int encodedKeySize() const;
|
virtual int encodedKeySize() const;
|
||||||
virtual int cipherBlockSize() const;
|
virtual int cipherBlockSize() const;
|
||||||
|
|
||||||
virtual void randomize( unsigned char *buf, int len ) const;
|
virtual bool randomize( unsigned char *buf, int len,
|
||||||
|
bool strongRandom ) const;
|
||||||
|
|
||||||
virtual uint64_t MAC_64(const unsigned char *data, int len,
|
virtual uint64_t MAC_64(const unsigned char *data, int len,
|
||||||
const CipherKey &key, uint64_t *chainedIV) const;
|
const CipherKey &key, uint64_t *chainedIV) const;
|
||||||
|
@ -32,8 +32,10 @@
|
|||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include <rlog/rlog.h>
|
#include <rlog/rlog.h>
|
||||||
#include <rlog/Error.h>
|
#include <rlog/Error.h>
|
||||||
@ -51,6 +53,9 @@ const int MAX_KEYLENGTH = 32; // in bytes (256 bit)
|
|||||||
const int MAX_IVLENGTH = 16;
|
const int MAX_IVLENGTH = 16;
|
||||||
const int KEY_CHECKSUM_BYTES = 4;
|
const int KEY_CHECKSUM_BYTES = 4;
|
||||||
|
|
||||||
|
// how long we'd like the PDF function to take, in micro seconds
|
||||||
|
const long DesiredPDFTime = 500 * 1000; // 1/2 second
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
inline int MIN(int a, int b)
|
inline int MIN(int a, int b)
|
||||||
{
|
{
|
||||||
@ -125,13 +130,57 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md,
|
|||||||
return keyLen;
|
return keyLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long time_diff(const timeval &end, const timeval &start)
|
||||||
|
{
|
||||||
|
return (end.tv_sec - start.tv_sec) * 1000 * 1000 +
|
||||||
|
(end.tv_usec - start.tv_usec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TimedPBKDF2(const char *pass, int passlen,
|
||||||
|
const unsigned char *salt, int saltlen,
|
||||||
|
int keylen, unsigned char *out,
|
||||||
|
int &numIterations)
|
||||||
|
{
|
||||||
|
int iter = 1000;
|
||||||
|
timeval start, end;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
gettimeofday( &start, 0 );
|
||||||
|
int res = PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, salt, saltlen,
|
||||||
|
iter, keylen, out);
|
||||||
|
if(res != 1)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
gettimeofday( &end, 0 );
|
||||||
|
|
||||||
|
long delta = time_diff(end, start);
|
||||||
|
if(delta < DesiredPDFTime / 8)
|
||||||
|
{
|
||||||
|
iter *= 4;
|
||||||
|
} else if(delta < (5 * DesiredPDFTime / 6))
|
||||||
|
{
|
||||||
|
// estimate number of iterations to get close to desired time
|
||||||
|
iter = (int)((double)iter * (double)DesiredPDFTime
|
||||||
|
/ (double)delta);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// done..
|
||||||
|
numIterations = iter;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for
|
// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for
|
||||||
// Blowfish key lengths > 128 bit.
|
// Blowfish key lengths > 128 bit.
|
||||||
// - Version 2:0 uses BytesToKey.
|
// - Version 2:0 uses BytesToKey.
|
||||||
// We support both 2:0 and 1:0, hence current:revision:age = 2:0:1
|
// We support both 2:0 and 1:0, hence current:revision:age = 2:0:1
|
||||||
// - Version 2:1 adds support for Message Digest function interface
|
// - Version 2:1 adds support for Message Digest function interface
|
||||||
static Interface BlowfishInterface( "ssl/blowfish", 2, 1, 1 );
|
// - Version 3:0 uses PBKDF2 for password derivation
|
||||||
static Interface AESInterface( "ssl/aes", 2, 1, 1 );
|
static Interface BlowfishInterface( "ssl/blowfish", 3, 0, 2 );
|
||||||
|
static Interface AESInterface( "ssl/aes", 3, 0, 2 );
|
||||||
|
|
||||||
#if defined(HAVE_EVP_BF)
|
#if defined(HAVE_EVP_BF)
|
||||||
|
|
||||||
@ -210,8 +259,8 @@ public:
|
|||||||
unsigned int keySize; // in bytes
|
unsigned int keySize; // in bytes
|
||||||
unsigned int ivLength;
|
unsigned int ivLength;
|
||||||
|
|
||||||
// key data is first _keySize bytes, followed by _ivLength length bytes for
|
// key data is first _keySize bytes,
|
||||||
// iv
|
// followed by iv of _ivLength bytes,
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
|
|
||||||
EVP_CIPHER_CTX block_enc;
|
EVP_CIPHER_CTX block_enc;
|
||||||
@ -232,6 +281,7 @@ SSLKey::SSLKey(int keySize_, int ivLength_)
|
|||||||
pthread_mutex_init( &mutex, 0 );
|
pthread_mutex_init( &mutex, 0 );
|
||||||
buffer = (unsigned char *)OPENSSL_malloc( keySize + ivLength );
|
buffer = (unsigned char *)OPENSSL_malloc( keySize + ivLength );
|
||||||
memset( buffer, 0, keySize + ivLength );
|
memset( buffer, 0, keySize + ivLength );
|
||||||
|
|
||||||
// most likely fails unless we're running as root, or a user-page-lock
|
// most likely fails unless we're running as root, or a user-page-lock
|
||||||
// kernel patch is applied..
|
// kernel patch is applied..
|
||||||
mlock( buffer, keySize + ivLength );
|
mlock( buffer, keySize + ivLength );
|
||||||
@ -351,7 +401,8 @@ Interface SSL_Cipher::interface() const
|
|||||||
This algorithm must remain constant for backward compatibility, as this key
|
This algorithm must remain constant for backward compatibility, as this key
|
||||||
is used to encipher/decipher the master key.
|
is used to encipher/decipher the master key.
|
||||||
*/
|
*/
|
||||||
CipherKey SSL_Cipher::newKey(const char *password, int passwdLength)
|
CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
|
||||||
|
int &iterationCount, const unsigned char *salt, int saltLen)
|
||||||
{
|
{
|
||||||
const EVP_MD *md = EVP_sha1();
|
const EVP_MD *md = EVP_sha1();
|
||||||
if(!md)
|
if(!md)
|
||||||
@ -363,7 +414,35 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength)
|
|||||||
shared_ptr<SSLKey> key( new SSLKey( _keySize, _ivLength) );
|
shared_ptr<SSLKey> key( new SSLKey( _keySize, _ivLength) );
|
||||||
|
|
||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
if( iface.current() > 1 )
|
if( iface.current() > 2 )
|
||||||
|
{
|
||||||
|
if(iterationCount == 0)
|
||||||
|
{
|
||||||
|
// timed run, fills in iteration count
|
||||||
|
if(TimedPBKDF2(password, passwdLength,
|
||||||
|
salt, saltLen,
|
||||||
|
_keySize+_ivLength, KeyData(key),
|
||||||
|
iterationCount) != 1)
|
||||||
|
{
|
||||||
|
rWarning("openssl error, PBKDF2 failed");
|
||||||
|
return CipherKey();
|
||||||
|
} else if(iterationCount == 0)
|
||||||
|
{
|
||||||
|
rWarning("TimedPBKDF2 failed to fill in iteration count");
|
||||||
|
return CipherKey();
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// known iteration length
|
||||||
|
if(PKCS5_PBKDF2_HMAC_SHA1(password, passwdLength, salt, saltLen,
|
||||||
|
iterationCount, _keySize + _ivLength,
|
||||||
|
KeyData(key)) != 1)
|
||||||
|
{
|
||||||
|
rWarning("openssl error, PBKDF2 failed");
|
||||||
|
return CipherKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if( iface.current() > 1 )
|
||||||
{
|
{
|
||||||
// now we use BytesToKey, which can deal with Blowfish keys larger then
|
// now we use BytesToKey, which can deal with Blowfish keys larger then
|
||||||
// 128 bits.
|
// 128 bits.
|
||||||
@ -402,32 +481,25 @@ CipherKey SSL_Cipher::newRandomKey()
|
|||||||
{
|
{
|
||||||
const int bufLen = MAX_KEYLENGTH;
|
const int bufLen = MAX_KEYLENGTH;
|
||||||
unsigned char tmpBuf[ bufLen ];
|
unsigned char tmpBuf[ bufLen ];
|
||||||
// to avoid warnings of uninitialized data from valgrind
|
int saltLen = 20;
|
||||||
memset(tmpBuf, 0, sizeof(tmpBuf));
|
unsigned char saltBuf[ saltLen ];
|
||||||
if(RAND_bytes( tmpBuf, bufLen ) != 1)
|
|
||||||
{
|
if(!randomize(tmpBuf, bufLen, true) ||
|
||||||
char errStr[120]; // specs require string at least 120 bytes long..
|
!randomize(saltBuf, saltLen, true))
|
||||||
unsigned long errVal = 0;
|
|
||||||
if((errVal = ERR_get_error()) != 0)
|
|
||||||
{
|
|
||||||
rWarning("openssl error: %s", ERR_error_string( errVal, errStr ));
|
|
||||||
return CipherKey();
|
return CipherKey();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr<SSLKey> key( new SSLKey( _keySize, _ivLength) );
|
shared_ptr<SSLKey> key( new SSLKey( _keySize, _ivLength) );
|
||||||
|
|
||||||
// doesn't need to be versioned, because a random key is a random key..
|
// doesn't need to be versioned, because a random key is a random key..
|
||||||
// Doesn't need to be reproducable..
|
// Doesn't need to be reproducable..
|
||||||
int bytes = BytesToKey( _keySize, _ivLength, EVP_sha1(), tmpBuf,
|
if(PKCS5_PBKDF2_HMAC_SHA1((char*)tmpBuf, bufLen, saltBuf, saltLen,
|
||||||
bufLen, 16, KeyData(key), IVData(key) );
|
1000, _keySize + _ivLength, KeyData(key)) != 1)
|
||||||
if(bytes != (int)_keySize)
|
|
||||||
{
|
{
|
||||||
rWarning("newKey: BytesToKey returned %i, expecting %i key bytes",
|
rWarning("openssl error, PBKDF2 failed");
|
||||||
bytes, _keySize);
|
return CipherKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
memset( tmpBuf, 0, bufLen );
|
OPENSSL_cleanse(tmpBuf, bufLen);
|
||||||
|
|
||||||
initKey( key, _blockCipher, _streamCipher, _keySize );
|
initKey( key, _blockCipher, _streamCipher, _keySize );
|
||||||
|
|
||||||
@ -478,11 +550,27 @@ static uint64_t _checksum_64( SSLKey *key,
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSL_Cipher::randomize( unsigned char *buf, int len ) const
|
bool SSL_Cipher::randomize( unsigned char *buf, int len,
|
||||||
|
bool strongRandom ) const
|
||||||
{
|
{
|
||||||
|
// to avoid warnings of uninitialized data from valgrind
|
||||||
memset(buf, 0, len);
|
memset(buf, 0, len);
|
||||||
int result = RAND_pseudo_bytes( buf, len );
|
int result;
|
||||||
rAssert( result >= 0 );
|
if(strongRandom)
|
||||||
|
result = RAND_bytes( buf, len );
|
||||||
|
else
|
||||||
|
result = RAND_pseudo_bytes( buf, 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)
|
||||||
|
rWarning("openssl error: %s", ERR_error_string( errVal, errStr ));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t SSL_Cipher::MAC_64( const unsigned char *data, int len,
|
uint64_t SSL_Cipher::MAC_64( const unsigned char *data, int len,
|
||||||
|
@ -87,7 +87,8 @@ public:
|
|||||||
virtual rel::Interface interface() const;
|
virtual rel::Interface interface() const;
|
||||||
|
|
||||||
// create a new key based on a password
|
// create a new key based on a password
|
||||||
virtual CipherKey newKey(const char *password, int passwdLength);
|
virtual CipherKey newKey(const char *password, int passwdLength,
|
||||||
|
int &iterationCount, const unsigned char *salt, int saltLen);
|
||||||
// create a new random key
|
// create a new random key
|
||||||
virtual CipherKey newRandomKey();
|
virtual CipherKey newRandomKey();
|
||||||
|
|
||||||
@ -105,7 +106,8 @@ public:
|
|||||||
virtual int encodedKeySize() const;
|
virtual int encodedKeySize() const;
|
||||||
virtual int cipherBlockSize() const;
|
virtual int cipherBlockSize() const;
|
||||||
|
|
||||||
virtual void randomize( unsigned char *buf, int len ) const;
|
virtual bool randomize( unsigned char *buf, int len,
|
||||||
|
bool strongRandom ) const;
|
||||||
|
|
||||||
virtual uint64_t MAC_64( const unsigned char *src, int len,
|
virtual uint64_t MAC_64( const unsigned char *src, int len,
|
||||||
const CipherKey &key, uint64_t *augment ) const;
|
const CipherKey &key, uint64_t *augment ) const;
|
||||||
|
@ -669,7 +669,9 @@ static int do_chpasswd( bool useStdin, int argc, char **argv )
|
|||||||
|
|
||||||
// ask for existing password
|
// ask for existing password
|
||||||
cout << _("Enter current Encfs password\n");
|
cout << _("Enter current Encfs password\n");
|
||||||
CipherKey userKey = getUserKey( cipher, useStdin );
|
CipherKey userKey = getUserKey( cipher, useStdin,
|
||||||
|
config.saltData, config.saltSize,
|
||||||
|
config.kdfIterations );
|
||||||
if(!userKey)
|
if(!userKey)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
@ -691,9 +693,13 @@ static int do_chpasswd( bool useStdin, int argc, char **argv )
|
|||||||
userKey.reset();
|
userKey.reset();
|
||||||
cout << _("Enter new Encfs password\n");
|
cout << _("Enter new Encfs password\n");
|
||||||
if( useStdin )
|
if( useStdin )
|
||||||
userKey = getUserKey( cipher, true );
|
userKey = getUserKey( cipher, true,
|
||||||
|
config.saltData, config.saltSize,
|
||||||
|
config.kdfIterations );
|
||||||
else
|
else
|
||||||
userKey = getNewUserKey( cipher );
|
userKey = getNewUserKey( cipher,
|
||||||
|
config.saltData, config.saltSize,
|
||||||
|
config.kdfIterations );
|
||||||
|
|
||||||
// re-encode the volume key using the new user key and write it out..
|
// re-encode the volume key using the new user key and write it out..
|
||||||
int result = EXIT_FAILURE;
|
int result = EXIT_FAILURE;
|
||||||
|
Loading…
Reference in New Issue
Block a user