Fix .desktop file path
[keepassx] / src / Kdb3Database.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2008 by Tarek Saidi                                *
3  *   tarek.saidi@arcor.de                                                  *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; version 2 of the License.               *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19
20 #include "Kdb3Database.h"
21
22 #include "crypto/twoclass.h"
23 #include <QBuffer>
24 #include <algorithm>
25
26 #define UNEXP_ERROR error=QString("Unexpected error in: %1, Line:%2").arg(__FILE__).arg(__LINE__);
27
28 const QDateTime Date_Never(QDate(2999,12,28),QTime(23,59,59));
29
30
31 bool Kdb3Database::EntryHandleLessThan(const IEntryHandle* This,const IEntryHandle* Other){
32         if(!This->isValid() && Other->isValid())return true;
33         if(This->isValid() && !Other->isValid())return false;
34         if(!This->isValid() && !Other->isValid())return false;
35         return This->visualIndex()<Other->visualIndex();
36 }
37
38 bool Kdb3Database::EntryHandleLessThanStd(const IEntryHandle* This,const IEntryHandle* Other){
39         int comp = This->title().compare(Other->title());
40         if (comp < 0) return true;
41         else if (comp > 0) return false;
42         
43         comp = This->username().compare(Other->username());
44         if (comp < 0) return true;
45         else if (comp > 0) return false;
46         
47         return true;
48 }
49
50 bool Kdb3Database::StdEntryLessThan(const Kdb3Database::StdEntry& This,const Kdb3Database::StdEntry& Other){
51         return This.Index<Other.Index;
52 }
53
54
55 Kdb3Database::Kdb3Database() : RawMasterKey(32), RawMasterKey_CP1252(32),
56         RawMasterKey_Latin1(32), RawMasterKey_UTF8(32), MasterKey(32){
57 }
58
59 QString Kdb3Database::getError(){
60         return error;
61 }
62
63 void Kdb3Database::addIcon(const QPixmap& icon){
64         CustomIcons << icon;
65         emit iconsModified();
66 }
67
68 QPixmap& Kdb3Database::icon(int i){
69         if(i>=builtinIcons()+CustomIcons.size())
70                 return EntryIcons[0];
71         if(i<builtinIcons())
72                 return EntryIcons[i];
73         return CustomIcons[i-builtinIcons()];
74 }
75
76 void Kdb3Database::removeIcon(int id){
77         id-=builtinIcons();
78         if(id < 0 ) return;
79         if(id >= CustomIcons.size()) return;
80         CustomIcons.removeAt(id); // .isNull()==true
81         for(int i=0;i<Entries.size();i++){
82                 if(Entries[i].Image == id+builtinIcons())
83                         Entries[i].Image=0;
84                 if(Entries[i].Image>id+builtinIcons())
85                         Entries[i].Image--;
86         }
87         for(int i=0;i<Groups.size();i++){
88                 if(Groups[i].Image == id+builtinIcons())
89                         Groups[i].Image=0;
90                 if(Groups[i].Image>id+builtinIcons())
91                         Groups[i].Image--;
92         }
93         emit iconsModified();
94 }
95
96 void Kdb3Database::replaceIcon(int id,const QPixmap& icon){
97         if(id<builtinIcons())return;
98                 CustomIcons[id-builtinIcons()]=icon;
99         emit iconsModified();
100 }
101
102 int Kdb3Database::numIcons(){
103         return builtinIcons()+CustomIcons.size();
104 }
105
106 bool Kdb3Database::parseMetaStream(const StdEntry& entry){
107
108         qDebug("Found Metastream: %s", CSTR(entry.Comment));
109
110         if(entry.Comment=="KPX_GROUP_TREE_STATE"){
111                 parseGroupTreeStateMetaStream(entry.Binary);
112                 return true;
113         }
114         else if(entry.Comment=="KPX_CUSTOM_ICONS_4"){
115                 parseCustomIconsMetaStream(entry.Binary);
116                 return true;
117         }
118         else if(entry.Comment=="KPX_CUSTOM_ICONS_3"){
119                 if (!hasV4IconMetaStream)
120                         parseCustomIconsMetaStreamV3(entry.Binary);
121                 return true;
122         }
123         else if(entry.Comment=="KPX_CUSTOM_ICONS_2"){
124                 qDebug("Removed old CuIcMeSt v2");
125                 return true;
126         }
127         else if(entry.Comment=="KPX_CUSTOM_ICONS"){
128                 qDebug("Removed old CuIcMeSt v1");
129                 return true;
130         }
131
132         return false; //unknown MetaStream
133 }
134
135 bool Kdb3Database::isMetaStream(StdEntry& p){
136         if(p.Binary.isNull()) return false;
137         if(p.Comment == "") return false;
138         if(p.BinaryDesc != "bin-stream") return false;
139         if(p.Title != "Meta-Info") return false;
140         if(p.Username != "SYSTEM") return false;
141         if(p.Url != "$") return false;
142         if(p.Image != 0) return false;
143         return true;
144 }
145
146 void Kdb3Database::parseCustomIconsMetaStream(const QByteArray& dta){
147         //Rev 4 (KeePassX 0.3.2)
148         quint32 NumIcons,NumEntries,NumGroups,offset;
149         memcpyFromLEnd32(&NumIcons,dta.data());
150         memcpyFromLEnd32(&NumEntries,dta.data()+4);
151         memcpyFromLEnd32(&NumGroups,dta.data()+8);
152         offset=12;
153         CustomIcons.clear();
154         for(int i=0;i<NumIcons;i++){
155                 CustomIcons << QPixmap();
156                 quint32 Size;
157                 memcpyFromLEnd32(&Size,dta.data()+offset);
158                 if(offset+Size > dta.size()){
159                         CustomIcons.clear();
160                         qWarning("Discarded metastream KPX_CUSTOM_ICONS_4 because of a parsing error.");
161                         return;
162                 }
163                 offset+=4;
164                 if(!CustomIcons.back().loadFromData((const unsigned char*)dta.data()+offset,Size,"PNG")){
165                         CustomIcons.clear();
166                         qWarning("Discarded metastream KPX_CUSTOM_ICONS_4 because of a parsing error.");
167                         return;
168                 }
169                 offset+=Size;
170                 if(offset > dta.size()){
171                         CustomIcons.clear();
172                         qWarning("Discarded metastream KPX_CUSTOM_ICONS_4 because of a parsing error.");
173                         return;
174                 }
175         }
176         for(int i=0;i<NumEntries;i++){
177                 quint32 Icon;
178                 KpxUuid EntryUuid;
179                 EntryUuid.fromRaw(dta.data()+offset);
180                 offset+=16;
181                 memcpyFromLEnd32(&Icon,dta.data()+offset);
182                 offset+=4;
183                 StdEntry* entry=getEntry(EntryUuid);
184                 if(entry)
185                         entry->Image=Icon+BUILTIN_ICONS;
186         }
187         for(int i=0;i<NumGroups;i++){
188                 quint32 GroupId,Icon;
189                 memcpyFromLEnd32(&GroupId,dta.data()+offset);
190                 offset+=4;
191                 memcpyFromLEnd32(&Icon,dta.data()+offset);
192                 offset+=4;
193                 StdGroup* Group=getGroup(GroupId);
194                 if(Group)
195                         Group->Image=Icon+BUILTIN_ICONS;
196         }
197         return;
198 }
199
200 void Kdb3Database::parseCustomIconsMetaStreamV3(const QByteArray& dta){
201         //Rev 3
202         quint32 NumIcons,NumEntries,NumGroups,offset;
203         memcpyFromLEnd32(&NumIcons,dta.data());
204         memcpyFromLEnd32(&NumEntries,dta.data()+4);
205         memcpyFromLEnd32(&NumGroups,dta.data()+8);
206         offset=12;
207         CustomIcons.clear();
208         for(int i=0;i<NumIcons;i++){
209                 CustomIcons << QPixmap();
210                 quint32 Size;
211                 memcpyFromLEnd32(&Size,dta.data()+offset);
212                 if(offset+Size > dta.size()){
213                         CustomIcons.clear();
214                         qWarning("Discarded metastream KPX_CUSTOM_ICONS_3 because of a parsing error.");
215                         return;
216                 }
217                 offset+=4;
218                 if(!CustomIcons.back().loadFromData((const unsigned char*)dta.data()+offset,Size,"PNG")){
219                         CustomIcons.clear();
220                         qWarning("Discarded metastream KPX_CUSTOM_ICONS_3 because of a parsing error.");
221                         return;
222                 }
223                 offset+=Size;
224                 if(offset > dta.size()){
225                         CustomIcons.clear();
226                         qWarning("Discarded metastream KPX_CUSTOM_ICONS_3 because of a parsing error.");
227                         return;
228                 }
229         }
230         for(int i=0;i<NumEntries;i++){
231                 quint32 Icon;
232                 KpxUuid EntryUuid;
233                 EntryUuid.fromRaw(dta.data()+offset);
234                 offset+=16;
235                 memcpyFromLEnd32(&Icon,dta.data()+offset);
236                 offset+=4;
237                 StdEntry* entry=getEntry(EntryUuid);
238                 if(entry){
239                         if (Icon>=65)
240                                 entry->Image=Icon+4; // Since v0.3.2 the BUILTIN_ICONS number has increased by 4
241                         else
242                                 entry->Image=Icon;
243                 }
244         }
245         for(int i=0;i<NumGroups;i++){
246                 quint32 GroupId,Icon;
247                 memcpyFromLEnd32(&GroupId,dta.data()+offset);
248                 offset+=4;
249                 memcpyFromLEnd32(&Icon,dta.data()+offset);
250                 offset+=4;
251                 StdGroup* Group=getGroup(GroupId);
252                 if(Group){
253                         if (Group->Image>=65)
254                                 Group->Image=Icon+4; // Since v0.3.2 the BUILTIN_ICONS number has increased by 4
255                         else
256                                 Group->Image=Icon;
257                 }
258         }
259         return;
260 }
261
262 void Kdb3Database::parseGroupTreeStateMetaStream(const QByteArray& dta){
263         if(dta.size()<4){
264                 qWarning("Discarded metastream KPX_GROUP_TREE_STATE because of a parsing error.");
265                 return;
266         }
267         quint32 Num;
268         memcpyFromLEnd32(&Num,dta.data());
269         if(Num*5!=dta.size()-4){
270                 qWarning("Discarded metastream KPX_GROUP_TREE_STATE because of a parsing error.");
271                 return;
272         }
273         TreeStateMetaStream.clear();
274         for(int i=0;i<Num;i++){
275                 quint32 GroupID;
276                 quint8 IsExpanded;
277                 memcpyFromLEnd32(&GroupID,dta.data()+4+5*i);
278                 memcpy(&IsExpanded,dta.data()+8+5*i,1);
279                 TreeStateMetaStream.insert(GroupID,(bool)IsExpanded);
280         }
281         return;
282 }
283
284 void Kdb3Database::createGroupTreeStateMetaStream(StdEntry* e){
285         e->BinaryDesc="bin-stream";
286         e->Title="Meta-Info";
287         e->Username="SYSTEM";
288         e->Comment="KPX_GROUP_TREE_STATE";
289         e->Url="$";
290         e->Image=0;
291         if(Groups.size())e->GroupId=Groups[0].Id;
292         QByteArray bin;
293         quint32 Num=Groups.size();
294         bin.resize(Num*5+4);
295         memcpyToLEnd32(bin.data(),&Num);
296         for(int i=0;i<Num;i++){
297                 memcpyToLEnd32(bin.data()+4+5*i,&Groups[i].Id);
298                 if(Groups[i].IsExpanded)
299                         bin.data()[8+5*i]=1;
300                 else
301                         bin.data()[8+5*i]=0;
302         }
303         e->Binary=bin;
304 }
305
306 Kdb3Database::StdEntry* Kdb3Database::getEntry(const KpxUuid& uuid){
307         for(int i=0; i<Entries.size();i++)
308                 if(Entries[i].Uuid==uuid)return &Entries[i];
309         return NULL;
310 }
311
312 Kdb3Database::StdGroup* Kdb3Database::getGroup(quint32 Id){
313         for(int i=0; i<Groups.size();i++)
314                 if(Groups[i].Id==Id)return &Groups[i];
315         return NULL;
316 }
317
318
319 //! Extracts one entry from raw decrypted data.
320 bool Kdb3Database::readEntryField(StdEntry* entry, quint16 FieldType, quint32 FieldSize, quint8 *pData){
321 switch(FieldType)
322         {
323         case 0x0000:
324                 // Ignore field
325                 break;
326         case 0x0001:
327                 entry->Uuid=KpxUuid(pData);
328                 break;
329         case 0x0002:
330                 memcpyFromLEnd32(&entry->GroupId, (char*)pData);
331                 break;
332         case 0x0003:
333                 memcpyFromLEnd32(&entry->Image, (char*)pData);
334                 break;
335         case 0x0004:
336                 entry->Title=QString::fromUtf8((char*)pData);
337                 break;
338         case 0x0005:
339                 entry->Url=QString::fromUtf8((char*)pData);
340                 break;
341         case 0x0006:
342                 entry->Username=QString::fromUtf8((char*)pData);
343                 break;
344         case 0x0007:{
345                 QString s=QString::fromUtf8((char*)pData);
346                 entry->Password.setString(s,true);
347                 break;}
348         case 0x0008:
349                 entry->Comment=QString::fromUtf8((char*)pData);
350                 break;
351         case 0x0009:
352                 entry->Creation=dateFromPackedStruct5(pData);
353                 break;
354         case 0x000A:
355                 entry->LastMod=dateFromPackedStruct5(pData);
356                 break;
357         case 0x000B:
358                 entry->LastAccess=dateFromPackedStruct5(pData);
359                 break;
360         case 0x000C:
361                 entry->Expire=dateFromPackedStruct5(pData);
362                 break;
363         case 0x000D:
364                 entry->BinaryDesc=QString::fromUtf8((char*)pData);
365                 break;
366         case 0x000E:
367                 if(FieldSize != 0)
368                         entry->Binary=QByteArray((char*)pData,FieldSize);
369                 else
370                         entry->Binary=QByteArray();
371                 break;
372         case 0xFFFF:
373                 break;
374         default:
375                 return false;
376         }
377         return true;
378 }
379
380 //! Extracts one group from raw decrypted data.
381 bool Kdb3Database::readGroupField(StdGroup* group,QList<quint32>& Levels,quint16 FieldType, quint8 *pData)
382 {
383         switch(FieldType)
384         {
385         case 0x0000:
386                 // Ignore field
387                 break;
388         case 0x0001:
389                 memcpyFromLEnd32(&group->Id, (char*)pData);
390                 break;
391         case 0x0002:
392                 group->Title=QString::fromUtf8((char*)pData);
393                 break;
394         case 0x0003: //not longer used by KeePassX but part of the KDB format
395                 break;
396         case 0x0004: //not longer used by KeePassX but part of the KDB format
397                 break;
398         case 0x0005: //not longer used by KeePassX but part of the KDB format
399                 break;
400         case 0x0006: //not longer used by KeePassX but part of the KDB format
401                 break;
402         case 0x0007:
403                 memcpyFromLEnd32(&group->Image, (char*)pData);
404                 break;
405         case 0x0008:
406                 quint16 Level;
407                 memcpyFromLEnd16(&Level, (char*)pData);
408                 Levels.append(Level);
409                 break;
410         case 0x0009:
411                  //not used by KeePassX but part of the KDB format
412                  //memcpyFromLEnd32(&Flags, (char*)pData);
413                 break;
414         case 0xFFFF:
415                 break;
416         default:
417                 return false; // Field unsupported
418         }
419
420         return true; // Field supported
421 }
422
423 bool Kdb3Database::createGroupTree(QList<quint32>& Levels){
424         if(Levels[0]!=0) return false;
425         //find the parent for every group
426         for(int i=0;i<Groups.size();i++){
427                 if(Levels[i]==0){
428                         Groups[i].Parent=&RootGroup;
429                         Groups[i].Index=RootGroup.Children.size();
430                         RootGroup.Children.append(&Groups[i]);
431                         continue;
432                 }
433                 int j;
434                 //the first item with a lower level is the parent
435                 for(j=i-1;j>=0;j--){
436                         if(Levels[j]<Levels[i]){
437                                 if(Levels[i]-Levels[j]!=1)return false;
438                                 break;
439                         }
440                         if(j==0)return false; //No parent found
441                 }
442                 Groups[i].Parent=&Groups[j];
443                 Groups[i].Index=Groups[j].Children.size();
444                 Groups[i].Parent->Children.append(&Groups[i]);
445         }
446
447         QList<int> EntryIndexCounter;
448         for(int i=0;i<Groups.size();i++)EntryIndexCounter << 0;
449
450         for(int e=0;e<Entries.size();e++){
451                 for(int g=0;g<Groups.size();g++){
452                         if(Entries[e].GroupId==Groups[g].Id){
453                                 Groups[g].Entries.append(&Entries[e]);
454                                 Entries[e].Group=&Groups[g];
455                                 Entries[e].Index=EntryIndexCounter[g];
456                                 EntryIndexCounter[g]++;
457                         }
458                 }
459         }
460
461         return true;
462 }
463
464 void Kdb3Database::createHandles(){
465         for(int i=0;i<Groups.size();i++){
466                 GroupHandles.append(GroupHandle(this));
467                 Groups[i].Handle=&GroupHandles.back();
468                 GroupHandles.back().Group=&Groups[i];
469         }
470         for(int i=0;i<Entries.size();i++){
471                 EntryHandles.append(EntryHandle(this));
472                 Entries[i].Handle=&EntryHandles.back();
473                 EntryHandles.back().Entry=&Entries[i];
474         }
475 }
476
477 void Kdb3Database::restoreGroupTreeState(){
478         switch (config->groupTreeState()){
479                 case KpxConfig::RestoreLast:
480                         for(int i=0;i<Groups.size();i++){
481                                 if(TreeStateMetaStream.contains(Groups[i].Id))
482                                         Groups[i].IsExpanded=TreeStateMetaStream.value(Groups[i].Id);
483                         }
484                         break;
485
486                 case KpxConfig::ExpandAll:
487                         for(int i=0;i<Groups.size();i++)
488                                 Groups[i].IsExpanded=true;
489                         break;
490                 
491                 case KpxConfig::DoNothing:
492                         break;
493         }
494 }
495
496 bool Kdb3Database::load(QString identifier, bool readOnly){
497         return loadReal(identifier, readOnly, false);
498 }
499
500 #define LOAD_RETURN_CLEANUP \
501         delete File; \
502         File = NULL; \
503         delete[] buffer; \
504         return false;
505
506 bool Kdb3Database::loadReal(QString filename, bool readOnly, bool differentEncoding) {
507         unsigned long total_size,crypto_size;
508         quint32 Signature1,Signature2,Version,NumGroups,NumEntries,Flags;
509         quint8 FinalRandomSeed[16];
510         quint8 ContentsHash[32];
511         quint8 EncryptionIV[16];
512         
513         File = new QFile(filename);
514         if (readOnly) {
515                 if(!File->open(QIODevice::ReadOnly)){
516                         error=tr("Could not open file.");
517                         delete File;
518                         File = NULL;
519                         return false;
520                 }
521         }
522         else {
523                 if(!File->open(QIODevice::ReadWrite)){
524                         if(!File->open(QIODevice::ReadOnly)){
525                                 error=tr("Could not open file.");
526                                 delete File;
527                                 File = NULL;
528                                 return false;
529                         }
530                         else{
531                                 readOnly = true;
532                         }
533                 }
534         }
535         
536         total_size=File->size();
537         char* buffer = new char[total_size];
538         File->read(buffer,total_size);
539         
540         if(total_size < DB_HEADER_SIZE){
541                 error=tr("Unexpected file size (DB_TOTAL_SIZE < DB_HEADER_SIZE)");
542                 LOAD_RETURN_CLEANUP
543         }
544         
545         memcpyFromLEnd32(&Signature1,buffer);
546         memcpyFromLEnd32(&Signature2,buffer+4);
547         memcpyFromLEnd32(&Flags,buffer+8);
548         memcpyFromLEnd32(&Version,buffer+12);
549         memcpy(FinalRandomSeed,buffer+16,16);
550         memcpy(EncryptionIV,buffer+32,16);
551         memcpyFromLEnd32(&NumGroups,buffer+48);
552         memcpyFromLEnd32(&NumEntries,buffer+52);
553         memcpy(ContentsHash,buffer+56,32);
554         memcpy(TransfRandomSeed,buffer+88,32);
555         memcpyFromLEnd32(&KeyTransfRounds,buffer+120);
556         
557         if((Signature1!=PWM_DBSIG_1) || (Signature2!=PWM_DBSIG_2)){
558                 error=tr("Wrong Signature");
559                 LOAD_RETURN_CLEANUP
560         }
561         
562         if((Version & 0xFFFFFF00) != (PWM_DBVER_DW & 0xFFFFFF00)){
563                 error=tr("Unsupported File Version.");
564                 LOAD_RETURN_CLEANUP
565         }
566         
567         if (Flags & PWM_FLAG_RIJNDAEL)
568                 Algorithm = Rijndael_Cipher;
569         else if (Flags & PWM_FLAG_TWOFISH)
570                 Algorithm = Twofish_Cipher;
571         else{
572                 error=tr("Unknown Encryption Algorithm.");
573                 LOAD_RETURN_CLEANUP
574         }
575         
576         RawMasterKey.unlock();
577         MasterKey.unlock();
578         KeyTransform::transform(*RawMasterKey,*MasterKey,TransfRandomSeed,KeyTransfRounds);
579         
580         quint8 FinalKey[32];
581         
582         SHA256 sha;
583         sha.update(FinalRandomSeed,16);
584         sha.update(*MasterKey,32);
585         sha.finish(FinalKey);
586         
587         RawMasterKey.lock();
588         MasterKey.lock();
589         
590         if(Algorithm == Rijndael_Cipher){
591                 AESdecrypt aes;
592                 aes.key256(FinalKey);
593                 aes.cbc_decrypt((unsigned char*)buffer+DB_HEADER_SIZE,(unsigned char*)buffer+DB_HEADER_SIZE,total_size-DB_HEADER_SIZE,(unsigned char*)EncryptionIV);
594                 crypto_size=total_size-((quint8*)buffer)[total_size-1]-DB_HEADER_SIZE;
595         }
596         else if(Algorithm == Twofish_Cipher){
597                 CTwofish twofish;
598                 if (twofish.init(FinalKey, 32, EncryptionIV) != true){
599                         error=tr("Unable to initialize the twofish algorithm.");
600                         LOAD_RETURN_CLEANUP
601                 }
602                 crypto_size = (unsigned long)twofish.padDecrypt((quint8 *)buffer + DB_HEADER_SIZE,
603                 total_size - DB_HEADER_SIZE, (quint8 *)buffer + DB_HEADER_SIZE);
604         }
605         else{
606                 error=tr("Unknown encryption algorithm.");
607                 LOAD_RETURN_CLEANUP
608         }
609         
610         if ((crypto_size > 2147483446) || (!crypto_size && NumGroups)){
611                 error=tr("Decryption failed.\nThe key is wrong or the file is damaged.");
612                 LOAD_RETURN_CLEANUP
613         }
614         SHA256::hashBuffer(buffer+DB_HEADER_SIZE,FinalKey,crypto_size);
615         
616         if(memcmp(ContentsHash, FinalKey, 32) != 0){
617                 if(PotentialEncodingIssueLatin1){
618                         delete[] buffer;
619                         delete File;
620                         File = NULL;
621                         
622                         RawMasterKey.copyData(RawMasterKey_Latin1);
623                         PotentialEncodingIssueLatin1 = false;
624                         qDebug("Decryption failed. Retrying with Latin-1.");
625                         return loadReal(filename, readOnly, true); // second try
626                 }
627                 if(PotentialEncodingIssueUTF8){
628                         delete[] buffer;
629                         delete File;
630                         File = NULL;
631                         
632                         RawMasterKey.copyData(RawMasterKey_UTF8);
633                         PotentialEncodingIssueUTF8 = false;
634                         qDebug("Decryption failed. Retrying with UTF-8.");
635                         return loadReal(filename, readOnly, true); // second/third try
636                 }
637                 error=tr("Hash test failed.\nThe key is wrong or the file is damaged.");
638                 KeyError=true;
639                 LOAD_RETURN_CLEANUP
640         }
641         
642         unsigned long pos = DB_HEADER_SIZE;
643         quint16 FieldType;
644         quint32 FieldSize;
645         char* pField;
646         bool bRet;
647         StdGroup group;
648         QList<quint32> Levels;
649         RootGroup.Title="$ROOT$";
650         RootGroup.Parent=NULL;
651         RootGroup.Handle=NULL;
652         
653         for(unsigned long CurGroup = 0; CurGroup < NumGroups; )
654         {
655                 pField = buffer+pos;
656         
657                 memcpyFromLEnd16(&FieldType, pField);
658                 pField += 2; pos += 2;
659                 if (pos >= total_size){
660                         error=tr("Unexpected error: Offset is out of range.").append(" [G1]");
661                         LOAD_RETURN_CLEANUP
662                 }
663         
664                 memcpyFromLEnd32(&FieldSize, pField);
665                 pField += 4; pos += 4;
666                 if (pos >= (total_size + FieldSize)){
667                         error=tr("Unexpected error: Offset is out of range.").append(" [G2]");
668                         LOAD_RETURN_CLEANUP
669                 }
670         
671                 bRet = readGroupField(&group,Levels, FieldType, (quint8 *)pField);
672                 if ((FieldType == 0xFFFF) && (bRet == true)){
673                         Groups << group;
674                         CurGroup++; // Now and ONLY now the counter gets increased
675                 }
676                 pField += FieldSize;
677                 pos += FieldSize;
678                 if (pos >= total_size){
679                         error=tr("Unexpected error: Offset is out of range.").append(" [G1]");
680                         LOAD_RETURN_CLEANUP
681                 }
682         }
683         
684         StdEntry entry;
685         
686         for (unsigned long CurEntry = 0; CurEntry < NumEntries;)
687         {
688                 pField = buffer+pos;
689         
690                 memcpyFromLEnd16(&FieldType, pField);
691                 pField += 2; pos += 2;
692                 if(pos >= total_size){
693                         error=tr("Unexpected error: Offset is out of range.").append(" [E1]");
694                         LOAD_RETURN_CLEANUP
695                 }
696         
697                 memcpyFromLEnd32(&FieldSize, pField);
698                 pField += 4; pos += 4;
699                 if (pos >= (total_size + FieldSize)){
700                         error=tr("Unexpected error: Offset is out of range.").append(" [E2]");
701                         LOAD_RETURN_CLEANUP
702                 }
703         
704                 bRet = readEntryField(&entry,FieldType,FieldSize,(quint8*)pField);
705         
706                 if((FieldType == 0xFFFF) && (bRet == true)){
707                         Entries << entry;
708                         if(!entry.GroupId)
709                                 qDebug("NULL: %i, '%s'", (int)CurEntry, (char*)entry.Title.toUtf8().data());
710                         CurEntry++;
711                 }
712         
713                 pField += FieldSize;
714                 pos += FieldSize;
715                 if (pos >= total_size){
716                         error=tr("Unexpected error: Offset is out of range.").append(" [E3]");
717                         LOAD_RETURN_CLEANUP
718                 }
719         }
720         
721         if(!createGroupTree(Levels)){
722                 error=tr("Invalid group tree.");
723                 LOAD_RETURN_CLEANUP
724         }
725         
726         delete [] buffer;
727         
728         hasV4IconMetaStream = false;
729         for(int i=0;i<Entries.size();i++){
730                 if(isMetaStream(Entries[i]) && Entries[i].Comment=="KPX_CUSTOM_ICONS_4"){
731                         hasV4IconMetaStream = true;
732                         break;
733                 }
734         }
735         
736         //Remove the metastreams from the entry list
737         for(int i=0;i<Entries.size();i++){
738                 if(isMetaStream(Entries[i])){
739                         if(!parseMetaStream(Entries[i]))
740                                 UnknownMetaStreams << Entries[i];
741                         Entries.removeAt(i);
742                         i--;
743                 }
744         }
745         
746         int* EntryIndices=new int[Groups.size()];
747         for(int i=0;i<Groups.size();i++)EntryIndices[i]=0;
748         
749         for(int g=0;g<Groups.size();g++){
750                 for(int e=0;e<Entries.size();e++){
751                         if(Entries[e].GroupId==Groups[g].Id){
752                                 Entries[e].Index=EntryIndices[g];
753                                 EntryIndices[g]++;
754                         }
755                 }
756         }
757         delete [] EntryIndices;
758         createHandles();
759         restoreGroupTreeState();
760         
761         passwordEncodingChanged = differentEncoding;
762         if (differentEncoding) {
763                 RawMasterKey.copyData(RawMasterKey_CP1252);
764                 generateMasterKey();
765         }
766         
767         return true;
768 }
769
770 QDateTime Kdb3Database::dateFromPackedStruct5(const unsigned char* pBytes){
771         quint32 dw1, dw2, dw3, dw4, dw5;
772         dw1 = (quint32)pBytes[0]; dw2 = (quint32)pBytes[1]; dw3 = (quint32)pBytes[2];
773         dw4 = (quint32)pBytes[3]; dw5 = (quint32)pBytes[4];
774         int y = (dw1 << 6) | (dw2 >> 2);
775         int mon = ((dw2 & 0x00000003) << 2) | (dw3 >> 6);
776         int d = (dw3 >> 1) & 0x0000001F;
777         int h = ((dw3 & 0x00000001) << 4) | (dw4 >> 4);
778         int min = ((dw4 & 0x0000000F) << 2) | (dw5 >> 6);
779         int s = dw5 & 0x0000003F;
780         return QDateTime(QDate(y,mon,d),QTime(h,min,s));
781 }
782
783
784 void Kdb3Database::dateToPackedStruct5(const QDateTime& d,unsigned char* pBytes){
785         pBytes[0] = (quint8)(((quint32)d.date().year() >> 6) & 0x0000003F);
786         pBytes[1] = (quint8)((((quint32)d.date().year() & 0x0000003F) << 2) | (((quint32)d.date().month() >> 2) & 0x00000003));
787         pBytes[2] = (quint8)((((quint32)d.date().month() & 0x00000003) << 6) | (((quint32)d.date().day() & 0x0000001F) << 1) | (((quint32)d.time().hour() >> 4) & 0x00000001));
788         pBytes[3] = (quint8)((((quint32)d.time().hour() & 0x0000000F) << 4) | (((quint32)d.time().minute() >> 2) & 0x0000000F));
789         pBytes[4] = (quint8)((((quint32)d.time().minute() & 0x00000003) << 6) | ((quint32)d.time().second() & 0x0000003F));
790 }
791
792
793 int Kdb3Database::numGroups(){
794         return Groups.size();
795 }
796
797 int Kdb3Database::numEntries(){
798         return Entries.size();
799 }
800
801 void Kdb3Database::deleteGroup(StdGroup* group){
802
803         while(group->Children.size())
804                 deleteGroup(group->Children.front());
805
806         QList<IEntryHandle*> GroupEntries;
807         GroupEntries=entries(group->Handle);
808         deleteEntries(GroupEntries);
809
810         Q_ASSERT(group==group->Parent->Children[group->Index]);
811         group->Parent->Children.removeAt(group->Index);
812         for(int i=group->Index;i<group->Parent->Children.size();i++){
813                 group->Parent->Children[i]->Index--;
814         }
815         group->Handle->invalidate();
816
817         for(int i=0;i<Groups.size();i++){
818                 if(&Groups[i]==group){
819                         Groups.removeAt(i);
820                         break;
821                 }
822         }
823
824 }
825
826
827 void Kdb3Database::deleteGroup(IGroupHandle* group){
828         deleteGroup(((GroupHandle*)group)->Group);
829 }
830
831 /*
832 void Kdb3Database::GroupHandle::setIndex(int index){
833         quint32 ParentId=((GroupHandle*)parent())->Id;
834         int Pos=pDB->getGroupListIndex(this);
835         int NewPos=0;
836         // Move the group to the new position in the list
837         if(ParentId)
838                 NewPos=pDB->getGroupListIndex((GroupHandle*)parent());
839         if(!index){
840                 if(ParentId)
841                         pDB->Groups.move(Pos,NewPos+1);
842                 else
843                         pDB->Groups.move(Pos,NewPos);
844         }
845         else{
846                 for(NewPos;NewPos<pDB->Groups.size();NewPos++){
847                         if(pDB->Groups[NewPos].ParentId==ParentId && pDB->Groups[NewPos].Index+1==index)
848                                 break;
849                 }
850                 //skip the children of the found sibling
851                 for(NewPos;NewPos<Groups.size();NewPos++){
852                         if(Groups[NewPos]
853                         pDB->Groups.move(Pos,NewPos);
854                 }
855
856         }
857         // adjust the indices
858         int NewIndex=0;
859         for(int i=0;i<pDB->Groups.size();i++){
860                 if(pDB->Groups[i].ParentId==ParentId){
861                         pDB->Groups[i].Index=NewIndex;
862                         NewIndex++;
863                 }
864         }
865 }
866 */
867
868 bool Kdb3Database::convHexToBinaryKey(char* HexKey, char* dst){
869         QString hex=QString::fromAscii(HexKey,64);
870         for(int i=0; i<64; i+=2){
871                 bool err;
872                 quint8 bin;
873                 bin=hex.mid(i,2).toUInt(&err,16);
874                 if(!err)return false;
875                 memcpy(dst+(i/2),&bin,1);
876         }
877         return true;
878 }
879
880 bool Kdb3Database::setKey(const QString& password,const QString& keyfile){
881         if(!password.isEmpty() && !keyfile.isEmpty())
882                 return setCompositeKey(password,keyfile);
883         if(!password.isEmpty())
884                 return setPasswordKey(password);
885         if(!keyfile.isEmpty())
886                 return setFileKey(keyfile);
887         Q_ASSERT(false);
888         return false;
889 }
890
891 bool Kdb3Database::setPasswordKey(const QString& Password){
892         Q_ASSERT(Password.size());
893         QTextCodec* codec=QTextCodec::codecForName("Windows-1252");
894         QByteArray Password_CP1252 = codec->fromUnicode(Password);
895         RawMasterKey_CP1252.unlock();
896         SHA256::hashBuffer(Password_CP1252.data(),*RawMasterKey_CP1252,Password_CP1252.size());
897         RawMasterKey_CP1252.lock();
898         RawMasterKey.copyData(RawMasterKey_CP1252);
899         
900         QByteArray Password_Latin1 = Password.toLatin1();
901         QByteArray Password_UTF8 = Password.toUtf8();
902         PotentialEncodingIssueLatin1 = false;
903         PotentialEncodingIssueUTF8 = false;
904         
905         if (Password_Latin1 != Password_CP1252){
906                 // KeePassX used Latin-1 encoding for passwords until version 0.3.1
907                 // but KeePass/Win32 uses Windows Codepage 1252.
908                 // To stay compatible with databases created with KeePassX <= 0.3.1
909                 // the loading function gives both encodings a try.
910                 PotentialEncodingIssueLatin1 = true;
911                 RawMasterKey_Latin1.unlock();
912                 SHA256::hashBuffer(Password_Latin1.data(),*RawMasterKey_Latin1,Password_Latin1.size());
913                 RawMasterKey_Latin1.lock();
914         }
915         
916         if (Password_UTF8 != Password_CP1252){
917                 // KeePassX used UTF-8 encoding for passwords until version 0.2.2
918                 // but KeePass/Win32 uses Windows Codepage 1252.
919                 // To stay compatible with databases created with KeePassX <= 0.2.2
920                 // the loading function gives both encodings a try.
921                 PotentialEncodingIssueUTF8 = true;
922                 RawMasterKey_UTF8.unlock();
923                 SHA256::hashBuffer(Password_UTF8.data(),*RawMasterKey_UTF8,Password_UTF8.size());
924                 RawMasterKey_UTF8.lock();
925         }
926         
927         return true;
928 }
929
930 bool Kdb3Database::setFileKey(const QString& filename){
931         QFile file(filename);
932         if(!file.open(QIODevice::ReadOnly|QIODevice::Unbuffered)){
933                 error=decodeFileError(file.error());
934                 return false;
935         }
936         qint64 FileSize=file.size();
937         if(FileSize == 0){
938                 error=tr("Key file is empty.");
939                 return false;
940         }
941         RawMasterKey.unlock();
942         if(FileSize == 32){
943                 if(file.read((char*)(*RawMasterKey),32) != 32){
944                         error=decodeFileError(file.error());
945                         RawMasterKey.lock();
946                         return false;
947                 }
948                 RawMasterKey.lock();
949                 return true;
950         }
951         if(FileSize == 64){
952                 char hex[64];
953                 if(file.read(hex,64) != 64){
954                         error=decodeFileError(file.error());
955                         RawMasterKey.lock();
956                         return false;
957                 }
958                 if (convHexToBinaryKey(hex,(char*)(*RawMasterKey))){
959                         RawMasterKey.lock();
960                         return true;
961                 }
962         }
963         SHA256 sha;
964         unsigned char* buffer[2048];
965         unsigned long read;
966         do {
967                 read = file.read((char*)buffer,2048);
968                 if (read != 0)
969                         sha.update(buffer,read);
970         } while (read == 2048);
971         sha.finish(*RawMasterKey);
972         RawMasterKey.lock();
973         return true;
974 }
975
976 bool Kdb3Database::setCompositeKey(const QString& Password,const QString& filename){
977         SHA256 sha;
978         
979         setPasswordKey(Password);
980         RawMasterKey.unlock();
981         sha.update(*RawMasterKey,32);
982         RawMasterKey.lock();
983         
984         if(!setFileKey(filename))return false;
985         RawMasterKey.unlock();
986         sha.update(*RawMasterKey,32);
987         sha.finish(*RawMasterKey);
988         RawMasterKey.lock();
989         
990         return true;
991 }
992
993 QList<IEntryHandle*> Kdb3Database::entries(){
994         QList<IEntryHandle*> handles;
995         for(int i=0; i<EntryHandles.size(); i++){
996                 if(EntryHandles[i].isValid())handles.append(&EntryHandles[i]);
997         }
998         return handles;
999 }
1000
1001 QList<IEntryHandle*> Kdb3Database::expiredEntries(){
1002         QList<IEntryHandle*> handles;
1003         for(int i=0; i<EntryHandles.size(); i++){
1004                 if(EntryHandles[i].isValid() &&
1005                   (EntryHandles[i].expire()<=QDateTime::currentDateTime()) &&
1006                   (EntryHandles[i].expire()!=Date_Never))
1007                         handles.append(&EntryHandles[i]);
1008         }
1009         return handles;
1010 }
1011
1012 QList<IEntryHandle*> Kdb3Database::entries(IGroupHandle* Group){
1013         QList<IEntryHandle*> handles;
1014         for(int i=0; i<EntryHandles.size(); i++){
1015                 if(EntryHandles[i].isValid() && (EntryHandles[i].group()==Group))
1016                         handles.append(&EntryHandles[i]);
1017         }
1018         qSort(handles.begin(),handles.end(),EntryHandleLessThan);
1019
1020         return handles;
1021 }
1022
1023 QList<IEntryHandle*> Kdb3Database::entriesSortedStd(IGroupHandle* Group){
1024         QList<IEntryHandle*> handles;
1025         for(int i=0; i<EntryHandles.size(); i++){
1026                 if(EntryHandles[i].isValid() && (EntryHandles[i].group()==Group))
1027                         handles.append(&EntryHandles[i]);
1028         }
1029         qSort(handles.begin(),handles.end(),EntryHandleLessThanStd);
1030
1031         return handles;
1032 }
1033
1034 void Kdb3Database::deleteEntry(IEntryHandle* entry){
1035         if(!entry)return;
1036         int j;
1037         for(j=0;j<Entries.size();j++){
1038                 if(&Entries[j]==((EntryHandle*)entry)->Entry)
1039                         break;
1040         }
1041         Entries[j].Handle->invalidate();
1042         Entries.removeAt(j);
1043 }
1044
1045 void Kdb3Database::moveEntry(IEntryHandle* entry, IGroupHandle* group){
1046         ((EntryHandle*)entry)->Entry->GroupId=((GroupHandle*)group)->Group->Id;
1047         ((EntryHandle*)entry)->Entry->Group=((GroupHandle*)group)->Group;
1048 }
1049
1050
1051 void Kdb3Database::deleteEntries(QList<IEntryHandle*> entries){
1052         if(!entries.size())return;
1053         StdGroup* Group=((EntryHandle*)entries[0])->Entry->Group;
1054         for(int i=0;i<entries.size();i++){
1055                 int j;
1056                 for(j=0;j<Entries.size();j++){
1057                         if(&Entries[j]==((EntryHandle*)entries[i])->Entry)
1058                                 break;
1059                 }
1060                 Group->Children.removeAt(Entries[j].Index);
1061                 Entries[j].Handle->invalidate();
1062                 Entries.removeAt(j);
1063         }
1064
1065         for(int i=0;i<Group->Children.size();i++){
1066                 Group->Children[i]->Index=i;
1067         }
1068 };
1069
1070 QList<IGroupHandle*> Kdb3Database::groups(){
1071         QList<IGroupHandle*> handles;
1072         for(int i=0; i<GroupHandles.size(); i++){
1073                 if(GroupHandles[i].isValid())handles.append(&GroupHandles[i]);
1074         }
1075         return handles;
1076 }
1077
1078 quint32 Kdb3Database::getNewGroupId(){
1079         quint32 id;
1080         bool used;
1081         do{
1082                 used=false;
1083                 randomize(&id,4);
1084                 if(!id)continue; //group IDs must not be 0
1085                 for(int j=0;j<Groups.size();j++){
1086                         if(Groups[j].Id==id){
1087                                 used=true;
1088                                 break;
1089                         }
1090                 }
1091         } while(used);
1092         return id;
1093 }
1094
1095 IGroupHandle* Kdb3Database::addGroup(const CGroup* group,IGroupHandle* ParentHandle){
1096         GroupHandles.append(GroupHandle(this));
1097         Groups.append(*group);
1098         Groups.back().Id=getNewGroupId();
1099         Groups.back().Handle=&GroupHandles.back();
1100         GroupHandles.back().Group=&Groups.back();
1101         if(ParentHandle){
1102                 Groups.back().Parent=((GroupHandle*)ParentHandle)->Group;
1103                 Groups.back().Index=Groups.back().Parent->Children.size();
1104                 Groups.back().Parent->Children.append(&Groups.back());
1105         }
1106         else{
1107                 Groups.back().Parent=&RootGroup;
1108                 Groups.back().Index=RootGroup.Children.size();
1109                 if (group->Title!="Backup" && RootGroup.Children.size() && RootGroup.Children.last()->Title=="Backup"){
1110                         RootGroup.Children.last()->Index = Groups.back().Index;
1111                         Groups.back().Index--;
1112                 }
1113                 Groups.back().Parent->Children.append(&Groups.back());
1114         }
1115         return &GroupHandles.back();
1116 }
1117
1118 IGroupHandle* Kdb3Database::backupGroup(bool create){
1119         IGroupHandle* group = NULL;
1120         QList<IGroupHandle*> allGroups = groups();
1121         for (int i=0; i<allGroups.size(); i++){
1122                 if (allGroups[i]->parent()==NULL && allGroups[i]->title()=="Backup"){
1123                         group = allGroups[i];
1124                         break;
1125                 }
1126         }
1127         
1128         if (group==NULL && create){
1129                 CGroup newGroup;
1130                 newGroup.Title = "Backup";
1131                 newGroup.Image = 4;
1132                 group = addGroup(&newGroup, NULL);
1133         }
1134         
1135         return group;
1136 }
1137
1138 Kdb3Database::StdGroup::StdGroup(const CGroup& other){
1139         Index=0;
1140         Id=other.Id;
1141         Image=other.Image;
1142         Title=other.Title;
1143 }
1144
1145 void Kdb3Database::EntryHandle::setTitle(const QString& Title){Entry->Title=Title; }
1146 void Kdb3Database::EntryHandle::setUsername(const QString& Username){Entry->Username=Username;}
1147 void Kdb3Database::EntryHandle::setUrl(const QString& Url){Entry->Url=Url;}
1148 void Kdb3Database::EntryHandle::setPassword(const SecString& Password){Entry->Password=Password;}
1149 void Kdb3Database::EntryHandle::setExpire(const KpxDateTime& s){Entry->Expire=s;}
1150 void Kdb3Database::EntryHandle::setCreation(const KpxDateTime& s){Entry->Creation=s;}
1151 void Kdb3Database::EntryHandle::setLastAccess(const KpxDateTime& s){Entry->LastAccess=s;}
1152 void Kdb3Database::EntryHandle::setLastMod(const KpxDateTime& s){Entry->LastMod=s;}
1153 void Kdb3Database::EntryHandle::setBinaryDesc(const QString& s){Entry->BinaryDesc=s;}
1154 void Kdb3Database::EntryHandle::setComment(const QString& s){Entry->Comment=s;}
1155 void Kdb3Database::EntryHandle::setBinary(const QByteArray& s){Entry->Binary=s;}
1156 void Kdb3Database::EntryHandle::setImage(const quint32& s){Entry->Image=s;}
1157 KpxUuid Kdb3Database::EntryHandle::uuid()const{return Entry->Uuid;}
1158 IGroupHandle* Kdb3Database::EntryHandle::group()const{return Entry->Group->Handle;}
1159 quint32 Kdb3Database::EntryHandle::image()const{return Entry->Image;}
1160 QString Kdb3Database::EntryHandle::title()const{return Entry->Title;}
1161 QString Kdb3Database::EntryHandle::url()const{return Entry->Url;}
1162 QString Kdb3Database::EntryHandle::username()const{return Entry->Username;}
1163 SecString Kdb3Database::EntryHandle::password()const{return Entry->Password;}
1164 QString Kdb3Database::EntryHandle::comment()const{return Entry->Comment;}
1165 QString Kdb3Database::EntryHandle::binaryDesc()const{return Entry->BinaryDesc;}
1166 KpxDateTime     Kdb3Database::EntryHandle::creation()const{return Entry->Creation;}
1167 KpxDateTime     Kdb3Database::EntryHandle::lastMod()const{return Entry->LastMod;}
1168 KpxDateTime     Kdb3Database::EntryHandle::lastAccess()const{return Entry->LastAccess;}
1169 KpxDateTime     Kdb3Database::EntryHandle::expire()const{return Entry->Expire;}
1170 QByteArray Kdb3Database::EntryHandle::binary()const{return Entry->Binary;}
1171 quint32 Kdb3Database::EntryHandle::binarySize()const{return Entry->Binary.size();}
1172
1173 QString Kdb3Database::EntryHandle::friendlySize()const
1174 {
1175     quint32 binsize = binarySize();
1176     QString unit;
1177     uint    faktor;
1178     int     prec;
1179
1180     if (binsize < 1024)
1181     {
1182         unit = tr("Bytes");
1183         faktor = 1;
1184         prec = 0;
1185     }
1186     else
1187     {
1188         if (binsize < 1048576)
1189         {
1190             unit = tr("KiB");
1191             faktor = 1024;
1192         }
1193         else
1194             if (binsize < 1073741824)
1195             {
1196                 unit = tr("MiB");
1197                 faktor = 1048576;
1198             }
1199             else
1200             {
1201                 unit = tr("GiB");
1202                 faktor = 1073741824;
1203             }
1204         prec = 1;
1205     }
1206     return (QString::number((float)binsize / (float)faktor, 'f', prec) + " " + unit);
1207 }
1208
1209 int Kdb3Database::EntryHandle::visualIndex()const{return Entry->Index;}
1210 void Kdb3Database::EntryHandle::setVisualIndexDirectly(int i){Entry->Index=i;}
1211 bool Kdb3Database::EntryHandle::isValid()const{return valid;}
1212
1213 CEntry Kdb3Database::EntryHandle::data()const{
1214         return *this->Entry;
1215 }
1216
1217 void Kdb3Database::EntryHandle::setVisualIndex(int index){
1218         QList<IEntryHandle*>Entries=pDB->entries(Entry->Group->Handle);
1219         Entries.move(visualIndex(),index);
1220         for(int i=0;i<Entries.size();i++){
1221                 dynamic_cast<Kdb3Database::EntryHandle*>(Entries[i])->Entry->Index=index;
1222         }
1223 }
1224
1225 Kdb3Database::EntryHandle::EntryHandle(Kdb3Database* db){
1226         pDB=db;
1227         valid=true;
1228 }
1229
1230
1231 bool Kdb3Database::GroupHandle::isValid(){return valid;}
1232 QString Kdb3Database::GroupHandle::title(){return Group->Title;}
1233 quint32 Kdb3Database::GroupHandle::image(){return Group->Image;}
1234 int Kdb3Database::GroupHandle::index(){return Group->Index;}
1235 void Kdb3Database::GroupHandle::setTitle(const QString& Title){Group->Title=Title;}
1236 void Kdb3Database::GroupHandle::setExpanded(bool IsExpanded){Group->IsExpanded=IsExpanded;}
1237 bool Kdb3Database::GroupHandle::expanded(){return Group->IsExpanded;}
1238 void Kdb3Database::GroupHandle::setImage(const quint32& New){Group->Image=New;}
1239
1240
1241 Kdb3Database::GroupHandle::GroupHandle(Kdb3Database* db){
1242         pDB=db;
1243         valid=true;
1244         Group=NULL;
1245 }
1246
1247 IGroupHandle* Kdb3Database::GroupHandle::parent(){
1248         return (IGroupHandle*)Group->Parent->Handle;
1249 }
1250
1251 int Kdb3Database::GroupHandle::level(){
1252         int i=0;
1253         StdGroup* group=Group;
1254         while(group->Parent){
1255                 group=group->Parent;
1256                 i++;
1257         }
1258         i--;
1259         return i;
1260 }
1261
1262
1263 QList<IGroupHandle*> Kdb3Database::GroupHandle::children(){
1264         QList<IGroupHandle*> children;
1265         for(int i=0; i < Group->Children.size(); i++){
1266                 children.append(Group->Children[i]->Handle);
1267         }
1268         return children;
1269 }
1270
1271
1272 void memcpyFromLEnd32(quint32* dst,const char* src){
1273         if (QSysInfo::ByteOrder==QSysInfo::BigEndian){
1274                 memcpy(((char*)dst)+3,src+0,1);
1275                 memcpy(((char*)dst)+2,src+1,1);
1276                 memcpy(((char*)dst)+1,src+2,1);
1277                 memcpy(((char*)dst)+0,src+3,1);
1278         }
1279         else{
1280                 memcpy(dst,src,4);
1281         }
1282 }
1283
1284 void memcpyFromLEnd16(quint16* dst,const char* src){
1285         if (QSysInfo::ByteOrder==QSysInfo::BigEndian){
1286                 memcpy(((char*)dst)+1,src+0,1);
1287                 memcpy(((char*)dst)+0,src+1,1);
1288         }
1289         else{
1290                 memcpy(dst,src,2);
1291         }
1292 }
1293
1294 void memcpyToLEnd32(char* dst,const quint32* src){
1295         if (QSysInfo::ByteOrder==QSysInfo::BigEndian){
1296                 memcpy(dst+0,((char*)src)+3,1);
1297                 memcpy(dst+1,((char*)src)+2,1);
1298                 memcpy(dst+2,((char*)src)+1,1);
1299                 memcpy(dst+3,((char*)src)+0,1);
1300         }
1301         else{
1302                 memcpy(dst,src,4);
1303         }
1304 }
1305
1306 void memcpyToLEnd16(char* dst,const quint16* src){
1307         if (QSysInfo::ByteOrder==QSysInfo::BigEndian){
1308                 memcpy(dst+0,((char*)src)+1,1);
1309                 memcpy(dst+1,((char*)src)+0,1);
1310         }
1311         else{
1312                 memcpy(dst,src,2);
1313         }
1314 }
1315
1316 bool Kdb3Database::save(){
1317         if(!Groups.size()){
1318                 error=tr("The database must contain at least one group.");
1319                 return false;
1320         }
1321         
1322         //Delete old backup entries
1323         if (config->backup() && config->backupDelete() && config->backupDeleteAfter()>0 && backupGroup()){
1324                 QDateTime time = QDateTime::currentDateTime().addDays(-config->backupDeleteAfter());
1325                 QList<IEntryHandle*> backupEntries = entries(backupGroup());
1326                 for (int i=0; i<backupEntries.size(); i++){
1327                         if (backupEntries[i]->lastMod()<time)
1328                                 deleteEntry(backupEntries[i]);
1329                 }
1330         }
1331         
1332         quint32 NumGroups,NumEntries,Signature1,Signature2,Flags,Version;
1333         quint8 FinalRandomSeed[16];
1334         quint8 ContentsHash[32];
1335         quint8 EncryptionIV[16];
1336
1337         if(!(File->openMode() & QIODevice::WriteOnly)){
1338                 error = tr("The database has been opened read-only.");
1339                 return false;
1340         }
1341
1342         unsigned int FileSize;
1343
1344         QList<StdEntry> MetaStreams;
1345         MetaStreams << StdEntry();
1346         createCustomIconsMetaStream(&MetaStreams.back());
1347         MetaStreams << StdEntry();
1348         createGroupTreeStateMetaStream(&MetaStreams.back());
1349
1350         FileSize=DB_HEADER_SIZE;
1351         // Get the size of all groups (94 Byte + length of the name string)
1352         for(int i = 0; i < Groups.size(); i++){
1353                 FileSize += 94 + Groups[i].Title.toUtf8().length()+1;
1354         }
1355         // Get the size of all entries
1356         for(int i = 0; i < Entries.size(); i++){
1357                 FileSize
1358                         += 134
1359                         +Entries[i].Title.toUtf8().length()+1
1360                         +Entries[i].Username.toUtf8().length()+1
1361                         +Entries[i].Url.toUtf8().length()+1
1362                         +Entries[i].Password.length()+1
1363                         +Entries[i].Comment.toUtf8().length()+1
1364                         +Entries[i].BinaryDesc.toUtf8().length()+1
1365                         +Entries[i].Binary.length();
1366         }
1367
1368         for(int i=0; i < UnknownMetaStreams.size(); i++){
1369                 FileSize
1370                         +=165
1371                         +UnknownMetaStreams[i].Comment.toUtf8().length()+1
1372                         +UnknownMetaStreams[i].Binary.length();
1373         }
1374
1375         for(int i=0; i < MetaStreams.size(); i++){
1376                 FileSize
1377                                 +=165
1378                                 +MetaStreams[i].Comment.toUtf8().length()+1
1379                                 +MetaStreams[i].Binary.length();
1380         }
1381
1382
1383         // Round up filesize to 16-byte boundary for Rijndael/Twofish
1384         FileSize = (FileSize + 16) - (FileSize % 16);
1385         char* buffer=new char[FileSize+16];
1386
1387         Signature1 = PWM_DBSIG_1;
1388         Signature2 = PWM_DBSIG_2;
1389         Flags = PWM_FLAG_SHA2;
1390         if(Algorithm == Rijndael_Cipher) Flags |= PWM_FLAG_RIJNDAEL;
1391         else if(Algorithm == Twofish_Cipher) Flags |= PWM_FLAG_TWOFISH;
1392         Version = PWM_DBVER_DW;
1393         NumGroups = Groups.size();
1394         NumEntries = Entries.size()+UnknownMetaStreams.size()+MetaStreams.size();
1395
1396         QList<StdEntry> saveEntries = Entries;
1397         qSort(saveEntries.begin(),saveEntries.end(),StdEntryLessThan);
1398
1399         randomize(FinalRandomSeed,16);
1400         randomize(EncryptionIV,16);
1401
1402         unsigned int pos=DB_HEADER_SIZE; // Skip the header, it will be written later
1403
1404         serializeGroups(buffer,pos);
1405         serializeEntries(saveEntries,buffer,pos);
1406         serializeEntries(UnknownMetaStreams,buffer,pos);
1407         serializeEntries(MetaStreams,buffer,pos);
1408         SHA256::hashBuffer(buffer+DB_HEADER_SIZE,ContentsHash,pos-DB_HEADER_SIZE);
1409         memcpyToLEnd32(buffer,&Signature1);
1410         memcpyToLEnd32(buffer+4,&Signature2);
1411         memcpyToLEnd32(buffer+8,&Flags);
1412         memcpyToLEnd32(buffer+12,&Version);
1413         memcpy(buffer+16,FinalRandomSeed,16);
1414         memcpy(buffer+32,EncryptionIV,16);
1415         memcpyToLEnd32(buffer+48,&NumGroups);
1416         memcpyToLEnd32(buffer+52,&NumEntries);
1417         memcpy(buffer+56,ContentsHash,32);
1418         memcpy(buffer+88,TransfRandomSeed,32);
1419         memcpyToLEnd32(buffer+120,&KeyTransfRounds);
1420         quint8 FinalKey[32];
1421
1422         SHA256 sha;
1423         sha.update(FinalRandomSeed,16);
1424         MasterKey.unlock();
1425         sha.update(*MasterKey,32);
1426         MasterKey.lock();
1427         sha.finish(FinalKey);
1428
1429         unsigned long EncryptedPartSize;
1430
1431         if(Algorithm == Rijndael_Cipher){
1432                 EncryptedPartSize=((pos-DB_HEADER_SIZE)/16+1)*16;
1433                 quint8 PadLen=EncryptedPartSize-(pos-DB_HEADER_SIZE);
1434                 for(int i=0;i<PadLen;i++)
1435                         ((quint8*)buffer)[DB_HEADER_SIZE+EncryptedPartSize-1-i]=PadLen;
1436                 AESencrypt aes;
1437                 aes.key256(FinalKey);
1438                 aes.cbc_encrypt((unsigned char*)buffer+DB_HEADER_SIZE,(unsigned char*)buffer+DB_HEADER_SIZE,EncryptedPartSize,(unsigned char*)EncryptionIV);
1439         }
1440         else{ // Algorithm == Twofish_Cipher
1441                 CTwofish twofish;
1442                 if(twofish.init(FinalKey, 32, EncryptionIV) == false){
1443                         UNEXP_ERROR
1444                         delete [] buffer;
1445                         return false;
1446                 }
1447                 EncryptedPartSize = (unsigned long)twofish.padEncrypt((quint8*)buffer+DB_HEADER_SIZE,
1448                         pos - DB_HEADER_SIZE,(quint8*)buffer+DB_HEADER_SIZE);
1449         }
1450         if((EncryptedPartSize > (0xFFFFFFE - 202)) || (!EncryptedPartSize && Groups.size())){
1451                 UNEXP_ERROR
1452                 delete [] buffer;
1453                 return false;
1454         }
1455         
1456         int size = EncryptedPartSize+DB_HEADER_SIZE;
1457         
1458         if (!File->resize(size)){
1459                 // only recreate file if the new database is smaller
1460                 if (File->size() > size) {
1461                         qDebug("Unable to resize, trying to recreate file");
1462                         if (!File->remove() || !File->open(QIODevice::ReadWrite)) {
1463                                 delete [] buffer;
1464                                 error=decodeFileError(File->error());
1465                                 return false;
1466                         }
1467                 }
1468         }
1469         File->seek(0);
1470         if (File->write(buffer,size)!=size){
1471                 delete [] buffer;
1472                 error=decodeFileError(File->error());
1473                 return false;
1474         }
1475         if (!syncFile(File))
1476                 qWarning("Unable to flush file to disk");
1477
1478         delete [] buffer;
1479         //if(SearchGroupID!=-1)Groups.push_back(SearchGroup);
1480         return true;
1481 }
1482
1483 void Kdb3Database::createCustomIconsMetaStream(StdEntry* e){
1484         /* Rev 3 */
1485         e->BinaryDesc="bin-stream";
1486         e->Title="Meta-Info";
1487         e->Username="SYSTEM";
1488         e->Comment="KPX_CUSTOM_ICONS_4";
1489         e->Url="$";
1490         if(Groups.size())e->GroupId=Groups[0].Id;
1491         int Size=12;
1492         quint32 NumEntries=0;
1493         for(quint32 i=0;i<Entries.size();i++){
1494                 if (Entries[i].Image>=BUILTIN_ICONS)
1495                         NumEntries++;
1496         }
1497         quint32 NumGroups=0;
1498         for(quint32 i=0;i<Groups.size();i++){
1499                 if (Groups[i].Image>=BUILTIN_ICONS)
1500                         NumGroups++;
1501         }
1502         Size+=8*NumGroups+20*NumEntries;
1503         Size+=CustomIcons.size()*1000; // 1KB
1504         e->Binary.reserve(Size);
1505         e->Binary.resize(12);
1506         quint32 NumIcons=CustomIcons.size();
1507
1508         memcpyToLEnd32(e->Binary.data(),&NumIcons);
1509         memcpyToLEnd32(e->Binary.data()+4,&NumEntries);
1510         memcpyToLEnd32(e->Binary.data()+8,&NumGroups);
1511         for(int i=0;i<CustomIcons.size();i++){
1512                 quint32 ImgSize;
1513                 char ImgSizeBin[4];
1514                 QByteArray png;
1515                 png.reserve(1000);
1516                 QBuffer buffer(&png);
1517                 CustomIcons[i].save(&buffer,"PNG",0);
1518                 ImgSize=png.size();
1519                 memcpyToLEnd32(ImgSizeBin,&ImgSize);
1520                 e->Binary.append(QByteArray::fromRawData(ImgSizeBin,4));
1521                 e->Binary.append(png);
1522         }
1523         
1524         for(quint32 i=0;i<Entries.size();i++){
1525                 if (Entries[i].Image>=BUILTIN_ICONS){
1526                         char Bin[20];
1527                         Entries[i].Uuid.toRaw(Bin);
1528                         quint32 id=Entries[i].Image-BUILTIN_ICONS;
1529                         memcpyToLEnd32(Bin+16,&id);
1530                         e->Binary.append(QByteArray::fromRawData(Bin,20));
1531                 }
1532         }
1533         for(quint32 i=0;i<Groups.size();i++){
1534                 if (Groups[i].Image>=BUILTIN_ICONS){
1535                         char Bin[8];
1536                         memcpyToLEnd32(Bin,&Groups[i].Id);
1537                         quint32 id=Groups[i].Image-BUILTIN_ICONS;
1538                         memcpyToLEnd32(Bin+4,&id);
1539                         e->Binary.append(QByteArray::fromRawData(Bin,8));
1540                 }
1541         }
1542 }
1543
1544 QList<IGroupHandle*> Kdb3Database::sortedGroups(){
1545         QList<IGroupHandle*> SortedGroups;
1546         appendChildrenToGroupList(SortedGroups,RootGroup);
1547         return SortedGroups;
1548 }
1549
1550
1551 void Kdb3Database::appendChildrenToGroupList(QList<IGroupHandle*>& list,StdGroup& group){
1552         for(int i=0;i<group.Children.size();i++){
1553                 list << group.Children[i]->Handle;
1554                 appendChildrenToGroupList(list,*group.Children[i]);
1555         }
1556 }
1557
1558
1559 void Kdb3Database::appendChildrenToGroupList(QList<StdGroup*>& list,StdGroup& group){
1560         for(int i=0;i<group.Children.size();i++){
1561                 list << group.Children[i];
1562                 appendChildrenToGroupList(list,*group.Children[i]);
1563         }
1564 }
1565
1566
1567 void Kdb3Database::serializeGroups(char* buffer,unsigned int& pos){
1568         quint16 FieldType;
1569         quint32 FieldSize;
1570         quint32 Flags=0; //unused
1571         QList<StdGroup*>SortedGroups;
1572         appendChildrenToGroupList(SortedGroups,RootGroup);
1573
1574         for(int i=0; i < SortedGroups.size(); i++){
1575                 unsigned char Date[5];
1576                 dateToPackedStruct5(Date_Never,Date);
1577                 quint16 Level=0;
1578                 StdGroup* group=SortedGroups[i];
1579                 while(group->Parent){
1580                         Level++;
1581                         group=group->Parent;
1582                 }
1583                 Level--;
1584
1585                 FieldType = 0x0001; FieldSize = 4;
1586                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1587                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1588                 memcpyToLEnd32(buffer+pos, &SortedGroups[i]->Id); pos += 4;
1589
1590                 FieldType = 0x0002; FieldSize = SortedGroups[i]->Title.toUtf8().length() + 1;
1591                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1592                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1593                 memcpy(buffer+pos, SortedGroups[i]->Title.toUtf8(),FieldSize); pos += FieldSize;
1594
1595                 FieldType = 0x0003; FieldSize = 5; //Creation
1596                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1597                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1598                 memcpy(buffer+pos, Date,5); pos+=5;
1599
1600                 FieldType = 0x0004; FieldSize = 5; //LastMod
1601                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1602                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1603                 memcpy(buffer+pos, Date,5); pos+=5;
1604
1605                 FieldType = 0x0005; FieldSize = 5; //LastAccess
1606                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1607                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1608                 memcpy(buffer+pos, Date,5); pos+=5;
1609
1610                 FieldType = 0x0006; FieldSize = 5; //Expire
1611                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1612                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1613                 memcpy(buffer+pos, Date,5); pos+=5;
1614
1615                 FieldType = 0x0007; FieldSize = 4;
1616                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1617                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1618                 memcpyToLEnd32(buffer+pos, &SortedGroups[i]->Image); pos += 4;
1619
1620                 FieldType = 0x0008; FieldSize = 2;
1621                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1622                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1623                 memcpyToLEnd16(buffer+pos, &Level); pos += 2;
1624
1625                 FieldType = 0x0009; FieldSize = 4;
1626                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1627                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1628                 memcpyToLEnd32(buffer+pos, &Flags); pos += 4;
1629
1630                 FieldType = 0xFFFF; FieldSize = 0;
1631                 memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1632                 memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1633         }
1634
1635 }
1636
1637
1638 void Kdb3Database::serializeEntries(QList<StdEntry>& EntryList,char* buffer,unsigned int& pos){
1639          quint16 FieldType;
1640          quint32 FieldSize;
1641          for(int i = 0; i < EntryList.size(); i++){
1642                  FieldType = 0x0001; FieldSize = 16;
1643                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1644                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1645                  EntryList[i].Uuid.toRaw(buffer+pos);           pos += 16;
1646
1647                  FieldType = 0x0002; FieldSize = 4;
1648                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1649                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1650                  memcpyToLEnd32(buffer+pos, &EntryList[i].GroupId); pos += 4;
1651
1652                  FieldType = 0x0003; FieldSize = 4;
1653                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1654                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1655                  memcpyToLEnd32(buffer+pos,&EntryList[i].Image); pos += 4;
1656
1657
1658                  FieldType = 0x0004;
1659                  FieldSize = EntryList[i].Title.toUtf8().length() + 1; // Add terminating NULL character space
1660                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1661                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1662                  memcpy(buffer+pos, EntryList[i].Title.toUtf8(),FieldSize);  pos += FieldSize;
1663
1664                  FieldType = 0x0005;
1665                  FieldSize = EntryList[i].Url.toUtf8().length() + 1; // Add terminating NULL character space
1666                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1667                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1668                  memcpy(buffer+pos, EntryList[i].Url.toUtf8(),FieldSize);  pos += FieldSize;
1669
1670                  FieldType = 0x0006;
1671                  FieldSize = EntryList[i].Username.toUtf8().length() + 1; // Add terminating NULL character space
1672                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1673                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1674                  memcpy(buffer+pos, EntryList[i].Username.toUtf8(),FieldSize);  pos += FieldSize;
1675
1676                  FieldType = 0x0007;
1677                  FieldSize = EntryList[i].Password.length() + 1; // Add terminating NULL character space
1678                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1679                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1680                  EntryList[i].Password.unlock();
1681                  memcpy(buffer+pos, EntryList[i].Password.string().toUtf8(),FieldSize);  pos += FieldSize;
1682                  EntryList[i].Password.lock();
1683
1684                  FieldType = 0x0008;
1685                  FieldSize = EntryList[i].Comment.toUtf8().length() + 1; // Add terminating NULL character space
1686                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1687                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1688                  memcpy(buffer+pos, EntryList[i].Comment.toUtf8(),FieldSize);  pos += FieldSize;
1689
1690                  FieldType = 0x0009; FieldSize = 5;
1691                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1692                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1693                  dateToPackedStruct5(EntryList[i].Creation,(unsigned char*)buffer+pos); pos+=5;
1694
1695
1696                  FieldType = 0x000A; FieldSize = 5;
1697                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1698                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1699                  dateToPackedStruct5(EntryList[i].LastMod,(unsigned char*)buffer+pos); pos+=5;
1700
1701                  FieldType = 0x000B; FieldSize = 5;
1702                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1703                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1704                  dateToPackedStruct5(EntryList[i].LastAccess,(unsigned char*)buffer+pos); pos+=5;
1705
1706                  FieldType = 0x000C; FieldSize = 5;
1707                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1708                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1709                  dateToPackedStruct5(EntryList[i].Expire,(unsigned char*)buffer+pos); pos+=5;
1710
1711                  FieldType = 0x000D;
1712                  FieldSize = EntryList[i].BinaryDesc.toUtf8().length() + 1; // Add terminating NULL character space
1713                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1714                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1715                  memcpy(buffer+pos, EntryList[i].BinaryDesc.toUtf8(),FieldSize);  pos += FieldSize;
1716
1717                  FieldType = 0x000E; FieldSize = EntryList[i].Binary.length();
1718                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1719                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1720                  if((!EntryList[i].Binary.isNull()) && (FieldSize != 0))
1721                          memcpy(buffer+pos, EntryList[i].Binary.data(), FieldSize);
1722                  pos += FieldSize;
1723
1724                  FieldType = 0xFFFF; FieldSize = 0;
1725                  memcpyToLEnd16(buffer+pos, &FieldType); pos += 2;
1726                  memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4;
1727          }
1728  }
1729
1730 bool Kdb3Database::close(){
1731         if (File!=NULL)
1732                 delete File;
1733         return true;
1734 }
1735
1736 void Kdb3Database::create(){
1737         File=NULL;
1738         RootGroup.Title="$ROOT$";
1739         RootGroup.Parent=NULL;
1740         RootGroup.Handle=NULL;
1741         Algorithm=Rijndael_Cipher;
1742         KeyTransfRounds=50000;
1743         KeyError=false;
1744 }
1745
1746 bool Kdb3Database::isKeyError(){
1747         if(KeyError){
1748                 KeyError=false;
1749                 return true;
1750         }
1751         else
1752                 return false;
1753 }
1754
1755 IEntryHandle* Kdb3Database::cloneEntry(const IEntryHandle* entry){
1756         StdEntry dolly;
1757         dolly=*((EntryHandle*)entry)->Entry;
1758         dolly.Uuid.generate();
1759         Entries.append(dolly);
1760         EntryHandles.append(EntryHandle(this));
1761         EntryHandles.back().Entry=&Entries.back();
1762         Entries.back().Handle=&EntryHandles.back();
1763         return &EntryHandles.back();
1764 }
1765
1766 IEntryHandle* Kdb3Database::newEntry(IGroupHandle* group){
1767         StdEntry Entry;
1768         Entry.Uuid.generate();
1769         Entry.Group=((GroupHandle*)group)->Group;
1770         Entry.GroupId=Entry.Group->Id;
1771         Entries.append(Entry);
1772         EntryHandles.append(EntryHandle(this));
1773         EntryHandles.back().Entry=&Entries.back();
1774         Entries.back().Handle=&EntryHandles.back();
1775         return &EntryHandles.back();
1776 }
1777
1778 IEntryHandle* Kdb3Database::addEntry(const CEntry* NewEntry, IGroupHandle* Group){
1779         StdEntry Entry(*((StdEntry*)NewEntry));
1780         Entry.Uuid.generate();
1781         Entry.Group=((GroupHandle*)Group)->Group;
1782         Entry.GroupId=Entry.Group->Id;
1783         Entries.append(Entry);
1784         EntryHandles.append(EntryHandle(this));
1785         EntryHandles.back().Entry=&Entries.back();
1786         Entries.back().Handle=&EntryHandles.back();
1787         return &EntryHandles.back();
1788 }
1789
1790 void Kdb3Database::deleteLastEntry(){
1791         Entries.removeAt(Entries.size()-1);
1792         EntryHandles.back().invalidate();
1793 }
1794
1795 bool Kdb3Database::isParent(IGroupHandle* parent, IGroupHandle* child){
1796         StdGroup* group=((GroupHandle*)child)->Group;
1797         while(group->Parent!=&RootGroup){
1798                 if(group->Parent==((GroupHandle*)parent)->Group)return true;
1799                 group=group->Parent;
1800         }
1801         return false;
1802 }
1803
1804
1805
1806 void Kdb3Database::cleanUpHandles(){}
1807
1808 bool Kdb3Database::searchStringContains(const QString& search, const QString& string,bool Cs, bool RegExp){
1809         if(RegExp){
1810                 QRegExp exp(search,Cs ? Qt::CaseSensitive : Qt::CaseInsensitive);
1811                 if(string.contains(exp)==0)return false;}
1812                 else
1813                         if(string.contains(search,Cs ? Qt::CaseSensitive : Qt::CaseInsensitive)==0)return false;
1814
1815                 return true;
1816 }
1817
1818 void Kdb3Database::getEntriesRecursive(IGroupHandle* Group, QList<IEntryHandle*>& EntryList){
1819         EntryList<<entries(Group);
1820         for(int i=0;i<((GroupHandle*)Group)->Group->Children.size();    i++){
1821                 getEntriesRecursive(((GroupHandle*)Group)->Group->Children[i]->Handle,EntryList);
1822         }
1823 }
1824
1825 QList<IEntryHandle*> Kdb3Database::search(IGroupHandle* Group,const QString& search, bool CaseSensitive, bool RegExp, bool Recursive,bool* Fields){
1826         bool fields[6]={true,true,true,false,true,true};
1827         if(!Fields)
1828                 Fields=fields;
1829         QList<IEntryHandle*> SearchEntries;
1830         if(search==QString())return Group ? entries(Group) : entries();
1831         if(Group){
1832                 if(Recursive)
1833                         getEntriesRecursive(Group,SearchEntries);
1834                 else
1835                         SearchEntries=entries(Group);
1836         }
1837         else
1838                 SearchEntries=entries();
1839         
1840         IGroupHandle* bGroup = backupGroup();
1841         
1842         QList<IEntryHandle*> ResultEntries;
1843         for(int i=0; i<SearchEntries.size(); i++){
1844                 IGroupHandle* entryGroup = SearchEntries[i]->group();
1845                 while (entryGroup->parent())
1846                         entryGroup = entryGroup->parent();
1847                 if (entryGroup == bGroup)
1848                         continue;
1849                 
1850                 bool match=false;
1851                 if(Fields[0])match=match||searchStringContains(search,SearchEntries[i]->title(),CaseSensitive,RegExp);
1852                 if(Fields[1])match=match||searchStringContains(search,SearchEntries[i]->username(),CaseSensitive,RegExp);
1853                 if(Fields[2])match=match||searchStringContains(search,SearchEntries[i]->url(),CaseSensitive,RegExp);
1854                 SecString Password=SearchEntries[i]->password();
1855                 Password.unlock();
1856                 if(Fields[3])match=match||searchStringContains(search,Password.string(),CaseSensitive,RegExp);
1857                 Password.lock();
1858                 if(Fields[4])match=match||searchStringContains(search,SearchEntries[i]->comment(),CaseSensitive,RegExp);
1859                 if(Fields[5])match=match||searchStringContains(search,SearchEntries[i]->binaryDesc(),CaseSensitive,RegExp);
1860                 if(match)
1861                         ResultEntries << SearchEntries[i];
1862         }
1863
1864         return ResultEntries;
1865 }
1866
1867 void Kdb3Database::rebuildIndices(QList<StdGroup*>& list){
1868         for(int i=0;i<list.size();i++){
1869                 list[i]->Index=i;
1870         }
1871 }
1872
1873
1874 void Kdb3Database::moveGroup(IGroupHandle* groupHandle,IGroupHandle* NewParent,int Pos){
1875         StdGroup* Parent;
1876         StdGroup* Group=((GroupHandle*)groupHandle)->Group;
1877         if(NewParent)
1878                 Parent=((GroupHandle*)NewParent)->Group;
1879         else
1880                 Parent=&RootGroup;
1881         Group->Parent->Children.removeAt(Group->Index);
1882         rebuildIndices(Group->Parent->Children);
1883         Group->Parent=Parent;
1884         if(Pos==-1){
1885                 Parent->Children.append(Group);
1886         }
1887         else
1888         {
1889                 Q_ASSERT(Parent->Children.size()>=Pos);
1890                 Parent->Children.insert(Pos,Group);
1891         }
1892         rebuildIndices(Parent->Children);
1893 }
1894
1895 bool Kdb3Database::changeFile(const QString& filename){
1896         QFile* tmpFile = new QFile(filename);
1897         if(!tmpFile->open(QIODevice::ReadWrite)){
1898                 error = decodeFileError(File->error());
1899                 delete tmpFile;
1900                 return false;
1901         }
1902         
1903         if (File)
1904                 delete File;
1905         
1906         File = tmpFile;
1907
1908         return true;
1909 }
1910
1911 void Kdb3Database::generateMasterKey(){
1912         randomize(TransfRandomSeed,32);
1913         RawMasterKey.unlock();
1914         MasterKey.unlock();
1915         KeyTransform::transform(*RawMasterKey,*MasterKey,TransfRandomSeed,KeyTransfRounds);
1916         RawMasterKey.lock();
1917         MasterKey.lock();
1918 }
1919
1920 /*void Kdb3Database::copyTree(Kdb3Database* db, GroupHandle* orgGroup, IGroupHandle* parent) {
1921         IGroupHandle* newParent = db->addGroup(orgGroup->Group, parent);
1922         
1923         QList<IEntryHandle*> entryList = entries(orgGroup);
1924         for (int i=0; i<entryList.size(); i++) {
1925                 EntryHandle* entry = static_cast<EntryHandle*>(entryList[i]);
1926                 db->addEntry(entry->Entry, newParent);
1927         }
1928         
1929         QList<IGroupHandle*> children = orgGroup->children();
1930         for (int i=0; i<children.size(); i++) {
1931                 GroupHandle* child = static_cast<GroupHandle*>(children[i]);
1932                 copyTree(db, child, newParent);
1933         }
1934 }
1935
1936 IDatabase* Kdb3Database::groupToNewDb(IGroupHandle* group){
1937         Kdb3Database* db = new Kdb3Database();
1938         db->create();
1939         copyTree(db, static_cast<GroupHandle*>(group), NULL);
1940         
1941         db->changeFile("/ramtmp/test.kdb");
1942         if (!db->save())
1943                 qWarning("%s", CSTR(db->error));
1944         
1945         return db;
1946 }*/
1947
1948
1949 void KeyTransform::transform(quint8* src, quint8* dst, quint8* KeySeed, int rounds){
1950         KeyTransform* ktLeft = new KeyTransform(&src[0], &dst[0], KeySeed, rounds);
1951         KeyTransform* ktRight = new KeyTransform(&src[16], &dst[16], KeySeed, rounds);
1952         ktLeft->start();
1953         ktRight->start();
1954         ktLeft->wait();
1955         ktRight->wait();
1956         SHA256::hashBuffer(dst,dst,32);
1957         delete ktLeft;
1958         delete ktRight;
1959 }
1960
1961 KeyTransform::KeyTransform(quint8* pSrc, quint8* pDst, quint8* pKeySeed, int pRounds){
1962         src = pSrc;
1963         dst = pDst;
1964         KeySeed = pKeySeed;
1965         rounds = pRounds;
1966 }
1967
1968 void KeyTransform::run(){
1969         AESencrypt aes;
1970         aes.key256(KeySeed);
1971         memcpy(dst,src,16);
1972         for (int i=0; i<rounds; i++){
1973                 aes.ecb_encrypt(dst,dst,16);
1974         }
1975 }
1976
1977
1978 int KeyTransformBenchmark::benchmark(int pMSecs){
1979         KeyTransformBenchmark* ktbLeft = new KeyTransformBenchmark(pMSecs);
1980         KeyTransformBenchmark* ktbRight = new KeyTransformBenchmark(pMSecs);
1981         ktbLeft->start();
1982         ktbRight->start();
1983         ktbLeft->wait();
1984         ktbRight->wait();
1985         int num = std::min(ktbLeft->rounds, ktbRight->rounds);
1986         delete ktbLeft;
1987         delete ktbRight;
1988         
1989         return num;
1990 }
1991
1992 KeyTransformBenchmark::KeyTransformBenchmark(int pMSecs){
1993         msecs = pMSecs;
1994         rounds = 0;
1995 }
1996
1997 void KeyTransformBenchmark::run(){
1998         quint8 KeySeed[32];
1999         memset(KeySeed, 0x4B, 32);
2000         quint8 dst[16];
2001         memset(dst, 0x7E, 16);
2002         
2003         QTime t;
2004         t.start();
2005         
2006         AESencrypt aes;
2007         aes.key256(KeySeed);
2008         
2009         do {
2010                 for (int i=0; i<64; i++){
2011                         aes.ecb_encrypt(dst,dst,16);
2012                 }
2013                 rounds += 64;
2014         } while (t.elapsed() < msecs);
2015 }