nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * genpmk - Generate a file with precomputed PMK's and words |
||
3 | * |
||
4 | * Copyright (c) 2005, Joshua Wright <jwright@hasborg.com> |
||
5 | * |
||
6 | * $Id: genpmk.c,v 4.1 2008-03-20 16:49:38 jwright Exp $ |
||
7 | * |
||
8 | * This program is free software; you can redistribute it and/or modify |
||
9 | * it under the terms of the GNU General Public License version 2 as |
||
10 | * published by the Free Software Foundation. See COPYING for more |
||
11 | * details. |
||
12 | * |
||
13 | * coWPAtty is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | * GNU General Public License for more details. |
||
17 | */ |
||
18 | |||
19 | #include <stdlib.h> |
||
20 | #include <stdio.h> |
||
21 | #include <string.h> |
||
22 | #include <sys/stat.h> |
||
23 | #include <unistd.h> |
||
24 | #include <pcap.h> |
||
25 | #include <signal.h> |
||
26 | #include <sys/types.h> |
||
27 | #include <fcntl.h> |
||
28 | #include <errno.h> |
||
29 | |||
30 | #include "cowpatty.h" |
||
31 | #include "common.h" |
||
32 | #include "utils.h" |
||
33 | #include "sha1.h" |
||
34 | |||
35 | #define PROGNAME "genpmk" |
||
36 | #define VER "1.1" |
||
37 | |||
38 | /* Globals */ |
||
39 | int sig = 0; /* Used for handling signals */ |
||
40 | char *words; |
||
41 | |||
42 | /* Prototypes */ |
||
43 | void usage(char *message); |
||
44 | int nextword(char *word, FILE * fp); |
||
45 | |||
46 | void usage(char *message) |
||
47 | { |
||
48 | |||
49 | if (strlen(message) > 0) { |
||
50 | printf("%s: %s\n", PROGNAME, message); |
||
51 | } |
||
52 | |||
53 | printf("Usage: %s [options]\n", PROGNAME); |
||
54 | printf("\n" |
||
55 | "\t-f \tDictionary file\n" |
||
56 | "\t-d \tOutput hash file\n" |
||
57 | "\t-s \tNetwork SSID\n" |
||
58 | "\t-h \tPrint this help information and exit\n" |
||
59 | "\t-v \tPrint verbose information (more -v for more verbosity)\n" |
||
60 | "\t-V \tPrint program version and exit\n" "\n"); |
||
61 | printf("After precomputing the hash file, run cowpatty with the -d " |
||
62 | "argument.\n"); |
||
63 | } |
||
64 | |||
65 | void cleanup() |
||
66 | { |
||
67 | /* lame-o-meter++ */ |
||
68 | sig = 1; |
||
69 | } |
||
70 | |||
71 | |||
72 | int nextword(char *word, FILE * fp) |
||
73 | { |
||
74 | |||
75 | if (fgets(word, MAXPASSLEN + 1, fp) == NULL) { |
||
76 | return (-1); |
||
77 | } |
||
78 | |||
79 | /* Remove newline */ |
||
80 | word[strlen(word) - 1] = '\0'; |
||
81 | |||
82 | if (feof(fp)) { |
||
83 | return (-1); |
||
84 | } |
||
85 | |||
86 | return (strlen(word)); |
||
87 | } |
||
88 | |||
89 | int main(int argc, char **argv) |
||
90 | { |
||
91 | int fret = 0, c, ret; |
||
92 | unsigned long int wordstested=0; |
||
93 | float elapsed = 0; |
||
94 | char passphrase[MAXPASSLEN + 1]; |
||
95 | struct user_opt opt; |
||
96 | struct hashdb_head hf_header; |
||
97 | struct hashdb_rec rec; |
||
98 | struct stat teststat; |
||
99 | FILE *fpin = NULL, *fpout = NULL; |
||
100 | struct timeval start, end; |
||
101 | u8 pmk[32]; |
||
102 | |||
103 | printf("%s %s - WPA-PSK precomputation attack. <jwright@hasborg.com>\n", |
||
104 | PROGNAME, VER); |
||
105 | |||
106 | memset(&opt, 0, sizeof(opt)); |
||
107 | memset(&hf_header, 0, sizeof(hf_header)); |
||
108 | |||
109 | signal(SIGINT, cleanup); |
||
110 | signal(SIGTERM, cleanup); |
||
111 | signal(SIGQUIT, cleanup); |
||
112 | |||
113 | /* Collect and test command-line arguments */ |
||
114 | while ((c = getopt(argc, argv, "f:d:s:hvV")) != EOF) { |
||
115 | switch(c) { |
||
116 | case 'f': |
||
117 | strncpy(opt.dictfile, optarg, sizeof(opt.dictfile)); |
||
118 | break; |
||
119 | case 'd': |
||
120 | strncpy(opt.hashfile, optarg, sizeof(opt.hashfile)); |
||
121 | break; |
||
122 | case 's': |
||
123 | strncpy(opt.ssid, optarg, sizeof(opt.ssid)); |
||
124 | break; |
||
125 | case 'h': |
||
126 | usage(""); |
||
127 | exit(0); |
||
128 | case 'v': |
||
129 | opt.verbose++; |
||
130 | break; |
||
131 | case 'V': |
||
132 | printf("$Id: genpmk.c,v 4.1 2008-03-20 16:49:38 jwright Exp $\n"); |
||
133 | exit(0); |
||
134 | } |
||
135 | } |
||
136 | |||
137 | if (IsBlank(opt.dictfile)) { |
||
138 | usage("Must specify a dictionary file with -f"); |
||
139 | exit(1); |
||
140 | } |
||
141 | |||
142 | if (IsBlank(opt.hashfile)) { |
||
143 | usage("Must specify an output hasfile with -d"); |
||
144 | exit(1); |
||
145 | } |
||
146 | |||
147 | if (IsBlank(opt.ssid)) { |
||
148 | usage("Must specify a SSID with -s"); |
||
149 | exit(1); |
||
150 | } |
||
151 | |||
152 | /* Open the dictionary file */ |
||
153 | if (*opt.dictfile == '-') { |
||
154 | printf("Using STDIN for words.\n"); |
||
155 | fpin = stdin; |
||
156 | } else { |
||
157 | fpin = fopen(opt.dictfile, "r"); |
||
158 | if (fpin == NULL) { |
||
159 | perror("fopen"); |
||
160 | exit(-1); |
||
161 | } |
||
162 | } |
||
163 | |||
164 | |||
165 | /* stat the hashfile, if it exists, print a message and check to |
||
166 | ensure specified SSID matches header information. If so, append |
||
167 | new words to the end of the hashdb file. |
||
168 | If the file does not exist, populate the hashdb_head record and |
||
169 | create the file. */ |
||
170 | ret = stat(opt.hashfile, &teststat); |
||
171 | if (errno == ENOENT || teststat.st_size == 0) { |
||
172 | /* File does not exist or is empty, populate header and |
||
173 | create */ |
||
174 | printf("File %s does not exist, creating.\n", opt.hashfile); |
||
175 | memcpy(hf_header.ssid, opt.ssid, strlen(opt.ssid)); |
||
176 | hf_header.ssidlen = strlen(opt.ssid); |
||
177 | hf_header.magic = GENPMKMAGIC; |
||
178 | |||
179 | fpout = fopen(opt.hashfile, "wb"); |
||
180 | if (fpout == NULL) { |
||
181 | perror("fopen"); |
||
182 | exit(-1); |
||
183 | } |
||
184 | |||
185 | if (fwrite(&hf_header, sizeof(hf_header), 1, fpout) != 1) { |
||
186 | perror("fwrite"); |
||
187 | exit(-1); |
||
188 | } |
||
189 | |||
190 | } else { |
||
191 | |||
192 | /* File does exist, append to EOF after matching SSID */ |
||
193 | fpout = fopen(opt.hashfile, "r+b"); |
||
194 | if (fpout == NULL) { |
||
195 | perror("fopen"); |
||
196 | exit(-1); |
||
197 | } |
||
198 | |||
199 | if (fread(&hf_header, sizeof(hf_header), 1, fpout) != 1) { |
||
200 | perror("fread"); |
||
201 | exit(-1); |
||
202 | } |
||
203 | |||
204 | if (fclose(fpout) != 0) { |
||
205 | perror("fclose"); |
||
206 | exit(-1); |
||
207 | } |
||
208 | |||
209 | if (memcmp(opt.ssid, hf_header.ssid, hf_header.ssidlen) != 0) { |
||
210 | fprintf(stderr, "Specified SSID \"%s\" and the SSID in " |
||
211 | "the output file (\"%s\") do not match.\nCreate" |
||
212 | " a new file, or change SSID to match.\n", |
||
213 | opt.ssid, hf_header.ssid); |
||
214 | exit(-1); |
||
215 | } |
||
216 | |||
217 | printf("File %s exists, appending new data.\n", opt.hashfile); |
||
218 | if (fopen(opt.hashfile, "ab") == NULL) { |
||
219 | perror("fopen"); |
||
220 | exit(-1); |
||
221 | } |
||
222 | } |
||
223 | |||
224 | |||
225 | |||
226 | /* Populate capdata struct */ |
||
227 | |||
228 | gettimeofday(&start, 0); |
||
229 | |||
230 | while (feof(fpin) == 0 && sig == 0) { |
||
231 | |||
232 | /* Populate "passphrase" with the next word */ |
||
233 | fret = nextword(passphrase, fpin); |
||
234 | if (fret < 0) { |
||
235 | break; |
||
236 | } |
||
237 | |||
238 | if (opt.verbose > 1) { |
||
239 | printf("Testing passphrase: %s\n", passphrase); |
||
240 | } |
||
241 | |||
242 | /* |
||
243 | * Test length of word. IEEE 802.11i indicates the passphrase must be |
||
244 | * at least 8 characters in length, and no more than 63 characters in |
||
245 | * length. |
||
246 | */ |
||
247 | if (fret < 8 || fret > 63) { |
||
248 | if (opt.verbose) { |
||
249 | printf("Invalid passphrase length: %s (%u).\n", |
||
250 | passphrase, strlen(passphrase)); |
||
251 | } |
||
252 | continue; |
||
253 | } else { |
||
254 | /* This word is good, increment the words tested counter */ |
||
255 | wordstested++; |
||
256 | } |
||
257 | |||
258 | /* Status display */ |
||
259 | if ((wordstested % 1000) == 0) { |
||
260 | printf("key no. %ld: %s\n", wordstested, passphrase); |
||
261 | fflush(stdout); |
||
262 | } |
||
263 | |||
264 | if (opt.verbose > 1) { |
||
265 | printf("Calculating PMK for \"%s\".\n", passphrase); |
||
266 | } |
||
267 | pbkdf2_sha1(passphrase, opt.ssid, strlen(opt.ssid), 4096, |
||
268 | pmk, sizeof(pmk), USECACHED); |
||
269 | if (opt.verbose > 2) { |
||
270 | printf("PMK is"); |
||
271 | lamont_hdump(pmk, sizeof(pmk)); |
||
272 | } |
||
273 | |||
274 | /* Populate record with PMK and record length */ |
||
275 | memcpy(rec.pmk, pmk, sizeof(pmk)); |
||
276 | rec.rec_size = (strlen(passphrase) + sizeof(rec.rec_size) + |
||
277 | sizeof(rec.pmk)); |
||
278 | |||
279 | /* Write the record contents to the file */ |
||
280 | if (fwrite(&rec.rec_size, sizeof(rec.rec_size), 1, fpout) != 1) { |
||
281 | perror("fwrite"); |
||
282 | break; |
||
283 | } |
||
284 | if (fwrite(passphrase, strlen(passphrase), 1, fpout) != 1) { |
||
285 | perror("fwrite"); |
||
286 | break; |
||
287 | } |
||
288 | if (fwrite(rec.pmk, sizeof(rec.pmk), 1, fpout) != 1) { |
||
289 | perror("fwrite"); |
||
290 | break; |
||
291 | } |
||
292 | |||
293 | } |
||
294 | |||
295 | if (fclose(fpin) != 0) { |
||
296 | perror("fclose"); |
||
297 | exit(-1); |
||
298 | } |
||
299 | if (fclose(fpout) != 0) { |
||
300 | perror("fclose"); |
||
301 | exit(-1); |
||
302 | } |
||
303 | |||
304 | gettimeofday(&end, 0); |
||
305 | |||
306 | /* print time elapsed */ |
||
307 | if (end.tv_usec < start.tv_usec) { |
||
308 | end.tv_sec -= 1; |
||
309 | end.tv_usec += 1000000; |
||
310 | } |
||
311 | end.tv_sec -= start.tv_sec; |
||
312 | end.tv_usec -= start.tv_usec; |
||
313 | elapsed = end.tv_sec + end.tv_usec / 1000000.0; |
||
314 | |||
315 | printf("\n%lu passphrases tested in %.2f seconds: %.2f passphrases/" |
||
316 | "second\n", wordstested, elapsed, wordstested / elapsed); |
||
317 | |||
318 | return (0); |
||
319 | } |