2323target == 0 if container password is to be cracked
2424target == 1 if private key password(s) are to be cracked
2525
26- TODO:
27-
28- 1. Private Keys can be encrypted with a password different from the container
29- password. Add support for cracking such keys.
30-
31- 2. Add ability to select any key for cracking in case multiple keys are present.
32-
3326KEYSTORE FORMAT:
3427
3528Magic number (big-endian integer),
7568VERSION_2 = 0x02
7669
7770
71+ def read_utf_string (fd ):
72+ buf = fd .read (2 )
73+ if len (buf ) < 2 :
74+ return b""
75+ length = struct .unpack (">H" , buf )[0 ]
76+ return fd .read (length )
77+
78+
7879def process_file (filename ):
7980 try :
8081 fd = open (filename , "rb" )
8182 except IOError :
8283 e = sys .exc_info ()[1 ]
83- sys .stderr .write ("! %s: %s\n " % filename , str (e ))
84+ sys .stderr .write ("! %s: %s\n " % ( filename , str (e ) ))
8485 return
8586
8687 # read the entire file into data variable
@@ -89,27 +90,33 @@ def process_file(filename):
8990
9091 # start actual processing
9192 buf = fd .read (4 )
93+ if len (buf ) < 4 :
94+ return
9295 xMagic = struct .unpack ("> I" , buf )[0 ]
9396 buf = fd .read (4 )
97+ if len (buf ) < 4 :
98+ return
9499 xVersion = struct .unpack ("> I" , buf )[0 ]
95100
96101 if (xMagic != MAGIC or (xVersion != VERSION_1 and xVersion != VERSION_2 )):
97- sys .stderr .write ("Invalid keystore format\n " )
102+ sys .stderr .write ("%s: Invalid keystore format\n " % filename )
98103 return
99104
100105 buf = fd .read (4 )
106+ if len (buf ) < 4 :
107+ return
101108 count = struct .unpack ("> I" , buf )[0 ]
102109
110+ keys = []
103111 for i in range (0 , count ):
104112 buf = fd .read (4 )
113+ if len (buf ) < 4 :
114+ break
105115 tag = struct .unpack ("> I" , buf )[0 ]
106116
107117 if (tag == 1 ): # key entry
108118 # Read the alias
109- p = ord (fd .read (1 ))
110- length = ord (fd .read (1 ))
111- buf = fd .read (length )
112- assert (len (buf ) == length )
119+ alias = read_utf_string (fd )
113120
114121 # Read the (entry creation) date
115122 buf = fd .read (8 )
@@ -119,6 +126,7 @@ def process_file(filename):
119126 buf = fd .read (4 )
120127 keysize = struct .unpack ("> I" , buf )[0 ]
121128 protectedPrivKey = fd .read (keysize )
129+ assert (len (protectedPrivKey ) == keysize )
122130
123131 # read certificates
124132 buf = fd .read (4 )
@@ -127,39 +135,34 @@ def process_file(filename):
127135 for j in range (0 , numOfCerts ):
128136 if xVersion == 2 :
129137 # read the certificate type
130- p = ord (fd .read (1 ))
131- assert (p == 1 or p == 0 )
132- length = ord (fd .read (1 ))
133- buf = fd .read (length )
138+ read_utf_string (fd )
134139
135140 # read certificate data
136141 buf = fd .read (4 )
137142 certsize = struct .unpack ("> I" , buf )[0 ]
138143 certdata = fd .read (certsize )
139144 assert (len (certdata ) == certsize )
140145
141- # We can be sure now that numOfCerts of certs are read
146+ keys .append ((alias , protectedPrivKey ))
147+
142148 elif (tag == 2 ): # trusted certificate entry
143149 # Read the alias
144- p = fd .read (1 )
145- length = ord (fd .read (1 ))
146- buf = fd .read (length )
150+ read_utf_string (fd )
147151
148152 # Read the (entry creation) date
149153 buf = fd .read (8 )
150154
151155 # Read the trusted certificate
152156 if xVersion == 2 :
153157 # read the certificate type
154- p = fd .read (1 )
155- length = ord (fd .read (1 ))
156- buf = fd .read (length )
158+ read_utf_string (fd )
157159
158160 buf = fd .read (4 )
159161 certsize = struct .unpack ("> I" , buf )[0 ]
160162 certdata = fd .read (certsize )
163+ assert (len (certdata ) == certsize )
161164 else :
162- sys .stderr .write ("Unrecognized keystore entry\n " )
165+ sys .stderr .write ("%s: Unrecognized keystore entry\n " % filename )
163166 fd .close ()
164167 return
165168
@@ -170,13 +173,46 @@ def process_file(filename):
170173 md = fd .read (20 )
171174 assert (len (md ) == 20 )
172175
176+ # Output for container password (target 0)
177+ if keys :
178+ # Use the first key for the container password hash
179+ alias , protectedPrivKey = keys [0 ]
180+ keysize = len (protectedPrivKey )
181+ keydata = hexlify (protectedPrivKey ).decode ('ascii' )
182+ nkeys = 1
183+ else :
184+ keysize = 0
185+ keydata = ""
186+ nkeys = 0
187+
173188 sys .stdout .write ("%s:$keystore$0$%d$%s" % (os .path .basename (filename ), pos ,
174- hexlify (data [0 :pos ]).decode ('utf-8 ' )))
189+ hexlify (data [0 :pos ]).decode ('ascii ' )))
175190
176- sys .stdout .write ("$%s" % hexlify (md ).decode ('utf-8 ' ))
177- sys .stdout .write ("$%d$%d$%s" % (count , keysize , hexlify ( protectedPrivKey ). decode ( 'utf-8' ) ))
191+ sys .stdout .write ("$%s" % hexlify (md ).decode ('ascii ' ))
192+ sys .stdout .write ("$%d$%d$%s" % (nkeys , keysize , keydata ))
178193 sys .stdout .write (":::::%s\n " % filename )
179194
195+ # Output for each key password (target 1)
196+ for alias , protectedPrivKey in keys :
197+ try :
198+ alias_str = alias .decode ('utf-8' , 'replace' )
199+ except :
200+ alias_str = str (alias )
201+
202+ # JtR label shouldn't contain ':'
203+ alias_str = alias_str .replace (':' , '_' )
204+
205+ keysize = len (protectedPrivKey )
206+ keydata = hexlify (protectedPrivKey ).decode ('ascii' )
207+
208+ sys .stdout .write ("%s-%s:$keystore$1$%d$%s" % (os .path .basename (filename ), alias_str , pos ,
209+ hexlify (data [0 :pos ]).decode ('ascii' )))
210+ sys .stdout .write ("$%s" % hexlify (md ).decode ('ascii' ))
211+ sys .stdout .write ("$1$%d$%s" % (keysize , keydata ))
212+ sys .stdout .write (":::::%s\n " % filename )
213+
214+ fd .close ()
215+
180216
181217if __name__ == "__main__" :
182218 if len (sys .argv ) < 2 :
0 commit comments