StuffIt 1-4 archive password cracker
at main 340 lines 14 kB view raw
1/* 2 * StuffIt 1-4 Password Cracker 3 * written by Claude 4 * 5 * This code is released to the public domain. 6 */ 7 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <stdint.h> 12#include <signal.h> 13#include <err.h> 14 15/* character set for brute force is all printable ASCII */ 16static const char charset[] = 17 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:',.<>?/`~ "; 18 19typedef struct { 20 uint32_t subkeys[16][2]; 21} StuffItDESKeySchedule; 22 23unsigned long long total_tested = 0; 24char last_password[9] = { 0 }; 25StuffItDESKeySchedule initial_ks; 26int initial_ks_ready = 0; 27 28void siginfo_handler(int sig); 29void usage(char *p); 30int parse_hex(const char *hex, uint8_t *out, size_t len); 31uint32_t ReverseBits(uint32_t val); 32int test_password(const uint8_t mkey[8], const uint8_t passblock[8]); 33void brute_force(const uint8_t mkey[8], uint8_t *passblock, int pos, int max_len); 34static void StuffItDESSetKey(const uint8_t key[8], StuffItDESKeySchedule *ks); 35static inline void Encrypt(uint32_t *left, uint32_t right, uint32_t *subkey); 36static void StuffItDESCrypt(uint8_t data[8], StuffItDESKeySchedule *ks, int enc); 37 38int 39main(int argc, char **argv) 40{ 41 uint8_t mkey[8]; 42 uint8_t passblock[9] = {0}; 43 int wflag = 0; 44 int min_len = -1, max_len = -1; 45 46 if (argc < 2) 47 usage(argv[0]); 48 49 if (parse_hex(argv[1], mkey, 8) != 0) 50 errx(1, "mkey must be 16 hex characters"); 51 52 if (argc == 3 && strcmp(argv[2], "-w") == 0) 53 wflag = 1; 54 else if (argc == 4) { 55 min_len = atoi(argv[2]); 56 max_len = atoi(argv[3]); 57 if (min_len < 1) 58 errx(1, "invalid min value"); 59 if (max_len > 8) 60 errx(1, "invalid max value"); 61 if (min_len > max_len) 62 errx(1, "min cannot be greater than max"); 63 } else 64 usage(argv[0]); 65 66 signal(SIGINFO, siginfo_handler); 67 68 /* wordlist mode */ 69 if (wflag) { 70 char line[256]; 71 72 while (fgets(line, sizeof(line), stdin)) { 73 size_t len = strlen(line); 74 if (len > 0 && line[len-1] == '\n') 75 line[--len] = 0; 76 if (len > 0 && line[len-1] == '\r') 77 line[--len] = 0; 78 if (len > 8) 79 len = 8; 80 81 memset(passblock, 0, sizeof(passblock)); 82 memcpy(passblock, line, len); 83 84 /* for SIGINFO */ 85 strncpy(last_password, line, 8); 86 last_password[8] = 0; 87 88 total_tested++; 89 if (test_password(mkey, passblock)) 90 printf("%s\n", line); 91 } 92 return 0; 93 } 94 95 /* brute force mode */ 96 for (int len = min_len; len <= max_len; len++) { 97 memset(passblock, 0, sizeof(passblock)); 98 brute_force(mkey, passblock, 0, len); 99 } 100 101 return 0; 102} 103 104void 105siginfo_handler(int sig) 106{ 107 (void)sig; 108 warnx("tested %llu passwords, last: %s", total_tested, last_password); 109} 110 111void 112usage(char *p) 113{ 114 printf("StuffIt 1-4 archive password cracker\n"); 115 printf("\n"); 116 printf("Usage:\n"); 117 printf(" %s <mkey_hex> <min> <max> - brute force length range\n", p); 118 printf(" %s <mkey_hex> -w - read passwords from stdin\n", p); 119 printf("\n"); 120 printf("mkey_hex are 16 hex characters from the archive's 'MKey' " 121 "in its resource fork.\n"); 122 printf("\n"); 123 printf("Examples:\n"); 124 printf("\tgzip -cd rockyou.txt.gz | %s 590e0f73e71c9b60 -w\n", p); 125 printf("\t%s 590e0f73e71c9b60 3 8\n", p); 126 printf("\n"); 127 printf("Multiple passwords may verify against the hash, but will not " 128 "unlock the\n"); 129 printf("archive (and will likely crash StuffIt). Let this keep " 130 "running while\n"); 131 printf("you try the most likely of the passwords found.\n"); 132 exit(1); 133} 134 135 136int 137parse_hex(const char *hex, uint8_t *out, size_t len) 138{ 139 if (strlen(hex) != len * 2) 140 return -1; 141 142 for (size_t i = 0; i < len; i++) { 143 int hi, lo; 144 char c; 145 146 c = hex[i * 2]; 147 if (c >= '0' && c <= '9') 148 hi = c - '0'; 149 else if (c >= 'a' && c <= 'f') 150 hi = c - 'a' + 10; 151 else if (c >= 'A' && c <= 'F') 152 hi = c - 'A' + 10; 153 else 154 return -1; 155 156 c = hex[i * 2 + 1]; 157 if (c >= '0' && c <= '9') 158 lo = c - '0'; 159 else if (c >= 'a' && c <= 'f') 160 lo = c - 'a' + 10; 161 else if (c >= 'A' && c <= 'F') 162 lo = c - 'A' + 10; 163 else 164 return -1; 165 166 out[i] = (hi << 4) | lo; 167 } 168 169 return 0; 170} 171 172int 173test_password(const uint8_t mkey[8], const uint8_t passblock[8]) 174{ 175 StuffItDESKeySchedule ks; 176 uint8_t archivekey[8], archiveiv[8], verifyblock[8]; 177 static const uint8_t initialkey[8] = { 178 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef 179 }; 180 181 for (int i = 0; i < 8; i++) 182 archivekey[i] = initialkey[i] ^ (passblock[i] & 0x7f); 183 184 /* Initialize key schedule for initial key (once) */ 185 if (!initial_ks_ready) { 186 StuffItDESSetKey(initialkey, &initial_ks); 187 initial_ks_ready = 1; 188 } 189 190 /* Encrypt archive key with initial key */ 191 StuffItDESCrypt(archivekey, &initial_ks, 1); 192 193 /* Decrypt MKey to get archive IV */ 194 memcpy(archiveiv, mkey, 8); 195 StuffItDESSetKey(archivekey, &ks); 196 StuffItDESCrypt(archiveiv, &ks, 0); 197 198 /* Verify: encrypt first 4 bytes of IV + {0,0,0,4} */ 199 memcpy(verifyblock, archiveiv, 4); 200 verifyblock[4] = verifyblock[5] = verifyblock[6] = 0; 201 verifyblock[7] = 4; 202 StuffItDESCrypt(verifyblock, &ks, 1); 203 204 /* Check last 4 bytes match */ 205 return memcmp(verifyblock + 4, archiveiv + 4, 4) == 0; 206} 207 208void 209brute_force(const uint8_t mkey[8], uint8_t *passblock, int pos, int max_len) 210{ 211 int i; 212 213 if (pos > 0) { 214 for (i = 0; i < 8; i++) 215 last_password[i] = passblock[i]; 216 last_password[8] = 0; 217 218 if (test_password(mkey, passblock)) { 219 /* found a match - convert to printable string */ 220 char pwd[9] = { 0 }; 221 for (i = 0; i < 8 && passblock[i]; i++) 222 pwd[i] = passblock[i]; 223 printf("%s\n", pwd); 224 } 225 total_tested++; 226 } 227 228 if (pos >= max_len) 229 return; 230 231 for (i = 0; i < (int)sizeof(charset) - 1; i++) { 232 passblock[pos] = charset[i]; 233 passblock[pos + 1] = 0; 234 brute_force(mkey, passblock, pos + 1, max_len); 235 } 236 passblock[pos] = 0; 237} 238 239static inline 240uint32_t RotateRight(uint32_t val, int n) 241{ 242 return (val >> n) | (val << (32 - n)); 243} 244 245uint32_t 246ReverseBits(uint32_t val) 247{ 248 val = ((val >> 1) & 0x55555555) | ((val & 0x55555555) << 1); 249 val = ((val >> 2) & 0x33333333) | ((val & 0x33333333) << 2); 250 val = ((val >> 4) & 0x0F0F0F0F) | ((val & 0x0F0F0F0F) << 4); 251 val = ((val >> 8) & 0x00FF00FF) | ((val & 0x00FF00FF) << 8); 252 return (val >> 16) | (val << 16); 253} 254 255static inline uint32_t Nibble(const uint8_t key[8], int n) 256{ 257 return (key[(n & 0x0f) >> 1] >> (((n ^ 1) & 1) << 2)) & 0x0f; 258} 259 260static const uint32_t DES_SPtrans[8][64] = { 261 {0x02080800,0x00080000,0x02000002,0x02080802,0x02000000,0x00080802,0x00080002,0x02000002,0x00080802,0x02080800,0x02080000,0x00000802,0x02000802,0x02000000,0x00000000,0x00080002,0x00080000,0x00000002,0x02000800,0x00080800,0x02080802,0x02080000,0x00000802,0x02000800,0x00000002,0x00000800,0x00080800,0x02080002,0x00000800,0x02000802,0x02080002,0x00000000,0x00000000,0x02080802,0x02000800,0x00080002,0x02080800,0x00080000,0x00000802,0x02000800,0x02080002,0x00000800,0x00080800,0x02000002,0x00080802,0x00000002,0x02000002,0x02080000,0x02080802,0x00080800,0x02080000,0x02000802,0x02000000,0x00000802,0x00080002,0x00000000,0x00080000,0x02000000,0x02000802,0x02080800,0x00000002,0x02080002,0x00000800,0x00080802}, 262 {0x40108010,0x00000000,0x00108000,0x40100000,0x40000010,0x00008010,0x40008000,0x00108000,0x00008000,0x40100010,0x00000010,0x40008000,0x00100010,0x40108000,0x40100000,0x00000010,0x00100000,0x40008010,0x40100010,0x00008000,0x00108010,0x40000000,0x00000000,0x00100010,0x40008010,0x00108010,0x40108000,0x40000010,0x40000000,0x00100000,0x00008010,0x40108010,0x00100010,0x40108000,0x40008000,0x00108010,0x40108010,0x00100010,0x40000010,0x00000000,0x40000000,0x00008010,0x00100000,0x40100010,0x00008000,0x40000000,0x00108010,0x40008010,0x40108000,0x00008000,0x00000000,0x40000010,0x00000010,0x40108010,0x00108000,0x40100000,0x40100010,0x00100000,0x00008010,0x40008000,0x40008010,0x00000010,0x40100000,0x00108000}, 263 {0x04000001,0x04040100,0x00000100,0x04000101,0x00040001,0x04000000,0x04000101,0x00040100,0x04000100,0x00040000,0x04040000,0x00000001,0x04040101,0x00000101,0x00000001,0x04040001,0x00000000,0x00040001,0x04040100,0x00000100,0x00000101,0x04040101,0x00040000,0x04000001,0x04040001,0x04000100,0x00040101,0x04040000,0x00040100,0x00000000,0x04000000,0x00040101,0x04040100,0x00000100,0x00000001,0x00040000,0x00000101,0x00040001,0x04040000,0x04000101,0x00000000,0x04040100,0x00040100,0x04040001,0x00040001,0x04000000,0x04040101,0x00000001,0x00040101,0x04000001,0x04000000,0x04040101,0x00040000,0x04000100,0x04000101,0x00040100,0x04000100,0x00000000,0x04040001,0x00000101,0x04000001,0x00040101,0x00000100,0x04040000}, 264 {0x00401008,0x10001000,0x00000008,0x10401008,0x00000000,0x10400000,0x10001008,0x00400008,0x10401000,0x10000008,0x10000000,0x00001008,0x10000008,0x00401008,0x00400000,0x10000000,0x10400008,0x00401000,0x00001000,0x00000008,0x00401000,0x10001008,0x10400000,0x00001000,0x00001008,0x00000000,0x00400008,0x10401000,0x10001000,0x10400008,0x10401008,0x00400000,0x10400008,0x00001008,0x00400000,0x10000008,0x00401000,0x10001000,0x00000008,0x10400000,0x10001008,0x00000000,0x00001000,0x00400008,0x00000000,0x10400008,0x10401000,0x00001000,0x10000000,0x10401008,0x00401008,0x00400000,0x10401008,0x00000008,0x10001000,0x00401008,0x00400008,0x00401000,0x10400000,0x10001008,0x00001008,0x10000000,0x10000008,0x10401000}, 265 {0x08000000,0x00010000,0x00000400,0x08010420,0x08010020,0x08000400,0x00010420,0x08010000,0x00010000,0x00000020,0x08000020,0x00010400,0x08000420,0x08010020,0x08010400,0x00000000,0x00010400,0x08000000,0x00010020,0x00000420,0x08000400,0x00010420,0x00000000,0x08000020,0x00000020,0x08000420,0x08010420,0x00010020,0x08010000,0x00000400,0x00000420,0x08010400,0x08010400,0x08000420,0x00010020,0x08010000,0x00010000,0x00000020,0x08000020,0x08000400,0x08000000,0x00010400,0x08010420,0x00000000,0x00010420,0x08000000,0x00000400,0x00010020,0x08000420,0x00000400,0x00000000,0x08010420,0x08010020,0x08010400,0x00000420,0x00010000,0x00010400,0x08010020,0x08000400,0x00000420,0x00000020,0x00010420,0x08010000,0x08000020}, 266 {0x80000040,0x00200040,0x00000000,0x80202000,0x00200040,0x00002000,0x80002040,0x00200000,0x00002040,0x80202040,0x00202000,0x80000000,0x80002000,0x80000040,0x80200000,0x00202040,0x00200000,0x80002040,0x80200040,0x00000000,0x00002000,0x00000040,0x80202000,0x80200040,0x80202040,0x80200000,0x80000000,0x00002040,0x00000040,0x00202000,0x00202040,0x80002000,0x00002040,0x80000000,0x80002000,0x00202040,0x80202000,0x00200040,0x00000000,0x80002000,0x80000000,0x00002000,0x80200040,0x00200000,0x00200040,0x80202040,0x00202000,0x00000040,0x80202040,0x00202000,0x00200000,0x80002040,0x80000040,0x80200000,0x00202040,0x00000000,0x00002000,0x80000040,0x80002040,0x80202000,0x80200000,0x00002040,0x00000040,0x80200040}, 267 {0x00004000,0x00000200,0x01000200,0x01000004,0x01004204,0x00004004,0x00004200,0x00000000,0x01000000,0x01000204,0x00000204,0x01004000,0x00000004,0x01004200,0x01004000,0x00000204,0x01000204,0x00004000,0x00004004,0x01004204,0x00000000,0x01000200,0x01000004,0x00004200,0x01004004,0x00004204,0x01004200,0x00000004,0x00004204,0x01004004,0x00000200,0x01000000,0x00004204,0x01004000,0x01004004,0x00000204,0x00004000,0x00000200,0x01000000,0x01004004,0x01000204,0x00004204,0x00004200,0x00000000,0x00000200,0x01000004,0x00000004,0x01000200,0x00000000,0x01000204,0x01000200,0x00004200,0x00000204,0x00004000,0x01004204,0x01000000,0x01004200,0x00000004,0x00004004,0x01004204,0x01000004,0x01004200,0x01004000,0x00004004}, 268 {0x20800080,0x20820000,0x00020080,0x00000000,0x20020000,0x00800080,0x20800000,0x20820080,0x00000080,0x20000000,0x00820000,0x00020080,0x00820080,0x20020080,0x20000080,0x20800000,0x00020000,0x00820080,0x00800080,0x20020000,0x20820080,0x20000080,0x00000000,0x00820000,0x20000000,0x00800000,0x20020080,0x20800080,0x00800000,0x00020000,0x20820000,0x00000080,0x00800000,0x00020000,0x20000080,0x20820080,0x00020080,0x20000000,0x00000000,0x00820000,0x20800080,0x20020080,0x20020000,0x00800080,0x20820000,0x00000080,0x00800080,0x20020000,0x20820080,0x00800000,0x20800000,0x20000080,0x00820000,0x00020080,0x20020080,0x20800000,0x00000080,0x20820000,0x00820080,0x00000000,0x20000000,0x20800080,0x00020000,0x00820080} 269}; 270 271static void 272StuffItDESSetKey(const uint8_t key[8], StuffItDESKeySchedule *ks) 273{ 274 for (int i = 0; i < 16; i++) { 275 uint32_t subkey1 = ((Nibble(key, i) >> 2) | (Nibble(key, i + 13) << 2)); 276 subkey1 |= ((Nibble(key, i + 11) >> 2) | (Nibble(key, i + 6) << 2)) << 8; 277 subkey1 |= ((Nibble(key, i + 3) >> 2) | (Nibble(key, i + 10) << 2)) << 16; 278 subkey1 |= ((Nibble(key, i + 8) >> 2) | (Nibble(key, i + 1) << 2)) << 24; 279 uint32_t subkey0 = ((Nibble(key, i + 9) | (Nibble(key, i) << 4)) & 0x3f); 280 subkey0 |= ((Nibble(key, i + 2) | (Nibble(key, i + 11) << 4)) & 0x3f) << 8; 281 subkey0 |= ((Nibble(key, i + 14) | (Nibble(key, i + 3) << 4)) & 0x3f) << 16; 282 subkey0 |= ((Nibble(key, i + 5) | (Nibble(key, i + 8) << 4)) & 0x3f) << 24; 283 ks->subkeys[i][0] = ReverseBits(subkey1); 284 ks->subkeys[i][1] = ReverseBits(subkey0); 285 } 286} 287 288static inline 289void Encrypt(uint32_t *left, uint32_t right, uint32_t *subkey) 290{ 291 uint32_t u = right ^ subkey[0]; 292 uint32_t t = RotateRight(right, 4) ^ subkey[1]; 293 *left ^= DES_SPtrans[0][(u >> 2) & 0x3f] ^ DES_SPtrans[2][(u >> 10) & 0x3f] ^ 294 DES_SPtrans[4][(u >> 18) & 0x3f] ^ DES_SPtrans[6][(u >> 26) & 0x3f] ^ 295 DES_SPtrans[1][(t >> 2) & 0x3f] ^ DES_SPtrans[3][(t >> 10) & 0x3f] ^ 296 DES_SPtrans[5][(t >> 18) & 0x3f] ^ DES_SPtrans[7][(t >> 26) & 0x3f]; 297} 298 299static inline 300uint32_t ReadBE32(const uint8_t *p) 301{ 302 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3]; 303} 304 305static inline 306void WriteBE32(uint8_t *p, uint32_t v) 307{ 308 p[0] = (v >> 24); 309 p[1] = (v >> 16); 310 p[2] = (v >> 8); 311 p[3] = v; 312} 313 314static void 315StuffItDESCrypt(uint8_t data[8], StuffItDESKeySchedule *ks, int enc) 316{ 317 uint32_t left = ReverseBits(ReadBE32(&data[0])); 318 uint32_t right = ReverseBits(ReadBE32(&data[4])); 319 320 right = RotateRight(right, 29); 321 left = RotateRight(left, 29); 322 323 if (enc) { 324 for (int i = 0; i < 16; i += 2) { 325 Encrypt(&left, right, ks->subkeys[i]); 326 Encrypt(&right, left, ks->subkeys[i + 1]); 327 } 328 } else { 329 for (int i = 15; i > 0; i -= 2) { 330 Encrypt(&left, right, ks->subkeys[i]); 331 Encrypt(&right, left, ks->subkeys[i - 1]); 332 } 333 } 334 335 left = RotateRight(left, 3); 336 right = RotateRight(right, 3); 337 338 WriteBE32(&data[0], ReverseBits(right)); 339 WriteBE32(&data[4], ReverseBits(left)); 340}