Skip to content

Commit

Permalink
PDF format: Bug fixes for R3 with RC4-40
Browse files Browse the repository at this point in the history
The 50x MD5 loop was hardcoded for 128 bits, which is not always correct.
  • Loading branch information
magnumripper committed Sep 13, 2024
1 parent 265947a commit 07aef97
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 33 deletions.
77 changes: 52 additions & 25 deletions src/pdf_fmt_plug.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/* PDF cracker patch for JtR. Hacked together during Monsoon of 2012 by
/*
* PDF cracker patch for JtR. Hacked together during Monsoon of 2012 by
* Dhiru Kholia <dhiru.kholia at gmail.com>.
*
* This software is Copyright (c) 2012, Dhiru Kholia <dhiru.kholia at gmail.com>
*
* Uses code from Sumatra PDF and MuPDF which are under GPL.
* This software is
* Copyright (c) 2012, Dhiru Kholia <dhiru.kholia at gmail.com>
* Copyright (c) 2013, Shane Quigley
* Copyright (c) 2024, magnum
*
* Edited by Shane Quigley in 2013.
* Uses code from pdfcrack, Sumatra PDF and MuPDF which are under GPL.
*/

#if FMT_EXTERNS_H
Expand All @@ -31,6 +33,8 @@ john_register_one(&fmt_pdf);
#include "rc4.h"
#include "pdfcrack_md5.h"
#include "loader.h"
#include "options.h"
#include "logger.h"

#define FORMAT_LABEL "PDF"
#define FORMAT_NAME ""
Expand Down Expand Up @@ -76,6 +80,10 @@ static struct custom_salt {
int length_oe;
} *crypt_out;

#define MAX_KEY_SIZE 256
#define MAX_U_SIZE sizeof(crypt_out->u)
#define MAX_O_SIZE sizeof(crypt_out->o)

static struct fmt_tests pdf_tests[] = {
{"$pdf$4*4*128*-1028*1*16*e03460febe17a048b0adc7f7631bcc56*32*3456205208ad52066d5604018d498a6400000000000000000000000000000000*32*6d598152b22f8fa8085b19a866dce1317f645788a065a74831588a739a579ac4", "openwall"},
{"$pdf$2*3*128*-4*1*16*34b1b6e593787af681a9b63fa8bf563b*32*289ece9b5ce451a5d7064693dab3badf101112131415161718191a1b1c1d1e1f*32*badad1e86442699427116d3e5d5271bc80a27814fc5e80f815efeef839354c5f", "test"},
Expand Down Expand Up @@ -140,7 +148,7 @@ static int valid(char *ciphertext, struct fmt_main *self)
goto err;
if (!isdec(p)) goto err;
res = atoi(p);
if (res > 256)
if (res > MAX_KEY_SIZE)
goto err;
if ((p = strtokm(NULL, "*")) == NULL) /* P */
goto err;
Expand All @@ -165,7 +173,7 @@ static int valid(char *ciphertext, struct fmt_main *self)
goto err;
if (!isdec(p)) goto err;
res = atoi(p);
if (res > 127)
if (res > MAX_U_SIZE)
goto err;
if ((p = strtokm(NULL, "*")) == NULL) /* u */
goto err;
Expand All @@ -177,7 +185,7 @@ static int valid(char *ciphertext, struct fmt_main *self)
goto err;
if (!isdec(p)) goto err;
res = atoi(p);
if (res > 127)
if (res > MAX_O_SIZE)
goto err;
if ((p = strtokm(NULL, "*")) == NULL) /* o */
goto err;
Expand Down Expand Up @@ -257,7 +265,7 @@ static int old_valid(char *ciphertext, struct fmt_main *self)
return 0;
}

char * convert_old_to_new(char ciphertext[])
char* convert_old_to_new(char ciphertext[])
{
char *ctcopy = xstrdup(ciphertext);
char *keeptr = ctcopy;
Expand Down Expand Up @@ -425,13 +433,20 @@ pdf_compute_encryption_key(unsigned char *password, int pwlen, unsigned char *ke
/* Step 8 (revision 3 or greater) - do some voodoo 50 times */
if (crypt_out->R >= 3)
{
/* for (i = 0; i < 50; i++)
{
MD5_Init(&md5);
MD5_Update(&md5, buf, n);
MD5_Final(buf, &md5);
} */
md5_50(buf);
switch(crypt_out->length) {
case 128:
md5x50_128(buf);
break;
case 40:
md5x50_40(buf);
break;
default:
for (int i = 0; i < 50; i++) {
MD5_Init(&md5);
MD5_Update(&md5, buf, n);
MD5_Final(buf, &md5);
}
}
}
/* Step 9 - the key is the first 'n' bytes of the result */
memcpy(key, buf, n);
Expand Down Expand Up @@ -548,26 +563,24 @@ pdf_compute_hardened_hash_r6(unsigned char *password, int pwlen, unsigned char s

static void pdf_compute_user_password(unsigned char *password, unsigned char *output)
{

int pwlen = strlen((char*)password);
unsigned char key[128];
unsigned char key[MAX_KEY_SIZE / 8];
int n = crypt_out->length / 8;

if (crypt_out->R == 2) {
RC4_KEY arc4;
int n;
n = crypt_out->length / 8;

pdf_compute_encryption_key(password, pwlen, key);
RC4_set_key(&arc4, n, key);
RC4(&arc4, 32, padding, output);
}

if (crypt_out->R == 3 || crypt_out->R == 4) {
else if (crypt_out->R == 3 || crypt_out->R == 4) {
unsigned char xor[32];
unsigned char digest[16];
MD5_CTX md5;
RC4_KEY arc4;
int i, x, n;
n = crypt_out->length / 8;
int i, x;

pdf_compute_encryption_key(password, pwlen, key);
MD5_Init(&md5);
MD5_Update(&md5, (char*)padding, 32);
Expand All @@ -581,7 +594,7 @@ static void pdf_compute_user_password(unsigned char *password, unsigned char *o
RC4_set_key(&arc4, n, xor);
RC4(&arc4, 16, output, output);
}
memcpy(output + 16, padding, 16);
//memcpy(output + 16, padding, 16); /* pointless - we only test 16 bytes of it */
}
if (crypt_out->R == 5) {
pdf_compute_encryption_key_r5(password, pwlen, 0, output);
Expand All @@ -590,6 +603,20 @@ static void pdf_compute_user_password(unsigned char *password, unsigned char *o
/* SumatraPDF: support crypt version 5 revision 6 */
if (crypt_out->R == 6)
pdf_compute_hardened_hash_r6(password, pwlen, crypt_out->u + 32, NULL, output);

if (!bench_or_test_running && crypt_out->length == 40 && !memcmp(output, crypt_out->u, 16)) {
char h_key[2 * 5 + 1], *p;
int i;

p = &h_key[0];
for (i = 0; i < 2 * n; i++)
*p++ = itoa16[key[i >> 1] >> (4 * ((i & 0x1) ^ 1)) & 0xf];
*p = 0;

log_event("+ RC4 key: %s", h_key);
if (options.verbosity > VERB_DEFAULT)
fprintf(stderr, "+ RC4 key: %s\n", h_key);
}
}

static int crypt_all(int *pcount, struct db_salt *salt)
Expand Down
4 changes: 2 additions & 2 deletions src/pdfcrack_md5.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

#include <stdint.h>

void md5(const uint8_t * msg, const unsigned int msgLen, uint8_t * digest);

void md5_50(uint8_t * msg);
extern void md5x50_40(uint8_t * msg);
extern void md5x50_128(uint8_t * msg);

#endif /** _MD5_H_ */
124 changes: 118 additions & 6 deletions src/pdfcrack_md5_plug.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,120 @@
#define CC 0x98badcfe
#define DD 0x10325476

/** fast version of "for (i=0; i<50; i++) { md5(msg, 16, msg); }" */
void md5_50(uint8_t * msg)
/** fast versions of "for (i=0; i<50; i++) { md5(msg, n, msg); }" */
void md5x50_40(uint8_t* msg)
{
register uint32_t a, b, c, d;
int i;

a = ((unsigned int)(((unsigned int)(((unsigned int)msg[3] << 8) + msg[2]) << 8) + msg[1]) << 8) + msg[0];
b = 0x8000 + (unsigned int)msg[4];
c = 0;
d = 0;

for (i = 0; i < 50; ++i) {
uint32_t aa, bb, cc, dd;

dd = d;
cc = c;
bb = b;
aa = a;

/** round 1 */
/**MD5_ROUND1(a,BB,CC,DD, aa, 7, 0xd76aa478);
MD5_ROUND1(d, a,BB,CC, bb,12, 0xe8c7b756);
MD5_ROUND1(c, d, a,BB, cc,17, 0x242070db);
MD5_ROUND1(b, c, d, a, dd,22, 0xc1bdceee);*/
a += 0xd76aa477;
RnA(a, BB, 7);
d = 0xf8fa0bcc + b + (CC ^ (a & 0x77777777));
RnA(d, a, 12);
c += 0xbcdb4dd9 + (BB ^ (d & (a ^ BB)));
RnA(c, d, 17);
b = 0xb18b7a77 + dd + (a ^ (c & (d ^ a)));
RnA(b, c, 22);
MD5_ROUND1(a, b, c, d, 0, 7, 0xf57c0faf);
MD5_ROUND1(d, a, b, c, 0, 12, 0x4787c62a);
MD5_ROUND1(c, d, a, b, 0, 17, 0xa8304613);
MD5_ROUND1(b, c, d, a, 0, 22, 0xfd469501);
MD5_ROUND1(a, b, c, d, 0, 7, 0x698098d8);
MD5_ROUND1(d, a, b, c, 0, 12, 0x8b44f7af);
MD5_ROUND1(c, d, a, b, 0, 17, 0xffff5bb1);
MD5_ROUND1(b, c, d, a, 0, 22, 0x895cd7be);
MD5_ROUND1(a, b, c, d, 0, 7, 0x6b901122);
MD5_ROUND1(d, a, b, c, 0, 12, 0xfd987193);
MD5_ROUND1(c, d, a, b, 40, 17, 0xa679438e);
MD5_ROUND1(b, c, d, a, 0, 22, 0x49b40821);

/** round 2 */
MD5_ROUND2(a, b, c, d, bb, 5, 0xf61e2562);
MD5_ROUND2(d, a, b, c, 0, 9, 0xc040b340);
MD5_ROUND2(c, d, a, b, 0, 14, 0x265e5a51);
MD5_ROUND2(b, c, d, a, aa, 20, 0xe9b6c7aa);
MD5_ROUND2(a, b, c, d, 0, 5, 0xd62f105d);
MD5_ROUND2(d, a, b, c, 0, 9, 0x02441453);
MD5_ROUND2(c, d, a, b, 0, 14, 0xd8a1e681);
MD5_ROUND2(b, c, d, a, 0, 20, 0xe7d3fbc8);
MD5_ROUND2(a, b, c, d, 0, 5, 0x21e1cde6);
MD5_ROUND2(d, a, b, c, 40, 9, 0xc33707d6);
MD5_ROUND2(c, d, a, b, dd, 14, 0xf4d50d87);
MD5_ROUND2(b, c, d, a, 0, 20, 0x455a14ed);
MD5_ROUND2(a, b, c, d, 0, 5, 0xa9e3e905);
MD5_ROUND2(d, a, b, c, cc, 9, 0xfcefa3f8);
MD5_ROUND2(c, d, a, b, 0, 14, 0x676f02d9);
MD5_ROUND2(b, c, d, a, 0, 20, 0x8d2a4c8a);

/** round 3 */
MD5_ROUND3(a, b, c, d, 0, 4, 0xfffa3942);
MD5_ROUND3(d, a, b, c, 0, 11, 0x8771f681);
MD5_ROUND3(c, d, a, b, 0, 16, 0x6d9d6122);
MD5_ROUND3(b, c, d, a, 40, 23, 0xfde5380c);
MD5_ROUND3(a, b, c, d, bb, 4, 0xa4beea44);
MD5_ROUND3(d, a, b, c, 0, 11, 0x4bdecfa9);
MD5_ROUND3(c, d, a, b, 0, 16, 0xf6bb4b60);
MD5_ROUND3(b, c, d, a, 0, 23, 0xbebfbc70);
MD5_ROUND3(a, b, c, d, 0, 4, 0x289b7ec6);
MD5_ROUND3(d, a, b, c, aa, 11, 0xeaa127fa);
MD5_ROUND3(c, d, a, b, dd, 16, 0xd4ef3085);
MD5_ROUND3(b, c, d, a, 0, 23, 0x04881d05);
MD5_ROUND3(a, b, c, d, 0, 4, 0xd9d4d039);
MD5_ROUND3(d, a, b, c, 0, 11, 0xe6db99e5);
MD5_ROUND3(c, d, a, b, 0, 16, 0x1fa27cf8);
MD5_ROUND3(b, c, d, a, cc, 23, 0xc4ac5665);

/** round 4 */
MD5_ROUND4(a, b, c, d, aa, 6, 0xf4292244);
MD5_ROUND4(d, a, b, c, 0, 10, 0x432aff97);
MD5_ROUND4(c, d, a, b, 40, 15, 0xab9423a7);
MD5_ROUND4(b, c, d, a, 0, 21, 0xfc93a039);
MD5_ROUND4(a, b, c, d, 0, 6, 0x655b59c3);
MD5_ROUND4(d, a, b, c, dd, 10, 0x8f0ccc92);
MD5_ROUND4(c, d, a, b, 0, 15, 0xffeff47d);
MD5_ROUND4(b, c, d, a, bb, 21, 0x85845dd1);
MD5_ROUND4(a, b, c, d, 0, 6, 0x6fa87e4f);
MD5_ROUND4(d, a, b, c, 0, 10, 0xfe2ce6e0);
MD5_ROUND4(c, d, a, b, 0, 15, 0xa3014314);
MD5_ROUND4(b, c, d, a, 0, 21, 0x4e0811a1);
MD5_ROUND4(a, b, c, d, 0, 6, 0xf7537e82);
MD5_ROUND4(d, a, b, c, 0, 10, 0xbd3af235);
MD5_ROUND4(c, d, a, b, cc, 15, 0x2ad7d2bb);
MD5_ROUND4(b, c, d, a, 0, 21, 0xeb86d391);

a += AA;
b = ((b + BB) & 0xff) + 0x8000;
c = 0;
d = 0;
}

/** break digest into bytes */
msg[0] = (uint8_t) (a & 0xff);
msg[1] = (uint8_t) ((a >>= 8) & 0xff);
msg[2] = (uint8_t) ((a >>= 8) & 0xff);
msg[3] = (uint8_t) ((a >>= 8) & 0xff);
msg[4] = (uint8_t) (b & 0xff);
}

void md5x50_128(uint8_t* msg)
{
register uint32_t a, b, c, d;
int i;
Expand Down Expand Up @@ -89,7 +201,7 @@ void md5_50(uint8_t * msg)
MD5_ROUND1(b, c, d, a, 0, 22, 0x895cd7be);
MD5_ROUND1(a, b, c, d, 0, 7, 0x6b901122);
MD5_ROUND1(d, a, b, c, 0, 12, 0xfd987193);
MD5_ROUND1(c, d, a, b, 0x80, 17, 0xa679438e);
MD5_ROUND1(c, d, a, b, 128, 17, 0xa679438e);
MD5_ROUND1(b, c, d, a, 0, 22, 0x49b40821);

/** round 2 */
Expand All @@ -102,7 +214,7 @@ void md5_50(uint8_t * msg)
MD5_ROUND2(c, d, a, b, 0, 14, 0xd8a1e681);
MD5_ROUND2(b, c, d, a, 0x80, 20, 0xe7d3fbc8);
MD5_ROUND2(a, b, c, d, 0, 5, 0x21e1cde6);
MD5_ROUND2(d, a, b, c, 0x80, 9, 0xc33707d6);
MD5_ROUND2(d, a, b, c, 128, 9, 0xc33707d6);
MD5_ROUND2(c, d, a, b, dd, 14, 0xf4d50d87);
MD5_ROUND2(b, c, d, a, 0, 20, 0x455a14ed);
MD5_ROUND2(a, b, c, d, 0, 5, 0xa9e3e905);
Expand All @@ -114,7 +226,7 @@ void md5_50(uint8_t * msg)
MD5_ROUND3(a, b, c, d, 0, 4, 0xfffa3942);
MD5_ROUND3(d, a, b, c, 0, 11, 0x8771f681);
MD5_ROUND3(c, d, a, b, 0, 16, 0x6d9d6122);
MD5_ROUND3(b, c, d, a, 0x80, 23, 0xfde5380c);
MD5_ROUND3(b, c, d, a, 128, 23, 0xfde5380c);
MD5_ROUND3(a, b, c, d, bb, 4, 0xa4beea44);
MD5_ROUND3(d, a, b, c, 0x80, 11, 0x4bdecfa9);
MD5_ROUND3(c, d, a, b, 0, 16, 0xf6bb4b60);
Expand All @@ -131,7 +243,7 @@ void md5_50(uint8_t * msg)
/** round 4 */
MD5_ROUND4(a, b, c, d, aa, 6, 0xf4292244);
MD5_ROUND4(d, a, b, c, 0, 10, 0x432aff97);
MD5_ROUND4(c, d, a, b, 0x80, 15, 0xab9423a7);
MD5_ROUND4(c, d, a, b, 128, 15, 0xab9423a7);
MD5_ROUND4(b, c, d, a, 0, 21, 0xfc93a039);
MD5_ROUND4(a, b, c, d, 0, 6, 0x655b59c3);
MD5_ROUND4(d, a, b, c, dd, 10, 0x8f0ccc92);
Expand Down

0 comments on commit 07aef97

Please sign in to comment.