mirror of
https://github.com/vgough/encfs.git
synced 2025-02-16 09:49:46 +01:00
Automatic upgrade to PBKDF2 when changing password of a V6 filesystem.
Increase desired KDF duration to 3 seconds in paranoia mode. Bump to version 1.5. git-svn-id: http://encfs.googlecode.com/svn/trunk@37 db9cf616-1c43-0410-9cb8-a902689de0d6
This commit is contained in:
parent
bcfe2aff09
commit
ab90e2d91f
@ -1,7 +1,7 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT(encfs/encfs.h) dnl a source file from your sub dir
|
||||
AM_INIT_AUTOMAKE(encfs, 1.4.3) dnl searches for some needed programs
|
||||
AM_INIT_AUTOMAKE(encfs, 1.5) dnl searches for some needed programs
|
||||
|
||||
dnl without this order in this file, automake will be confused!
|
||||
dnl
|
||||
|
@ -86,8 +86,13 @@ public:
|
||||
// create a new key based on a password
|
||||
// if iterationCount == 0, then iteration count will be determined
|
||||
// by newKey function and filled in.
|
||||
// If iterationCount == 0, then desiredFunctionDuration is how many
|
||||
// milliseconds the password derivation function should take to run.
|
||||
virtual CipherKey newKey(const char *password, int passwdLength,
|
||||
int &iterationCount, const unsigned char *salt, int saltLen) =0;
|
||||
int &iterationCount, long desiredFunctionDuration,
|
||||
const unsigned char *salt, int saltLen) =0;
|
||||
// deprecated - for backward compatibility
|
||||
virtual CipherKey newKey(const char *password, int passwdLength ) =0;
|
||||
// create a new random key
|
||||
virtual CipherKey newRandomKey() =0;
|
||||
|
||||
|
@ -75,6 +75,9 @@ static const int DefaultBlockSize = 1024;
|
||||
// use the extpass option, as extpass can return arbitrary length binary data.
|
||||
static const int MaxPassBuf = 512;
|
||||
|
||||
static const int NormalKDFDuration = 500; // 1/2 a second
|
||||
static const int ParanoiaKDFDuration = 3000; // 3 seconds
|
||||
|
||||
// environment variable names for values encfs stores in the environment when
|
||||
// calling an external password program.
|
||||
static const char ENCFS_ENV_ROOTDIR[] = "encfs_root";
|
||||
@ -173,6 +176,7 @@ namespace boost
|
||||
ar << make_nvp("saltData",
|
||||
serial::make_binary_object(cfg.saltData, cfg.saltSize));
|
||||
ar << make_nvp("kdfIterations", cfg.kdfIterations);
|
||||
ar << make_nvp("desiredKDFDuration", cfg.desiredKDFDuration);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
@ -200,11 +204,13 @@ namespace boost
|
||||
ar >> make_nvp("saltData",
|
||||
serial::make_binary_object(cfg.saltData, cfg.saltSize));
|
||||
ar >> make_nvp("kdfIterations", cfg.kdfIterations);
|
||||
ar >> make_nvp("desiredKDFDuration", cfg.desiredKDFDuration);
|
||||
} else
|
||||
{
|
||||
cfg.saltSize = 0;
|
||||
cfg.saltData = NULL;
|
||||
cfg.kdfIterations = 0;
|
||||
cfg.kdfIterations = 16;
|
||||
cfg.desiredKDFDuration = NormalKDFDuration;
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,7 +324,10 @@ ConfigType readConfig_load( ConfigInfo *nm, const char *path,
|
||||
try
|
||||
{
|
||||
if( (*nm->loadFunc)( path, config, nm ))
|
||||
{
|
||||
config->cfgType = nm->type;
|
||||
return nm->type;
|
||||
}
|
||||
} catch( rlog::Error & err )
|
||||
{
|
||||
err.log( _RLWarningChannel );
|
||||
@ -329,6 +338,7 @@ ConfigType readConfig_load( ConfigInfo *nm, const char *path,
|
||||
} else
|
||||
{
|
||||
// No load function - must be an unsupported type..
|
||||
config->cfgType = nm->type;
|
||||
return nm->type;
|
||||
}
|
||||
}
|
||||
@ -901,7 +911,7 @@ static
|
||||
bool selectZeroBlockPassThrough()
|
||||
{
|
||||
// xgroup(setup)
|
||||
return boolDefaultNo(
|
||||
return boolDefaultYes(
|
||||
_("Enable file-hole pass-through?\n"
|
||||
"This avoids writing encrypted blocks when file holes are created."));
|
||||
}
|
||||
@ -938,7 +948,8 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
|
||||
bool uniqueIV = false;
|
||||
bool chainedIV = false;
|
||||
bool externalIV = false;
|
||||
bool allowHoles = false;
|
||||
bool allowHoles = true;
|
||||
long desiredKDFDuration = NormalKDFDuration;
|
||||
|
||||
if (reverseEncryption)
|
||||
{
|
||||
@ -973,6 +984,7 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
|
||||
uniqueIV = true;
|
||||
chainedIV = true;
|
||||
externalIV = true;
|
||||
desiredKDFDuration = ParanoiaKDFDuration;
|
||||
} else
|
||||
if(answer[0] != 'x')
|
||||
{
|
||||
@ -1054,6 +1066,7 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
|
||||
|
||||
EncFSConfig config;
|
||||
|
||||
config.cfgType = Config_V6;
|
||||
config.cipherIface = cipher->interface();
|
||||
config.keySize = keySize;
|
||||
config.blockSize = blockSize;
|
||||
@ -1067,16 +1080,10 @@ 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.saltSize = 0;
|
||||
config.saltData = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
config.desiredKDFDuration = desiredKDFDuration;
|
||||
|
||||
cout << "\n";
|
||||
// xgroup(setup)
|
||||
@ -1114,17 +1121,11 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
|
||||
CipherKey userKey;
|
||||
rDebug( "useStdin: %i", useStdin );
|
||||
if(useStdin)
|
||||
userKey = getUserKey( cipher, useStdin,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations);
|
||||
else if(passwordProgram.empty())
|
||||
userKey = getNewUserKey( cipher,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
userKey = config.getUserKey( useStdin );
|
||||
else if(!passwordProgram.empty())
|
||||
userKey = config.getUserKey( passwordProgram, rootDir );
|
||||
else
|
||||
userKey = getUserKey( passwordProgram, cipher, rootDir,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
userKey = config.getNewUserKey();
|
||||
|
||||
cipher->writeKey( volumeKey, encodedKey, userKey );
|
||||
userKey.reset();
|
||||
@ -1232,7 +1233,7 @@ void showFSInfo( const EncFSConfig &config )
|
||||
}
|
||||
{
|
||||
cout << autosprintf(_("Key Size: %i bits"), config.keySize);
|
||||
cipher = Cipher::New( config.cipherIface, config.keySize );
|
||||
cipher = config.getCipher();
|
||||
if(!cipher)
|
||||
{
|
||||
// xgroup(diag)
|
||||
@ -1240,6 +1241,13 @@ void showFSInfo( const EncFSConfig &config )
|
||||
} else
|
||||
cout << "\n";
|
||||
}
|
||||
if(config.kdfIterations > 0 && config.saltSize > 0)
|
||||
{
|
||||
cout << autosprintf(_("Using PBKDF2, with %i iterations"),
|
||||
config.kdfIterations) << "\n";
|
||||
cout << autosprintf(_("Salt Size: %i bits"), 8*config.saltSize)
|
||||
<< "\n";
|
||||
}
|
||||
if(config.blockMACBytes)
|
||||
{
|
||||
if(config.subVersion < 20040813)
|
||||
@ -1287,9 +1295,48 @@ void showFSInfo( const EncFSConfig &config )
|
||||
}
|
||||
cout << "\n";
|
||||
}
|
||||
|
||||
CipherKey getUserKey( const shared_ptr<Cipher> &cipher, bool useStdin,
|
||||
const unsigned char *salt, int saltSize, int &iterations)
|
||||
|
||||
shared_ptr<Cipher> EncFSConfig::getCipher()
|
||||
{
|
||||
return Cipher::New( cipherIface, keySize );
|
||||
}
|
||||
|
||||
CipherKey EncFSConfig::makeKey(const char *password, int passwdLen)
|
||||
{
|
||||
CipherKey userKey;
|
||||
shared_ptr<Cipher> cipher = getCipher();
|
||||
|
||||
// if no salt is set and we're creating a new password for a new
|
||||
// FS type, then initialize salt..
|
||||
if(saltSize == 0 && kdfIterations == 0 && cfgType >= Config_V6)
|
||||
{
|
||||
// upgrade to using salt
|
||||
saltSize = 20;
|
||||
saltData = new unsigned char[saltSize];
|
||||
}
|
||||
|
||||
if(saltSize > 0)
|
||||
{
|
||||
// if iterations isn't known, then we're creating a new key, so
|
||||
// randomize the salt..
|
||||
if(kdfIterations == 0 && !cipher->randomize( saltData, saltSize, true))
|
||||
{
|
||||
cout << _("Error creating salt\n");
|
||||
return userKey;
|
||||
}
|
||||
|
||||
userKey = cipher->newKey( password, passwdLen,
|
||||
kdfIterations, desiredKDFDuration,
|
||||
saltData, saltSize);
|
||||
} else
|
||||
{
|
||||
userKey = cipher->newKey( password, passwdLen );
|
||||
}
|
||||
|
||||
return userKey;
|
||||
}
|
||||
|
||||
CipherKey EncFSConfig::getUserKey(bool useStdin)
|
||||
{
|
||||
char passBuf[MaxPassBuf];
|
||||
char *res;
|
||||
@ -1311,8 +1358,7 @@ 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),
|
||||
iterations, salt, saltSize);
|
||||
userKey = makeKey(passBuf, strlen(passBuf));
|
||||
|
||||
memset( passBuf, 0, sizeof(passBuf) );
|
||||
|
||||
@ -1345,9 +1391,8 @@ std::string readPassword( int FD )
|
||||
return result;
|
||||
}
|
||||
|
||||
CipherKey getUserKey( const std::string &passProg,
|
||||
const shared_ptr<Cipher> &cipher, const std::string &rootDir,
|
||||
const unsigned char *salt, int saltSize, int &iterations)
|
||||
CipherKey EncFSConfig::getUserKey( const std::string &passProg,
|
||||
const std::string &rootDir )
|
||||
{
|
||||
// have a child process run the command and get the result back to us.
|
||||
int fds[2], pid;
|
||||
@ -1418,8 +1463,7 @@ CipherKey getUserKey( const std::string &passProg,
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
// convert to key..
|
||||
result = cipher->newKey( password.c_str(), password.length(),
|
||||
iterations, salt, saltSize );
|
||||
result = makeKey(password.c_str(), password.length());
|
||||
|
||||
// clear buffer..
|
||||
password.assign( password.length(), '\0' );
|
||||
@ -1427,8 +1471,7 @@ CipherKey getUserKey( const std::string &passProg,
|
||||
return result;
|
||||
}
|
||||
|
||||
CipherKey getNewUserKey( const shared_ptr<Cipher> &cipher,
|
||||
const unsigned char *salt, int saltSize, int &iterations )
|
||||
CipherKey EncFSConfig::getNewUserKey()
|
||||
{
|
||||
CipherKey userKey;
|
||||
char passBuf[MaxPassBuf];
|
||||
@ -1444,9 +1487,9 @@ 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),
|
||||
iterations, salt, saltSize );
|
||||
else
|
||||
{
|
||||
userKey = makeKey(passBuf, strlen(passBuf));
|
||||
} else
|
||||
{
|
||||
// xgroup(common) -- probably not common, but group with the others
|
||||
cerr << _("Passwords did not match, please try again\n");
|
||||
@ -1478,8 +1521,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts )
|
||||
}
|
||||
|
||||
// first, instanciate the cipher.
|
||||
shared_ptr<Cipher> cipher =
|
||||
Cipher::New( config.cipherIface, config.keySize );
|
||||
shared_ptr<Cipher> cipher = config.getCipher();
|
||||
if(!cipher)
|
||||
{
|
||||
rError(_("Unable to find cipher %s, version %i:%i:%i"),
|
||||
@ -1494,14 +1536,13 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts )
|
||||
|
||||
// get user key
|
||||
CipherKey userKey;
|
||||
rDebug( "useStdin: %i", opts->useStdin );
|
||||
if(opts->passwordProgram.empty())
|
||||
userKey = getUserKey( cipher, opts->useStdin,
|
||||
config.saltData, config.saltSize, config.kdfIterations);
|
||||
else
|
||||
userKey = getUserKey( opts->passwordProgram,
|
||||
cipher, opts->rootDir,
|
||||
config.saltData, config.saltSize, config.kdfIterations);
|
||||
|
||||
if(opts->passwordProgram.empty())
|
||||
{
|
||||
rDebug( "useStdin: %i", opts->useStdin );
|
||||
userKey = config.getUserKey( opts->useStdin );
|
||||
} else
|
||||
userKey = config.getUserKey( opts->passwordProgram, opts->rootDir );
|
||||
|
||||
if(!userKey)
|
||||
return rootInfo;
|
||||
|
@ -38,8 +38,20 @@ std::string parentDirectory( const std::string &path );
|
||||
// do it and return true.
|
||||
bool userAllowMkdir( const char *dirPath, mode_t mode );
|
||||
|
||||
enum ConfigType
|
||||
{
|
||||
Config_None = 0,
|
||||
Config_Prehistoric,
|
||||
Config_V3,
|
||||
Config_V4,
|
||||
Config_V5,
|
||||
Config_V6
|
||||
};
|
||||
|
||||
struct EncFSConfig
|
||||
{
|
||||
ConfigType cfgType;
|
||||
|
||||
std::string creator;
|
||||
int subVersion;
|
||||
|
||||
@ -54,6 +66,7 @@ struct EncFSConfig
|
||||
int saltSize; // in bytes
|
||||
unsigned char *saltData;
|
||||
int kdfIterations;
|
||||
long desiredKDFDuration;
|
||||
|
||||
int blockMACBytes; // MAC headers on blocks..
|
||||
int blockMACRandBytes; // number of random bytes in the block header
|
||||
@ -66,6 +79,7 @@ struct EncFSConfig
|
||||
|
||||
EncFSConfig()
|
||||
{
|
||||
cfgType = Config_None;
|
||||
subVersion = 0;
|
||||
blockMACBytes = 0;
|
||||
blockMACRandBytes = 0;
|
||||
@ -77,6 +91,7 @@ struct EncFSConfig
|
||||
saltSize = 0;
|
||||
saltData = NULL;
|
||||
kdfIterations = 0;
|
||||
desiredKDFDuration = 500;
|
||||
}
|
||||
|
||||
~EncFSConfig()
|
||||
@ -84,16 +99,15 @@ struct EncFSConfig
|
||||
if(saltData != NULL)
|
||||
delete[] saltData;
|
||||
}
|
||||
};
|
||||
|
||||
enum ConfigType
|
||||
{
|
||||
Config_None = 0,
|
||||
Config_Prehistoric,
|
||||
Config_V3,
|
||||
Config_V4,
|
||||
Config_V5,
|
||||
Config_V6
|
||||
CipherKey getUserKey(bool useStdin);
|
||||
CipherKey getUserKey(const std::string &passwordProgram,
|
||||
const std::string &rootDir);
|
||||
CipherKey getNewUserKey();
|
||||
|
||||
shared_ptr<Cipher> getCipher();
|
||||
private:
|
||||
CipherKey makeKey(const char *password, int passwdLen);
|
||||
};
|
||||
|
||||
class Cipher;
|
||||
@ -178,14 +192,4 @@ bool readV6Config( const char *configFile, EncFSConfig *config,
|
||||
bool writeV6Config( const char *configFile, EncFSConfig *config);
|
||||
|
||||
|
||||
|
||||
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,
|
||||
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
|
||||
|
@ -84,7 +84,12 @@ Interface NullCipher::interface() const
|
||||
}
|
||||
|
||||
CipherKey NullCipher::newKey(const char *, int,
|
||||
int &, const unsigned char *, int )
|
||||
int &, long, const unsigned char *, int )
|
||||
{
|
||||
return gNullKey;
|
||||
}
|
||||
|
||||
CipherKey NullCipher::newKey(const char *, int)
|
||||
{
|
||||
return gNullKey;
|
||||
}
|
||||
|
@ -38,7 +38,9 @@ public:
|
||||
|
||||
// create a new key based on a password
|
||||
virtual CipherKey newKey(const char *password, int passwdLength,
|
||||
int &iterationCount, const unsigned char *salt, int saltLen);
|
||||
int &iterationCount, long desiredDuration,
|
||||
const unsigned char *salt, int saltLen);
|
||||
virtual CipherKey newKey(const char *password, int passwdLength);
|
||||
// create a new random key
|
||||
virtual CipherKey newRandomKey();
|
||||
|
||||
|
@ -53,9 +53,6 @@ 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)
|
||||
{
|
||||
@ -139,7 +136,7 @@ long time_diff(const timeval &end, const timeval &start)
|
||||
int TimedPBKDF2(const char *pass, int passlen,
|
||||
const unsigned char *salt, int saltlen,
|
||||
int keylen, unsigned char *out,
|
||||
int &numIterations)
|
||||
long desiredPDFTime)
|
||||
{
|
||||
int iter = 1000;
|
||||
timeval start, end;
|
||||
@ -150,25 +147,21 @@ int TimedPBKDF2(const char *pass, int passlen,
|
||||
int res = PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, salt, saltlen,
|
||||
iter, keylen, out);
|
||||
if(res != 1)
|
||||
return res;
|
||||
return -1;
|
||||
|
||||
gettimeofday( &end, 0 );
|
||||
|
||||
long delta = time_diff(end, start);
|
||||
if(delta < DesiredPDFTime / 8)
|
||||
if(delta < desiredPDFTime / 8)
|
||||
{
|
||||
iter *= 4;
|
||||
} else if(delta < (5 * DesiredPDFTime / 6))
|
||||
} else if(delta < (5 * desiredPDFTime / 6))
|
||||
{
|
||||
// estimate number of iterations to get close to desired time
|
||||
iter = (int)((double)iter * (double)DesiredPDFTime
|
||||
iter = (int)((double)iter * (double)desiredPDFTime
|
||||
/ (double)delta);
|
||||
} else
|
||||
{
|
||||
// done..
|
||||
numIterations = iter;
|
||||
return 1;
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,9 +171,9 @@ int TimedPBKDF2(const char *pass, int passlen,
|
||||
// - 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
|
||||
// - Version 3:0 uses PBKDF2 for password derivation
|
||||
static Interface BlowfishInterface( "ssl/blowfish", 3, 0, 2 );
|
||||
static Interface AESInterface( "ssl/aes", 3, 0, 2 );
|
||||
// - Version 2:2 adds PBKDF2 for password derivation
|
||||
static Interface BlowfishInterface( "ssl/blowfish", 2, 2, 1 );
|
||||
static Interface AESInterface( "ssl/aes", 2, 2, 1 );
|
||||
|
||||
#if defined(HAVE_EVP_BF)
|
||||
|
||||
@ -402,7 +395,8 @@ Interface SSL_Cipher::interface() const
|
||||
is used to encipher/decipher the master key.
|
||||
*/
|
||||
CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
|
||||
int &iterationCount, const unsigned char *salt, int saltLen)
|
||||
int &iterationCount, long desiredDuration,
|
||||
const unsigned char *salt, int saltLen)
|
||||
{
|
||||
const EVP_MD *md = EVP_sha1();
|
||||
if(!md)
|
||||
@ -414,35 +408,49 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
|
||||
shared_ptr<SSLKey> key( new SSLKey( _keySize, _ivLength) );
|
||||
|
||||
int bytes = 0;
|
||||
if( iface.current() > 2 )
|
||||
if(iterationCount == 0)
|
||||
{
|
||||
if(iterationCount == 0)
|
||||
// timed run, fills in iteration count
|
||||
int res = TimedPBKDF2(password, passwdLength,
|
||||
salt, saltLen,
|
||||
_keySize+_ivLength, KeyData(key),
|
||||
1000 * desiredDuration);
|
||||
if(res <= 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();
|
||||
}
|
||||
rWarning("openssl error, PBKDF2 failed");
|
||||
return CipherKey();
|
||||
} else
|
||||
iterationCount = res;
|
||||
} else
|
||||
{
|
||||
// known iteration length
|
||||
if(PKCS5_PBKDF2_HMAC_SHA1(password, passwdLength, salt, saltLen,
|
||||
iterationCount, _keySize + _ivLength,
|
||||
KeyData(key)) != 1)
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
rWarning("openssl error, PBKDF2 failed");
|
||||
return CipherKey();
|
||||
}
|
||||
} else if( iface.current() > 1 )
|
||||
}
|
||||
|
||||
initKey( key, _blockCipher, _streamCipher, _keySize );
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
CipherKey SSL_Cipher::newKey(const char *password, int passwdLength)
|
||||
{
|
||||
const EVP_MD *md = EVP_sha1();
|
||||
if(!md)
|
||||
{
|
||||
rError("Unknown digest SHA1");
|
||||
return CipherKey();
|
||||
}
|
||||
|
||||
shared_ptr<SSLKey> key( new SSLKey( _keySize, _ivLength) );
|
||||
|
||||
int bytes = 0;
|
||||
if( iface.current() > 1 )
|
||||
{
|
||||
// now we use BytesToKey, which can deal with Blowfish keys larger then
|
||||
// 128 bits.
|
||||
|
@ -88,7 +88,10 @@ public:
|
||||
|
||||
// create a new key based on a password
|
||||
virtual CipherKey newKey(const char *password, int passwdLength,
|
||||
int &iterationCount, const unsigned char *salt, int saltLen);
|
||||
int &iterationCount, long desiredDuration,
|
||||
const unsigned char *salt, int saltLen);
|
||||
// deprecated - for backward compatibility
|
||||
virtual CipherKey newKey(const char *password, int passwdLength);
|
||||
// create a new random key
|
||||
virtual CipherKey newRandomKey();
|
||||
|
||||
|
@ -295,16 +295,18 @@ A choice is provided for two pre-configured settings ('standard' and
|
||||
'paranoia'), along with an expert configuration mode.
|
||||
|
||||
I<Standard> mode uses the following settings:
|
||||
Cipher: Blowfish
|
||||
Key Size: 160 bits
|
||||
Filesystem Block Size: 512 bytes
|
||||
Cipher: AES
|
||||
Key Size: 192 bits
|
||||
PBKDF2 with 1/2 second runtime, 160 bit salt
|
||||
Filesystem Block Size: 1024 bytes
|
||||
Filename Encoding: Block encoding with IV chaining
|
||||
Unique initialization vector file headers
|
||||
|
||||
I<Paranoia> mode uses the following settings:
|
||||
Cipher: AES
|
||||
Key Size: 256 bits
|
||||
Filesystem Block Size: 512 bytes
|
||||
PBKDF2 with 3 second runtime, 160 bit salt
|
||||
Filesystem Block Size: 1024 bytes
|
||||
Filename Encoding: Block encoding with IV chaining
|
||||
Unique initialization vector file headers
|
||||
Message Authentication Code block headers
|
||||
@ -314,6 +316,23 @@ In the expert / manual configuration mode, each of the above options is
|
||||
configurable. Here is a list of current options with some notes about what
|
||||
they mean:
|
||||
|
||||
=head1 Key Derivation Function
|
||||
|
||||
As of version 1.5, B<EncFS> now uses PBKDF2 as the default key derivation
|
||||
function. The number of iterations in the keying function is selected based on
|
||||
wall clock time to generate the key. In standard mode, a target time of 0.5
|
||||
seconds is used, and in paranoia mode a target of 3.0 seconds is used.
|
||||
|
||||
On a 1.6Ghz AMD 64 system, it rougly 64k iterations of the key derivation
|
||||
function can be handled in half a second. The exact number of iterations to
|
||||
use is stored in the configuration file, as it is needed to remount the
|
||||
filesystem.
|
||||
|
||||
If an B<EncFS> filesystem configuration from 1.4.x is modified with version 1.5
|
||||
(such as when using encfsctl to change the password), then the new PBKDF2
|
||||
function will be used and the filesystem will no longer be readable by older
|
||||
versions.
|
||||
|
||||
=over 4
|
||||
|
||||
=item I<Cipher>
|
||||
@ -382,7 +401,7 @@ vector. So "a/foo" and "b/foo" will have completely different encoded names
|
||||
for "foo". This features has almost no performance impact (for most
|
||||
operations), and so is the default in all modes.
|
||||
|
||||
B<Note:> One significant exception is directory renames. Since the
|
||||
B<Note:> One significant performance exception is directory renames. Since the
|
||||
initialization vector for filename encoding depends on the directory path, any
|
||||
rename requires re-encoding every filename in the tree of the directory being
|
||||
changed. If there are thousands of files, then EncFS will have to do thousands
|
||||
|
@ -669,9 +669,7 @@ 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,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
CipherKey userKey = config.getUserKey( useStdin );
|
||||
if(!userKey)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@ -694,27 +692,11 @@ static int do_chpasswd( bool useStdin, int argc, char **argv )
|
||||
cout << _("Enter new Encfs password\n");
|
||||
// reinitialize salt and iteration count
|
||||
config.kdfIterations = 0; // generate new
|
||||
if(config.saltSize != 20)
|
||||
{
|
||||
if(config.saltData != NULL)
|
||||
delete[] config.saltData;
|
||||
config.saltSize = 20;
|
||||
config.saltData = new unsigned char[config.saltSize];
|
||||
}
|
||||
if(!cipher->randomize(config.saltData, config.saltSize, 20))
|
||||
{
|
||||
cout << _("Error creating salt\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if( useStdin )
|
||||
userKey = getUserKey( cipher, true,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
userKey = config.getUserKey( true );
|
||||
else
|
||||
userKey = getNewUserKey( cipher,
|
||||
config.saltData, config.saltSize,
|
||||
config.kdfIterations );
|
||||
userKey = config.getNewUserKey();
|
||||
|
||||
// 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