mirror of
https://github.com/vgough/encfs.git
synced 2024-12-26 00:28:48 +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>
|
||||
* 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.
|
||||
* m4/iconv.m4: Upgrade to gettext-0.17.
|
||||
* m4/lib-link.m4: Upgrade to gettext-0.17.
|
||||
* m4/po.m4: Upgrade to gettext-0.17.
|
||||
* configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.17.
|
||||
Sun May 18 2008 Valient Gough <vgough@pobox.com>
|
||||
* add makeKey program and showKey option to encfsctl
|
||||
* replace C header includes with C++ versions
|
||||
|
||||
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>
|
||||
* fix bug in export - wasn't able to export symlinks.
|
||||
|
@ -84,7 +84,10 @@ public:
|
||||
virtual rel::Interface interface() const =0;
|
||||
|
||||
// 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
|
||||
virtual CipherKey newRandomKey() =0;
|
||||
|
||||
@ -109,7 +112,9 @@ public:
|
||||
// fill the supplied buffer with random data
|
||||
// The data may be pseudo random and might not be suitable for key
|
||||
// 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
|
||||
virtual uint64_t MAC_64( const unsigned char *src, int len,
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "MemoryPool.h"
|
||||
|
||||
#include <rlog/rlog.h>
|
||||
#include <rlog/Error.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <cerrno>
|
||||
@ -206,7 +207,8 @@ void CipherFileIO::initHeader( )
|
||||
unsigned char buf[8] = {0};
|
||||
do
|
||||
{
|
||||
cipher->randomize( buf, 8 );
|
||||
if(!cipher->randomize( buf, 8, false ))
|
||||
throw ERROR("Unable to generate a random file IV");
|
||||
|
||||
fileIV = 0;
|
||||
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 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
|
||||
{
|
||||
@ -118,6 +120,35 @@ namespace boost
|
||||
{
|
||||
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>
|
||||
void save(Archive &ar, const EncFSConfig &cfg,
|
||||
unsigned int version)
|
||||
@ -135,18 +166,18 @@ namespace boost
|
||||
ar << make_nvp("blockMACRandBytes", cfg.blockMACRandBytes);
|
||||
ar << make_nvp("allowHoles", cfg.allowHoles);
|
||||
|
||||
int keyLen = cfg.keyData.length();
|
||||
ar << make_nvp("encodedKeySize", keyLen);
|
||||
char key[keyLen];
|
||||
memcpy(key, cfg.keyData.data(), keyLen);
|
||||
ar << make_nvp("encodedKeyData",
|
||||
serial::make_binary_object(key, keyLen));
|
||||
encodeBinary(ar, "Key", cfg.keyData);
|
||||
|
||||
// version 20080816
|
||||
ar << make_nvp("saltSize", cfg.saltSize);
|
||||
ar << make_nvp("saltData",
|
||||
serial::make_binary_object(cfg.saltData, cfg.saltSize));
|
||||
ar << make_nvp("kdfIterations", cfg.kdfIterations);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive &ar, EncFSConfig &cfg, unsigned int version)
|
||||
{
|
||||
(void)version;
|
||||
cfg.subVersion = version;
|
||||
ar >> make_nvp("creator", cfg.creator);
|
||||
ar >> make_nvp("cipherAlg", cfg.cipherIface);
|
||||
@ -159,13 +190,22 @@ namespace boost
|
||||
ar >> make_nvp("blockMACBytes", cfg.blockMACBytes);
|
||||
ar >> make_nvp("blockMACRandBytes", cfg.blockMACRandBytes);
|
||||
ar >> make_nvp("allowHoles", cfg.allowHoles);
|
||||
|
||||
int encodedKeySize;
|
||||
ar >> make_nvp("encodedKeySize", encodedKeySize);
|
||||
char key[encodedKeySize];
|
||||
ar >> make_nvp("encodedKeyData",
|
||||
serial::make_binary_object(key, encodedKeySize));
|
||||
cfg.keyData.assign( (char*)key, encodedKeySize );
|
||||
|
||||
decodeBinary(ar, "Key", cfg.keyData);
|
||||
|
||||
if(version >= 20080816)
|
||||
{
|
||||
ar >> make_nvp("saltSize", cfg.saltSize);
|
||||
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>
|
||||
@ -1027,6 +1067,17 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
|
||||
config.externalIVChaining = externalIV;
|
||||
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";
|
||||
// xgroup(setup)
|
||||
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;
|
||||
rDebug( "useStdin: %i", useStdin );
|
||||
if(useStdin)
|
||||
userKey = getUserKey( cipher, useStdin );
|
||||
userKey = getUserKey( cipher, useStdin,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations);
|
||||
else if(passwordProgram.empty())
|
||||
userKey = getNewUserKey( cipher );
|
||||
userKey = getNewUserKey( cipher,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
else
|
||||
userKey = getUserKey( passwordProgram, cipher, rootDir );
|
||||
userKey = getUserKey( passwordProgram, cipher, rootDir,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
|
||||
cipher->writeKey( volumeKey, encodedKey, userKey );
|
||||
userKey.reset();
|
||||
@ -1231,7 +1288,8 @@ void showFSInfo( const EncFSConfig &config )
|
||||
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 *res;
|
||||
@ -1253,7 +1311,8 @@ CipherKey getUserKey( const shared_ptr<Cipher> &cipher, bool useStdin )
|
||||
if(!res)
|
||||
cerr << _("Zero length password not allowed\n");
|
||||
else
|
||||
userKey = cipher->newKey( passBuf, strlen(passBuf) );
|
||||
userKey = cipher->newKey( passBuf, strlen(passBuf),
|
||||
iterations, salt, saltSize);
|
||||
|
||||
memset( passBuf, 0, sizeof(passBuf) );
|
||||
|
||||
@ -1287,7 +1346,8 @@ std::string readPassword( int FD )
|
||||
}
|
||||
|
||||
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.
|
||||
int fds[2], pid;
|
||||
@ -1358,7 +1418,8 @@ CipherKey getUserKey( const std::string &passProg,
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
// convert to key..
|
||||
result = cipher->newKey( password.c_str(), password.length() );
|
||||
result = cipher->newKey( password.c_str(), password.length(),
|
||||
iterations, salt, saltSize );
|
||||
|
||||
// clear buffer..
|
||||
password.assign( password.length(), '\0' );
|
||||
@ -1366,7 +1427,8 @@ CipherKey getUserKey( const std::string &passProg,
|
||||
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;
|
||||
char passBuf[MaxPassBuf];
|
||||
@ -1382,7 +1444,8 @@ CipherKey getNewUserKey( const shared_ptr<Cipher> &cipher )
|
||||
sizeof(passBuf2)-1, RPP_ECHO_OFF);
|
||||
|
||||
if(res1 && res2 && !strcmp(passBuf, passBuf2))
|
||||
userKey = cipher->newKey( passBuf, strlen(passBuf) );
|
||||
userKey = cipher->newKey( passBuf, strlen(passBuf),
|
||||
iterations, salt, saltSize );
|
||||
else
|
||||
{
|
||||
// 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;
|
||||
rDebug( "useStdin: %i", opts->useStdin );
|
||||
if(opts->passwordProgram.empty())
|
||||
userKey = getUserKey( cipher, opts->useStdin );
|
||||
userKey = getUserKey( cipher, opts->useStdin,
|
||||
config.saltData, config.saltSize, config.kdfIterations);
|
||||
else
|
||||
userKey = getUserKey( opts->passwordProgram,
|
||||
cipher, opts->rootDir );
|
||||
cipher, opts->rootDir,
|
||||
config.saltData, config.saltSize, config.kdfIterations);
|
||||
|
||||
if(!userKey)
|
||||
return rootInfo;
|
||||
|
@ -51,6 +51,10 @@ struct EncFSConfig
|
||||
int blockSize; // reported in bytes
|
||||
std::string keyData;
|
||||
|
||||
int saltSize; // in bytes
|
||||
unsigned char *saltData;
|
||||
int kdfIterations;
|
||||
|
||||
int blockMACBytes; // MAC headers on blocks..
|
||||
int blockMACRandBytes; // number of random bytes in the block header
|
||||
|
||||
@ -69,6 +73,16 @@ struct EncFSConfig
|
||||
externalIVChaining = false;
|
||||
chainedNameIV = 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,
|
||||
const boost::shared_ptr<Cipher> &cipher,
|
||||
const std::string &rootDir );
|
||||
CipherKey getNewUserKey(const boost::shared_ptr<Cipher> &cipher);
|
||||
const std::string &rootDir,
|
||||
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
|
||||
|
@ -259,7 +259,10 @@ bool MACFileIO::writeOneBlock( const IORequest &req )
|
||||
memset( newReq.data, 0, headerSize );
|
||||
memcpy( newReq.data + headerSize, req.data, req.dataLen );
|
||||
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
|
||||
uint64_t mac = cipher->MAC_64( newReq.data+macBytes,
|
||||
|
@ -83,7 +83,8 @@ Interface NullCipher::interface() const
|
||||
return iface;
|
||||
}
|
||||
|
||||
CipherKey NullCipher::newKey(const char *, int )
|
||||
CipherKey NullCipher::newKey(const char *, int,
|
||||
int &, const unsigned char *, int )
|
||||
{
|
||||
return gNullKey;
|
||||
}
|
||||
@ -93,9 +94,10 @@ CipherKey NullCipher::newRandomKey()
|
||||
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 );
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t NullCipher::MAC_64(const unsigned char *, int ,
|
||||
|
@ -37,7 +37,8 @@ public:
|
||||
virtual rel::Interface interface() const;
|
||||
|
||||
// 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
|
||||
virtual CipherKey newRandomKey();
|
||||
|
||||
@ -55,7 +56,8 @@ public:
|
||||
virtual int encodedKeySize() 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,
|
||||
const CipherKey &key, uint64_t *chainedIV) const;
|
||||
|
@ -32,8 +32,10 @@
|
||||
#include "Mutex.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <rlog/rlog.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 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
|
||||
inline int MIN(int a, int b)
|
||||
{
|
||||
@ -125,13 +130,57 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md,
|
||||
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
|
||||
// Blowfish key lengths > 128 bit.
|
||||
// - Version 2:0 uses BytesToKey.
|
||||
// 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
|
||||
static Interface BlowfishInterface( "ssl/blowfish", 2, 1, 1 );
|
||||
static Interface AESInterface( "ssl/aes", 2, 1, 1 );
|
||||
// - Version 3:0 uses PBKDF2 for password derivation
|
||||
static Interface BlowfishInterface( "ssl/blowfish", 3, 0, 2 );
|
||||
static Interface AESInterface( "ssl/aes", 3, 0, 2 );
|
||||
|
||||
#if defined(HAVE_EVP_BF)
|
||||
|
||||
@ -210,8 +259,8 @@ public:
|
||||
unsigned int keySize; // in bytes
|
||||
unsigned int ivLength;
|
||||
|
||||
// key data is first _keySize bytes, followed by _ivLength length bytes for
|
||||
// iv
|
||||
// key data is first _keySize bytes,
|
||||
// followed by iv of _ivLength bytes,
|
||||
unsigned char *buffer;
|
||||
|
||||
EVP_CIPHER_CTX block_enc;
|
||||
@ -232,6 +281,7 @@ SSLKey::SSLKey(int keySize_, int ivLength_)
|
||||
pthread_mutex_init( &mutex, 0 );
|
||||
buffer = (unsigned char *)OPENSSL_malloc( keySize + ivLength );
|
||||
memset( buffer, 0, keySize + ivLength );
|
||||
|
||||
// most likely fails unless we're running as root, or a user-page-lock
|
||||
// kernel patch is applied..
|
||||
mlock( buffer, keySize + ivLength );
|
||||
@ -351,7 +401,8 @@ 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)
|
||||
CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
|
||||
int &iterationCount, const unsigned char *salt, int saltLen)
|
||||
{
|
||||
const EVP_MD *md = EVP_sha1();
|
||||
if(!md)
|
||||
@ -363,7 +414,35 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength)
|
||||
shared_ptr<SSLKey> key( new SSLKey( _keySize, _ivLength) );
|
||||
|
||||
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
|
||||
// 128 bits.
|
||||
@ -402,32 +481,25 @@ CipherKey SSL_Cipher::newRandomKey()
|
||||
{
|
||||
const int bufLen = MAX_KEYLENGTH;
|
||||
unsigned char tmpBuf[ bufLen ];
|
||||
// to avoid warnings of uninitialized data from valgrind
|
||||
memset(tmpBuf, 0, sizeof(tmpBuf));
|
||||
if(RAND_bytes( tmpBuf, bufLen ) != 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 CipherKey();
|
||||
}
|
||||
}
|
||||
int saltLen = 20;
|
||||
unsigned char saltBuf[ saltLen ];
|
||||
|
||||
if(!randomize(tmpBuf, bufLen, true) ||
|
||||
!randomize(saltBuf, saltLen, true))
|
||||
return CipherKey();
|
||||
|
||||
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 reproducable..
|
||||
int bytes = BytesToKey( _keySize, _ivLength, EVP_sha1(), tmpBuf,
|
||||
bufLen, 16, KeyData(key), IVData(key) );
|
||||
if(bytes != (int)_keySize)
|
||||
if(PKCS5_PBKDF2_HMAC_SHA1((char*)tmpBuf, bufLen, saltBuf, saltLen,
|
||||
1000, _keySize + _ivLength, KeyData(key)) != 1)
|
||||
{
|
||||
rWarning("newKey: BytesToKey returned %i, expecting %i key bytes",
|
||||
bytes, _keySize);
|
||||
rWarning("openssl error, PBKDF2 failed");
|
||||
return CipherKey();
|
||||
}
|
||||
|
||||
memset( tmpBuf, 0, bufLen );
|
||||
OPENSSL_cleanse(tmpBuf, bufLen);
|
||||
|
||||
initKey( key, _blockCipher, _streamCipher, _keySize );
|
||||
|
||||
@ -478,11 +550,27 @@ static uint64_t _checksum_64( SSLKey *key,
|
||||
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);
|
||||
int result = RAND_pseudo_bytes( buf, len );
|
||||
rAssert( result >= 0 );
|
||||
int result;
|
||||
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,
|
||||
|
@ -87,7 +87,8 @@ public:
|
||||
virtual rel::Interface interface() const;
|
||||
|
||||
// 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
|
||||
virtual CipherKey newRandomKey();
|
||||
|
||||
@ -105,7 +106,8 @@ public:
|
||||
virtual int encodedKeySize() 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,
|
||||
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
|
||||
cout << _("Enter current Encfs password\n");
|
||||
CipherKey userKey = getUserKey( cipher, useStdin );
|
||||
CipherKey userKey = getUserKey( cipher, useStdin,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
if(!userKey)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@ -691,9 +693,13 @@ static int do_chpasswd( bool useStdin, int argc, char **argv )
|
||||
userKey.reset();
|
||||
cout << _("Enter new Encfs password\n");
|
||||
if( useStdin )
|
||||
userKey = getUserKey( cipher, true );
|
||||
userKey = getUserKey( cipher, true,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
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..
|
||||
int result = EXIT_FAILURE;
|
||||
|
Loading…
Reference in New Issue
Block a user