mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-23 18:32:50 +00:00
kwalletd: extend Blowfish source to handle SHA512 keys
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
91780aff84
commit
3865870b97
7 changed files with 26 additions and 142 deletions
|
@ -14,14 +14,6 @@ set_package_properties(ZLIB PROPERTIES
|
|||
TYPE REQUIRED
|
||||
)
|
||||
|
||||
find_package(LibGcrypt 1.5.0)
|
||||
set_package_properties(LibGcrypt PROPERTIES
|
||||
DESCRIPTION "general purpose cryptographic library based on the code from GnuPG"
|
||||
URL "https://www.gnu.org/software/libgcrypt/"
|
||||
PURPOSE "kwalletd needs libgcrypt to perform PBKDF2-SHA512 hashing"
|
||||
TYPE REQUIRED
|
||||
)
|
||||
|
||||
find_package(JPEG)
|
||||
set_package_properties(JPEG PROPERTIES
|
||||
DESCRIPTION "Accelerated JPEG image codec"
|
||||
|
|
|
@ -18,7 +18,7 @@ set(kwalletbackend_LIB_SRCS
|
|||
|
||||
add_library(kwalletbackend SHARED ${kwalletbackend_LIB_SRCS})
|
||||
|
||||
target_link_libraries(kwalletbackend ${KDE4_KDEUI_LIBS} ${LIBGCRYPT_LIBRARIES})
|
||||
target_link_libraries(kwalletbackend ${KDE4_KDEUI_LIBS})
|
||||
|
||||
set_target_properties(kwalletbackend PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
|
||||
install(TARGETS kwalletbackend ${INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "blowfish.h"
|
||||
#include "cbc.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define KWALLET_CIPHER_BLOWFISH_ECB 0 // this was the old KWALLET_CIPHER_BLOWFISH_CBC
|
||||
|
@ -42,6 +41,7 @@
|
|||
#define KWALLET_HASH_SHA1 0 // fallback
|
||||
#define KWALLET_HASH_MD5 1 // unsupported
|
||||
#define KWALLET_HASH_PBKDF2_SHA512 2 // used since 4.13 version
|
||||
#define KWALLET_HASH_SHA512 3 // used since 4.13 version
|
||||
|
||||
namespace KWallet {
|
||||
|
||||
|
@ -67,8 +67,7 @@ BackendPersistHandler *BackendPersistHandler::getPersistHandler(BackendCipherTyp
|
|||
|
||||
BackendPersistHandler *BackendPersistHandler::getPersistHandler(char magicBuf[KWMAGIC_LEN])
|
||||
{
|
||||
if (magicBuf[2] == KWALLET_CIPHER_BLOWFISH_CBC &&
|
||||
(magicBuf[3] == KWALLET_HASH_SHA1 || magicBuf[3] == KWALLET_HASH_PBKDF2_SHA512)) {
|
||||
if (magicBuf[2] == KWALLET_CIPHER_BLOWFISH_CBC && magicBuf[3] == KWALLET_HASH_SHA512) {
|
||||
if (blowfishHandler == 0) {
|
||||
blowfishHandler = new BlowfishPersistHandler();
|
||||
}
|
||||
|
@ -82,11 +81,7 @@ int BlowfishPersistHandler::write(Backend* wb, KSaveFile& sf, QByteArray& versio
|
|||
assert(wb->_cipherType == BACKEND_CIPHER_BLOWFISH);
|
||||
|
||||
version[2] = KWALLET_CIPHER_BLOWFISH_CBC;
|
||||
if(!wb->_useNewHash) {
|
||||
version[3] = KWALLET_HASH_SHA1;
|
||||
} else {
|
||||
version[3] = KWALLET_HASH_PBKDF2_SHA512; // Since 4.13 we always use PBKDF2_SHA512
|
||||
}
|
||||
version[3] = KWALLET_HASH_SHA512; // Since 4.20 we always use SHA512
|
||||
|
||||
if (sf.write(version, 4) != 4) {
|
||||
sf.abort();
|
||||
|
@ -153,9 +148,12 @@ int BlowfishPersistHandler::write(Backend* wb, KSaveFile& sf, QByteArray& versio
|
|||
wholeFile.resize(newsize);
|
||||
|
||||
const int randBlockSize = blksz+delta;
|
||||
char *randomData = (char*) gcry_random_bytes(randBlockSize, GCRY_STRONG_RANDOM);
|
||||
char randomData[randBlockSize];
|
||||
::memset(randomData, 0, randBlockSize * sizeof(char));
|
||||
for (int i = 0; i < randBlockSize; i++) {
|
||||
randomData[i] = char(qrand() % (sizeof(char) * sizeof(char)));
|
||||
}
|
||||
QByteArray randBlock(randomData, randBlockSize);
|
||||
::free(randomData);
|
||||
|
||||
for (int i = 0; i < blksz; i++) {
|
||||
wholeFile[i] = randBlock[i];
|
||||
|
|
|
@ -107,7 +107,7 @@ BlowFish::~BlowFish() {
|
|||
|
||||
|
||||
int BlowFish::keyLen() const {
|
||||
return 448;
|
||||
return 512;
|
||||
}
|
||||
|
||||
|
||||
|
@ -117,7 +117,7 @@ bool BlowFish::readyToGo() const {
|
|||
|
||||
|
||||
bool BlowFish::setKey(void *key, int bitlength) {
|
||||
if (bitlength <= 0 || bitlength > 448 || bitlength % 8 != 0) {
|
||||
if (bitlength <= 0 || bitlength > 512 || bitlength % 8 != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,13 +37,10 @@
|
|||
#include "blowfish.h"
|
||||
#include "cbc.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <assert.h>
|
||||
|
||||
// quick fix to get random numbers on win32
|
||||
|
||||
#define KWALLET_VERSION_MAJOR 0
|
||||
#define KWALLET_VERSION_MINOR 1
|
||||
#define KWALLET_VERSION_MAJOR 0
|
||||
#define KWALLET_VERSION_MINOR 2
|
||||
|
||||
using namespace KWallet;
|
||||
|
||||
|
@ -61,7 +58,6 @@ static void initKWalletDir()
|
|||
Backend::Backend(const QString& name, bool isPath)
|
||||
: d(0)
|
||||
, _name(name)
|
||||
, _useNewHash(false)
|
||||
, _ref(0)
|
||||
, _cipherType(KWallet::BACKEND_CIPHER_UNKNOWN)
|
||||
{
|
||||
|
@ -90,34 +86,6 @@ void Backend::setCipherType(BackendCipherType ct)
|
|||
_cipherType = ct;
|
||||
}
|
||||
|
||||
static int password2PBKDF2_SHA512(const QByteArray &password, QByteArray& hash, const QByteArray &salt)
|
||||
{
|
||||
if (!gcry_check_version("1.5.0")) {
|
||||
printf("libcrypt version is too old \n");
|
||||
return GPG_ERR_USER_2;
|
||||
}
|
||||
|
||||
gcry_error_t error;
|
||||
bool static gcry_secmem_init = false;
|
||||
if (!gcry_secmem_init) {
|
||||
error = gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0);
|
||||
if (error != 0) {
|
||||
kWarning() << "Can't get secure memory:" << error;
|
||||
return error;
|
||||
}
|
||||
gcry_secmem_init = true;
|
||||
}
|
||||
|
||||
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
|
||||
error = gcry_kdf_derive(password.constData(), password.size(),
|
||||
GCRY_KDF_PBKDF2, GCRY_MD_SHA512,
|
||||
salt.data(), salt.size(),
|
||||
PBKDF2_SHA512_ITERATIONS, PBKDF2_SHA512_KEYSIZE, hash.data());
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int Backend::deref() {
|
||||
if (--_ref < 0) {
|
||||
kDebug() << "refCount negative!";
|
||||
|
@ -179,14 +147,11 @@ int Backend::openPreHashed(const QByteArray &passwordHash)
|
|||
}
|
||||
|
||||
// check the password hash for correct size (currently fixed)
|
||||
if (passwordHash.size() != 20 && passwordHash.size() != 40 &&
|
||||
passwordHash.size() != 56) {
|
||||
if (passwordHash.size() != 20 && passwordHash.size() != 128) {
|
||||
return -42; // unsupported encryption scheme
|
||||
}
|
||||
|
||||
_passhash = passwordHash;
|
||||
_newPassHash = passwordHash;
|
||||
_useNewHash = true;//Only new hash is supported
|
||||
|
||||
return openInternal();
|
||||
}
|
||||
|
@ -227,10 +192,10 @@ int Backend::openInternal(WId w)
|
|||
return -4; // unknown version
|
||||
}
|
||||
|
||||
// 0 has been the MINOR version until 4.13, from that point we use it to upgrade the hash
|
||||
if (magicBuf[1] == 1) {
|
||||
// 0 has been the MINOR version until 4.13
|
||||
// 1 has been the MINOR version until 4.20
|
||||
if (magicBuf[1] == 2) {
|
||||
kDebug() << "Wallet new enough, using new hash";
|
||||
swapToNewHash();
|
||||
} else if (magicBuf[1] != 0){
|
||||
kDebug() << "Wallet is old, sad panda :(";
|
||||
return -4; // unknown version
|
||||
|
@ -243,40 +208,6 @@ int Backend::openInternal(WId w)
|
|||
return phandler->read(this, db, w);
|
||||
}
|
||||
|
||||
void Backend::swapToNewHash()
|
||||
{
|
||||
//Runtime error happened and we can't use the new hash
|
||||
if (!_useNewHash) {
|
||||
kDebug() << "Runtime error on the new hash";
|
||||
return;
|
||||
}
|
||||
_passhash.fill(0); // Making sure the old passhash is not around in memory
|
||||
_passhash = _newPassHash; // Use the new hash, means the wallet is modern enough
|
||||
}
|
||||
|
||||
QByteArray Backend::createAndSaveSalt(const QString& path) const
|
||||
{
|
||||
QFile saltFile(path);
|
||||
saltFile.remove();
|
||||
|
||||
if (!saltFile.open(QIODevice::WriteOnly)) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
char *randomData = (char*) gcry_random_bytes(PBKDF2_SHA512_SALTSIZE, GCRY_STRONG_RANDOM);
|
||||
QByteArray salt(randomData, PBKDF2_SHA512_SALTSIZE);
|
||||
::free(randomData);
|
||||
|
||||
if (saltFile.write(salt) != PBKDF2_SHA512_SALTSIZE) {
|
||||
kWarning() << "Could not save salt to" << path;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
saltFile.close();
|
||||
|
||||
return salt;
|
||||
}
|
||||
|
||||
int Backend::sync(WId w) {
|
||||
if (!_open) {
|
||||
return -255; // not open yet
|
||||
|
@ -297,13 +228,7 @@ int Backend::sync(WId w) {
|
|||
// Write the version number
|
||||
QByteArray version(4, 0);
|
||||
version[0] = KWALLET_VERSION_MAJOR;
|
||||
if (_useNewHash) {
|
||||
version[1] = KWALLET_VERSION_MINOR;
|
||||
// Use the sync to update the hash to PBKDF2_SHA512
|
||||
swapToNewHash();
|
||||
} else {
|
||||
version[1] = 0; //was KWALLET_VERSION_MINOR before the new hash
|
||||
}
|
||||
version[1] = KWALLET_VERSION_MINOR;
|
||||
|
||||
BackendPersistHandler *phandler = BackendPersistHandler::getPersistHandler(_cipherType);
|
||||
if (0 == phandler) {
|
||||
|
@ -340,7 +265,6 @@ int Backend::close(bool save) {
|
|||
|
||||
// empty the password hash
|
||||
_passhash.fill(0);
|
||||
_newPassHash.fill(0);
|
||||
|
||||
_open = false;
|
||||
|
||||
|
@ -542,29 +466,5 @@ bool Backend::entryDoesNotExist(const QString& folder, const QString& entry) con
|
|||
}
|
||||
|
||||
void Backend::setPassword(const QByteArray &password) {
|
||||
_passhash.fill(0); // empty just in case
|
||||
BlowFish _bf;
|
||||
CipherBlockChain bf(&_bf);
|
||||
_newPassHash.resize(bf.keyLen()/8);
|
||||
_newPassHash.fill(0);
|
||||
|
||||
// this should be SHA-512 for release probably
|
||||
_passhash = QCryptographicHash::hash(password, QCryptographicHash::Sha1);
|
||||
|
||||
QByteArray salt;
|
||||
QFile saltFile(KGlobal::dirs()->saveLocation("kwallet") + _name + ".salt");
|
||||
if (!saltFile.exists() || saltFile.size() == 0) {
|
||||
salt = createAndSaveSalt(saltFile.fileName());
|
||||
} else {
|
||||
if (!saltFile.open(QIODevice::ReadOnly)) {
|
||||
salt = createAndSaveSalt(saltFile.fileName());
|
||||
} else {
|
||||
salt = saltFile.readAll();
|
||||
}
|
||||
}
|
||||
|
||||
if (!salt.isEmpty() && password2PBKDF2_SHA512(password, _newPassHash, salt) == 0) {
|
||||
kDebug() << "Setting useNewHash to true";
|
||||
_useNewHash = true;
|
||||
}
|
||||
_passhash = QCryptographicHash::hash(password, QCryptographicHash::Sha512);
|
||||
}
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
#include "kwalletentry.h"
|
||||
#include "backendpersisthandler.h"
|
||||
|
||||
#define PBKDF2_SHA512_KEYSIZE 56
|
||||
#define PBKDF2_SHA512_SALTSIZE 56
|
||||
#define PBKDF2_SHA512_ITERATIONS 50000
|
||||
|
||||
namespace KWallet {
|
||||
|
||||
/**
|
||||
|
@ -160,7 +156,6 @@ private:
|
|||
QString _name;
|
||||
QString _path;
|
||||
bool _open;
|
||||
bool _useNewHash;
|
||||
QString _folder;
|
||||
int _ref;
|
||||
// Map Folder->Entries
|
||||
|
@ -170,7 +165,6 @@ private:
|
|||
typedef QMap<MD5Digest, QList<MD5Digest> > HashMap;
|
||||
HashMap _hashes;
|
||||
QByteArray _passhash; // password hash used for saving the wallet
|
||||
QByteArray _newPassHash; //Modern hash using KWALLET_HASH_PBKDF2_SHA512
|
||||
BackendCipherType _cipherType; // the kind of encryption used for this wallet
|
||||
|
||||
friend class BlowfishPersistHandler;
|
||||
|
@ -178,8 +172,6 @@ private:
|
|||
// open the wallet with the password already set. This is
|
||||
// called internally by both open and openPreHashed.
|
||||
int openInternal(WId w=0);
|
||||
void swapToNewHash();
|
||||
QByteArray createAndSaveSalt(const QString &path) const;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "backend/kwalletbackend.h" //For the hash size
|
||||
|
||||
#define BSIZE 1000
|
||||
#define KWALLET_SHA512_KEYSIZE 128
|
||||
|
||||
static int pipefd = 0;
|
||||
static int socketfd = 0;
|
||||
static bool isWalletEnabled()
|
||||
|
@ -51,10 +53,10 @@ static char *waitForHash()
|
|||
int totalRead = 0;
|
||||
int readBytes = 0;
|
||||
int attemps = 0;
|
||||
char *buf = (char*)malloc(sizeof(char) * PBKDF2_SHA512_KEYSIZE);
|
||||
memset(buf, '\0', PBKDF2_SHA512_KEYSIZE);
|
||||
while(totalRead != PBKDF2_SHA512_KEYSIZE) {
|
||||
readBytes = read(pipefd, buf + totalRead, PBKDF2_SHA512_KEYSIZE - totalRead);
|
||||
char *buf = (char*)malloc(sizeof(char) * KWALLET_SHA512_KEYSIZE);
|
||||
memset(buf, '\0', KWALLET_SHA512_KEYSIZE);
|
||||
while(totalRead != KWALLET_SHA512_KEYSIZE) {
|
||||
readBytes = read(pipefd, buf + totalRead, KWALLET_SHA512_KEYSIZE - totalRead);
|
||||
if (readBytes == -1 || attemps > 5) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
|
@ -180,7 +182,7 @@ int main(int argc, char **argv)
|
|||
KWalletD walletd;
|
||||
if (hash) {
|
||||
kDebug() << "LOGIN INSIDE!";
|
||||
QByteArray passHash(hash, PBKDF2_SHA512_KEYSIZE);
|
||||
QByteArray passHash(hash, KWALLET_SHA512_KEYSIZE);
|
||||
int wallet = walletd.pamOpen(KWallet::Wallet::LocalWallet(), passHash, 0);
|
||||
kDebug() << "Wallet handler: " << wallet;
|
||||
free(hash);
|
||||
|
|
Loading…
Add table
Reference in a new issue