1 /* keepass2john utility (modified KeeCracker) written in March of 2012
2 * by Dhiru Kholia. keepass2john processes input KeePass 1.x and 2.x
3 * database files into a format suitable for use with JtR. This software
4 * is Copyright (c) 2012, Dhiru Kholia <dhiru.kholia at gmail.com> and it
5 * is hereby released under GPL license.
6 *
7 * KeePass 2.x support is based on KeeCracker - The KeePass 2 Database
8 * Cracker, http://keecracker.mbw.name/
9 *
10 * KeePass 1.x support is based on kppy - A Python-module to provide
11 * an API to KeePass 1.x files. https://github.com/raymontag/kppy
12 * Copyright (C) 2012 Karsten-Kai König <kkoenig@posteo.de>
13 *
14 * Keyfile support for Keepass 1.x and Keepass 2.x was added by Fist0urs
15 * <eddy.maaalou at gmail.com>
16 *
17 * kppy is free software: you can redistribute it and/or modify it under the terms
18 * of the GNU General Public License as published by the Free Software Foundation,
19 * either version 3 of the License, or at your option) any later version.
20 *
21 * kppy is distributed in the hope that it will be useful, but WITHOUT ANY
22 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
23 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License along with
26 * kppy. If not, see <http://www.gnu.org/licenses/>. */
27
28 #if AC_BUILT
29 #include "autoconfig.h"
30 #endif
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stdint.h>
37 #ifdef _MSC_VER
38 #include "missing_getopt.h"
39 #endif
40 #include <errno.h>
41 // needs to be above sys/types.h and sys/stat.h for mingw, if -std=c99 used.
42 #include "jumbo.h"
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #if (!AC_BUILT || HAVE_UNISTD_H) && !_MSC_VER
46 #include <unistd.h> // getopt defined here for unix
47 #endif
48 #include "params.h"
49 #include "memory.h"
50
51 #include "sha2.h"
52 #include "base64_convert.h"
53
54 const char *extension[] = {".kdbx"};
55 static char *keyfile = NULL;
56
57 // KeePass 1.x signature
58 uint32_t FileSignatureOld1 = 0x9AA2D903;
59 uint32_t FileSignatureOld2 = 0xB54BFB65;
60 /// <summary>
61 /// File identifier, first 32-bit value.
62 /// </summary>
63 uint32_t FileSignature1 = 0x9AA2D903;
64 /// <summary>
65 /// File identifier, second 32-bit value.
66 /// </summary>
67 uint32_t FileSignature2 = 0xB54BFB67;
68 // KeePass 2.x pre-release (alpha and beta) signature
69 uint32_t FileSignaturePreRelease1 = 0x9AA2D903;
70 uint32_t FileSignaturePreRelease2 = 0xB54BFB66;
71 uint32_t FileVersionCriticalMask = 0xFFFF0000;
72 /// <summary>
73 /// File version of files saved by the current <c>Kdb4File</c> class.
74 /// KeePass 2.07 has version 1.01, 2.08 has 1.02, 2.09 has 2.00,
75 /// 2.10 has 2.02, 2.11 has 2.04, 2.15 has 3.00.
76 /// The first 2 bytes are critical (i.e. loading will fail, if the
77 /// file version is too high), the last 2 bytes are informational.
78 /// </summary>
79 // uint32_t FileVersion32 = 0x00030000;
80 uint32_t FileVersion32 = 0x00040000;
81 uint32_t FileVersion32_4 = 0x00040000; // from KeePass 2.36 sources
82
83 // We currently support database formats up to KDBX v3.x. KDBX 4.x is not
84 // supported yet. See "KdbxFile.cs" in KeePass 2.36 for more information on
85 // KDBX 4.x format.
86
87 enum Kdb4HeaderFieldID
88 {
89 EndOfHeader = 0,
90 CipherID = 2,
91 MasterSeed = 4,
92 TransformSeed = 5, // KDBX 3.1, for backward compatibility only
93 TransformRounds = 6, // KDBX 3.1, for backward compatibility only
94 EncryptionIV = 7,
95 StreamStartBytes = 9, // KDBX 3.1, for backward compatibility only
96 KdfParameters = 11, // KDBX 4, superseding Transform*
97 };
98
get_file_size(char * filename)99 static off_t get_file_size(char * filename)
100 {
101 struct stat sb;
102 if (stat(filename, & sb) != 0) {
103 fprintf(stderr, "! %s : stat failed, %s\n", filename, strerror(errno));
104 exit(-2);
105 }
106 return sb.st_size;
107 }
108
print_hex(unsigned char * str,int len)109 static void print_hex(unsigned char *str, int len)
110 {
111 int i;
112 for (i = 0; i < len; ++i)
113 printf("%02x", str[i]);
114 }
115
BytesToUInt64(unsigned char * s,const int s_size)116 static uint64_t BytesToUInt64(unsigned char * s, const int s_size)
117 {
118 int i;
119 uint64_t v = 0;
120
121 for (i = 0; i < 8 && i < s_size; i++)
122 v |= (uint64_t)s[i] << 8 * i;
123 return v;
124 }
125
fget32(FILE * fp)126 static uint32_t fget32(FILE * fp)
127 {
128 uint32_t v = (uint32_t)fgetc(fp);
129 v |= (uint32_t)fgetc(fp) << 8;
130 v |= (uint32_t)fgetc(fp) << 16;
131 v |= (uint32_t)fgetc(fp) << 24;
132 return v;
133 }
134
fget16(FILE * fp)135 static uint16_t fget16(FILE * fp)
136 {
137 uint32_t v = fgetc(fp);
138 v |= fgetc(fp) << 8;
139 return v;
140 }
141
warn(const char * fmt,...)142 static void warn(const char *fmt, ...)
143 {
144 va_list ap;
145
146 va_start(ap, fmt);
147 if (fmt != NULL)
148 vfprintf(stderr, fmt, ap);
149 va_end(ap);
150 fprintf(stderr, "\n");
151
152 // exit(EXIT_FAILURE);
153 }
154
155 /* process KeePass 1.x databases */
process_old_database(FILE * fp,char * encryptedDatabase)156 static void process_old_database(FILE *fp, char* encryptedDatabase)
157 {
158 uint32_t enc_flag;
159 uint32_t version;
160 unsigned char final_randomseed[16];
161 unsigned char enc_iv[16];
162 unsigned char contents_hash[32];
163 unsigned char transf_randomseed[32];
164 uint32_t num_groups;
165 uint32_t num_entries;
166 uint32_t key_transf_rounds;
167 unsigned char *buffer;
168 int64_t filesize = 0;
169 int64_t datasize;
170 int algorithm = -1;
171 char *dbname;
172 FILE *kfp = NULL;
173
174 /* specific to keyfile handling */
175 int64_t filesize_keyfile = 0;
176 SHA256_CTX ctx;
177 unsigned char hash[32];
178 int counter;
179
180 enc_flag = fget32(fp);
181 version = fget32(fp);
182
183 if (fread(final_randomseed, 16, 1, fp) != 1) {
184 warn("%s: Error: read failed: %s.", encryptedDatabase,
185 strerror(errno));
186 return;
187 }
188 if (fread(enc_iv, 16, 1, fp) != 1) {
189 warn("%s: Error: read failed: %s.", encryptedDatabase,
190 strerror(errno));
191 return;
192 }
193
194 num_groups = fget32(fp);
195 num_entries = fget32(fp);
196 (void)num_groups;
197 (void)num_entries;
198
199 if (fread(contents_hash, 32, 1, fp) != 1) {
200 warn("%s: Error: read failed: %s.", encryptedDatabase,
201 strerror(errno));
202 return;
203 }
204 if (fread(transf_randomseed, 32, 1, fp) != 1) {
205 warn("%s: Error: read failed: %s.", encryptedDatabase,
206 strerror(errno));
207 return;
208 }
209
210 key_transf_rounds = fget32(fp);
211 /* Check if the database is supported */
212 if ((version & 0xFFFFFF00) != (0x00030002 & 0xFFFFFF00)) {
213 fprintf(stderr, "! %s : Unsupported file version (%u)!\n", encryptedDatabase, version);
214 return;
215 }
216 /* src/Kdb3Database.cpp from KeePass 0.4.3 is authoritative */
217 if (enc_flag & 2) {
218 algorithm = 0; // AES
219 } else if (enc_flag & 8) {
220 algorithm = 1; // Twofish
221 } else {
222 fprintf(stderr, "! %s : Unsupported file encryption (%u)!\n", encryptedDatabase, enc_flag);
223 return;
224 }
225
226 /* keyfile processing */
227 if (keyfile) {
228 kfp = fopen(keyfile, "rb");
229 if (!kfp) {
230 fprintf(stderr, "! %s : %s\n", keyfile, strerror(errno));
231 return;
232 }
233 filesize_keyfile = (int64_t)get_file_size(keyfile);
234 }
235
236 dbname = strip_suffixes(basename(encryptedDatabase), extension, 1);
237 filesize = (int64_t)get_file_size(encryptedDatabase);
238 datasize = filesize - 124;
239 if (datasize < 0) {
240 warn("%s: Error in validating datasize.", encryptedDatabase);
241 return;
242 }
243 // offset (124) field below is not used, we hijack it to convey the
244 // algorithm.
245 // printf("%s:$keepass$*1*%d*%d*", dbname, key_transf_rounds, 124);
246 printf("%s:$keepass$*1*%d*%d*", dbname, key_transf_rounds, algorithm);
247 print_hex(final_randomseed, 16);
248 printf("*");
249 print_hex(transf_randomseed, 32);
250 printf("*");
251 print_hex(enc_iv, 16);
252 printf("*");
253 print_hex(contents_hash, 32);
254
255 buffer = (unsigned char*)malloc(datasize * sizeof(char));
256
257 /* we inline the content with the hash */
258 fprintf(stderr, "Inlining %s\n", encryptedDatabase);
259 printf("*1*%"PRId64"*", datasize);
260 fseek(fp, 124, SEEK_SET);
261 if (fread(buffer, datasize, 1, fp) != 1) {
262 warn("%s: Error: read failed: %s.",
263 encryptedDatabase, strerror(errno));
264 MEM_FREE(buffer);
265 return;
266 }
267
268 print_hex(buffer, datasize);
269 MEM_FREE(buffer);
270
271 if (keyfile) {
272 buffer = (unsigned char*)malloc(filesize_keyfile * sizeof(char));
273 printf("*1*64*"); /* inline keyfile content */
274 if (fread(buffer, filesize_keyfile, 1, kfp) != 1) {
275 warn("%s: Error: read failed: %s.",
276 encryptedDatabase, strerror(errno));
277 return;
278 }
279
280 /* as in Keepass 1.x implementation:
281 * if filesize_keyfile == 32 then assume byte_array
282 * if filesize_keyfile == 64 then assume hex(byte_array)
283 * else byte_array = sha256(keyfile_content)
284 */
285
286 if (filesize_keyfile == 32)
287 print_hex(buffer, filesize_keyfile);
288 else if (filesize_keyfile == 64){
289 for (counter = 0; counter <64; counter++)
290 printf("%c", buffer[counter]);
291 }
292 else{
293 /* precompute sha256 to speed-up cracking */
294 SHA256_Init(&ctx);
295 SHA256_Update(&ctx, buffer, filesize_keyfile);
296 SHA256_Final(hash, &ctx);
297 print_hex(hash, 32);
298 }
299 MEM_FREE(buffer);
300 }
301 printf("\n");
302 }
303
304 // Synchronize with KdbxFile.Read.cs from KeePass 2.x
process_database(char * encryptedDatabase)305 static void process_database(char* encryptedDatabase)
306 {
307 // long dataStartOffset;
308 unsigned long transformRounds = 0;
309 unsigned char *masterSeed = NULL;
310 int masterSeedLength = 0;
311 unsigned char *transformSeed = NULL;
312 int transformSeedLength = 0;
313 unsigned char *initializationVectors = NULL;
314 int initializationVectorsLength = 0;
315 unsigned char *expectedStartBytes = NULL;
316 int endReached, expectedStartBytesLength = 0;
317 uint32_t uSig1, uSig2, uVersion;
318 FILE *fp;
319 unsigned char out[32];
320 char *dbname;
321 long algorithm = 0; // 0 -> AES
322 size_t fsize = 0;
323
324 /* specific to keyfile handling */
325 unsigned char *buffer;
326 int64_t filesize_keyfile = 0;
327 char *p;
328 char *data;
329 char b64_decoded[128+1];
330 FILE *kfp = NULL;
331 SHA256_CTX ctx;
332 unsigned char hash[32];
333 int counter;
334
335 fp = fopen(encryptedDatabase, "rb");
336 if (!fp) {
337 fprintf(stderr, "! %s : %s\n", encryptedDatabase, strerror(errno));
338 return;
339 }
340 fseek(fp, 0, SEEK_END);
341 fsize = ftell(fp);
342 fseek(fp, 0, SEEK_SET);
343 uSig1 = fget32(fp);
344 uSig2 = fget32(fp);
345 if ((uSig1 == FileSignatureOld1) && (uSig2 == FileSignatureOld2)) {
346 process_old_database(fp, encryptedDatabase);
347 fclose(fp);
348 return;
349 }
350 if ((uSig1 == FileSignature1) && (uSig2 == FileSignature2)) {
351 }
352 else if ((uSig1 == FileSignaturePreRelease1) && (uSig2 == FileSignaturePreRelease2)) {
353 }
354 else {
355 fprintf(stderr, "! %s : Unknown format: File signature invalid\n", encryptedDatabase);
356 fclose(fp);
357 return;
358 }
359 uVersion = fget32(fp);
360 if ((uVersion & FileVersionCriticalMask) > (FileVersion32 & FileVersionCriticalMask)) {
361 fprintf(stderr, "! %s : Unknown format: File version '%x' unsupported\n", encryptedDatabase, uVersion);
362 fclose(fp);
363 return;
364 }
365 endReached = 0;
366 while (!endReached) {
367 uint32_t uSize;
368 unsigned char btFieldID = fgetc(fp);
369 enum Kdb4HeaderFieldID kdbID = btFieldID;
370 unsigned char *pbData = NULL;
371
372 if (uVersion < FileVersion32_4)
373 uSize = fget16(fp);
374 else
375 uSize = fget32(fp);
376
377 if (fsize * 64 < uSize) {
378 fprintf(stderr, "uSize too large, is the database corrupt?\n");
379 goto bailout;
380 }
381 if (uSize == 0 && (kdbID != EndOfHeader)) {
382 fprintf(stderr, "error validating uSize for EndOfHeader, is the database corrupt?\n");
383 goto bailout;
384 }
385 if (uSize > 0) {
386 pbData = (unsigned char*)malloc(uSize);
387 if (!pbData || fread(pbData, uSize, 1, fp) != 1) {
388 fprintf(stderr, "error allocating / reading pbData, is the database corrupt?\n");
389 MEM_FREE(pbData);
390 goto bailout;
391 }
392 }
393 switch (kdbID)
394 {
395 case EndOfHeader:
396 endReached = 1; // end of header
397 MEM_FREE(pbData);
398 break;
399
400 case MasterSeed:
401 if (masterSeed)
402 MEM_FREE(masterSeed);
403 masterSeed = pbData;
404 masterSeedLength = uSize;
405 break;
406
407 case TransformSeed: // Obsolete in FileVersion32_4; for backward compatibility only
408 if (transformSeed)
409 MEM_FREE(transformSeed);
410
411 transformSeed = pbData;
412 transformSeedLength = uSize;
413 break;
414
415 case TransformRounds: // Obsolete in FileVersion32_4; for backward compatibility only
416 if (uSize < 4) {
417 fprintf(stderr, "error validating uSize for TransformRounds, is the database corrupt?\n");
418 MEM_FREE(pbData);
419 goto bailout;
420 }
421 if (!pbData) {
422 fprintf(stderr, "! %s : parsing failed (pbData is NULL), please open a bug if target is valid KeepPass database.\n", encryptedDatabase);
423 goto bailout;
424 }
425 else {
426 transformRounds = BytesToUInt64(pbData, uSize);
427 MEM_FREE(pbData);
428 }
429 break;
430
431 case EncryptionIV:
432 if (initializationVectors)
433 MEM_FREE(initializationVectors);
434 initializationVectors = pbData;
435 initializationVectorsLength = uSize;
436 break;
437
438 case StreamStartBytes: // Not present in FileVersion32_4
439 if (expectedStartBytes)
440 MEM_FREE(expectedStartBytes);
441 expectedStartBytes = pbData;
442 expectedStartBytesLength = uSize;
443 break;
444
445 case CipherID:
446 // pbData == 31c1f2e6bf714350be5805216afc5aff => AES ("Standard" KDBX 3.1)
447 // pbData == d6038a2b8b6f4cb5a524339a31dbb59a => ChaCha20
448 // pbData == ad68f29f576f4bb9a36ad47af965346c => TwoFish
449 if (uSize < 4) {
450 fprintf(stderr, "error validating uSize for CipherID, is the database corrupt?\n");
451 MEM_FREE(pbData);
452 goto bailout;
453 }
454 if (memcmp(pbData, "\xd6\x03\x8a\x2b", 4) == 0) {
455 // fprintf(stderr, "! %s : ChaCha20 usage is not supported yet!\n", encryptedDatabase);
456 // MEM_FREE(pbData);
457 algorithm = 2;
458 // goto bailout;
459 }
460 /* if (memcmp(pbData, "\x31\xc1\xf2\xe6", 4) != 0) {
461 fprintf(stderr, "! %s : Unsupported CipherID found!\n", encryptedDatabase);
462 MEM_FREE(pbData);
463 goto bailout;
464 } */
465
466 default:
467 MEM_FREE(pbData);
468 break;
469 }
470 }
471 // dataStartOffset = ftell(fp);
472 if (transformRounds == 0 && uVersion < FileVersion32_4) {
473 fprintf(stderr, "! %s : transformRounds can't be 0\n", encryptedDatabase);
474 goto bailout;
475 }
476 #ifdef KEEPASS_DEBUG
477 fprintf(stderr, "%d, %d, %d, %d\n", masterSeedLength, transformSeedLength, initializationVectorsLength, expectedStartBytesLength);
478 #endif
479 if ((uVersion < FileVersion32_4) && (!masterSeed || !transformSeed || !initializationVectors || !expectedStartBytes)) {
480 fprintf(stderr, "! %s : parsing failed, please open a bug if target is valid KeepPass database.\n", encryptedDatabase);
481 goto bailout;
482 }
483
484 if (uVersion >= FileVersion32_4) {
485 fprintf(stderr, "! %s : File version '%x' is currently not supported!\n", encryptedDatabase, uVersion);
486 goto bailout;
487 }
488
489 if (keyfile) {
490 kfp = fopen(keyfile, "rb");
491 if (!kfp) {
492 fprintf(stderr, "! %s : %s\n", keyfile, strerror(errno));
493 return;
494 }
495 filesize_keyfile = (int64_t)get_file_size(keyfile);
496 }
497
498 dbname = strip_suffixes(basename(encryptedDatabase),extension, 1);
499 // printf("%s:$keepass$*2*%ld*%ld*", dbname, transformRounds, dataStartOffset);
500 printf("%s:$keepass$*2*%ld*%ld*", dbname, transformRounds, algorithm); // dataStartOffset field is now used to convey algorithm information
501 print_hex(masterSeed, masterSeedLength);
502 printf("*");
503 print_hex(transformSeed, transformSeedLength);
504 printf("*");
505 print_hex(initializationVectors, initializationVectorsLength);
506 printf("*");
507 print_hex(expectedStartBytes, expectedStartBytesLength);
508 if (fread(out, 32, 1, fp) != 1) {
509 fprintf(stderr, "error reading encrypted data!\n");
510 goto bailout;
511 }
512 printf("*");
513 print_hex(out, 32);
514
515 if (keyfile) {
516 buffer = (unsigned char*)malloc(filesize_keyfile * sizeof(char));
517 printf("*1*64*"); /* inline keyfile content */
518 if (fread(buffer, filesize_keyfile, 1, kfp) != 1) {
519 warn("%s: Error: read failed: %s.",
520 encryptedDatabase, strerror(errno));
521 return;
522 }
523
524 /* as in Keepass 2.x implementation:
525 * if keyfile is an xml, get <Data> content
526 * if filesize_keyfile == 32 then assume byte_array
527 * if filesize_keyfile == 64 then assume hex(byte_array)
528 * else byte_array = sha256(keyfile_content)
529 */
530
531 if (!memcmp((char *) buffer, "<?xml", 5)
532 && ((p = strstr((char *) buffer, "<Key>")) != NULL)
533 && ((p = strstr(p, "<Data>")) != NULL)
534 )
535 {
536 p += strlen("<Data>");
537 data = p;
538 p = strstr(p, "</Data>");
539 printf ("%s", base64_convert_cp(data, e_b64_mime, p - data, b64_decoded, e_b64_hex, sizeof(b64_decoded), flg_Base64_NO_FLAGS, 0));
540 }
541 else if (filesize_keyfile == 32)
542 print_hex(buffer, filesize_keyfile);
543 else if (filesize_keyfile == 64)
544 {
545 for (counter = 0; counter <64; counter++)
546 printf("%c", buffer[counter]);
547 }
548 else
549 {
550 /* precompute sha256 to speed-up cracking */
551
552 SHA256_Init(&ctx);
553 SHA256_Update(&ctx, buffer, filesize_keyfile);
554 SHA256_Final(hash, &ctx);
555 print_hex(hash, 32);
556 }
557 MEM_FREE(buffer);
558 }
559 printf("\n");
560
561 bailout:
562 MEM_FREE(masterSeed);
563 MEM_FREE(transformSeed);
564 MEM_FREE(initializationVectors);
565 MEM_FREE(expectedStartBytes);
566 fclose(fp);
567 }
568
569 #ifndef HAVE_LIBFUZZER
usage(char * name)570 static int usage(char *name)
571 {
572 fprintf(stderr, "Usage: %s [-k <keyfile>] <.kdbx database(s)>\n", name);
573
574 return EXIT_FAILURE;
575 }
576
main(int argc,char ** argv)577 int main(int argc, char **argv)
578 {
579 int c;
580
581 errno = 0;
582 /* Parse command line */
583 while ((c = getopt(argc, argv, "k:")) != -1) {
584 switch (c) {
585 case 'k':
586 keyfile = (char *)malloc(strlen(optarg) + 1);
587 strcpy(keyfile, optarg);
588 break;
589 case '?':
590 default:
591 return usage(argv[0]);
592 }
593 }
594 argc -= optind;
595 if (argc == 0)
596 return usage(argv[0]);
597 argv += optind;
598
599 while(argc--)
600 process_database(*argv++);
601
602 return 0;
603 }
604 #endif
605
606 #ifdef HAVE_LIBFUZZER
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)607 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
608 {
609 int fd;
610 char name[] = "/tmp/libFuzzer-XXXXXX";
611
612 fd = mkstemp(name); // this approach is somehow faster than the fmemopen way
613 if (fd < 0) {
614 fprintf(stderr, "Problem detected while creating the input file, %s, aborting!\n", strerror(errno));
615 exit(-1);
616 }
617 write(fd, data, size);
618 close(fd);
619 process_database(name);
620 remove(name);
621
622 return 0;
623 }
624 #endif
625