Kennwortmanager KeePassX Weiterentwicklung der Version 1
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
keepassx1/src/Kdb3Database.cpp

1741 lines
50 KiB

/***************************************************************************
* Copyright (C) 2005-2007 by Tarek Saidi *
* tarek.saidi@arcor.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License. *
* *
* 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. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "global.h"
#include <iostream>
#include <time.h>
#include <qfile.h>
#include <qstringlist.h>
#include <qobject.h>
#include <qdatetime.h>
#include <QSysInfo>
#include <QBuffer>
#include <QDir>
#include "crypto/twoclass.h"
#include "crypto/aescpp.h"
#include "crypto/sha256.h"
#include "crypto/yarrow.h"
#include "lib/random.h"
using namespace std;
#include "Kdb3Database.h"
#include "KpxConfig.h"
#define UNEXP_ERROR error=QString("Unexpected error in: %1, Line:%2").arg(__FILE__).arg(__LINE__);
const QDateTime Date_Never(QDate(2999,12,28),QTime(23,59,59));
bool EntryHandleLessThan(const IEntryHandle* This,const IEntryHandle* Other){
if(!This->isValid() && Other->isValid())return true;
if(This->isValid() && !Other->isValid())return false;
if(!This->isValid() && !Other->isValid())return false;
return This->visualIndex()<Other->visualIndex();
}
bool StdEntryLessThan(const Kdb3Database::StdEntry& This,const Kdb3Database::StdEntry& Other){
return This.Index<Other.Index;
}
QString Kdb3Database::getError(){
return error;
}
void Kdb3Database::addIcon(const QPixmap& icon){
CustomIcons << icon;
emit iconsModified();
}
QPixmap& Kdb3Database::icon(int i){
if(i>=builtinIcons()+CustomIcons.size())
return EntryIcons[0];
if(i<builtinIcons())
return EntryIcons[i];
return CustomIcons[i-builtinIcons()];
}
void Kdb3Database::removeIcon(int id){
id-=builtinIcons();
if(id < 0 ) return;
if(id >= CustomIcons.size()) return;
CustomIcons.removeAt(id); // .isNull()==true
for(int i=0;i<Entries.size();i++){
if(Entries[i].Image == id+builtinIcons())
Entries[i].Image=Entries[i].OldImage;
if(Entries[i].Image>id+builtinIcons())
Entries[i].Image--;
}
for(int i=0;i<Groups.size();i++){
if(Groups[i].Image == id+builtinIcons())
Groups[i].Image=Groups[i].OldImage;
if(Groups[i].Image>id+builtinIcons())
Groups[i].Image--;
}
emit iconsModified();
}
void Kdb3Database::replaceIcon(int id,const QPixmap& icon){
if(id<builtinIcons())return;
CustomIcons[id-builtinIcons()]=icon;
emit iconsModified();
}
int Kdb3Database::numIcons(){
return builtinIcons()+CustomIcons.size();
}
bool Kdb3Database::parseMetaStream(const StdEntry& entry){
qDebug("Found Metastream: %s",entry.Comment.toUtf8().data());
if(entry.Comment=="KPX_GROUP_TREE_STATE"){
parseGroupTreeStateMetaStream(entry.Binary);
return true;}
if(entry.Comment=="KPX_CUSTOM_ICONS_3"){
parseCustomIconsMetaStream(entry.Binary);
return true;}
if(entry.Comment=="KPX_CUSTOM_ICONS_2")
return parseCustomIconsMetaStreamV2(entry.Binary);
if(entry.Comment=="KPX_CUSTOM_ICONS")
return parseCustomIconsMetaStreamV1(entry.Binary);
return false; //unknown MetaStream
}
bool Kdb3Database::isMetaStream(StdEntry& p){
if(p.Binary.isNull()) return false;
if(p.Comment == "") return false;
if(p.BinaryDesc != "bin-stream") return false;
if(p.Title != "Meta-Info") return false;
if(p.Username != "SYSTEM") return false;
if(p.Url != "$") return false;
if(p.Image != 0) return false;
return true;
}
bool Kdb3Database::parseCustomIconsMetaStreamV1(const QByteArray& dta){
qDebug("Removed old CuIcMeSt v1");
return true;
}
bool Kdb3Database::parseCustomIconsMetaStreamV2(const QByteArray& dta){
qDebug("Removed old CuIcMeSt v2");
return true;
}
void Kdb3Database::parseCustomIconsMetaStream(const QByteArray& dta){
//Rev 3
quint32 NumIcons,NumEntries,NumGroups,offset;
memcpyFromLEnd32(&NumIcons,dta.data());
memcpyFromLEnd32(&NumEntries,dta.data()+4);
memcpyFromLEnd32(&NumGroups,dta.data()+8);
offset=12;
CustomIcons.clear();
for(int i=0;i<NumIcons;i++){
CustomIcons << QPixmap();
quint32 Size;
memcpyFromLEnd32(&Size,dta.data()+offset);
if(offset+Size > dta.size()){
CustomIcons.clear();
qWarning("Discarded metastream KPX_CUSTOM_ICONS_3 because of a parsing error.");
return;}
offset+=4;
if(!CustomIcons.back().loadFromData((const unsigned char*)dta.data()+offset,Size,"PNG")){
CustomIcons.clear();
qWarning("Discarded metastream KPX_CUSTOM_ICONS_3 because of a parsing error.");
return;}
offset+=Size;
if(offset > dta.size()){
CustomIcons.clear();
qWarning("Discarded metastream KPX_CUSTOM_ICONS_3 because of a parsing error.");
return;}
}
for(int i=0;i<NumEntries;i++){
quint32 Icon;
KpxUuid EntryUuid;
EntryUuid.fromRaw(dta.data()+offset);
offset+=16;
memcpyFromLEnd32(&Icon,dta.data()+offset);
offset+=4;
StdEntry* entry=getEntry(EntryUuid);
if(entry){
entry->OldImage=entry->Image;
entry->Image=Icon;
}
}
for(int i=0;i<NumGroups;i++){
quint32 GroupId,Icon;
memcpyFromLEnd32(&GroupId,dta.data()+offset);
offset+=4;
memcpyFromLEnd32(&Icon,dta.data()+offset);
offset+=4;
StdGroup* Group=getGroup(GroupId);
if(Group){
Group->OldImage=Group->Image;
Group->Image=Icon;
}
}
return;
}
void Kdb3Database::parseGroupTreeStateMetaStream(const QByteArray& dta){
if(dta.size()<4){qWarning("Discarded metastream KPX_GROUP_TREE_STATE because of a parsing error."); return;}
quint32 Num;
memcpyFromLEnd32(&Num,dta.data());
if(Num*5!=dta.size()-4){qWarning("Discarded metastream KPX_GROUP_TREE_STATE because of a parsing error."); return;}
TreeStateMetaStream.clear();
for(int i=0;i<Num;i++){
quint32 GroupID;
quint8 IsExpanded;
memcpyFromLEnd32(&GroupID,dta.data()+4+5*i);
memcpy(&IsExpanded,dta.data()+8+5*i,1);
TreeStateMetaStream.insert(GroupID,(bool)IsExpanded);
}
return;
}
void Kdb3Database::createGroupTreeStateMetaStream(StdEntry* e){
e->BinaryDesc="bin-stream";
e->Title="Meta-Info";
e->Username="SYSTEM";
e->Comment="KPX_GROUP_TREE_STATE";
e->Url="$";
e->OldImage=0;
e->Image=0;
if(Groups.size())e->GroupId=Groups[0].Id;
QByteArray bin;
quint32 Num=Groups.size();
bin.resize(Num*5+4);
memcpyToLEnd32(bin.data(),&Num);
for(int i=0;i<Num;i++){
memcpyToLEnd32(bin.data()+4+5*i,&Groups[i].Id);
if(Groups[i].IsExpanded)
bin.data()[8+5*i]=1;
else
bin.data()[8+5*i]=0;
}
e->Binary=bin;
}
Kdb3Database::StdEntry* Kdb3Database::getEntry(const KpxUuid& uuid){
for(int i=0; i<Entries.size();i++)
if(Entries[i].Uuid==uuid)return &Entries[i];
return NULL;
}
Kdb3Database::StdGroup* Kdb3Database::getGroup(quint32 Id){
for(int i=0; i<Groups.size();i++)
if(Groups[i].Id==Id)return &Groups[i];
return NULL;
}
//! Extracts one entry from raw decrypted data.
bool Kdb3Database::readEntryField(StdEntry* entry, quint16 FieldType, quint32 FieldSize, quint8 *pData){
switch(FieldType)
{
case 0x0000:
// Ignore field
break;
case 0x0001:
entry->Uuid=KpxUuid(pData);
break;
case 0x0002:
memcpyFromLEnd32(&entry->GroupId, (char*)pData);
break;
case 0x0003:
memcpyFromLEnd32(&entry->Image, (char*)pData);
entry->OldImage=entry->Image;
break;
case 0x0004:
entry->Title=QString::fromUtf8((char*)pData);
break;
case 0x0005:
entry->Url=QString::fromUtf8((char*)pData);
break;
case 0x0006:
entry->Username=QString::fromUtf8((char*)pData);
break;
case 0x0007:{
QString s=QString::fromUtf8((char*)pData);
entry->Password.setString(s,true);
break;}
case 0x0008:
entry->Comment=QString::fromUtf8((char*)pData);
break;
case 0x0009:
entry->Creation=dateFromPackedStruct5(pData);
break;
case 0x000A:
entry->LastMod=dateFromPackedStruct5(pData);
break;
case 0x000B:
entry->LastAccess=dateFromPackedStruct5(pData);
break;
case 0x000C:
entry->Expire=dateFromPackedStruct5(pData);
break;
case 0x000D:
entry->BinaryDesc=(char*)pData;
break;
case 0x000E:
if(FieldSize != 0)
entry->Binary=QByteArray((char*)pData,FieldSize);
else
entry->Binary=QByteArray();
break;
case 0xFFFF:
break;
default:
return false;
}
return true;
}
//! Extracts one group from raw decrypted data.
bool Kdb3Database::readGroupField(StdGroup* group,QList<quint32>& Levels,quint16 FieldType, quint32 FieldSize, quint8 *pData)
{
switch(FieldType)
{
case 0x0000:
// Ignore field
break;
case 0x0001:
memcpyFromLEnd32(&group->Id, (char*)pData);
break;
case 0x0002:
group->Title=QString::fromUtf8((char*)pData);
break;
case 0x0003: //not longer used by KeePassX but part of the KDB format
break;
case 0x0004: //not longer used by KeePassX but part of the KDB format
break;
case 0x0005: //not longer used by KeePassX but part of the KDB format
break;
case 0x0006: //not longer used by KeePassX but part of the KDB format
break;
case 0x0007:
memcpyFromLEnd32(&group->Image, (char*)pData);
group->OldImage=group->Image;
break;
case 0x0008:
quint16 Level;
memcpyFromLEnd16(&Level, (char*)pData);
Levels.append(Level);
break;
case 0x0009:
//not used by KeePassX but part of the KDB format
//memcpyFromLEnd32(&Flags, (char*)pData);
break;
case 0xFFFF:
break;
default:
return false; // Field unsupported
}
return true; // Field supported
}
bool Kdb3Database::createGroupTree(QList<quint32>& Levels){
if(Levels[0]!=0) return false;
//find the parent for every group
for(int i=0;i<Groups.size();i++){
if(Levels[i]==0){
Groups[i].Parent=&RootGroup;
Groups[i].Index=RootGroup.Childs.size();
RootGroup.Childs.append(&Groups[i]);
continue;}
int j=i-1;
//the first item with a lower level is the parent
for(j;j>=0;j--){
if(Levels[j]<Levels[i]){
if(Levels[i]-Levels[j]!=1)return false;
break;
}
if(j==0)return false; //No parent found
}
Groups[i].Parent=&Groups[j];
Groups[i].Index=Groups[j].Childs.size();
Groups[i].Parent->Childs.append(&Groups[i]);
}
QList<int> EntryIndexCounter;
for(int i=0;i<Groups.size();i++)EntryIndexCounter << 0;
for(int e=0;e<Entries.size();e++){
for(int g=0;g<Groups.size();g++){
if(Entries[e].GroupId==Groups[g].Id){
Groups[g].Entries.append(&Entries[e]);
Entries[e].Group=&Groups[g];
Entries[e].Index=EntryIndexCounter[g];
EntryIndexCounter[g]++;
}
}
}
return true;
}
void Kdb3Database::createHandles(){
for(int i=0;i<Groups.size();i++){
GroupHandles.append(GroupHandle(this));
Groups[i].Handle=&GroupHandles.back();
GroupHandles.back().Group=&Groups[i];
}
for(int i=0;i<Entries.size();i++){
EntryHandles.append(EntryHandle(this));
Entries[i].Handle=&EntryHandles.back();
EntryHandles.back().Entry=&Entries[i];
}
}
void Kdb3Database::restoreGroupTreeState(){
switch (config->groupTreeState()){
case KpxConfig::RestoreLast:
for(int i=0;i<Groups.size();i++){
if(TreeStateMetaStream.contains(Groups[i].Id))
Groups[i].IsExpanded=TreeStateMetaStream.value(Groups[i].Id);
}
break;
case KpxConfig::ExpandAll:
for(int i=0;i<Groups.size();i++)
Groups[i].IsExpanded=true;
break;
}
}
bool Kdb3Database::load(QString filename){
unsigned long total_size,crypto_size;
quint32 Signature1,Signature2,Version,NumGroups,NumEntries,Flags;
quint8 TransfRandomSeed[32];
quint8 FinalRandomSeed[16];
quint8 ContentsHash[32];
quint8 EncryptionIV[16];
File=new QFile(filename);
if(!File->open(QIODevice::ReadWrite)){
if(!File->open(QIODevice::ReadOnly)){
error=tr("Could not open file.");
delete File;
File=NULL;
return false;
}
}
total_size=File->size();
char* buffer = new char[total_size];
File->read(buffer,total_size);
if(total_size < DB_HEADER_SIZE){
error=tr("Unexpected file size (DB_TOTAL_SIZE < DB_HEADER_SIZE)");
return false; }
memcpyFromLEnd32(&Signature1,buffer);
memcpyFromLEnd32(&Signature2,buffer+4);
memcpyFromLEnd32(&Flags,buffer+8);
memcpyFromLEnd32(&Version,buffer+12);
memcpy(FinalRandomSeed,buffer+16,16);
memcpy(EncryptionIV,buffer+32,16);
memcpyFromLEnd32(&NumGroups,buffer+48);
memcpyFromLEnd32(&NumEntries,buffer+52);
memcpy(ContentsHash,buffer+56,32);
memcpy(TransfRandomSeed,buffer+88,32);
memcpyFromLEnd32(&KeyTransfRounds,buffer+120);
if((Signature1!=PWM_DBSIG_1) || (Signature2!=PWM_DBSIG_2)){
error=tr("Wrong Signature");
return false;}
if((Version & 0xFFFFFF00) != (PWM_DBVER_DW & 0xFFFFFF00)){
error=tr("Unsupported File Version.");
return false;}
if(Flags & PWM_FLAG_RIJNDAEL) Algorithm = Rijndael_Cipher;
else if(Flags & PWM_FLAG_TWOFISH) Algorithm = Twofish_Cipher;
else{error=tr("Unknown Encryption Algorithm.");
return false;}
if(!transformKey(RawMasterKey,MasterKey,TransfRandomSeed,KeyTransfRounds))return false;
quint8 FinalKey[32];
SHA256 sha;
sha.update(FinalRandomSeed,16);
sha.update(MasterKey,32);
sha.finish(FinalKey);
if(Algorithm == Rijndael_Cipher)
{ AESdecrypt aes;
aes.key256(FinalKey);
aes.cbc_decrypt((unsigned char*)buffer+DB_HEADER_SIZE,(unsigned char*)buffer+DB_HEADER_SIZE,total_size-DB_HEADER_SIZE,(unsigned char*)EncryptionIV);
crypto_size=total_size-((quint8*)buffer)[total_size-1]-DB_HEADER_SIZE;
}
else if(Algorithm == Twofish_Cipher)
{
CTwofish twofish;
if(twofish.init(FinalKey, 32, EncryptionIV) != true){return false;}
crypto_size = (unsigned long)twofish.padDecrypt((quint8 *)buffer + DB_HEADER_SIZE,
total_size - DB_HEADER_SIZE, (quint8 *)buffer + DB_HEADER_SIZE);
}
if((crypto_size > 2147483446) || (!crypto_size && NumGroups)){error=tr("Decryption failed.\nThe key is wrong or the file is damaged."); return false;}
SHA256::hashBuffer(buffer+DB_HEADER_SIZE,FinalKey,crypto_size);
if(memcmp(ContentsHash, FinalKey, 32) != 0){
error=tr("Hash test failed.\nThe key is wrong or the file is damaged.");
KeyError=true;
return false;}
unsigned long tmp_id=0;
unsigned long pos = DB_HEADER_SIZE;
quint16 FieldType;
quint32 FieldSize;
char* pField;
bool bRet;
StdGroup group;
QList<quint32> Levels;
RootGroup.Title="$ROOT$";
RootGroup.Parent=NULL;
RootGroup.Handle=NULL;
for(unsigned long CurGroup = 0; CurGroup < NumGroups; )
{
pField = buffer+pos;
memcpyFromLEnd16(&FieldType, pField);
pField += 2; pos += 2;
if(pos >= total_size) {
error=tr("Unexpected error: Offset is out of range. [G1]");
return false; }
memcpyFromLEnd32(&FieldSize, pField);
pField += 4; pos += 4;
if(pos >= (total_size + FieldSize)){
error=tr("Unexpected error: Offset is out of range. [G2]");
return false;}
bRet = readGroupField(&group,Levels, FieldType, FieldSize, (quint8 *)pField);
if((FieldType == 0xFFFF) && (bRet == true)){
Groups << group;
CurGroup++;} // Now and ONLY now the counter gets increased
pField += FieldSize;
pos += FieldSize;
if(pos >= total_size) {
error=tr("Unexpected error: Offset is out of range. [G1]");
return false;}
}
StdEntry entry;
for(unsigned long CurEntry = 0; CurEntry < NumEntries;)
{
pField = buffer+pos;
memcpyFromLEnd16(&FieldType, pField);
pField += 2; pos += 2;
if(pos >= total_size){
error=tr("Unexpected error: Offset is out of range. [E1]");
return false;}
memcpyFromLEnd32(&FieldSize, pField);
pField += 4; pos += 4;
if(pos >= (total_size + FieldSize)) {
error=tr("Unexpected error: Offset is out of range. [E2]");
return false; }
bRet = readEntryField(&entry,FieldType,FieldSize,(quint8*)pField);
if((FieldType == 0xFFFF) && (bRet == true)){
Entries << entry;
if(!entry.GroupId)qDebug("NULL: %i, '%s'",(int)CurEntry,(char*)entry.Title.toUtf8().data());
CurEntry++;}
pField += FieldSize;
pos += FieldSize;
if(pos >= total_size) {
error=tr("Unexpected error: Offset is out of range. [E3]");
return false; }
}
if(!createGroupTree(Levels)){
error=tr("Invalid group tree.");
return false;
}
unsigned long CurGID, g, e, z, num;
delete [] buffer;
//Remove the metastreams from the entry list
for(int i=0;i<Entries.size();i++){
if(isMetaStream(Entries[i])==true){
if(!parseMetaStream(Entries[i]))
UnknownMetaStreams << Entries[i];
Entries.removeAt(i);
i--;}
}
int* EntryIndices=new int[Groups.size()];
for(int i=0;i<Groups.size();i++)EntryIndices[i]=0;
for(int g=0;g<Groups.size();g++){
for(int e=0;e<Entries.size();e++){
if(Entries[e].GroupId==Groups[g].Id){
Entries[e].Index=EntryIndices[g];
EntryIndices[g]++;
}
}
}
delete [] EntryIndices;
createHandles();
restoreGroupTreeState();
return true;
}
QDateTime Kdb3Database::dateFromPackedStruct5(const unsigned char* pBytes){
quint32 dw1, dw2, dw3, dw4, dw5;
dw1 = (quint32)pBytes[0]; dw2 = (quint32)pBytes[1]; dw3 = (quint32)pBytes[2];
dw4 = (quint32)pBytes[3]; dw5 = (quint32)pBytes[4];
int y = (dw1 << 6) | (dw2 >> 2);
int mon = ((dw2 & 0x00000003) << 2) | (dw3 >> 6);
int d = (dw3 >> 1) & 0x0000001F;
int h = ((dw3 & 0x00000001) << 4) | (dw4 >> 4);
int min = ((dw4 & 0x0000000F) << 2) | (dw5 >> 6);
int s = dw5 & 0x0000003F;
return QDateTime(QDate(y,mon,d),QTime(h,min,s));
}
void Kdb3Database::dateToPackedStruct5(const QDateTime& d,unsigned char* pBytes){
pBytes[0] = (quint8)(((quint32)d.date().year() >> 6) & 0x0000003F);
pBytes[1] = (quint8)((((quint32)d.date().year() & 0x0000003F) << 2) | (((quint32)d.date().month() >> 2) & 0x00000003));
pBytes[2] = (quint8)((((quint32)d.date().month() & 0x00000003) << 6) | (((quint32)d.date().day() & 0x0000001F) << 1) | (((quint32)d.time().hour() >> 4) & 0x00000001));
pBytes[3] = (quint8)((((quint32)d.time().hour() & 0x0000000F) << 4) | (((quint32)d.time().minute() >> 2) & 0x0000000F));
pBytes[4] = (quint8)((((quint32)d.time().minute() & 0x00000003) << 6) | ((quint32)d.time().second() & 0x0000003F));
}
bool Kdb3Database::transformKey(quint8* src,quint8* dst,quint8* KeySeed,int rounds){
quint8 tmp[32];
AESencrypt aes;
aes.key256(KeySeed);
memcpy(tmp,src,32);
for(int i=0;i<rounds;i++){
aes.ecb_encrypt(tmp,tmp,32);
}
SHA256::hashBuffer(tmp,dst,32);
return true;
}
int Kdb3Database::numGroups(){
return Groups.size();
}
int Kdb3Database::numEntries(){
return Entries.size();
}
void Kdb3Database::deleteGroup(StdGroup* group){
while(group->Childs.size())
deleteGroup(group->Childs.front());
QList<IEntryHandle*> GroupEntries;
GroupEntries=entries(group->Handle);
deleteEntries(GroupEntries);
Q_ASSERT(group==group->Parent->Childs[group->Index]);
group->Parent->Childs.removeAt(group->Index);
for(int i=group->Index;i<group->Parent->Childs.size();i++){
group->Parent->Childs[i]->Index--;
}
group->Handle->invalidate();
for(int i=0;i<Groups.size();i++){
if(&Groups[i]==group){
Groups.removeAt(i);
break;
}
}
}
void Kdb3Database::deleteGroup(IGroupHandle* group){
deleteGroup(((GroupHandle*)group)->Group);
}
void Kdb3Database::GroupHandle::setIndex(int index){
/*
quint32 ParentId=((GroupHandle*)parent())->Id;
int Pos=pDB->getGroupListIndex(this);
int NewPos=0;
// Move the group to the new position in the list
if(ParentId)
NewPos=pDB->getGroupListIndex((GroupHandle*)parent());
if(!index){
if(ParentId)
pDB->Groups.move(Pos,NewPos+1);
else
pDB->Groups.move(Pos,NewPos);
}
else{
for(NewPos;NewPos<pDB->Groups.size();NewPos++){
if(pDB->Groups[NewPos].ParentId==ParentId && pDB->Groups[NewPos].Index+1==index)
break;
}
//skip the childs of the found sibling
for(NewPos;NewPos<Groups.size();NewPos++){
if(Groups[NewPos]
pDB->Groups.move(Pos,NewPos);
}
}
// adjust the indices
int NewIndex=0;
for(int i=0;i<pDB->Groups.size();i++){
if(pDB->Groups[i].ParentId==ParentId){
pDB->Groups[i].Index=NewIndex;
NewIndex++;
}
}
*/
}
bool Kdb3Database::convHexToBinaryKey(char* HexKey, char* dst){
QString hex=QString::fromAscii(HexKey,64);
for(int i=0; i<64; i+=2){
bool err;
quint8 bin;
bin=hex.mid(i,2).toUInt(&err,16);
if(!err)return false;
memcpy(dst+(i/2),&bin,1);
}
return true;
}
/*
void Kdb3Database::authByPwd(QString& Password){
if(!Password.size()) {
memcpy(RawMasterKey,QByteArray(32,'\0').data(),32);
return;
}
SHA256::hashBuffer(Password.toUtf8().data(),RawMasterKey,Password.toUtf8().size());
return;
}*/
void Kdb3Database::authByPwd(QString& Password){
if(!Password.size()) {
memcpy(RawMasterKey,QByteArray(32,'\0').data(),32);
return;
}
SHA256::hashBuffer(Password.toLatin1().data(),RawMasterKey,Password.toLatin1().size());
QByteArray lat,utf;
utf=Password.toUtf8();
lat=Password.toLatin1();
char *Lat=lat.data();
char *Utf=utf.data();
return;
}
bool Kdb3Database::authByFile(QString& filename){
QFile file(filename);
if(!file.open(QIODevice::ReadOnly|QIODevice::Unbuffered)){
error=decodeFileError(file.error());
return false;
}
unsigned long FileSize=file.size();
if(FileSize == 0){
error=tr("Key file is empty.");
return false;
}
if(FileSize == 32){
if(file.read((char*)RawMasterKey,32) != 32){
error=decodeFileError(file.error());
return false;}
return true;
}
if(FileSize == 64){
char hex[64];
if(file.read(hex,64) != 64){
error=decodeFileError(file.error());
return false;}
if(convHexToBinaryKey(hex,(char*)RawMasterKey))return true;
}
SHA256 sha;
unsigned char* buffer = new unsigned char[2048];
while(1)
{
unsigned long read=file.read((char*)buffer,2048);
if(read == 0) break;
sha.update(buffer,read);
if(read != 2048) break;
}
sha.finish(RawMasterKey);
delete [] buffer;
return true;
}
bool Kdb3Database::authByFileAndPwd(QString& Password, QString& filename){
unsigned char PasswordKey[32];
unsigned char FileKey[32];
if(!authByFile(filename))return false;
memcpy(FileKey,RawMasterKey,32);
authByPwd(Password);
memcpy(PasswordKey,RawMasterKey,32);
SHA256 sha;
sha.update(PasswordKey,32);
sha.update(FileKey,32);
sha.finish(RawMasterKey);
return true;
}
QList<IEntryHandle*> Kdb3Database::entries(){
QList<IEntryHandle*> handles;
for(int i=0; i<EntryHandles.size(); i++){
if(EntryHandles[i].isValid())handles.append(&EntryHandles[i]);
}
return handles;
}
QList<IEntryHandle*> Kdb3Database::expiredEntries(){
QList<IEntryHandle*> handles;
for(int i=0; i<EntryHandles.size(); i++){
if(EntryHandles[i].isValid() &&
(EntryHandles[i].expire()<=QDateTime::currentDateTime()) &&
(EntryHandles[i].expire()!=Date_Never))
handles.append(&EntryHandles[i]);
}
return handles;
}
QList<IEntryHandle*> Kdb3Database::entries(IGroupHandle* group){
QList<IEntryHandle*> handles;
for(int i=0; i<EntryHandles.size(); i++){
if(EntryHandles[i].isValid() && (EntryHandles[i].group()==group))
handles.append(&EntryHandles[i]);
}
qSort(handles.begin(),handles.end(),EntryHandleLessThan);
return handles;
}
void Kdb3Database::deleteEntry(IEntryHandle* entry){
if(!entry)return;
StdGroup* Group=((EntryHandle*)entry)->Entry->Group;
int j;
for(j=0;j<Entries.size();j++){
if(&Entries[j]==((EntryHandle*)entry)->Entry)
break;
}
Entries[j].Handle->invalidate();
Entries.removeAt(j);
}
void Kdb3Database::moveEntry(IEntryHandle* entry, IGroupHandle* group){
((EntryHandle*)entry)->Entry->GroupId=((GroupHandle*)group)->Group->Id;
((EntryHandle*)entry)->Entry->Group=((GroupHandle*)group)->Group;
}
void Kdb3Database::deleteEntries(QList<IEntryHandle*> entries){
if(!entries.size())return;
StdGroup* Group=((EntryHandle*)entries[0])->Entry->Group;
for(int i=0;i<entries.size();i++){
int j;
for(j=0;j<Entries.size();j++){
if(&Entries[j]==((EntryHandle*)entries[i])->Entry)
break;
}
Group->Childs.removeAt(Entries[j].Index);
Entries[j].Handle->invalidate();
Entries.removeAt(j);
}
for(int i=0;i<Group->Childs.size();i++){
Group->Childs[i]->Index=i;
}
};
QList<IGroupHandle*> Kdb3Database::groups(){
QList<IGroupHandle*> handles;