qtkeychain/keychain_win.cpp

183 lines
6.2 KiB
C++
Raw Normal View History

2011-10-27 16:15:46 +00:00
/******************************************************************************
2015-03-17 13:31:48 +00:00
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
2011-10-27 16:15:46 +00:00
* *
* This program 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. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
2011-10-27 16:14:37 +00:00
#include "keychain_p.h"
2011-10-28 23:21:07 +00:00
#include <QSettings>
2012-04-06 15:02:13 +00:00
#include <windows.h>
#include <wincrypt.h>
2011-10-28 23:21:07 +00:00
#include <memory>
2011-10-28 07:38:02 +00:00
using namespace QKeychain;
#if defined(USE_CREDENTIAL_STORE)
#include <wincred.h>
void ReadPasswordJobPrivate::scheduledStart() {
LPCWSTR name = (LPCWSTR)key.utf16();
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
PCREDENTIALW cred;
if (!CredReadW(name, CRED_TYPE_GENERIC, 0, &cred)) {
Error error;
QString msg;
switch(GetLastError()) {
case ERROR_NOT_FOUND:
error = EntryNotFound;
msg = tr("Password entry not found");
break;
default:
error = OtherError;
msg = tr("Could not decrypt data");
break;
}
q->emitFinishedWithError( error, msg );
return;
}
data = QByteArray((char*)cred->CredentialBlob, cred->CredentialBlobSize);
CredFree(cred);
q->emitFinished();
}
void WritePasswordJobPrivate::scheduledStart() {
CREDENTIALW cred;
char *pwd = data.data();
LPWSTR name = (LPWSTR)key.utf16();
memset(&cred, 0, sizeof(cred));
cred.Comment = const_cast<wchar_t*>(L"QtKeychain");
cred.Type = CRED_TYPE_GENERIC;
cred.TargetName = name;
cred.CredentialBlobSize = data.size();
cred.CredentialBlob = (LPBYTE)pwd;
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
if (!CredWriteW(&cred, 0)) {
q->emitFinishedWithError( OtherError, tr("Encryption failed") ); //TODO more details available?
} else {
q->emitFinished();
}
}
void DeletePasswordJobPrivate::scheduledStart() {
LPCWSTR name = (LPCWSTR)key.utf16();
if (!CredDeleteW(name, CRED_TYPE_GENERIC, 0)) {
Error error;
QString msg;
switch(GetLastError()) {
case ERROR_NOT_FOUND:
error = EntryNotFound;
msg = tr("Password entry not found");
break;
default:
error = OtherError;
msg = tr("Could not decrypt data");
break;
}
q->emitFinishedWithError( error, msg );
} else {
q->emitFinished();
}
}
#else
void ReadPasswordJobPrivate::scheduledStart() {
//Use settings member if there, create local settings object if not
2012-05-05 08:37:48 +00:00
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
QByteArray encrypted = actual->value( key ).toByteArray();
2011-10-28 23:21:07 +00:00
if ( encrypted.isNull() ) {
2012-05-05 08:37:48 +00:00
q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
return;
2011-10-28 23:21:07 +00:00
}
DATA_BLOB blob_in, blob_out;
blob_in.pbData = reinterpret_cast<BYTE*>( encrypted.data() );
blob_in.cbData = encrypted.size();
const BOOL ret = CryptUnprotectData( &blob_in,
2012-05-05 08:37:48 +00:00
NULL,
2011-10-28 23:21:07 +00:00
NULL,
NULL,
NULL,
0,
&blob_out );
if ( !ret ) {
2012-05-05 08:37:48 +00:00
q->emitFinishedWithError( OtherError, tr("Could not decrypt data") );
return;
2011-10-28 23:21:07 +00:00
}
2012-05-05 08:37:48 +00:00
data = QByteArray( reinterpret_cast<char*>( blob_out.pbData ), blob_out.cbData );
2011-10-28 23:21:07 +00:00
SecureZeroMemory( blob_out.pbData, blob_out.cbData );
LocalFree( blob_out.pbData );
2012-05-05 08:37:48 +00:00
q->emitFinished();
2011-10-28 07:38:02 +00:00
}
void WritePasswordJobPrivate::scheduledStart() {
2011-10-28 23:21:07 +00:00
DATA_BLOB blob_in, blob_out;
blob_in.pbData = reinterpret_cast<BYTE*>( data.data() );
blob_in.cbData = data.size();
const BOOL res = CryptProtectData( &blob_in,
L"QKeychain-encrypted data",
NULL,
NULL,
NULL,
0,
&blob_out );
if ( !res ) {
2012-05-05 08:37:48 +00:00
q->emitFinishedWithError( OtherError, tr("Encryption failed") ); //TODO more details available?
return;
2011-10-28 23:21:07 +00:00
}
const QByteArray encrypted( reinterpret_cast<char*>( blob_out.pbData ), blob_out.cbData );
LocalFree( blob_out.pbData );
//Use settings member if there, create local settings object if not
2012-05-05 08:37:48 +00:00
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
actual->setValue( key, encrypted );
actual->sync();
if ( actual->status() != QSettings::NoError ) {
2012-05-05 08:37:48 +00:00
const QString errorString = actual->status() == QSettings::AccessError
2011-10-28 23:21:07 +00:00
? tr("Could not store encrypted data in settings: access error")
: tr("Could not store encrypted data in settings: format error");
2012-05-05 08:37:48 +00:00
q->emitFinishedWithError( OtherError, errorString );
return;
2011-10-28 23:21:07 +00:00
}
2012-05-05 08:37:48 +00:00
q->emitFinished();
2011-10-28 07:38:02 +00:00
}
void DeletePasswordJobPrivate::scheduledStart() {
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
actual->remove( key );
actual->sync();
if ( actual->status() != QSettings::NoError ) {
const QString err = actual->status() == QSettings::AccessError
? tr("Could not delete encrypted data from settings: access error")
: tr("Could not delete encrypted data from settings: format error");
q->emitFinishedWithError( OtherError, err );
} else {
q->emitFinished();
}
}
#endif