· 7 years ago · Dec 22, 2018, 04:44 PM
1#!/usr/bin/python
2
3
4# Python port of keepass2john from the John the Ripper suite (http://www.openwall.com/john/)
5# ./keepass2john.c was written by Dhiru Kholia <dhiru.kholia at gmail.com> in March of 2012
6# ./keepass2john.c was released under the GNU General Public License
7# source keepass2john.c source code from: http://fossies.org/linux/john/src/keepass2john.c
8#
9# Python port by @harmj0y, GNU General Public License
10#
11# TODO: handle keyfiles, test file inlining for 1.X databases, database version sanity check for 1.X
12#
13
14import sys
15import os
16import struct
17from binascii import hexlify
18
19
20def process_1x_database(data, databaseName, maxInlineSize=1024):
21 index = 8
22 algorithm = -1
23
24 encFlag = struct.unpack("<L", data[index:index+4])[0]
25 index += 4
26 if (encFlag & 2 == 2):
27 # AES
28 algorithm = 0
29 elif (enc_flag & 8):
30 # Twofish
31 algorithm = 1
32 else:
33 print "Unsupported file encryption!"
34 return
35
36 # TODO: keyfile processing
37
38 # TODO: database version checking
39 version = hexlify(data[index:index+4])
40 index += 4
41
42 finalRandomseed = hexlify(data[index:index+16])
43 index += 16
44
45 encIV = hexlify(data[index:index+16])
46 index += 16
47
48 numGroups = struct.unpack("<L", data[index:index+4])[0]
49 index += 4
50 numEntries = struct.unpack("<L", data[index:index+4])[0]
51 index += 4
52
53 contentsHash = hexlify(data[index:index+32])
54 index += 32
55
56 transfRandomseed = hexlify(data[index:index+32])
57 index += 32
58
59 keyTransfRounds = struct.unpack("<L", data[index:index+4])[0]
60
61 filesize = len(data)
62 datasize = filesize - 124
63
64 if((filesize + datasize) < maxInlineSize):
65 dataBuffer = hexlify(data[124:])
66 end = "*1*%ld*%s" %(datasize, hexlify(dataBuffer))
67 else:
68 end = "0*%s" %(databaseName)
69
70 return "%s:$keepass$*1*%s*%s*%s*%s*%s*%s*%s" %(databaseName, keyTransfRounds, algorithm, finalRandomseed, transfRandomseed, encIV, contentsHash, end)
71
72
73def process_2x_database(data, databaseName):
74
75 index = 12
76 endReached = False
77 masterSeed = ''
78 transformSeed = ''
79 transformRounds = 0
80 initializationVectors = ''
81 expectedStartBytes = ''
82
83 while endReached == False:
84
85 btFieldID = struct.unpack("B", data[index])[0]
86 index += 1
87 uSize = struct.unpack("H", data[index:index+2])[0]
88 index += 2
89 # print "btFieldID : %s , uSize : %s" %(btFieldID, uSize)
90
91 if btFieldID == 0:
92 endReached = True
93
94 if btFieldID == 4:
95 masterSeed = hexlify(data[index:index+uSize])
96
97 if btFieldID == 5:
98 transformSeed = hexlify(data[index:index+uSize])
99
100 if btFieldID == 6:
101 transformRounds = struct.unpack("H", data[index:index+2])[0]
102
103 if btFieldID == 7:
104 initializationVectors = hexlify(data[index:index+uSize])
105
106 if btFieldID == 9:
107 expectedStartBytes = hexlify(data[index:index+uSize])
108
109 index += uSize
110
111 dataStartOffset = index
112 firstEncryptedBytes = hexlify(data[index:index+32])
113
114 return "%s:$keepass$*2*%s*%s*%s*%s*%s*%s*%s" %(databaseName, transformRounds, dataStartOffset, masterSeed, transformSeed, initializationVectors, expectedStartBytes, firstEncryptedBytes)
115
116
117def process_database(filename):
118
119 f = open(filename, 'rb')
120 data = f.read()
121 f.close()
122
123 base = os.path.basename(filename)
124 databaseName = os.path.splitext(base)[0]
125
126 fileSignature = hexlify(data[0:8])
127
128 if(fileSignature == '03d9a29a67fb4bb5'):
129 # "2.X"
130 print process_2x_database(data, databaseName)
131
132 elif(fileSignature == '03d9a29a66fb4bb5'):
133 # "2.X pre release"
134 print process_2x_database(data, databaseName)
135
136 elif(fileSignature == '03d9a29a65fb4bb5'):
137 # "1.X"
138 print process_1x_database(data, databaseName)
139 else:
140 print "ERROR: KeePass signaure unrecognized"
141
142
143if __name__ == "__main__":
144 if len(sys.argv) < 2:
145 sys.stderr.write("Usage: %s <kdb[x] file[s]>\n" % sys.argv[0])
146 sys.exit(-1)
147
148 for i in range(1, len(sys.argv)):
149 process_database(sys.argv[i])