├── CVS ├── Repository ├── Root └── Entries ├── AUTHORS ├── eap-test.dump ├── TODO ├── WISHLIST ├── INSTALL ├── utils.h ├── Makefile ├── CHANGELOG ├── common.h ├── md5.h ├── sha1.h ├── FAQ ├── README ├── cowpatty.h ├── utils.c ├── md5.c ├── COPYING ├── cowpatty.c └── sha1.c /CVS/Repository: -------------------------------------------------------------------------------- 1 | cowpatty 2 | -------------------------------------------------------------------------------- /CVS/Root: -------------------------------------------------------------------------------- 1 | /home/jwright/cvsroot 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Joshua Wright 2 | -------------------------------------------------------------------------------- /eap-test.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roobixx/cowpatty/HEAD/eap-test.dump -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Further optimize pbkdf2 handling. 2 | Windows port? 3 | Signal handler is not right. Need to be able to break and handle closing files 4 | at any time. 5 | Add support for multi-threading 6 | Handle multiple TKIP four-ways in the same capture file properly 7 | Decide how to properly handle multiple TKIP four-ways 8 | -------------------------------------------------------------------------------- /WISHLIST: -------------------------------------------------------------------------------- 1 | Soekris engineering makes a crypto accelerator. If someone feels generous 2 | enough to drop the $75/US on it and send it to me, I'd see about implementing 3 | support to improve performance by using this card to offload processing. 4 | 5 | http://www.soekris.com/vpn1401.htm 6 | 7 | Alternatively, I'm always receptive to systems with high-end processors as 8 | well. ;) 9 | 10 | Drop me a note at jwright@hasborg.com if you are interested. Thanks! 11 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | coWPAtty - Brute-force dictionary attack against WPA-PSK. 2 | 3 | Copyright(c) 2004, Joshua Wright 4 | 5 | INSTALLATION 6 | 7 | Most users will want to just run "make" to generate the coWPAtty binary. 8 | Running "make strip" will result in a smaller binary without symbols. 9 | 10 | Note that the default settings in the Makefile assume you have OpenSSL 11 | installed on your system. OpenSSL has a considerably faster SHA1 12 | implementation than the C or i386 assembler code included in sha1.c. If you 13 | don't have OpenSSL on your system ... install it. It's at www.openssl.org. 14 | 15 | If you don't want to install OpenSSL and don't mind a ~25 performance 16 | performance hit, edit the Makefile such that the line with "-DOPENSSL" is 17 | commented out, and uncomment the line with "-Di386_ASM". 18 | -------------------------------------------------------------------------------- /CVS/Entries: -------------------------------------------------------------------------------- 1 | /AUTHORS/1.1.1.1/Tue Nov 2 11:43:30 2004// 2 | /CHANGELOG/1.1.1.1/Tue Nov 2 11:43:30 2004// 3 | /COPYING/1.1.1.1/Tue Nov 2 11:43:30 2004// 4 | /INSTALL/1.1.1.1/Tue Nov 2 11:43:30 2004// 5 | /Makefile/1.1.1.1/Tue Nov 2 11:43:30 2004// 6 | /README/1.2/Tue Nov 2 11:49:03 2004// 7 | /TODO/1.1.1.1/Tue Nov 2 11:43:30 2004// 8 | /WISHLIST/1.1.1.1/Tue Nov 2 11:43:30 2004// 9 | /common.h/1.1.1.1/Tue Nov 2 11:43:30 2004// 10 | /cowpatty.c/1.2/Tue Nov 2 11:46:42 2004// 11 | /cowpatty.h/1.1.1.1/Tue Nov 2 11:43:30 2004// 12 | /dict/1.1.1.1/Tue Nov 2 11:43:30 2004// 13 | /eap-test.dump/1.1.1.1/Tue Nov 2 11:43:30 2004// 14 | /md5.c/1.1.1.1/Tue Nov 2 11:43:30 2004// 15 | /md5.h/1.1.1.1/Tue Nov 2 11:43:30 2004// 16 | /sha1.c/1.1.1.1/Tue Nov 2 11:43:30 2004// 17 | /sha1.h/1.1.1.1/Tue Nov 2 11:43:30 2004// 18 | /utils.c/1.1.1.1/Tue Nov 2 11:43:30 2004// 19 | /utils.h/1.1.1.1/Tue Nov 2 11:43:30 2004// 20 | /FAQ/1.2/Tue Nov 2 11:55:43 2004// 21 | D 22 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * coWPAtty - Brute-force dictionary attack against WPA-PSK. 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: utils.h,v 1.1.1.1 2004/11/02 11:43:30 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 | /* 20 | * Significant code is graciously taken from the following: 21 | * wpa_supplicant by Jouni Malinen. This tool would have been MUCH more 22 | * difficult for me if not for this code. Thanks Jouni. 23 | */ 24 | 25 | 26 | /* Prototypes */ 27 | void lamont_hdump(unsigned char *bp, unsigned int length); 28 | int IsBlank(char *s); 29 | char *printmac(unsigned char *mac); 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ################################## 2 | # Well, I may be doing stupid things with make 3 | # OK, it was Makefile stupid'ness 4 | # I don't really understand what the hell I am doing with Make, I'm 5 | # just copying other files and seeing what works. 6 | # heh 7 | # i think thats all anyone does 8 | # make is a twisted beast 9 | ################################## 10 | LDLIBS = -lpcap 11 | CFLAGS = -pipe -Wall -DOPENSSL -O3 12 | LDLIBS += -lcrypto 13 | #CFLAGS = -g3 -ggdb -pipe -Wall -Di386_ASM 14 | #CFLAGS = -g3 -ggdb -pipe -Wall 15 | #CFLAGS += -g3 -ggdb 16 | #CFLAGS += -static 17 | PROGOBJ = md5.o sha1.o utils.o cowpatty.o 18 | PROG = cowpatty 19 | 20 | all: $(PROGOBJ) $(PROG) 21 | 22 | cowpatty: common.h md5.c md5.h sha1.h cowpatty.c cowpatty.h sha1.c \ 23 | sha1.h utils.c utils.h 24 | $(CC) $(CFLAGS) cowpatty.c -o cowpatty utils.o md5.o sha1.o $(LDLIBS) 25 | 26 | utils: utils.c utils.h 27 | $(CC) $(CFLAGS) utils.c -c 28 | 29 | md5: md5.c md5.h 30 | $(CC) $(CFLAGS) md5.c -c 31 | 32 | sha1: sha1.c sha1.h 33 | $(CC) $(CFLAGS) sha1.c -c 34 | 35 | clean: 36 | $(RM) $(PROGOBJ) $(PROG) *~ 37 | 38 | strip: 39 | @ls -l $(PROG) 40 | @strip $(PROG) 41 | @ls -l $(PROG) 42 | 43 | love: 44 | @echo "Not right now, I have a headache." 45 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Noc 02 2004 Changed name to coWPAtty, thanks T. Brian Granier for the tip. 2 | Oct 12 2004 Fixed bug that occured from the lack of a multicast key delivery 3 | following the four-way handshake. Thanks Seth Fogie for the caps. 4 | Sep 22 2004 Fixed bug in parsing frames that caused the SPA to be incorrectly 5 | reported. 6 | Sep 12 2004 Removed code to load words into memory before processing. Added 7 | functionality to read words from STDIN to interoperate with John 8 | the Ripper or other tools. 9 | Aug 21 2004 Fixed logic to handle incomplete four-way TKIP exchanges with an 10 | error message and exit. 11 | Aug 20 2004 Added Makefile option to use OpenSSL's SHA1 functions instead of 12 | the assembler code - big performance boost from 4.2 to 9.09 13 | passphrases/second. P4 3GHz gets ~47.4 passphrases/second. 14 | Aug 19 2004 Optimized hmac-sha1 handling specific to pbdfk2 by caching 15 | repetitive values. Resulted in 25% performance gain. 16 | Aug 18 2004 Load words into memory instead of reverting to a read for each 17 | new word. Minor performance gain. 18 | Aug 11 2004 Merged patch from dragorn to use i386-optimized code from Ted 19 | Krovetz. My system's performance went from 2.37 passphrases/sec to 20 | 3.13/sec. Thanks dragorn! 21 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * coWPAtty - Brute-force dictionary attack against WPA-PSK. 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: common.h,v 1.1.1.1 2004/11/02 11:43:30 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 | /* 20 | * Significant code is graciously taken from the following: 21 | * wpa_supplicant by Jouni Malinen. This tool would have been MUCH more 22 | * difficult for me if not for this code. Thanks Jouni. 23 | */ 24 | 25 | 26 | #ifndef COMMON_H 27 | #define COMMON_H 28 | 29 | #include 30 | #include 31 | #if __BYTE_ORDER == __LITTLE_ENDIAN 32 | #define le_to_host16(n) (n) 33 | #define host_to_le16(n) (n) 34 | #define be_to_host16(n) bswap_16(n) 35 | #define host_to_be16(n) bswap_16(n) 36 | #else 37 | #define le_to_host16(n) bswap_16(n) 38 | #define host_to_le16(n) bswap_16(n) 39 | #define be_to_host16(n) (n) 40 | #define host_to_be16(n) (n) 41 | #endif 42 | 43 | #ifndef ETH_ALEN 44 | #define ETH_ALEN 6 45 | #endif 46 | 47 | #include 48 | typedef uint64_t u64; 49 | typedef uint32_t u32; 50 | typedef uint16_t u16; 51 | typedef uint8_t u8; 52 | typedef int64_t s64; 53 | typedef int32_t s32; 54 | typedef int16_t s16; 55 | typedef int8_t s8; 56 | 57 | #endif /* COMMON_H */ 58 | -------------------------------------------------------------------------------- /md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * coWPAtty - Brute-force dictionary attack against WPA-PSK. 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: md5.h,v 1.1.1.1 2004/11/02 11:43:30 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 | /* 20 | * Significant code is graciously taken from the following: 21 | * wpa_supplicant by Jouni Malinen. This tool would have been MUCH more 22 | * difficult for me if not for this code. Thanks Jouni. 23 | */ 24 | 25 | 26 | #ifndef MD5_H 27 | #define MD5_H 28 | 29 | #ifdef OPENSSL 30 | 31 | #include 32 | 33 | #define MD5Init MD5_Init 34 | #define MD5Update MD5_Update 35 | #define MD5Final MD5_Final 36 | #define MD5Transform MD5_Transform 37 | 38 | #define MD5_MAC_LEN MD5_DIGEST_LENGTH 39 | 40 | #else /* OPENSSL */ 41 | 42 | #define MD5_MAC_LEN 16 43 | 44 | struct MD5Context { 45 | u32 buf[4]; 46 | u32 bits[2]; 47 | u8 in[64]; 48 | }; 49 | 50 | void MD5Init(struct MD5Context *context); 51 | void MD5Update(struct MD5Context *context, unsigned char const *buf, 52 | unsigned len); 53 | void MD5Final(unsigned char digest[16], struct MD5Context *context); 54 | void MD5Transform(u32 buf[4], u32 const in[16]); 55 | 56 | typedef struct MD5Context MD5_CTX; 57 | 58 | #endif /* OPENSSL */ 59 | 60 | 61 | void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); 62 | void hmac_md5_vector(u8 *key, size_t key_len, size_t num_elem, 63 | u8 *addr[], size_t *len, u8 *mac); 64 | void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); 65 | 66 | #endif /* MD5_H */ 67 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * coWPAtty - Brute-force dictionary attack against WPA-PSK. 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: sha1.h,v 1.1.1.1 2004/11/02 11:43:30 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 | /* 20 | * Significant code is graciously taken from the following: 21 | * wpa_supplicant by Jouni Malinen. This tool would have been MUCH more 22 | * difficult for me if not for this code. Thanks Jouni. 23 | */ 24 | 25 | 26 | #ifndef SHA1_H 27 | #define SHA1_H 28 | 29 | #ifdef OPENSSL 30 | 31 | #include 32 | 33 | #define SHA1_CTX SHA_CTX 34 | #define SHA1Init SHA1_Init 35 | #define SHA1Update SHA1_Update 36 | #define SHA1Final SHA1_Final 37 | #define SHA1Transform SHA1_Transform 38 | #define SHA1_MAC_LEN SHA_DIGEST_LENGTH 39 | 40 | #else /* OPENSSL */ 41 | 42 | #define SHA1_MAC_LEN 20 43 | 44 | typedef struct { 45 | u32 state[5]; 46 | u32 count[2]; 47 | unsigned char buffer[64]; 48 | } SHA1_CTX; 49 | 50 | void SHA1Init(SHA1_CTX *context); 51 | void SHA1Update(SHA1_CTX *context, unsigned char *data, u32 len); 52 | void SHA1Final(unsigned char digest[20], SHA1_CTX* context); 53 | void SHA1Transform(u32 state[5], u32 state_out[5], unsigned char buffer[64]); 54 | 55 | #endif /* OPENSSL */ 56 | 57 | #define USECACHED 1 58 | #define NOCACHED 0 59 | 60 | typedef struct { 61 | unsigned char k_ipad[65]; 62 | unsigned char k_opad[65]; 63 | unsigned char k_ipad_set; 64 | unsigned char k_opad_set; 65 | } SHA1_CACHE; 66 | 67 | void sha1_mac(unsigned char *key, unsigned int key_len, 68 | unsigned char *data, unsigned int data_len, 69 | unsigned char *mac); 70 | void hmac_sha1_vector(unsigned char *key, unsigned int key_len, 71 | size_t num_elem, unsigned char *addr[], 72 | unsigned int *len, unsigned char *mac, int usecached); 73 | void hmac_sha1(unsigned char *key, unsigned int key_len, 74 | unsigned char *data, unsigned int data_len, 75 | unsigned char *mac, int usecached); 76 | void sha1_prf(unsigned char *key, unsigned int key_len, 77 | char *label, unsigned char *data, unsigned int data_len, 78 | unsigned char *buf, size_t buf_len); 79 | void pbkdf2_sha1(char *passphrase, char *ssid, size_t ssid_len, int iterations, 80 | unsigned char *buf, size_t buflen, int usecached); 81 | void sha1_transform(u8 *state, u8 data[64]); 82 | 83 | #endif /* SHA1_H */ 84 | -------------------------------------------------------------------------------- /FAQ: -------------------------------------------------------------------------------- 1 | coWPAtty - Brute-force dictionary attack against WPA-PSK. 2 | 3 | Copyright(c) 2004, Joshua Wright 4 | 5 | FAQ 6 | 7 | Please send questions to the author, and I'll do my best to update this file 8 | to answer common questions. 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | Q: Why is it taking so long to test password entries for the correct WPA-PSK 13 | key? 14 | A: The design of the WPA-PSK algorithms is such that it is difficult to mount 15 | an effective dictionary attack. When mounting a dictionary attack, the 16 | passphrase we are testing has to be hashed with 4096 iterations of the 17 | HMAC-SHA1 algorithm (which is really 8192 full SHA1 invocations). This 18 | takes a long time, and has to be repeated for each word in the dictionary 19 | file. 20 | 21 | Q: What kind of performance can I expect with coWPAtty? 22 | A: I've done my best to optimize the code to squeeze out as much performance as 23 | possible. The OpenSSL SHA1 code is faster then the C and i386-assembler 24 | implementations that are included with the tool, and the default option in 25 | the Makefile. Here are the results from the two systems I use for 26 | development and testing: 27 | 28 | Processor: Intel Pentium 3 450Mhz, 897.84 bogomips, 9.8 passphrases/second 29 | Processor: Intel Pentium 4 3.8GHz, 5570.56 bogomips, 69.3 passphrases/second 30 | 31 | Q: How can I accelerate the dictionary cracking process? 32 | A: Make sure you are using the OpenSSL libraries on your system (openssl.org). 33 | If you are running an OpenSSL package that came with your Linux vendor, try 34 | downloading and compile your own local version, using optimizations for your 35 | processor. Don't expect this to result in a major performance increase 36 | though. 37 | The best thing to do is run coWPAtty on the system with the fastest 38 | processor you have access to. If you have success running coWPAtty on 39 | systems other than Intel 32-bit systems, please drop me a line. 40 | Alternatively, you can distribute the cracking load across multiple systems. 41 | Simply split the dictionary file into multiple pieces, and distribute the 42 | pieces to each system you want to use in the cracking process, along with a 43 | copy of the code and the capture file. 44 | If you want to support me making coWPAtty faster, see the WISHLIST file. 45 | 46 | Q: My passphrase isn't reported by coWPAtty, even though I know it's in the 47 | dictionary file. What gives? 48 | A: Make sure you have supplied the correct SSID on the command-line. An 49 | incorrect SSID will cause coWPAtty to be unable to identify the correct 50 | passphrase. 51 | 52 | Q: Is the SSID case-sensitive? 53 | A: Yes. Be certain you have the correct case for the SSID. 54 | 55 | Q: Why don't you add code to automatically cull the SSID from beacon frames? 56 | A: Too lazy. Send me a patch. 57 | 58 | Q: What is the pertinent information for the sample capture file? 59 | A: Use the following information for the sample WPA four-way handshake in the 60 | eap-test.dump file: 61 | 62 | SSID: "somethingclever" 63 | Passphrase: "family movie night" 64 | 65 | Q: Does your choice of the name coWPAtty reflect your feelings about the IEEE 66 | 802.11i specification? 67 | A: No, not at all. In fact, the coWPAtty name was selected to reflect the 68 | quality of this tool. The IEEE 802.11i committee did a good job designing 69 | TKIP with the problems with paucity of processing capacity and desire to 70 | be applied with a software upgrade to existing hardware. The use of the 71 | pbkdf2 algorithm to hash the PSK was a good call - it makes dictionary 72 | attacks such as this one much less effective. 73 | 74 | Q: What's up with Ken Jennings? 75 | A: That's what I'd like to know too! Maybe he can take a look at this code for 76 | me when he's not busy kicking everyone's ass on Jeopardy. 77 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ### This is just a holding for the CoWPAtty code. 2 | 3 | coWPAtty - Brute-force dictionary attack against WPA-PSK. 4 | 5 | Copyright(c) 2004, Joshua Wright 6 | 7 | $Id: README,v 1.2 2004/11/02 11:49:03 jwright Exp $ 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | INTRO 12 | 13 | Right off the bat, this code isn't very useful. The PBKDF2 function makes 14 | 4096 SHA-1 passes for each passphrase, which takes quite a bit of time. On 15 | my Pentium II development system, I'm getting ~4 passphrases/second. 16 | The SHA-1 code I'm using has been optimized to the best of my ability (which 17 | isn't saying that much), but I doubt if it would be possible to optimize it 18 | such that the tool experiences an exponential performance increase. 19 | 20 | However, if you are auditing WPA-PSK networks, you can use this tool to 21 | identify weak passphrases that were used to generate the PMK. Supply a 22 | libpcap capture file that includes the 4-way handshake, a dictionary file of 23 | passphrases to guess with, and the SSID for the network: 24 | 25 | $ ./cowpatty -r eap-test.dump -f dict -s somethingclever 26 | coWPAtty 2.0 - WPA-PSK dictionary attack. 27 | 28 | Collected all necessary data to mount crack against passphrase. 29 | Loading words into memory, please be patient ... Done (10201 words). 30 | Starting dictionary attack. Please be patient. 31 | [1000] [2000] [3000] [4000] 32 | The PSK is "family movie night". 33 | 34 | 4087 passphrases tested in 59.05 seconds: 69.22 passphrases/second 35 | $ 36 | 37 | The files "dict" and "eap-test.dump" are included with this distribution 38 | for testing purposes. 39 | 40 | This tool can also accept dictionary words from STDIN, allowing us to utilize 41 | a tool such as John the Ripper to create lots of word permutations from a 42 | dictionary file: 43 | 44 | $ john -wordfile:dictfile -rules -session:johnrestore.dat -stdout:63 | \ 45 | cowpatty -r eap-test.dump -f - -s somethingclever 46 | 47 | In the default configuration of John the Ripper, common permutations of 48 | dictionary words will be sent as potential passwords to coWPAtty. For 49 | example, here is a list of the words John will create from the input word 50 | "password": 51 | 52 | jwright@mercury:~$ echo password >word 53 | jwright@mercury:~$ john -session:/tmp/delme -wordfile:word -rules -stdout 54 | password 55 | Password 56 | passwords 57 | password1 58 | Password1 59 | drowssap 60 | 1password 61 | PASSWORD 62 | password2 63 | password! 64 | password3 65 | password7 66 | password9 67 | password5 68 | password4 69 | password8 70 | password6 71 | password0 72 | password. 73 | password? 74 | psswrd 75 | drowssaP 76 | Drowssap 77 | passworD 78 | 2password 79 | 4password 80 | Password2 81 | Password! 82 | Password3 83 | Password9 84 | Password5 85 | Password7 86 | Password4 87 | Password6 88 | Password8 89 | Password. 90 | Password? 91 | Password0 92 | 3password 93 | 7password 94 | 9password 95 | 5password 96 | 6password 97 | 8password 98 | Passwords 99 | passworded 100 | passwording 101 | Passworded 102 | Passwording 103 | words: 49 time: 0:00:00:00 100% w/s: 49.00 current: Passwording 104 | jwright@mercury:~$ 105 | 106 | John the Ripper is available at http://www.openwall.com/john/. 107 | 108 | 109 | REFERENCE 110 | 111 | See Robert Moskowitz's paper "Weakness in Passphrase Choice in WPA Interface" 112 | for more information on WPA-PSK attacks at 113 | http://wifinetnews.com/archives/002452.html. 114 | 115 | 116 | THANKS 117 | 118 | My sincere thanks to dragorn for merging in the assembly SHA1 code, and to 119 | Randy Chou for advice on optimizing the pbkdf2 function. 120 | 121 | 122 | QUESTIONS, COMMENTS, CONCERNS 123 | 124 | Please contact jwright@hasborg.com with any questions, comments or concerns. 125 | My PGP key is located at http://home.jwu.edu/jwright/pgpkey.htm. 126 | 127 | -------------------------------------------------------------------------------- /cowpatty.h: -------------------------------------------------------------------------------- 1 | /* 2 | * coWPAtty - Brute-force dictionary attack against WPA-PSK. 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: cowpatty.h,v 1.1.1.1 2004/11/02 11:43:30 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 | /* 20 | * Significant code is graciously taken from the following: 21 | * wpa_supplicant by Jouni Malinen. This tool would have been MUCH more 22 | * difficult for me if not for this code. Thanks Jouni. 23 | */ 24 | 25 | 26 | #include "common.h" 27 | 28 | struct ieee802_1x_hdr { 29 | u8 version; 30 | u8 type; 31 | u16 length; 32 | /* followed by length octets of data */ 33 | } __attribute__ ((packed)); 34 | 35 | /* The 802.1x header indicates a version, type and length */ 36 | struct ieee8021x { 37 | u8 version; 38 | u8 type; 39 | u16 length; 40 | } __attribute__ ((packed)); 41 | 42 | 43 | #define MAXPASSLEN 63 44 | #define MEMORY_DICT 0 45 | #define STDIN_DICT 1 46 | #define EAPDOT1XOFFSET 4 47 | #define BIT(n) (1 << (n)) 48 | #define WPA_KEY_INFO_TYPE_MASK (BIT(0) | BIT(1) | BIT(2)) 49 | #define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) 50 | #define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) 51 | #define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ 52 | /* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ 53 | #define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5)) 54 | #define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 55 | #define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */ 56 | #define WPA_KEY_INFO_TXRX BIT(6) /* group */ 57 | #define WPA_KEY_INFO_ACK BIT(7) 58 | #define WPA_KEY_INFO_MIC BIT(8) 59 | #define WPA_KEY_INFO_SECURE BIT(9) 60 | #define WPA_KEY_INFO_ERROR BIT(10) 61 | #define WPA_KEY_INFO_REQUEST BIT(11) 62 | #define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */ 63 | #define WPA_NONCE_LEN 32 64 | #define WPA_REPLAY_COUNTER_LEN 8 65 | 66 | struct wpa_eapol_key { 67 | u8 type; 68 | u16 key_info; 69 | u16 key_length; 70 | u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; 71 | u8 key_nonce[WPA_NONCE_LEN]; 72 | u8 key_iv[16]; 73 | u8 key_rsc[8]; 74 | u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */ 75 | u8 key_mic[16]; 76 | u16 key_data_length; 77 | /* u8 key_data[0]; */ 78 | } __attribute__ ((packed)); 79 | 80 | 81 | struct wpa_ptk { 82 | u8 mic_key[16]; /* EAPOL-Key MIC Key (MK) */ 83 | u8 encr_key[16]; /* EAPOL-Key Encryption Key (EK) */ 84 | u8 tk1[16]; /* Temporal Key 1 (TK1) */ 85 | union { 86 | u8 tk2[16]; /* Temporal Key 2 (TK2) */ 87 | struct { 88 | u8 tx_mic_key[8]; 89 | u8 rx_mic_key[8]; 90 | } auth; 91 | } u; 92 | } __attribute__ ((packed)); 93 | 94 | struct user_opt { 95 | char ssid[256]; 96 | char dictfile[256]; 97 | char pcapfile[256]; 98 | int verbose; 99 | }; 100 | 101 | struct capture_data { 102 | char pcapfilename[256]; 103 | int pcaptype; 104 | int dot1x_offset; 105 | int l2type_offset; 106 | int dstmac_offset; 107 | int srcmac_offset; 108 | }; 109 | 110 | struct crack_data { 111 | u8 aa[6]; 112 | u8 spa[6]; 113 | u8 snonce[32]; 114 | u8 anonce[32]; 115 | u8 eapolframe[99]; /* Length the same for all packets? */ 116 | u8 keymic[16]; 117 | u8 aaset; 118 | u8 spaset; 119 | u8 snonceset; 120 | u8 anonceset; 121 | u8 keymicset; 122 | u8 eapolframeset; 123 | u8 replay_counter[8]; 124 | }; 125 | 126 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * coWPAtty - Brute-force dictionary attack against WPA-PSK. 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: utils.c,v 1.1.1.1 2004/11/02 11:43:30 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 | /* 20 | * Significant code is graciously taken from the following: 21 | * wpa_supplicant by Jouni Malinen. This tool would have been MUCH more 22 | * difficult for me if not for this code. Thanks Jouni. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include /* for ntohs() */ 34 | #include "utils.h" 35 | 36 | 37 | void lamont_hdump(unsigned char *bp, unsigned int length); 38 | char *printmac(unsigned char *mac); 39 | int IsBlank(char *s); 40 | 41 | /* A better version of hdump, from Lamont Granquist. Modified slightly 42 | by Fyodor (fyodor@DHP.com) */ 43 | void lamont_hdump(unsigned char *bp, unsigned int length) { 44 | 45 | /* stolen from tcpdump, then kludged extensively */ 46 | 47 | static const char asciify[] = "................................ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~................................................................................................................................."; 48 | 49 | const unsigned short *sp; 50 | const unsigned char *ap; 51 | unsigned int i, j; 52 | int nshorts, nshorts2; 53 | int padding; 54 | 55 | printf("\n\t"); 56 | padding = 0; 57 | sp = (unsigned short *)bp; 58 | ap = (unsigned char *)bp; 59 | nshorts = (unsigned int) length / sizeof(unsigned short); 60 | nshorts2 = (unsigned int) length / sizeof(unsigned short); 61 | i = 0; 62 | j = 0; 63 | while(1) { 64 | while (--nshorts >= 0) { 65 | printf(" %04x", ntohs(*sp)); 66 | sp++; 67 | if ((++i % 8) == 0) 68 | break; 69 | } 70 | if (nshorts < 0) { 71 | if ((length & 1) && (((i-1) % 8) != 0)) { 72 | printf(" %02x ", *(unsigned char *)sp); 73 | padding++; 74 | } 75 | nshorts = (8 - (nshorts2 - nshorts)); 76 | while(--nshorts >= 0) { 77 | printf(" "); 78 | } 79 | if (!padding) printf(" "); 80 | } 81 | printf(" "); 82 | 83 | while (--nshorts2 >= 0) { 84 | printf("%c%c", asciify[*ap], asciify[*(ap+1)]); 85 | ap += 2; 86 | if ((++j % 8) == 0) { 87 | printf("\n\t"); 88 | break; 89 | } 90 | } 91 | if (nshorts2 < 0) { 92 | if ((length & 1) && (((j-1) % 8) != 0)) { 93 | printf("%c", asciify[*ap]); 94 | } 95 | break; 96 | } 97 | } 98 | if ((length & 1) && (((i-1) % 8) == 0)) { 99 | printf(" %02x", *(unsigned char *)sp); 100 | printf(" %c", asciify[*ap]); 101 | } 102 | printf("\n"); 103 | } 104 | 105 | int IsBlank(char *s) { 106 | 107 | int len, i; 108 | if (s == NULL) { 109 | return(1); 110 | } 111 | 112 | len = strlen(s); 113 | 114 | if (len == 0) { 115 | return(1); 116 | } 117 | 118 | for (i=0; i < len; i++) { 119 | if (s[i] != ' ') { 120 | return(0); 121 | } 122 | } 123 | return(0); 124 | } 125 | 126 | char *printmac(unsigned char *mac) { 127 | static char macstring[18]; 128 | 129 | memset(&macstring, 0, sizeof(macstring)); 130 | (void)snprintf(macstring, sizeof(macstring), 131 | "%02x:%02x:%02x:%02x:%02x:%02x", 132 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 133 | return(macstring); 134 | } 135 | 136 | -------------------------------------------------------------------------------- /md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MD5 hash implementation and interface functions 3 | * Copyright (c) 2003-2004, Jouni Malinen 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 version 2 as 7 | * published by the Free Software Foundation. 8 | * 9 | * Alternatively, this software may be distributed under the terms of BSD 10 | * license. 11 | * 12 | * See README and COPYING for more details. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #if __BYTE_ORDER == __BIG_ENDIAN 21 | #define WORDS_BIGENDIAN 22 | #endif 23 | 24 | #ifdef OPENSSL 25 | #include 26 | #endif 27 | 28 | #include "common.h" 29 | #include "md5.h" 30 | 31 | 32 | void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) 33 | { 34 | MD5_CTX context; 35 | MD5Init(&context); 36 | MD5Update(&context, key, key_len); 37 | MD5Update(&context, data, data_len); 38 | MD5Update(&context, key, key_len); 39 | MD5Final(mac, &context); 40 | } 41 | 42 | 43 | /* HMAC code is based on RFC 2104 */ 44 | void hmac_md5_vector(u8 *key, size_t key_len, size_t num_elem, 45 | u8 *addr[], size_t *len, u8 *mac) 46 | { 47 | MD5_CTX context; 48 | u8 k_ipad[65]; /* inner padding - key XORd with ipad */ 49 | u8 k_opad[65]; /* outer padding - key XORd with opad */ 50 | u8 tk[16]; 51 | int i; 52 | 53 | /* if key is longer than 64 bytes reset it to key = MD5(key) */ 54 | if (key_len > 64) { 55 | MD5Init(&context); 56 | MD5Update(&context, key, key_len); 57 | MD5Final(tk, &context); 58 | 59 | key = tk; 60 | key_len = 16; 61 | } 62 | 63 | /* the HMAC_MD5 transform looks like: 64 | * 65 | * MD5(K XOR opad, MD5(K XOR ipad, text)) 66 | * 67 | * where K is an n byte key 68 | * ipad is the byte 0x36 repeated 64 times 69 | * opad is the byte 0x5c repeated 64 times 70 | * and text is the data being protected */ 71 | 72 | /* start out by storing key in pads */ 73 | memset(k_ipad, 0, sizeof(k_ipad)); 74 | memset(k_opad, 0, sizeof(k_opad)); 75 | memcpy(k_ipad, key, key_len); 76 | memcpy(k_opad, key, key_len); 77 | 78 | /* XOR key with ipad and opad values */ 79 | for (i = 0; i < 64; i++) { 80 | k_ipad[i] ^= 0x36; 81 | k_opad[i] ^= 0x5c; 82 | } 83 | 84 | /* perform inner MD5 */ 85 | MD5Init(&context); /* init context for 1st pass */ 86 | MD5Update(&context, k_ipad, 64); /* start with inner pad */ 87 | /* then text of datagram; all fragments */ 88 | for (i = 0; i < num_elem; i++) { 89 | MD5Update(&context, addr[i], len[i]); 90 | } 91 | MD5Final(mac, &context); /* finish up 1st pass */ 92 | 93 | /* perform outer MD5 */ 94 | MD5Init(&context); /* init context for 2nd pass */ 95 | MD5Update(&context, k_opad, 64); /* start with outer pad */ 96 | MD5Update(&context, mac, 16); /* then results of 1st hash */ 97 | MD5Final(mac, &context); /* finish up 2nd pass */ 98 | } 99 | 100 | 101 | void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) 102 | { 103 | hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); 104 | } 105 | 106 | 107 | #ifndef OPENSSL 108 | 109 | /* ===== start - public domain MD5 implementation ===== */ 110 | /* 111 | * This code implements the MD5 message-digest algorithm. 112 | * The algorithm is due to Ron Rivest. This code was 113 | * written by Colin Plumb in 1993, no copyright is claimed. 114 | * This code is in the public domain; do with it what you wish. 115 | * 116 | * Equivalent code is available from RSA Data Security, Inc. 117 | * This code has been tested against that, and is equivalent, 118 | * except that you don't need to include two pages of legalese 119 | * with every copy. 120 | * 121 | * To compute the message digest of a chunk of bytes, declare an 122 | * MD5Context structure, pass it to MD5Init, call MD5Update as 123 | * needed on buffers full of bytes, and then call MD5Final, which 124 | * will fill a supplied 16-byte array with the digest. 125 | */ 126 | 127 | #ifndef WORDS_BIGENDIAN 128 | #define byteReverse(buf, len) /* Nothing */ 129 | #else 130 | void byteReverse(unsigned char *buf, unsigned longs); 131 | 132 | /* 133 | * Note: this code is harmless on little-endian machines. 134 | */ 135 | void byteReverse(unsigned char *buf, unsigned longs) 136 | { 137 | u32 t; 138 | do { 139 | t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | 140 | ((unsigned) buf[1] << 8 | buf[0]); 141 | *(u32 *) buf = t; 142 | buf += 4; 143 | } while (--longs); 144 | } 145 | #endif 146 | 147 | /* 148 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious 149 | * initialization constants. 150 | */ 151 | void MD5Init(struct MD5Context *ctx) 152 | { 153 | ctx->buf[0] = 0x67452301; 154 | ctx->buf[1] = 0xefcdab89; 155 | ctx->buf[2] = 0x98badcfe; 156 | ctx->buf[3] = 0x10325476; 157 | 158 | ctx->bits[0] = 0; 159 | ctx->bits[1] = 0; 160 | } 161 | 162 | /* 163 | * Update context to reflect the concatenation of another buffer full 164 | * of bytes. 165 | */ 166 | void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) 167 | { 168 | u32 t; 169 | 170 | /* Update bitcount */ 171 | 172 | t = ctx->bits[0]; 173 | if ((ctx->bits[0] = t + ((u32) len << 3)) < t) 174 | ctx->bits[1]++; /* Carry from low to high */ 175 | ctx->bits[1] += len >> 29; 176 | 177 | t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ 178 | 179 | /* Handle any leading odd-sized chunks */ 180 | 181 | if (t) { 182 | unsigned char *p = (unsigned char *) ctx->in + t; 183 | 184 | t = 64 - t; 185 | if (len < t) { 186 | memcpy(p, buf, len); 187 | return; 188 | } 189 | memcpy(p, buf, t); 190 | byteReverse(ctx->in, 16); 191 | MD5Transform(ctx->buf, (u32 *) ctx->in); 192 | buf += t; 193 | len -= t; 194 | } 195 | /* Process data in 64-byte chunks */ 196 | 197 | while (len >= 64) { 198 | memcpy(ctx->in, buf, 64); 199 | byteReverse(ctx->in, 16); 200 | MD5Transform(ctx->buf, (u32 *) ctx->in); 201 | buf += 64; 202 | len -= 64; 203 | } 204 | 205 | /* Handle any remaining bytes of data. */ 206 | 207 | memcpy(ctx->in, buf, len); 208 | } 209 | 210 | /* 211 | * Final wrapup - pad to 64-byte boundary with the bit pattern 212 | * 1 0* (64-bit count of bits processed, MSB-first) 213 | */ 214 | void MD5Final(unsigned char digest[16], struct MD5Context *ctx) 215 | { 216 | unsigned count; 217 | unsigned char *p; 218 | 219 | /* Compute number of bytes mod 64 */ 220 | count = (ctx->bits[0] >> 3) & 0x3F; 221 | 222 | /* Set the first char of padding to 0x80. This is safe since there is 223 | always at least one byte free */ 224 | p = ctx->in + count; 225 | *p++ = 0x80; 226 | 227 | /* Bytes of padding needed to make 64 bytes */ 228 | count = 64 - 1 - count; 229 | 230 | /* Pad out to 56 mod 64 */ 231 | if (count < 8) { 232 | /* Two lots of padding: Pad the first block to 64 bytes */ 233 | memset(p, 0, count); 234 | byteReverse(ctx->in, 16); 235 | MD5Transform(ctx->buf, (u32 *) ctx->in); 236 | 237 | /* Now fill the next block with 56 bytes */ 238 | memset(ctx->in, 0, 56); 239 | } else { 240 | /* Pad block to 56 bytes */ 241 | memset(p, 0, count - 8); 242 | } 243 | byteReverse(ctx->in, 14); 244 | 245 | /* Append length in bits and transform */ 246 | ((u32 *) ctx->in)[14] = ctx->bits[0]; 247 | ((u32 *) ctx->in)[15] = ctx->bits[1]; 248 | 249 | MD5Transform(ctx->buf, (u32 *) ctx->in); 250 | byteReverse((unsigned char *) ctx->buf, 4); 251 | memcpy(digest, ctx->buf, 16); 252 | memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ 253 | } 254 | 255 | #ifndef ASM_MD5 256 | 257 | /* The four core functions - F1 is optimized somewhat */ 258 | 259 | /* #define F1(x, y, z) (x & y | ~x & z) */ 260 | #define F1(x, y, z) (z ^ (x & (y ^ z))) 261 | #define F2(x, y, z) F1(z, x, y) 262 | #define F3(x, y, z) (x ^ y ^ z) 263 | #define F4(x, y, z) (y ^ (x | ~z)) 264 | 265 | /* This is the central step in the MD5 algorithm. */ 266 | #define MD5STEP(f, w, x, y, z, data, s) \ 267 | ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) 268 | 269 | /* 270 | * The core of the MD5 algorithm, this alters an existing MD5 hash to 271 | * reflect the addition of 16 longwords of new data. MD5Update blocks 272 | * the data and converts bytes into longwords for this routine. 273 | */ 274 | void MD5Transform(u32 buf[4], u32 const in[16]) 275 | { 276 | register u32 a, b, c, d; 277 | 278 | a = buf[0]; 279 | b = buf[1]; 280 | c = buf[2]; 281 | d = buf[3]; 282 | 283 | MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); 284 | MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); 285 | MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); 286 | MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); 287 | MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); 288 | MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); 289 | MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); 290 | MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); 291 | MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); 292 | MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); 293 | MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); 294 | MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); 295 | MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); 296 | MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); 297 | MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); 298 | MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); 299 | 300 | MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); 301 | MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); 302 | MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); 303 | MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); 304 | MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); 305 | MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); 306 | MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); 307 | MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); 308 | MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); 309 | MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); 310 | MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); 311 | MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); 312 | MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); 313 | MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); 314 | MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); 315 | MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); 316 | 317 | MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); 318 | MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); 319 | MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); 320 | MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); 321 | MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); 322 | MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); 323 | MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); 324 | MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); 325 | MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); 326 | MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); 327 | MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); 328 | MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); 329 | MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); 330 | MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); 331 | MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); 332 | MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); 333 | 334 | MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); 335 | MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); 336 | MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); 337 | MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); 338 | MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); 339 | MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); 340 | MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); 341 | MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); 342 | MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); 343 | MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); 344 | MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); 345 | MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); 346 | MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); 347 | MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); 348 | MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); 349 | MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); 350 | 351 | buf[0] += a; 352 | buf[1] += b; 353 | buf[2] += c; 354 | buf[3] += d; 355 | } 356 | 357 | #endif 358 | /* ===== end - public domain MD5 implementation ===== */ 359 | 360 | #endif /* OPENSSL */ 361 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /cowpatty.c: -------------------------------------------------------------------------------- 1 | /* 2 | * coWPAtty - Brute-force dictionary attack against WPA-PSK. 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: cowpatty.c,v 1.2 2004/11/02 11:46:42 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 | /* 20 | * Significant code is graciously taken from the following: 21 | * wpa_supplicant by Jouni Malinen. This tool would have been MUCH more 22 | * difficult for me if not for this code. Thanks Jouni. 23 | */ 24 | 25 | /* 26 | * Right off the bat, this code isn't very useful. The PBKDF2 function makes 27 | * 4096 SHA-1 passes for each passphrase, which takes quite a bit of time. On 28 | * my Pentium II development system, I'm getting ~2.5 passphrases/second. 29 | * I've done my best to optimize the PBKDF2 function, but it's still pretty 30 | * slow. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "cowpatty.h" 45 | #include "common.h" 46 | #include "utils.h" 47 | #include "sha1.h" 48 | #include "md5.h" 49 | 50 | #define PROGNAME "cowpatty" 51 | #define VER "2.0" 52 | #define MAXPASSPHRASE 256 53 | #define DOT1X_LLCTYPE "\x88\x8e" 54 | #define DOT11_TYPEDATA "\x08" 55 | 56 | /* Globals */ 57 | pcap_t *p = NULL; 58 | unsigned char *packet; 59 | struct pcap_pkthdr *h; 60 | char errbuf[PCAP_ERRBUF_SIZE]; 61 | int sig=0; /* Used for handling signals */ 62 | char *words; 63 | 64 | /* Prototypes */ 65 | void wpa_pmk_to_ptk(u8 *pmk, u8 *addr1, u8 *addr2, 66 | u8 *nonce1, u8 *nonce2, u8 *ptk, size_t ptk_len); 67 | void hexdump(unsigned char *data, int len); 68 | void usage(char *message); 69 | void testopts(struct user_opt *opt); 70 | void cleanup(); 71 | void parseopts(struct user_opt *opt, int argc, char **argv); 72 | void closepcap(struct capture_data *capdata); 73 | void handle_dot1x(struct crack_data *cdata, struct capture_data *capdata); 74 | void dump_all_fields(struct crack_data cdata); 75 | void printstats(struct timeval start, struct timeval end, 76 | unsigned long int wordcount); 77 | int nextword(char *word, FILE *fp); 78 | 79 | 80 | void usage(char *message) { 81 | 82 | if (strlen(message) > 0) { 83 | printf("%s: %s\n", PROGNAME, message); 84 | } 85 | 86 | printf("Usage: %s [options]\n", PROGNAME); 87 | printf("\n" 88 | "\t-f \tDictionary file\n" 89 | "\t-r \tPacket capture file\n" 90 | "\t-s \tNetwork SSID\n" 91 | "\t-h \tPrint this help information and exit\n" 92 | "\t-v \tPrint verbose information (more -v for more verbosity)\n" 93 | "\t-V \tPrint program version and exit\n" 94 | "\n"); 95 | } 96 | 97 | void cleanup() { 98 | /* lame-o-meter++ */ 99 | sig=1; 100 | } 101 | 102 | void wpa_pmk_to_ptk(u8 *pmk, u8 *addr1, u8 *addr2, 103 | u8 *nonce1, u8 *nonce2, u8 *ptk, size_t ptk_len) 104 | { 105 | u8 data[2 * ETH_ALEN + 2 * 32]; 106 | 107 | memset(&data, 0, sizeof(data)); 108 | 109 | /* PTK = PRF-X(PMK, "Pairwise key expansion", 110 | * Min(AA, SA) || Max(AA, SA) || 111 | * Min(ANonce, SNonce) || Max(ANonce, SNonce)) */ 112 | 113 | if (memcmp(addr1, addr2, ETH_ALEN) < 0) { 114 | memcpy(data, addr1, ETH_ALEN); 115 | memcpy(data + ETH_ALEN, addr2, ETH_ALEN); 116 | } else { 117 | memcpy(data, addr2, ETH_ALEN); 118 | memcpy(data + ETH_ALEN, addr1, ETH_ALEN); 119 | } 120 | 121 | if (memcmp(nonce1, nonce2, 32) < 0) { 122 | memcpy(data + 2 * ETH_ALEN, nonce1, 32); 123 | memcpy(data + 2 * ETH_ALEN + 32, nonce2, 32); 124 | } else { 125 | memcpy(data + 2 * ETH_ALEN, nonce2, 32); 126 | memcpy(data + 2 * ETH_ALEN + 32, nonce1, 32); 127 | } 128 | 129 | sha1_prf(pmk, 32, "Pairwise key expansion", data, sizeof(data), 130 | ptk, ptk_len); 131 | } 132 | 133 | 134 | void hexdump(unsigned char *data, int len) { 135 | int i; 136 | for (i=0; i < len; i++) { 137 | printf("%02x ", data[i]); 138 | } 139 | } 140 | 141 | void parseopts(struct user_opt *opt, int argc, char **argv) { 142 | 143 | int c; 144 | 145 | while((c = getopt(argc, argv, "f:r:s:hvV")) != EOF) { 146 | switch(c) { 147 | case 'f': 148 | strncpy(opt->dictfile, optarg, sizeof(opt->dictfile)); 149 | break; 150 | case 'r': 151 | strncpy(opt->pcapfile, optarg, sizeof(opt->pcapfile)); 152 | break; 153 | case 's': 154 | strncpy(opt->ssid, optarg, sizeof(opt->ssid)); 155 | break; 156 | case 'h': 157 | usage(""); 158 | exit(0); 159 | break; 160 | case 'v': 161 | opt->verbose++; 162 | break; 163 | case 'V': 164 | printf("$Id: cowpatty.c,v 1.2 2004/11/02 11:46:42 jwright Exp $\n"); 165 | exit(0); 166 | break; 167 | default: 168 | usage(""); 169 | exit(1); 170 | } 171 | } 172 | } 173 | 174 | 175 | void testopts(struct user_opt *opt) { 176 | struct stat teststat; 177 | 178 | /* test for required parameters */ 179 | if (IsBlank(opt->dictfile)) { 180 | usage("Must supply a list of passphrases in a file with -f.\n" 181 | "\t Use \"-f -\" to accept words on stdin."); 182 | exit(1); 183 | } 184 | 185 | if (IsBlank(opt->ssid)) { 186 | usage("Must supply the SSID for the network with -s"); 187 | exit(1); 188 | } 189 | 190 | if (IsBlank(opt->pcapfile)) { 191 | usage("Must supply a pcap file with -r"); 192 | exit(1); 193 | } 194 | 195 | /* Test that the files specified exist and are greater than 0 bytes */ 196 | if (strncmp(opt->dictfile, "-", 1) != 0) { 197 | if (stat(opt->dictfile, &teststat)) { 198 | usage("Could not stat the dictionary file. Check file path."); 199 | exit(1); 200 | } else if (teststat.st_size == 0) { 201 | usage("Empty dictionary file (0 bytes). Check file contents."); 202 | exit(1); 203 | } 204 | } 205 | 206 | if (stat(opt->pcapfile, &teststat)) { 207 | usage("Could not stat the pcap file. Check file path."); 208 | exit(1); 209 | } else if (teststat.st_size == 0) { 210 | usage("Empty pcap file (0 bytes). Check file contents."); 211 | exit(1); 212 | } 213 | } 214 | 215 | int openpcap(struct capture_data *capdata) { 216 | 217 | /* Assume for now it's a libpcap file */ 218 | p = pcap_open_offline(capdata->pcapfilename, errbuf); 219 | if (p == NULL) { 220 | perror("Unable to open capture file"); 221 | return(-1); 222 | } 223 | 224 | /* Determine link type */ 225 | capdata->pcaptype = pcap_datalink(p); 226 | 227 | /* Determine offset to EAP frame based on link type */ 228 | switch(capdata->pcaptype) { 229 | case DLT_NULL: 230 | case DLT_EN10MB: 231 | /* Standard ethernet header */ 232 | capdata->dot1x_offset = 14; 233 | capdata->l2type_offset = 12; 234 | capdata->dstmac_offset = 0; 235 | capdata->srcmac_offset = 6; 236 | break; 237 | case DLT_IEEE802_11: 238 | /* 24 bytes 802.11 header, 8 for 802.2 header */ 239 | capdata->dot1x_offset = 32; 240 | capdata->l2type_offset = 30; 241 | capdata->dstmac_offset = 4; 242 | capdata->srcmac_offset = 10; 243 | break; 244 | case DLT_PRISM_HEADER: 245 | /* 802.11 frames with AVS header, AVS header is 144 bytes */ 246 | capdata->dot1x_offset = 32+144; 247 | capdata->l2type_offset = 30+144; 248 | capdata->dstmac_offset = 4+144; 249 | capdata->srcmac_offset = 10+144; 250 | break; 251 | default: 252 | /* Unknown/unsupported pcap type */ 253 | return(1); 254 | } 255 | 256 | return(0); 257 | } 258 | 259 | void closepcap(struct capture_data *capdata) { 260 | 261 | /* Assume it's a libpcap file for now */ 262 | pcap_close(p); 263 | } 264 | 265 | /* Populates global *packet, returns status */ 266 | int getpacket(struct capture_data *capdata) { 267 | 268 | /* Assume it's a libpcap file for now */ 269 | int ret; 270 | ret = pcap_next_ex(p, &h, (const u_char **)&packet); 271 | return(ret); 272 | } 273 | 274 | void handle_dot1x(struct crack_data *cdata, struct capture_data *capdata) { 275 | struct ieee8021x *dot1xhdr; 276 | struct wpa_eapol_key *eapolkeyhdr; 277 | int eapolkeyoffset; 278 | int key_info, ver, index; 279 | 280 | /* We're going after the last three frames in the 4-way handshake. 281 | In the last frame of the TKIP exchange, the authenticator nonce is 282 | omitted. In cases where there is a unicast and a multicast key 283 | distributed, frame 4 will include the authenticator nonce. In some 284 | cases however, there is no multicast key distribution, so frame 4 has 285 | no authenticator nonce. For this reason, we need to capture information 286 | from the 2nd, 3rd and 4th frames to accommodate cases where there is no 287 | multicast key delivery. Suckage. 288 | */ 289 | 290 | dot1xhdr = (struct ieee8021x *)&packet[capdata->dot1x_offset]; 291 | eapolkeyoffset = capdata->dot1x_offset + sizeof(struct ieee8021x); 292 | eapolkeyhdr = (struct wpa_eapol_key *)&packet[eapolkeyoffset]; 293 | 294 | /* Bitwise fields in the key_info field of the EAPOL-Key header */ 295 | key_info = be_to_host16(eapolkeyhdr->key_info); 296 | ver = key_info & WPA_KEY_INFO_TYPE_MASK; 297 | index = key_info & WPA_KEY_INFO_KEY_INDEX_MASK; 298 | 299 | /* Check for EAPOL version 1, type EAPOL-Key */ 300 | if (dot1xhdr->version != 1 || dot1xhdr->type != 3) { 301 | return; 302 | } 303 | 304 | if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { 305 | /* Only support WPA-I in this version */ 306 | return; 307 | } 308 | 309 | /* Check for WPA key, and pairwise key type */ 310 | if (eapolkeyhdr->type != 254 || (key_info & WPA_KEY_INFO_KEY_TYPE) == 0) { 311 | return; 312 | } 313 | 314 | /* Check for frame 2 of the 4-way handshake */ 315 | if ((key_info & WPA_KEY_INFO_MIC) && (key_info & WPA_KEY_INFO_ACK) == 0 && 316 | (key_info & WPA_KEY_INFO_INSTALL) == 0 && 317 | eapolkeyhdr->key_data_length > 0) { 318 | /* All we need from this frame is the authenticator nonce */ 319 | memcpy(cdata->snonce, eapolkeyhdr->key_nonce, 320 | sizeof(cdata->snonce)); 321 | cdata->snonceset=1; 322 | 323 | } else if ( /* Check for frame 3 of the 4-way handshake */ 324 | (key_info & WPA_KEY_INFO_MIC) && (key_info & WPA_KEY_INFO_INSTALL) && 325 | (key_info & WPA_KEY_INFO_ACK)) { 326 | 327 | memcpy(cdata->spa, &packet[capdata->dstmac_offset], 328 | sizeof(cdata->spa)); 329 | memcpy(cdata->aa, &packet[capdata->srcmac_offset], 330 | sizeof(cdata->aa)); 331 | memcpy(cdata->anonce, eapolkeyhdr->key_nonce, 332 | sizeof(cdata->anonce)); 333 | cdata->aaset=1; 334 | cdata->spaset=1; 335 | cdata->anonceset=1; 336 | /* We save the replay counter value in the 3rd frame to match 337 | against the 4th frame of the four-way handshake */ 338 | memcpy(cdata->replay_counter, eapolkeyhdr->replay_counter, 8); 339 | 340 | } else if ( /* Check for frame 4 of the four-way handshake */ 341 | (key_info & WPA_KEY_INFO_MIC) && (key_info & WPA_KEY_INFO_ACK) == 0 && 342 | (key_info & WPA_KEY_INFO_INSTALL) == 0 && 343 | (memcmp(cdata->replay_counter, eapolkeyhdr->replay_counter, 8) == 0)) { 344 | 345 | memcpy(cdata->keymic, eapolkeyhdr->key_mic, sizeof(cdata->keymic)); 346 | memcpy(cdata->eapolframe, &packet[capdata->dot1x_offset], 347 | sizeof(cdata->eapolframe)); 348 | cdata->keymicset=1; 349 | cdata->eapolframeset=1; 350 | } 351 | } 352 | 353 | void dump_all_fields(struct crack_data cdata) { 354 | 355 | printf("AA is:"); 356 | lamont_hdump(cdata.aa, 6); 357 | printf("\n"); 358 | 359 | printf("SPA is:"); 360 | lamont_hdump(cdata.spa, 6); 361 | printf("\n"); 362 | 363 | printf("snonce is:"); 364 | lamont_hdump(cdata.snonce, 32); 365 | printf("\n"); 366 | 367 | printf("anonce is:"); 368 | lamont_hdump(cdata.anonce, 32); 369 | printf("\n"); 370 | 371 | printf("keymic is:"); 372 | lamont_hdump(cdata.keymic, 16); 373 | printf("\n"); 374 | 375 | printf("eapolframe is:"); 376 | lamont_hdump(cdata.eapolframe, 99); /* Bug in lamont_hdump makes this look 377 | wrong, only shows 98 bytes */ 378 | printf("\n"); 379 | 380 | } 381 | 382 | void printstats(struct timeval start, struct timeval end, 383 | unsigned long int wordcount) { 384 | 385 | float elapsed=0; 386 | 387 | if(end.tv_usec < start.tv_usec) { 388 | end.tv_sec -= 1; 389 | end.tv_usec += 1000000; 390 | } 391 | end.tv_sec -= start.tv_sec; 392 | end.tv_usec -= start.tv_usec; 393 | elapsed = end.tv_sec + end.tv_usec / 1000000.0; 394 | 395 | printf("\n%lu passphrases tested in %.2f seconds: %.2f passphrases/" 396 | "second\n", wordcount, elapsed, wordcount / elapsed); 397 | } 398 | 399 | int nextword(char *word, FILE *fp) { 400 | 401 | if (fgets(word, MAXPASSLEN+1, fp) == NULL) { 402 | return(-1); 403 | } 404 | 405 | /* Remove newline */ 406 | word[strlen(word)-1] = '\0'; 407 | 408 | if (feof(fp)) { 409 | return(-1); 410 | } 411 | 412 | return(strlen(word)); 413 | } 414 | 415 | 416 | 417 | int main(int argc, char **argv) { 418 | struct user_opt opt; 419 | struct crack_data cdata; 420 | struct capture_data capdata; 421 | struct wpa_eapol_key *eapkeypacket; 422 | u8 pmk[32]; 423 | u8 ptk[64]; 424 | u8 keymic[16]; 425 | u8 eapolkey_nomic[99]; 426 | struct wpa_ptk *ptkset; 427 | struct timeval start, end; 428 | int wordstested=0, fret=0; 429 | char passphrase[MAXPASSLEN+1]; 430 | FILE *fp; 431 | 432 | printf("%s %s - WPA-PSK dictionary attack. \n", 433 | PROGNAME, VER); 434 | 435 | memset(&opt, 0, sizeof(struct user_opt)); 436 | memset(&capdata, 0, sizeof(struct capture_data)); 437 | memset(&cdata, 0, sizeof(struct crack_data)); 438 | memset(&eapolkey_nomic, 0, sizeof(eapolkey_nomic)); 439 | 440 | /* Collect and test command-line arguments */ 441 | parseopts(&opt, argc, argv); 442 | testopts(&opt); 443 | printf("\n"); 444 | 445 | /* Open the dictionary file */ 446 | if (*opt.dictfile == '-') { 447 | printf("Using STDIN for words.\n"); 448 | fp = stdin; 449 | } else { 450 | fp = fopen(opt.dictfile, "r"); 451 | if (fp == NULL) { 452 | perror("fopen"); 453 | exit(-1); 454 | } 455 | } 456 | 457 | 458 | /* Populate capdata struct */ 459 | strncpy(capdata.pcapfilename, opt.pcapfile, sizeof(capdata.pcapfilename)); 460 | if (openpcap(&capdata) != 0) { 461 | printf("Unsupported or unrecognized pcap file.\n"); 462 | exit(1); 463 | } 464 | 465 | /* populates global *packet */ 466 | while (getpacket(&capdata) > 0) { 467 | if (opt.verbose > 2) { 468 | lamont_hdump(packet, h->len); 469 | } 470 | /* test packet for data that we are looking for */ 471 | if (memcmp(&packet[capdata.l2type_offset], DOT1X_LLCTYPE, 2) == 0 && 472 | (h->len > capdata.l2type_offset+sizeof(struct wpa_eapol_key)) ) { 473 | /* It's a dot1x frame, process it */ 474 | handle_dot1x(&cdata, &capdata); 475 | if (cdata.aaset && cdata.spaset && cdata.snonceset && 476 | cdata.anonceset && cdata.keymicset && cdata.eapolframeset) { 477 | /* We've collected everything we need. */ 478 | break; 479 | } 480 | } 481 | } 482 | 483 | closepcap(&capdata); 484 | 485 | if (!(cdata.aaset && cdata.spaset && cdata.snonceset && 486 | cdata.anonceset && cdata.keymicset && cdata.eapolframeset)) { 487 | printf("End of pcap capture file, incomplete TKIP four-way " 488 | "exchange. Try using a\ndifferent capture.\n"); 489 | exit(1); 490 | } else { 491 | printf("Collected all necessary data to mount crack against " 492 | "passphrase.\n"); 493 | } 494 | 495 | if (opt.verbose > 1) { 496 | dump_all_fields(cdata); 497 | } 498 | 499 | /* Zero mic and length data for hmac-md5 calculation */ 500 | eapkeypacket = (struct wpa_eapol_key *)&cdata.eapolframe[EAPDOT1XOFFSET]; 501 | memset(&eapkeypacket->key_mic, 0, sizeof(eapkeypacket->key_mic)); 502 | eapkeypacket->key_data_length = 0; 503 | 504 | printf("Starting dictionary attack. Please be patient.\n"); 505 | fflush(stdout); 506 | 507 | signal(SIGINT, cleanup); 508 | signal(SIGTERM, cleanup); 509 | signal(SIGQUIT, cleanup); 510 | 511 | gettimeofday(&start, 0); 512 | 513 | while (feof(fp) == 0 && sig == 0) { 514 | 515 | /* Populate "passphrase" with the next word */ 516 | fret = nextword(passphrase, fp); 517 | if (fret < 0) { 518 | break; 519 | } 520 | 521 | if (opt.verbose > 1) { 522 | printf("Testing passphrase: %s\n", passphrase); 523 | } 524 | 525 | /* 526 | * Test length of word. IEEE 802.11i indicates the passphrase must be 527 | * at least 8 characters in length, and no more than 63 characters in 528 | * length. 529 | */ 530 | if (fret < 8 || fret > 63) { 531 | if (opt.verbose) { 532 | printf("Invalid passphrase length: %s (%d).\n", passphrase, 533 | strlen(passphrase)); 534 | } 535 | continue; 536 | } else { 537 | /* This word is good, increment the words tested counter */ 538 | wordstested++; 539 | } 540 | 541 | /* Status display */ 542 | if ((wordstested % 1000) == 0) { 543 | printf("key no. %d: %s\n", wordstested, passphrase); 544 | fflush(stdout); 545 | } 546 | 547 | if (opt.verbose > 1) { 548 | printf("Calculating PMK for \"%s\".\n", passphrase); 549 | } 550 | pbkdf2_sha1(passphrase, opt.ssid, strlen(opt.ssid), 4096, 551 | pmk, sizeof(pmk), USECACHED); 552 | if (opt.verbose > 2) { 553 | printf("PMK is"); 554 | lamont_hdump(pmk, sizeof(pmk)); 555 | } 556 | 557 | if (opt.verbose > 1) { 558 | printf("Calculating PTK with collected data and PMK.\n"); 559 | } 560 | wpa_pmk_to_ptk(pmk, cdata.aa, cdata.spa, cdata.anonce, cdata.snonce, 561 | ptk, sizeof(ptk)); 562 | 563 | if (opt.verbose > 2) { 564 | printf("Calculated PTK for \"%s\" is", passphrase); 565 | lamont_hdump(ptk, sizeof(ptk)); 566 | } 567 | 568 | ptkset = (struct wpa_ptk *)ptk; 569 | 570 | if (opt.verbose > 1) { 571 | printf("Calculating hmac-MD5 Key MIC for this frame.\n"); 572 | } 573 | 574 | hmac_md5(ptkset->mic_key, 16, cdata.eapolframe, 575 | sizeof(cdata.eapolframe), keymic); 576 | if (opt.verbose > 2) { 577 | printf("Calculated MIC with \"%s\" is", passphrase); 578 | lamont_hdump(keymic, sizeof(keymic)); 579 | } 580 | 581 | if (memcmp(&cdata.keymic, &keymic, sizeof(keymic)) == 0) { 582 | /* Right PSK */ 583 | printf("\nThe PSK is \"%s\".\n", passphrase); 584 | gettimeofday(&end, 0); 585 | printstats(start, end, wordstested); 586 | exit(0); 587 | } 588 | } 589 | 590 | gettimeofday(&end, 0); 591 | printstats(start, end, wordstested); 592 | printf("Unable to identify the PSK from the dictionary file. Try " 593 | "expanding your\npassphrase list, and double-check the SSID." 594 | " Sorry it didn't work out.\n"); 595 | return(0); 596 | } 597 | -------------------------------------------------------------------------------- /sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * coWPAtty - Brute-force dictionary attack against WPA-PSK. 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: sha1.c,v 1.1.1.1 2004/11/02 11:43:30 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 | /* 20 | * Significant code is graciously taken from the following: 21 | * wpa_supplicant by Jouni Malinen. This tool would have been MUCH more 22 | * difficult for me if not for this code. Thanks Jouni. 23 | * 24 | * i386 assembly SHA code taken from the umac.c message auth code by 25 | * Ted Krovetz (tdk@acm.org): 26 | * http://www.cs.ucdavis.edu/~rogaway/umac/umac.c 27 | * (dragorn) 28 | */ 29 | 30 | 31 | #include 32 | #include 33 | #include 34 | #include "common.h" 35 | #include "sha1.h" 36 | 37 | /* hack, hack, hack */ 38 | SHA1_CACHE cached; 39 | 40 | void sha1_mac(unsigned char *key, unsigned int key_len, 41 | unsigned char *data, unsigned int data_len, 42 | unsigned char *mac) 43 | { 44 | SHA1_CTX context; 45 | SHA1Init(&context); 46 | SHA1Update(&context, key, key_len); 47 | SHA1Update(&context, data, data_len); 48 | SHA1Update(&context, key, key_len); 49 | SHA1Final(mac, &context); 50 | } 51 | 52 | /* HMAC code is based on RFC 2104 53 | Modifications (hacks) by Joshua Wright. Optimized a bit for pbkdf2 54 | processing by caching values that are repetitive. There is some repetitive 55 | code in this function, which I've retained to make it more readable (for my 56 | sanity's sake). 57 | */ 58 | void hmac_sha1_vector(unsigned char *key, unsigned int key_len, 59 | size_t num_elem, unsigned char *addr[], 60 | unsigned int *len, unsigned char *mac, int usecached) 61 | { 62 | SHA1_CTX context; 63 | unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ 64 | unsigned char k_opad[65]; /* outer padding - key XORd with opad */ 65 | int i; 66 | 67 | /* the HMAC_SHA1 transform looks like: 68 | * 69 | * SHA1(K XOR opad, SHA1(K XOR ipad, text)) 70 | * 71 | * where K is an n byte key 72 | * ipad is the byte 0x36 repeated 64 times 73 | * opad is the byte 0x5c repeated 64 times 74 | * and text is the data being protected */ 75 | 76 | if (usecached == NOCACHED || !cached.k_ipad_set || !cached.k_opad_set) { 77 | /* We either don't want to cache values, or we do want to cache but 78 | haven't cached them yet. */ 79 | 80 | /* start out by storing key in pads */ 81 | memset(k_ipad, 0, sizeof(k_ipad)); 82 | memset(k_opad, 0, sizeof(k_opad)); 83 | memcpy(k_ipad, key, key_len); 84 | memcpy(k_opad, key, key_len); 85 | 86 | /* XOR key with ipad and opad values */ 87 | for (i = 0; i < 64; i++) { 88 | k_ipad[i] ^= 0x36; 89 | k_opad[i] ^= 0x5c; 90 | } 91 | 92 | SHA1Init(&context); /* init context for 1st pass */ 93 | SHA1Update(&context, k_ipad, 64); /* start with inner pad */ 94 | 95 | if (usecached) { 96 | /* Cached the context value */ 97 | memcpy(&cached.k_ipad, &context, sizeof(context)); 98 | cached.k_ipad_set=1; 99 | } 100 | 101 | /* then text of datagram; all fragments */ 102 | for (i = 0; i < num_elem; i++) { 103 | SHA1Update(&context, addr[i], len[i]); 104 | } 105 | SHA1Final(mac, &context); /* finish up 1st pass */ 106 | 107 | /* perform outer SHA1 */ 108 | SHA1Init(&context); /* init context for 2nd pass */ 109 | SHA1Update(&context, k_opad, 64); /* start with outer pad */ 110 | 111 | if (usecached) { 112 | /* Cached the context value */ 113 | memcpy(&cached.k_opad, &context, sizeof(context)); 114 | cached.k_opad_set=1; 115 | } 116 | 117 | SHA1Update(&context, mac, 20); /* then results of 1st hash */ 118 | SHA1Final(mac, &context); /* finish up 2nd pass */ 119 | 120 | return; 121 | 122 | } /* End NOCACHED SHA1 processing */ 123 | 124 | 125 | /* This code attempts to optimize the hmac-sha1 process by caching 126 | values that remain constant for the same key. This code is called 127 | many times by pbkdf2, so all optimizations help. 128 | 129 | If we've gotten here, we want to use caching, and have already cached 130 | the values for k_ipad and k_opad after SHA1Update. */ 131 | 132 | memcpy(&context, &cached.k_ipad, sizeof(context)); 133 | for (i = 0; i < num_elem; i++) { 134 | SHA1Update(&context, addr[i], len[i]); 135 | } 136 | SHA1Final(mac, &context); 137 | 138 | memcpy(&context, &cached.k_opad, sizeof(context)); 139 | SHA1Update(&context, mac, 20); 140 | SHA1Final(mac, &context); 141 | return; 142 | } 143 | 144 | static void pbkdf2_sha1_f(char *passphrase, char *ssid, 145 | size_t ssid_len, int iterations, int count, 146 | unsigned char *digest, int usecached) 147 | { 148 | unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; 149 | int i, j; 150 | unsigned char count_buf[4]; 151 | unsigned char *addr[] = { ssid, count_buf }; 152 | unsigned int len[] = { ssid_len, 4 }; 153 | size_t passphrase_len = strlen(passphrase); 154 | 155 | /* F(P, S, c, i) = U1 xor U2 xor ... Uc 156 | * U1 = PRF(P, S || i) 157 | * U2 = PRF(P, U1) 158 | * Uc = PRF(P, Uc-1) 159 | */ 160 | 161 | count_buf[0] = (count >> 24) & 0xff; 162 | count_buf[1] = (count >> 16) & 0xff; 163 | count_buf[2] = (count >> 8) & 0xff; 164 | count_buf[3] = count & 0xff; 165 | 166 | 167 | hmac_sha1_vector(passphrase, passphrase_len, 2, addr, len, tmp, NOCACHED); 168 | memcpy(digest, tmp, SHA1_MAC_LEN); 169 | 170 | for (i = 1; i < iterations; i++) { 171 | hmac_sha1(passphrase, passphrase_len, tmp, SHA1_MAC_LEN, 172 | tmp2, USECACHED); 173 | memcpy(tmp, tmp2, SHA1_MAC_LEN); 174 | for (j = 0; j < SHA1_MAC_LEN; j++) 175 | digest[j] ^= tmp2[j]; 176 | } 177 | 178 | /* clear the cached data set */ 179 | memset(&cached, 0, sizeof(cached)); 180 | } 181 | 182 | 183 | void pbkdf2_sha1(char *passphrase, char *ssid, size_t ssid_len, int iterations, 184 | unsigned char *buf, size_t buflen, int usecached) 185 | { 186 | int count = 0; 187 | unsigned char *pos = buf; 188 | size_t left = buflen, plen; 189 | unsigned char digest[SHA1_MAC_LEN]; 190 | 191 | while (left > 0) { 192 | count++; 193 | pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count, 194 | digest, NOCACHED); 195 | plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; 196 | memcpy(pos, digest, plen); 197 | pos += plen; 198 | left -= plen; 199 | } 200 | } 201 | 202 | 203 | void hmac_sha1(unsigned char *key, unsigned int key_len, 204 | unsigned char *data, unsigned int data_len, 205 | unsigned char *mac, int usecached) 206 | { 207 | hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac, usecached); 208 | } 209 | 210 | 211 | void sha1_prf(unsigned char *key, unsigned int key_len, 212 | char *label, unsigned char *data, unsigned int data_len, 213 | unsigned char *buf, size_t buf_len) 214 | { 215 | char zero = 0, counter = 0; 216 | size_t pos, plen; 217 | u8 hash[SHA1_MAC_LEN]; 218 | size_t label_len = strlen(label); 219 | unsigned char *addr[] = { label, &zero, data, &counter }; 220 | unsigned int len[] = { label_len, 1, data_len, 1 }; 221 | 222 | pos = 0; 223 | while (pos < buf_len) { 224 | plen = buf_len - pos; 225 | if (plen >= SHA1_MAC_LEN) { 226 | hmac_sha1_vector(key, key_len, 4, addr, len, 227 | &buf[pos], NOCACHED); 228 | pos += SHA1_MAC_LEN; 229 | } else { 230 | hmac_sha1_vector(key, key_len, 4, addr, len, 231 | hash, NOCACHED); 232 | memcpy(&buf[pos], hash, plen); 233 | break; 234 | } 235 | counter++; 236 | } 237 | } 238 | 239 | #ifndef OPENSSL 240 | 241 | #define SHA1HANDSOFF 242 | 243 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 244 | 245 | /* blk0() and blk() perform the initial expand. */ 246 | /* I got the idea of expanding during the round function from SSLeay */ 247 | #ifndef WORDS_BIGENDIAN 248 | #define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ 249 | (rol(block->l[i], 8) & 0x00FF00FF)) 250 | #else 251 | #define blk0(i) block->l[i] 252 | #endif 253 | #define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ 254 | block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) 255 | 256 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 257 | #ifndef i386_ASM 258 | #define R0(v,w,x,y,z,i) \ 259 | z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ 260 | w = rol(w, 30); 261 | #define R1(v,w,x,y,z,i) \ 262 | z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ 263 | w = rol(w, 30); 264 | #define R2(v,w,x,y,z,i) \ 265 | z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); 266 | #define R3(v,w,x,y,z,i) \ 267 | z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ 268 | w = rol(w, 30); 269 | #define R4(v,w,x,y,z,i) \ 270 | z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ 271 | w=rol(w, 30); 272 | #else 273 | #define R0(v,w,x,y,z,i) \ 274 | "movl %%"#x",%%edi\n\t" \ 275 | "xorl %%"#y",%%edi\n\t" \ 276 | "andl %%"#w",%%edi\n\t" \ 277 | "xorl %%"#y",%%edi\n\t" \ 278 | "leal 0x5A827999(%%"#z",%%edi),%%"#z"\n\t" \ 279 | "movl %%"#v",%%edi\n\t" \ 280 | "roll $5,%%edi\n\t" \ 281 | "addl %%edi,%%"#z"\n\t" \ 282 | "movl (("#i"*4)&63)(%%ebp),%%edi\n\t" \ 283 | "bswap %%edi\n\t" \ 284 | "movl %%edi,(("#i"*4)&63)(%%ebp)\n\t" \ 285 | "addl %%edi,%%"#z"\n\t" \ 286 | "roll $30,%%"#w"\n\t" 287 | 288 | #define R1(v,w,x,y,z,i) \ 289 | "movl %%"#x",%%edi\n\t" \ 290 | "xorl %%"#y",%%edi\n\t" \ 291 | "andl %%"#w",%%edi\n\t" \ 292 | "xorl %%"#y",%%edi\n\t" \ 293 | "leal 0x5A827999(%%"#z",%%edi),%%"#z"\n\t" \ 294 | "movl %%"#v",%%edi\n\t" \ 295 | "roll $5,%%edi\n\t" \ 296 | "addl %%edi,%%"#z"\n\t" \ 297 | "movl (("#i"*4)&63)(%%ebp),%%edi\n\t" \ 298 | "xorl (("#i"*4+8)&63)(%%ebp),%%edi\n\t" \ 299 | "xorl (("#i"*4+32)&63)(%%ebp),%%edi\n\t" \ 300 | "xorl (("#i"*4+52)&63)(%%ebp),%%edi\n\t" \ 301 | "roll $1,%%edi\n\t" \ 302 | "movl %%edi,(("#i"*4)&63)(%%ebp)\n\t" \ 303 | "addl %%edi,%%"#z"\n\t" \ 304 | "roll $30,%%"#w"\n\t" 305 | 306 | #define R2(v,w,x,y,z,i) \ 307 | "movl %%"#x",%%edi\n\t" \ 308 | "xorl %%"#y",%%edi\n\t" \ 309 | "xorl %%"#w",%%edi\n\t" \ 310 | "leal 0x6ED9EBA1(%%"#z",%%edi),%%"#z"\n\t" \ 311 | "movl %%"#v",%%edi\n\t" \ 312 | "roll $5,%%edi\n\t" \ 313 | "addl %%edi,%%"#z"\n\t" \ 314 | "movl (("#i"*4)&63)(%%ebp),%%edi\n\t" \ 315 | "xorl (("#i"*4+8)&63)(%%ebp),%%edi\n\t" \ 316 | "xorl (("#i"*4+32)&63)(%%ebp),%%edi\n\t" \ 317 | "xorl (("#i"*4+52)&63)(%%ebp),%%edi\n\t" \ 318 | "roll $1,%%edi\n\t" \ 319 | "movl %%edi,(("#i"*4)&63)(%%ebp)\n\t" \ 320 | "addl %%edi,%%"#z"\n\t" \ 321 | "roll $30,%%"#w"\n\t" 322 | 323 | #define R3(v,w,x,y,z,i) \ 324 | "movl %%"#x",%%edi\n\t" \ 325 | "orl %%"#w",%%edi\n\t" \ 326 | "andl %%"#y",%%edi\n\t" \ 327 | "movl %%"#x",%%ebp\n\t" \ 328 | "andl %%"#w",%%ebp\n\t" \ 329 | "orl %%ebp,%%edi\n\t" \ 330 | "movl (%%esp),%%ebp\n\t" \ 331 | "leal 0x8F1BBCDC(%%"#z",%%edi),%%"#z"\n\t" \ 332 | "movl %%"#v",%%edi\n\t" \ 333 | "roll $5,%%edi\n\t" \ 334 | "addl %%edi,%%"#z"\n\t" \ 335 | "movl (("#i"*4)&63)(%%ebp),%%edi\n\t" \ 336 | "xorl (("#i"*4+8)&63)(%%ebp),%%edi\n\t" \ 337 | "xorl (("#i"*4+32)&63)(%%ebp),%%edi\n\t" \ 338 | "xorl (("#i"*4+52)&63)(%%ebp),%%edi\n\t" \ 339 | "roll $1,%%edi\n\t" \ 340 | "movl %%edi,(("#i"*4)&63)(%%ebp)\n\t" \ 341 | "addl %%edi,%%"#z"\n\t" \ 342 | "roll $30,%%"#w"\n\t" 343 | 344 | #define R4(v,w,x,y,z,i) \ 345 | "movl %%"#x",%%edi\n\t" \ 346 | "xorl %%"#y",%%edi\n\t" \ 347 | "xorl %%"#w",%%edi\n\t" \ 348 | "leal 0xCA62C1D6(%%"#z",%%edi),%%"#z"\n\t" \ 349 | "movl %%"#v",%%edi\n\t" \ 350 | "roll $5,%%edi\n\t" \ 351 | "addl %%edi,%%"#z"\n\t" \ 352 | "movl (("#i"*4)&63)(%%ebp),%%edi\n\t" \ 353 | "xorl (("#i"*4+8)&63)(%%ebp),%%edi\n\t" \ 354 | "xorl (("#i"*4+32)&63)(%%ebp),%%edi\n\t" \ 355 | "xorl (("#i"*4+52)&63)(%%ebp),%%edi\n\t" \ 356 | "roll $1,%%edi\n\t" \ 357 | "movl %%edi,(("#i"*4)&63)(%%ebp)\n\t" \ 358 | "addl %%edi,%%"#z"\n\t" \ 359 | "roll $30,%%"#w"\n\t" 360 | #endif 361 | 362 | #ifdef VERBOSE /* SAK */ 363 | void SHAPrintContext(SHA1_CTX *context, char *msg) 364 | { 365 | printf("%s (%d,%d) %x %x %x %x %x\n", 366 | msg, 367 | context->count[0], context->count[1], 368 | context->state[0], 369 | context->state[1], 370 | context->state[2], 371 | context->state[3], 372 | context->state[4]); 373 | } 374 | #endif 375 | 376 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 377 | 378 | 379 | void SHA1Transform(u32 state[5], u32 state_out[5], unsigned char buffer[64]) 380 | { 381 | #ifdef i386_ASM 382 | u32 block[16]; /* Copy data to temporary buffer for */ 383 | memcpy(block,buffer,64); /* endian reversal required by sha1 */ 384 | 385 | asm volatile ( 386 | "pushl %%ebp\n\t" /* push ebp */ 387 | "pushl %%eax\n\t" /* push state_out */ 388 | "pushl %%edi\n\t" /* push state_in */ 389 | "pushl %%ebx\n\t" /* push buffer */ 390 | "movl %%ebx,%%ebp\n\t" 391 | "movl 0(%%edi),%%eax\n\t" 392 | "movl 4(%%edi),%%ebx\n\t" 393 | "movl 8(%%edi),%%ecx\n\t" 394 | "movl 12(%%edi),%%edx\n\t" 395 | "movl 16(%%edi),%%esi\n\t" 396 | R0(eax,ebx,ecx,edx,esi, 0) R0(esi,eax,ebx,ecx,edx, 1) 397 | R0(edx,esi,eax,ebx,ecx, 2) R0(ecx,edx,esi,eax,ebx, 3) 398 | R0(ebx,ecx,edx,esi,eax, 4) R0(eax,ebx,ecx,edx,esi, 5) 399 | R0(esi,eax,ebx,ecx,edx, 6) R0(edx,esi,eax,ebx,ecx, 7) 400 | R0(ecx,edx,esi,eax,ebx, 8) R0(ebx,ecx,edx,esi,eax, 9) 401 | R0(eax,ebx,ecx,edx,esi,10) R0(esi,eax,ebx,ecx,edx,11) 402 | R0(edx,esi,eax,ebx,ecx,12) R0(ecx,edx,esi,eax,ebx,13) 403 | R0(ebx,ecx,edx,esi,eax,14) R0(eax,ebx,ecx,edx,esi,15) 404 | R1(esi,eax,ebx,ecx,edx,16) R1(edx,esi,eax,ebx,ecx,17) 405 | R1(ecx,edx,esi,eax,ebx,18) R1(ebx,ecx,edx,esi,eax,19) 406 | R2(eax,ebx,ecx,edx,esi,20) R2(esi,eax,ebx,ecx,edx,21) 407 | R2(edx,esi,eax,ebx,ecx,22) R2(ecx,edx,esi,eax,ebx,23) 408 | R2(ebx,ecx,edx,esi,eax,24) R2(eax,ebx,ecx,edx,esi,25) 409 | R2(esi,eax,ebx,ecx,edx,26) R2(edx,esi,eax,ebx,ecx,27) 410 | R2(ecx,edx,esi,eax,ebx,28) R2(ebx,ecx,edx,esi,eax,29) 411 | R2(eax,ebx,ecx,edx,esi,30) R2(esi,eax,ebx,ecx,edx,31) 412 | R2(edx,esi,eax,ebx,ecx,32) R2(ecx,edx,esi,eax,ebx,33) 413 | R2(ebx,ecx,edx,esi,eax,34) R2(eax,ebx,ecx,edx,esi,35) 414 | R2(esi,eax,ebx,ecx,edx,36) R2(edx,esi,eax,ebx,ecx,37) 415 | R2(ecx,edx,esi,eax,ebx,38) R2(ebx,ecx,edx,esi,eax,39) 416 | R3(eax,ebx,ecx,edx,esi,40) R3(esi,eax,ebx,ecx,edx,41) 417 | R3(edx,esi,eax,ebx,ecx,42) R3(ecx,edx,esi,eax,ebx,43) 418 | R3(ebx,ecx,edx,esi,eax,44) R3(eax,ebx,ecx,edx,esi,45) 419 | R3(esi,eax,ebx,ecx,edx,46) R3(edx,esi,eax,ebx,ecx,47) 420 | R3(ecx,edx,esi,eax,ebx,48) R3(ebx,ecx,edx,esi,eax,49) 421 | R3(eax,ebx,ecx,edx,esi,50) R3(esi,eax,ebx,ecx,edx,51) 422 | R3(edx,esi,eax,ebx,ecx,52) R3(ecx,edx,esi,eax,ebx,53) 423 | R3(ebx,ecx,edx,esi,eax,54) R3(eax,ebx,ecx,edx,esi,55) 424 | R3(esi,eax,ebx,ecx,edx,56) R3(edx,esi,eax,ebx,ecx,57) 425 | R3(ecx,edx,esi,eax,ebx,58) R3(ebx,ecx,edx,esi,eax,59) 426 | R4(eax,ebx,ecx,edx,esi,60) R4(esi,eax,ebx,ecx,edx,61) 427 | R4(edx,esi,eax,ebx,ecx,62) R4(ecx,edx,esi,eax,ebx,63) 428 | R4(ebx,ecx,edx,esi,eax,64) R4(eax,ebx,ecx,edx,esi,65) 429 | R4(esi,eax,ebx,ecx,edx,66) R4(edx,esi,eax,ebx,ecx,67) 430 | R4(ecx,edx,esi,eax,ebx,68) R4(ebx,ecx,edx,esi,eax,69) 431 | R4(eax,ebx,ecx,edx,esi,70) R4(esi,eax,ebx,ecx,edx,71) 432 | R4(edx,esi,eax,ebx,ecx,72) R4(ecx,edx,esi,eax,ebx,73) 433 | R4(ebx,ecx,edx,esi,eax,74) R4(eax,ebx,ecx,edx,esi,75) 434 | R4(esi,eax,ebx,ecx,edx,76) R4(edx,esi,eax,ebx,ecx,77) 435 | R4(ecx,edx,esi,eax,ebx,78) R4(ebx,ecx,edx,esi,eax,79) 436 | "popl %%ebp\n\t" 437 | "popl %%edi\n\t" 438 | "popl %%ebp\n\t" 439 | "addl 0(%%edi),%%eax\n\t" 440 | "addl 4(%%edi),%%ebx\n\t" 441 | "addl 8(%%edi),%%ecx\n\t" 442 | "addl 12(%%edi),%%edx\n\t" 443 | "addl 16(%%edi),%%esi\n\t" 444 | "movl %%eax,0(%%ebp)\n\t" 445 | "movl %%ebx,4(%%ebp)\n\t" 446 | "movl %%ecx,8(%%ebp)\n\t" 447 | "movl %%edx,12(%%ebp)\n\t" 448 | "movl %%esi,16(%%ebp)\n\t" 449 | "popl %%ebp" 450 | : 451 | : "D" (state), "a" (state_out), "b" (block) 452 | : "memory"); 453 | #else 454 | u32 a, b, c, d, e; 455 | typedef union { 456 | unsigned char c[64]; 457 | u32 l[16]; 458 | } CHAR64LONG16; 459 | CHAR64LONG16* block; 460 | #ifdef SHA1HANDSOFF 461 | static unsigned char workspace[64]; 462 | block = (CHAR64LONG16 *) workspace; 463 | memcpy(block, buffer, 64); 464 | #else 465 | block = (CHAR64LONG16 *) buffer; 466 | #endif 467 | /* Copy context->state[] to working vars */ 468 | a = state[0]; 469 | b = state[1]; 470 | c = state[2]; 471 | d = state[3]; 472 | e = state[4]; 473 | /* 4 rounds of 20 operations each. Loop unrolled. */ 474 | R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); 475 | R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); 476 | R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); 477 | R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); 478 | R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); 479 | R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); 480 | R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); 481 | R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); 482 | R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); 483 | R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); 484 | R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); 485 | R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); 486 | R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); 487 | R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); 488 | R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); 489 | R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); 490 | R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); 491 | R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); 492 | R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); 493 | R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); 494 | /* Add the working vars back into context.state[] */ 495 | state[0] += a; 496 | state[1] += b; 497 | state[2] += c; 498 | state[3] += d; 499 | state[4] += e; 500 | /* Wipe variables */ 501 | a = b = c = d = e = 0; 502 | #endif 503 | } 504 | 505 | 506 | /* SHA1Init - Initialize new context */ 507 | 508 | void SHA1Init(SHA1_CTX* context) 509 | { 510 | /* SHA1 initialization constants */ 511 | context->state[0] = 0x67452301; 512 | context->state[1] = 0xEFCDAB89; 513 | context->state[2] = 0x98BADCFE; 514 | context->state[3] = 0x10325476; 515 | context->state[4] = 0xC3D2E1F0; 516 | context->count[0] = context->count[1] = 0; 517 | } 518 | 519 | 520 | /* Run your data through this. */ 521 | 522 | void SHA1Update(SHA1_CTX* context, unsigned char* data, u32 len) 523 | { 524 | u32 i, j; 525 | 526 | #ifdef VERBOSE 527 | SHAPrintContext(context, "before"); 528 | #endif 529 | j = (context->count[0] >> 3) & 63; 530 | if ((context->count[0] += len << 3) < (len << 3)) 531 | context->count[1]++; 532 | context->count[1] += (len >> 29); 533 | if ((j + len) > 63) { 534 | memcpy(&context->buffer[j], data, (i = 64-j)); 535 | SHA1Transform(context->state, context->state, context->buffer); 536 | for ( ; i + 63 < len; i += 64) { 537 | SHA1Transform(context->state, context->state, &data[i]); 538 | } 539 | j = 0; 540 | } 541 | else i = 0; 542 | memcpy(&context->buffer[j], &data[i], len - i); 543 | #ifdef VERBOSE 544 | SHAPrintContext(context, "after "); 545 | #endif 546 | } 547 | 548 | 549 | /* Add padding and return the message digest. */ 550 | 551 | void SHA1Final(unsigned char digest[20], SHA1_CTX* context) 552 | { 553 | u32 i; 554 | unsigned char finalcount[8]; 555 | 556 | for (i = 0; i < 8; i++) { 557 | finalcount[i] = (unsigned char) 558 | ((context->count[(i >= 4 ? 0 : 1)] >> 559 | ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ 560 | } 561 | SHA1Update(context, (unsigned char *) "\200", 1); 562 | while ((context->count[0] & 504) != 448) { 563 | SHA1Update(context, (unsigned char *) "\0", 1); 564 | } 565 | SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() 566 | */ 567 | for (i = 0; i < 20; i++) { 568 | digest[i] = (unsigned char) 569 | ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 570 | 255); 571 | } 572 | /* Wipe variables */ 573 | i = 0; 574 | memset(context->buffer, 0, 64); 575 | memset(context->state, 0, 20); 576 | memset(context->count, 0, 8); 577 | memset(finalcount, 0, 8); 578 | #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ 579 | SHA1Transform(context->state, context->state, context->buffer); 580 | #endif 581 | } 582 | 583 | #endif /* OPENSSL */ 584 | --------------------------------------------------------------------------------