pull upstream changes to kwalletd

This commit is contained in:
Ivailo Monev 2015-01-12 14:45:18 +00:00
parent b266785de5
commit edf361f7f5
7 changed files with 277 additions and 205 deletions

View file

@ -41,9 +41,10 @@
#include "cbc.h"
#define KWALLET_CIPHER_BLOWFISH_CBC 0
#define KWALLET_CIPHER_BLOWFISH_ECB 0 // this was the old KWALLET_CIPHER_BLOWFISH_CBC
#define KWALLET_CIPHER_3DES_CBC 1 // unsupported
#define KWALLET_CIPHER_GPG 2
#define KWALLET_CIPHER_BLOWFISH_CBC 3
#define KWALLET_HASH_SHA1 0
#define KWALLET_HASH_MD5 1 // unsupported
@ -139,13 +140,18 @@ BackendPersistHandler *BackendPersistHandler::getPersistHandler(BackendCipherTyp
return 0;
}
}
BackendPersistHandler *BackendPersistHandler::getPersistHandler(char magicBuf[12])
{
if (magicBuf[2] == KWALLET_CIPHER_BLOWFISH_CBC &&
if ((magicBuf[2] == KWALLET_CIPHER_BLOWFISH_ECB || magicBuf[2] == KWALLET_CIPHER_BLOWFISH_CBC) &&
(magicBuf[3] == KWALLET_HASH_SHA1 || magicBuf[3] == KWALLET_HASH_PBKDF2_SHA512)) {
if (0 == blowfishHandler)
blowfishHandler = new BlowfishPersistHandler;
if (0 == blowfishHandler) {
bool useECBforReading = magicBuf[2] == KWALLET_CIPHER_BLOWFISH_ECB;
if (useECBforReading) {
qDebug() << "this wallet uses ECB encryption. It'll be converted to CBC on next save.";
}
blowfishHandler = new BlowfishPersistHandler(useECBforReading);
}
return blowfishHandler;
}
#ifdef HAVE_QGPGME
@ -158,11 +164,16 @@ BackendPersistHandler *BackendPersistHandler::getPersistHandler(char magicBuf[12
#endif // HAVE_QGPGME
return 0; // unknown cipher or hash
}
int BlowfishPersistHandler::write(Backend* wb, KSaveFile& sf, QByteArray& version, WId)
{
assert(wb->_cipherType == BACKEND_CIPHER_BLOWFISH);
if (_useECBforReading) {
qDebug() << "This wallet used ECB and is now saved using CBC";
_useECBforReading = false;
}
version[2] = KWALLET_CIPHER_BLOWFISH_CBC;
if(!wb->_useNewHash) {
version[3] = KWALLET_HASH_SHA1;
@ -333,7 +344,7 @@ int BlowfishPersistHandler::read(Backend* wb, QFile& db, WId)
assert(encrypted.size() < db.size());
BlowFish _bf;
CipherBlockChain bf(&_bf);
CipherBlockChain bf(&_bf, _useECBforReading);
int blksz = bf.blockSize();
if ((encrypted.size() % blksz) != 0) {
return -5; // invalid file structure
@ -477,7 +488,7 @@ int GpgPersistHandler::write(Backend* wb, KSaveFile& sf, QByteArray& version, WI
sf.abort();
return -5;
}
boost::shared_ptr< GpgME::Context > ctx( GpgME::Context::createForProtocol(GpgME::OpenPGP) );
if (0 == ctx) {
kDebug() << "Cannot setup OpenPGP context!";
@ -486,7 +497,7 @@ int GpgPersistHandler::write(Backend* wb, KSaveFile& sf, QByteArray& version, WI
}
assert(wb->_cipherType == BACKEND_CIPHER_GPG);
QByteArray hashes;
QDataStream hashStream(&hashes, QIODevice::WriteOnly);
KMD5 md5;
@ -524,7 +535,7 @@ int GpgPersistHandler::write(Backend* wb, KSaveFile& sf, QByteArray& version, WI
dataStream << keyID;
dataStream << hashes;
dataStream << values;
GpgME::Data decryptedData(dataBuffer.data(), dataBuffer.size(), false);
GpgME::Data encryptedData;
std::vector< GpgME::Key > keys;
@ -549,7 +560,7 @@ int GpgPersistHandler::write(Backend* wb, KSaveFile& sf, QByteArray& version, WI
return -4; // write error
}
}
return 0;
}
@ -571,7 +582,7 @@ int GpgPersistHandler::read(Backend* wb, QFile& sf, WId w)
while (bytes = sf.read(buffer, sizeof(buffer)/sizeof(buffer[0]))){
encryptedData.write(buffer, bytes);
}
retry_label:
boost::shared_ptr< GpgME::Context > ctx( GpgME::Context::createForProtocol(GpgME::OpenPGP) );
if (0 == ctx) {
@ -595,13 +606,13 @@ int GpgPersistHandler::read(Backend* wb, QFile& sf, WId w)
}
return -1;
}
decryptedData.seek(0, SEEK_SET);
QByteArray dataBuffer;
while (bytes = decryptedData.read(buffer, sizeof(buffer)/sizeof(buffer[0]))){
dataBuffer.append(buffer, bytes);
}
// load the wallet from the decrypted data
QDataStream dataStream(dataBuffer);
QString keyID;
@ -636,10 +647,10 @@ int GpgPersistHandler::read(Backend* wb, QFile& sf, WId w)
return -1;
}
QDataStream hashStream(hashes);
QDataStream valueStream(values);
quint32 hashCount;
hashStream >> hashCount;
if (hashCount > 0xFFFF) {
@ -650,10 +661,10 @@ int GpgPersistHandler::read(Backend* wb, QFile& sf, WId w)
while (hashCount--){
KMD5::Digest d;
hashStream.readRawData(reinterpret_cast<char *>(d), 16);
quint32 folderSize;
hashStream >> folderSize;
MD5Digest ba = MD5Digest(reinterpret_cast<char *>(d));
QMap<MD5Digest, QList<MD5Digest> >::iterator it = wb->_hashes.insert(ba, QList<MD5Digest>());
while (folderSize--){
@ -663,27 +674,27 @@ int GpgPersistHandler::read(Backend* wb, QFile& sf, WId w)
(*it).append(ba);
}
}
while (folderCount--){
QString folder;
valueStream >> folder;
quint32 entryCount;
valueStream >> entryCount;
wb->_entries[folder].clear();
while (entryCount--){
KWallet::Wallet::EntryType et = KWallet::Wallet::Unknown;
Entry *e = new Entry;
QString key;
valueStream >> key;
qint32 x =0; // necessary to read properly
valueStream >> x;
et = static_cast<KWallet::Wallet::EntryType>(x);
switch (et) {
case KWallet::Wallet::Password:
case KWallet::Wallet::Stream:
@ -693,7 +704,7 @@ int GpgPersistHandler::read(Backend* wb, QFile& sf, WId w)
delete e;
continue;
}
QByteArray a;
valueStream >> a;
e->setValue(a);
@ -702,7 +713,7 @@ int GpgPersistHandler::read(Backend* wb, QFile& sf, WId w)
wb->_entries[folder][key] = e;
}
}
wb->_open = true;
return 0;

View file

@ -60,11 +60,13 @@ public:
class BlowfishPersistHandler : public BackendPersistHandler {
public:
BlowfishPersistHandler() {}
explicit BlowfishPersistHandler(bool useECBforReading =false) : _useECBforReading(useECBforReading) {}
virtual ~BlowfishPersistHandler() {}
virtual int write(Backend* wb, KSaveFile& sf, QByteArray& version, WId w);
virtual int read(Backend* wb, QFile& sf, WId w);
private:
bool _useECBforReading;
};
#ifdef HAVE_QGPGME

View file

@ -1,149 +1,212 @@
/* This file is part of the KDE project
Copyright (C) 2001 George Staikos <staikos@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "cbc.h"
#include <string.h>
#include <kdebug.h>
CipherBlockChain::CipherBlockChain(BlockCipher *cipher) : _cipher(cipher) {
_next = 0L;
_register = 0L;
_len = -1;
_reader = _writer = 0L;
if (cipher) {
_blksz = cipher->blockSize();
}
CipherBlockChain::CipherBlockChain(BlockCipher *cipher, bool useECBforReading) :
_cipher(cipher)
, _useECBforReading(useECBforReading)
{
_next = 0L;
_register = 0L;
_len = -1;
_reader = _writer = 0L;
if (cipher) {
_blksz = cipher->blockSize();
}
}
CipherBlockChain::~CipherBlockChain() {
delete[] (char *)_register;
_register = 0L;
delete[] (char *)_next;
_next = 0L;
CipherBlockChain::~CipherBlockChain()
{
delete[](char *)_register;
_register = 0L;
delete[](char *)_next;
_next = 0L;
}
bool CipherBlockChain::setKey(void *key, int bitlength) {
if (_cipher) {
return _cipher->setKey(key, bitlength);
}
return false;
bool CipherBlockChain::setKey(void *key, int bitlength)
{
if (_cipher) {
return _cipher->setKey(key, bitlength);
}
return false;
}
int CipherBlockChain::keyLen() const {
if (_cipher) {
return _cipher->keyLen();
}
return -1;
int CipherBlockChain::keyLen() const
{
if (_cipher) {
return _cipher->keyLen();
}
return -1;
}
bool CipherBlockChain::variableKeyLen() const {
if (_cipher) {
return _cipher->variableKeyLen();
}
return false;
bool CipherBlockChain::variableKeyLen() const
{
if (_cipher) {
return _cipher->variableKeyLen();
}
return false;
}
bool CipherBlockChain::readyToGo() const {
if (_cipher) {
return _cipher->readyToGo();
}
return false;
bool CipherBlockChain::readyToGo() const
{
if (_cipher) {
return _cipher->readyToGo();
}
return false;
}
int CipherBlockChain::encrypt(void *block, int len) {
if (_cipher && !_reader) {
int rc;
_writer |= 1;
if (!_register) {
_register = new unsigned char[len];
_len = len;
memset(_register, 0, len);
} else if (len > _len) {
return -1;
}
// This might be optimizable
char *tb = (char *)block;
for (int i = 0; i < len; i++) {
tb[i] ^= ((char *)_register)[i];
}
rc = _cipher->encrypt(block, len);
if (rc != -1) {
memcpy(_register, block, len);
}
return rc;
}
return -1;
void CipherBlockChain::initRegister() {
if (_register == 0L) {
size_t registerLen = _cipher->blockSize();
_register = new unsigned char[registerLen];
_len = registerLen;
}
memset(_register, 0, _len);
}
int CipherBlockChain::encrypt(void *block, int len)
{
if (_cipher && !_reader) {
int rc;
int CipherBlockChain::decrypt(void *block, int len) {
if (_cipher && !_writer) {
int rc;
_writer |= 1;
_reader |= 1;
initRegister();
if (!_register) {
_register = new unsigned char[len];
_len = len;
memset(_register, 0, len);
} else if (len > _len) {
return -1;
}
if ((len % _len) >0) {
kDebug() << "Block length given encrypt (" << len << ") is not a multiple of " << _len;
return -1;
}
if (!_next)
_next = new unsigned char[_len];
memcpy(_next, block, _len);
char *elemBlock = static_cast<char*>(block);
for (int b = 0; b < len/_len; b++) {
rc = _cipher->decrypt(block, len);
// This might be optimizable
char *tb = static_cast<char*>(elemBlock);
for (int i = 0; i < _len; i++) {
*tb++ ^= ((char *)_register)[i];
}
if (rc != -1) {
// This might be optimizable
char *tb = (char *)block;
for (int i = 0; i < len; i++) {
tb[i] ^= ((char *)_register)[i];
}
}
rc = _cipher->encrypt(elemBlock, _len);
void *temp;
temp = _next;
_next = _register;
_register = temp;
if (rc != -1) {
memcpy(_register, elemBlock, _len);
}
elemBlock += _len;
}
return rc;
}
return -1;
return rc;
}
return -1;
}
// This is the old decrypt method, that was decrypting using ECB
// instead of CBC
int CipherBlockChain::decryptECB(void *block, int len) {
if (_cipher && !_writer) {
int rc;
_reader |= 1;
if (!_register) {
_register = new unsigned char[len];
_len = len;
memset(_register, 0, len);
} else if (len > _len) {
return -1;
}
if (!_next) {
_next = new unsigned char[_len];
}
memcpy(_next, block, _len);
rc = _cipher->decrypt(block, len);
if (rc != -1) {
// This might be optimizable
char *tb = (char *)block;
for (int i = 0; i < len; i++) {
tb[i] ^= ((char *)_register)[i];
}
}
void *temp;
temp = _next;
_next = _register;
_register = temp;
return rc;
}
return -1;
}
int CipherBlockChain::decrypt(void *block, int len)
{
if (_useECBforReading) {
kDebug() << "decrypting using ECB!";
return decryptECB(block, len);
}
if (_cipher && !_writer) {
int rc = 0;
_reader |= 1;
initRegister();
if ((len % _len) >0) {
kDebug() << "Block length given for decrypt (" << len << ") is not a multiple of " << _len;
return -1;
}
char *elemBlock = static_cast<char*>(block);
for (int b = 0; b < len/_len; b++) {
if (_next == 0L) {
_next = new unsigned char[_len];
}
memcpy(_next, elemBlock, _len);
int bytesDecrypted = _cipher->decrypt(elemBlock, _len);
if (bytesDecrypted != -1) {
rc += bytesDecrypted;
// This might be optimizable
char *tb = (char *)elemBlock;
for (int i = 0; i < _len; i++) {
*tb++ ^= ((char *)_register)[i];
}
}
void *temp;
temp = _next;
_next = _register;
_register = temp;
elemBlock += _len;
}
return rc;
}
return -1;
}

View file

@ -1,24 +1,22 @@
/* This file is part of the KDE project
Copyright (C) 2001 George Staikos <staikos@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef __CBC__KO__H
#define __CBC__KO__H
@ -33,30 +31,34 @@
* calls to the other will fail in this instance.
*/
class CipherBlockChain : public BlockCipher {
public:
CipherBlockChain(BlockCipher *cipher);
virtual ~CipherBlockChain();
class CipherBlockChain : public BlockCipher
{
public:
CipherBlockChain(BlockCipher *cipher, bool useECBforReading =false);
virtual ~CipherBlockChain();
virtual bool setKey(void *key, int bitlength);
virtual bool setKey(void *key, int bitlength);
virtual int keyLen() const;
virtual int keyLen() const;
virtual bool variableKeyLen() const;
virtual bool variableKeyLen() const;
virtual bool readyToGo() const;
virtual bool readyToGo() const;
virtual int encrypt(void *block, int len);
virtual int encrypt(void *block, int len);
virtual int decrypt(void *block, int len);
virtual int decrypt(void *block, int len);
private:
BlockCipher *_cipher;
void *_register;
void *_next;
int _len;
int _reader, _writer;
private:
void initRegister();
int decryptECB(void *block, int len);
BlockCipher *_cipher;
void *_register;
void *_next;
int _len;
int _reader, _writer;
bool _useECBforReading;
};
#endif

View file

@ -4,64 +4,60 @@
#include "blowfish.h"
#include "cbc.h"
int main()
{
BlockCipher *bf;
char data[] = "This is a test.";
char expect[] = "\x3f\x3c\x2d\xae\x8c\x7\x84\xf2\xa7\x6d\x28\xbd\xd\xb\xb8\x79";
char key[] = "testkey";
unsigned long et[] = {0x11223344};
int main() {
BlockCipher *bf;
char data[] = "This is a test.";
char expect[] = "\x22\x30\x7e\x2f\x42\x28\x44\x01\xda\xdf\x5a\x81\xd7\xe5\x7c\xd0";
char key[] = "testkey";
unsigned long et[] = {0x11223344};
printf("%d: 0x11 == %d and 0x44 == %d\n", ((unsigned char *)et)[0],
0x11, 0x44);
bf = new BlowFish();
printf("%d: 0x11 == %d and 0x44 == %d\n", ((unsigned char *)et)[0],
0x11, 0x44);
bf = new BlowFish();
// bf = new CipherBlockChain(new BlowFish());
bf->setKey((void *)key, 7*8);
bf->setKey((void *)key, 7 * 8);
if (!bf->readyToGo()) {
printf("Error: not ready to go!\n");
return -1;
}
printf("About to encrypt...\n"); fflush(stdout);
if (-1 == bf->encrypt((void *)data, 8)) {
printf("Error: encrypt failed!\n");
return -1;
}
printf("About to encrypt part 2...\n"); fflush(stdout);
bf->encrypt((void *)(data+8), 8);
printf("Encryption done. data[] is now: ");
for (int i = 0; i < 16; i++) {
printf("0x%x ", data[i]&0xff);
if ((data[i]&0xff) != (expect[i]&0xff)) {
printf("Error. This byte failed the comparison. It should have been 0x%x.\n", expect[i]&0xff);
if (!bf->readyToGo()) {
printf("Error: not ready to go!\n");
return -1;
}
}
printf("\n");
}
delete bf;
bf = new BlowFish();
printf("About to encrypt...\n"); fflush(stdout);
if (-1 == bf->encrypt((void *)data, 16)) {
printf("Error: encrypt failed!\n");
return -1;
}
printf("Encryption done. data[] is now: ");
for (int i = 0; i < 16; i++) {
printf("0x%x ", data[i] & 0xff);
if ((data[i] & 0xff) != (expect[i] & 0xff)) {
printf("Error. This byte failed the comparison. It should have been 0x%x.\n", expect[i] & 0xff);
break;
}
}
printf("\n");
delete bf;
bf = new BlowFish();
// bf = new CipherBlockChain(new BlowFish());
bf->setKey((void *)key, 7*8);
bf->setKey((void *)key, 7 * 8);
printf("About to decrypt...\n"); fflush(stdout);
if (-1 == bf->decrypt((void *)data, 16)) {
printf("Error: decrypt failed!\n");
return -1;
}
//bf->decrypt((void *)(data+8), 8);
printf("About to decrypt...\n"); fflush(stdout);
if (-1 == bf->decrypt((void *)data, 16)) {
printf("Error: decrypt failed!\n");
return -1;
}
//bf->decrypt((void *)(data+8), 8);
printf("All done! Result... data[] = \"%s\"\n", data);
if (strcmp(data, "This is a test.")) {
printf("ERROR. Decryption failed.\n");
return -1;
}
printf("All done! Result... data[] = \"%s\"\n", data);
if (strcmp(data, "This is a test.")) {
printf("ERROR. Decryption failed.\n");
return -1;
}
delete bf;
delete bf;
}

View file

@ -150,9 +150,9 @@ KWalletD::~KWalletD() {
qDeleteAll(_transactions);
}
#ifdef Q_WS_X11
void KWalletD::connectToScreenSaver()
{
#ifdef Q_WS_X11
screensaver = new QDBusInterface("org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver");
if (!screensaver->isValid()) {
kDebug() << "Service org.freedesktop.ScreenSaver not found. Retrying in 10 seconds...";
@ -162,8 +162,8 @@ void KWalletD::connectToScreenSaver()
connect(screensaver, SIGNAL(ActiveChanged(bool)), SLOT(screenSaverChanged(bool)));
kDebug() << "connected to screen saver service.";
}
}
#endif
}
int KWalletD::generateHandle() {
int rc;

View file

@ -182,9 +182,7 @@ class KWalletD : public QObject, protected QDBusContext {
void notifyFailures();
void processTransactions();
void activatePasswordDialog();
#ifdef Q_WS_X11
void connectToScreenSaver();
#endif
private:
// Internal - open a wallet