From 76b77219b93e4c7a2202f259d01df4a6d34921df Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Wed, 8 Aug 2012 18:44:13 +0100 Subject: Give a warning when we ignore a transfer function. Inspired by bug 693187. --- pdf/pdf_interpret.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'pdf') diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index 704f6e78..f596b0ed 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -1538,7 +1538,7 @@ pdf_run_extgstate(pdf_csi *csi, pdf_obj *rdb, pdf_obj *extgstate) if (pdf_is_dict(val)) { pdf_xobject *xobj; - pdf_obj *group, *luminosity, *bc; + pdf_obj *group, *luminosity, *bc, *tr; if (gstate->softmask) { @@ -1572,6 +1572,19 @@ pdf_run_extgstate(pdf_csi *csi, pdf_obj *rdb, pdf_obj *extgstate) gstate->luminosity = 1; else gstate->luminosity = 0; + + tr = pdf_dict_gets(val, "TR2"); + if (tr) + { + if (strcmp(pdf_to_name(tr), "Identity") && strcmp(pdf_to_name(tr), "Default")) + fz_warn(ctx, "ignoring transfer function"); + } + else + { + tr = pdf_dict_gets(val, "TR"); + if (strcmp(pdf_to_name(tr), "Identity")) + fz_warn(ctx, "ignoring transfer function"); + } } else if (pdf_is_name(val) && !strcmp(pdf_to_name(val), "None")) { -- cgit v1.2.3 From 30ca8ec09890bf2e11055c49ce8cc47b8f8180c1 Mon Sep 17 00:00:00 2001 From: Paul Gardiner Date: Thu, 9 Aug 2012 11:28:41 +0100 Subject: Fix bug 693245: pdf_new_rect()'s implementation is questionable pdf_new_rect stored x0,y0,w,h. Now corrected to x0,y0,x1,y1. No current use is affected by the alteration, so no other changes are needed. --- pdf/pdf_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pdf') diff --git a/pdf/pdf_object.c b/pdf/pdf_object.c index 955cd5cf..35291fc9 100644 --- a/pdf/pdf_object.c +++ b/pdf/pdf_object.c @@ -588,12 +588,12 @@ pdf_obj *pdf_new_rect(fz_context *ctx, fz_rect *rect) pdf_drop_obj(item); item = NULL; - item = pdf_new_real(ctx, rect->x1 - rect->x0); + item = pdf_new_real(ctx, rect->x1); pdf_array_push(arr, item); pdf_drop_obj(item); item = NULL; - item = pdf_new_real(ctx, rect->y1 - rect->y0); + item = pdf_new_real(ctx, rect->y1); pdf_array_push(arr, item); pdf_drop_obj(item); item = NULL; -- cgit v1.2.3 From 54897267992fb0eefab3bb124577e3225ce9c672 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Thu, 9 Aug 2012 00:54:47 +0200 Subject: Fix comparison typo in encryption code --- pdf/pdf_crypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pdf') diff --git a/pdf/pdf_crypt.c b/pdf/pdf_crypt.c index 5329e845..298e105b 100644 --- a/pdf/pdf_crypt.c +++ b/pdf/pdf_crypt.c @@ -318,7 +318,7 @@ pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_crypt *crypt, (cf->length < 0 || cf->length > 256)) fz_throw(ctx, "invalid key length: %d", cf->length); if (crypt->r == 5 && - (cf->length != 128 && cf->length != 192 && cf->length == 256)) + (cf->length != 128 && cf->length != 192 && cf->length != 256)) fz_throw(ctx, "invalid key length: %d", cf->length); } -- cgit v1.2.3 From 2d2e897cd20f168dc7d93490afe61fa0b5d3ffb0 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 14 Aug 2012 19:20:02 +0200 Subject: Add PDF 1.7 ExtensionLevel 8 encryption algorithm Thanks to zeniko for implementing the algorithm. --- pdf/pdf_crypt.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 8 deletions(-) (limited to 'pdf') diff --git a/pdf/pdf_crypt.c b/pdf/pdf_crypt.c index 298e105b..aa9b1711 100644 --- a/pdf/pdf_crypt.c +++ b/pdf/pdf_crypt.c @@ -103,8 +103,8 @@ pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id) obj = pdf_dict_gets(dict, "O"); if (pdf_is_string(obj) && pdf_to_str_len(obj) == 32) memcpy(crypt->o, pdf_to_str_buf(obj), 32); - /* /O and /U are supposed to be 48 bytes long for revision 5, they're often longer, though */ - else if (crypt->r == 5 && pdf_is_string(obj) && pdf_to_str_len(obj) >= 48) + /* /O and /U are supposed to be 48 bytes long for revision 5 and 6, they're often longer, though */ + else if (crypt->r >= 5 && pdf_is_string(obj) && pdf_to_str_len(obj) >= 48) memcpy(crypt->o, pdf_to_str_buf(obj), 48); else { @@ -115,8 +115,8 @@ pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id) obj = pdf_dict_gets(dict, "U"); if (pdf_is_string(obj) && pdf_to_str_len(obj) == 32) memcpy(crypt->u, pdf_to_str_buf(obj), 32); - /* /O and /U are supposed to be 48 bytes long for revision 5, they're often longer, though */ - else if (crypt->r == 5 && pdf_is_string(obj) && pdf_to_str_len(obj) >= 48) + /* /O and /U are supposed to be 48 bytes long for revision 5 and 6, they're often longer, though */ + else if (crypt->r >= 5 && pdf_is_string(obj) && pdf_to_str_len(obj) >= 48) memcpy(crypt->u, pdf_to_str_buf(obj), 48); else if (pdf_is_string(obj) && pdf_to_str_len(obj) < 32) { @@ -138,7 +138,7 @@ pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id) crypt->p = 0xfffffffc; } - if (crypt->r == 5) + if (crypt->r == 5 || crypt->r == 6) { obj = pdf_dict_gets(dict, "OE"); if (!pdf_is_string(obj) || pdf_to_str_len(obj) != 32) @@ -320,6 +320,9 @@ pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_crypt *crypt, if (crypt->r == 5 && (cf->length != 128 && cf->length != 192 && cf->length != 256)) fz_throw(ctx, "invalid key length: %d", cf->length); + if (crypt->r == 6 && + (cf->length != 256)) + fz_throw(ctx, "invalid key length: %d", cf->length); } /* @@ -444,6 +447,101 @@ pdf_compute_encryption_key_r5(pdf_crypt *crypt, unsigned char *password, int pwl aes_crypt_cbc(&aes, AES_DECRYPT, 32, buffer + 32, ownerkey ? crypt->oe : crypt->ue, crypt->key); } +/* + * Compute an encryption key (PDF 1.7 ExtensionLevel 8 algorithm) + * + * Adobe has not yet released the details, so the algorithm reference is: + * http://esec-lab.sogeti.com/post/The-undocumented-password-validation-algorithm-of-Adobe-Reader-X + */ + +static void +pdf_compute_hardened_hash_r6(unsigned char *password, int pwlen, unsigned char salt[16], unsigned char *ownerkey, unsigned char hash[32]) +{ + unsigned char data[(128 + 64 + 48) * 64]; + unsigned char block[64]; + int block_size = 32; + int data_len = 0; + int i, j, sum; + + fz_sha256 sha256; + fz_sha384 sha384; + fz_sha512 sha512; + fz_aes aes; + + /* Step 1: calculate initial data block */ + fz_sha256_init(&sha256); + fz_sha256_update(&sha256, password, pwlen); + fz_sha256_update(&sha256, salt, 8); + if (ownerkey) + fz_sha256_update(&sha256, ownerkey, 48); + fz_sha256_final(&sha256, block); + + for (i = 0; i < 64 || i < data[data_len * 64 - 1] + 32; i++) + { + /* Step 2: repeat password and data block 64 times */ + memcpy(data, password, pwlen); + memcpy(data + pwlen, block, block_size); + memcpy(data + pwlen + block_size, ownerkey, ownerkey ? 48 : 0); + data_len = pwlen + block_size + (ownerkey ? 48 : 0); + for (j = 1; j < 64; j++) + memcpy(data + j * data_len, data, data_len); + + /* Step 3: encrypt data using data block as key and iv */ + aes_setkey_enc(&aes, block, 128); + aes_crypt_cbc(&aes, AES_ENCRYPT, data_len * 64, block + 16, data, data); + + /* Step 4: determine SHA-2 hash size for this round */ + for (j = 0, sum = 0; j < 16; j++) + sum += data[j]; + + /* Step 5: calculate data block for next round */ + block_size = 32 + (sum % 3) * 16; + switch (block_size) + { + case 32: + fz_sha256_init(&sha256); + fz_sha256_update(&sha256, data, data_len * 64); + fz_sha256_final(&sha256, block); + break; + case 48: + fz_sha384_init(&sha384); + fz_sha384_update(&sha384, data, data_len * 64); + fz_sha384_final(&sha384, block); + break; + case 64: + fz_sha512_init(&sha512); + fz_sha512_update(&sha512, data, data_len * 64); + fz_sha512_final(&sha512, block); + break; + } + } + + memset(data, 0, sizeof(data)); + memcpy(hash, block, 32); +} + +static void +pdf_compute_encryption_key_r6(pdf_crypt *crypt, unsigned char *password, int pwlen, int ownerkey, unsigned char *validationkey) +{ + unsigned char hash[32]; + unsigned char iv[16]; + fz_aes aes; + + if (pwlen > 127) + pwlen = 127; + + pdf_compute_hardened_hash_r6(password, pwlen, + (ownerkey ? crypt->o : crypt->u) + 32, + ownerkey ? crypt->u : NULL, validationkey); + pdf_compute_hardened_hash_r6(password, pwlen, + crypt->u + 40, NULL, hash); + + memset(iv, 0, sizeof(iv)); + aes_setkey_dec(&aes, hash, 256); + aes_crypt_cbc(&aes, AES_DECRYPT, 32, iv, + ownerkey ? crypt->oe : crypt->ue, crypt->key); +} + /* * Computing the user password (PDF 1.7 algorithm 3.4 and 3.5) * Also save the generated key for decrypting objects and streams in crypt->key. @@ -496,6 +594,11 @@ pdf_compute_user_password(pdf_crypt *crypt, unsigned char *password, int pwlen, { pdf_compute_encryption_key_r5(crypt, password, pwlen, 0, output); } + + if (crypt->r == 6) + { + pdf_compute_encryption_key_r6(crypt, password, pwlen, 0, output); + } } /* @@ -510,7 +613,7 @@ pdf_authenticate_user_password(pdf_crypt *crypt, unsigned char *password, int pw { unsigned char output[32]; pdf_compute_user_password(crypt, password, pwlen, output); - if (crypt->r == 2 || crypt->r == 5) + if (crypt->r == 2 || crypt->r == 5 || crypt->r == 6) return memcmp(output, crypt->u, 32) == 0; if (crypt->r == 3 || crypt->r == 4) return memcmp(output, crypt->u, 16) == 0; @@ -538,9 +641,13 @@ pdf_authenticate_owner_password(pdf_crypt *crypt, unsigned char *ownerpass, int if (crypt->r == 5) { /* PDF 1.7 ExtensionLevel 3 algorithm 3.12 */ - pdf_compute_encryption_key_r5(crypt, ownerpass, pwlen, 1, key); - + return !memcmp(key, crypt->o, 32); + } + else if (crypt->r == 6) + { + /* PDF 1.7 ExtensionLevel 8 algorithm */ + pdf_compute_encryption_key_r6(crypt, ownerpass, pwlen, 1, key); return !memcmp(key, crypt->o, 32); } -- cgit v1.2.3 From 57d4f42f76a8a019915f9e28f3d451590fb08af9 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Tue, 14 Aug 2012 20:32:19 +0200 Subject: Adjust out of range tests for encryption key lengths Encryption keys for rev. 4 and prior may at most be 128-bits. Encryption keys for rev. 5/6 may only be 256-bits long Thanks to zeniko for pointing this out. --- pdf/pdf_crypt.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'pdf') diff --git a/pdf/pdf_crypt.c b/pdf/pdf_crypt.c index aa9b1711..ec6f792b 100644 --- a/pdf/pdf_crypt.c +++ b/pdf/pdf_crypt.c @@ -315,13 +315,9 @@ pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_crypt *crypt, fz_throw(ctx, "invalid key length: %d", cf->length); if ((crypt->r == 1 || crypt->r == 2 || crypt->r == 4) && - (cf->length < 0 || cf->length > 256)) + (cf->length < 0 || cf->length > 128)) fz_throw(ctx, "invalid key length: %d", cf->length); - if (crypt->r == 5 && - (cf->length != 128 && cf->length != 192 && cf->length != 256)) - fz_throw(ctx, "invalid key length: %d", cf->length); - if (crypt->r == 6 && - (cf->length != 256)) + if ((crypt->r == 5 || crypt->r == 6) && cf->length != 256) fz_throw(ctx, "invalid key length: %d", cf->length); } -- cgit v1.2.3 From 293ea3cb17baf14ad935880345092fbc531ab705 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Thu, 16 Aug 2012 12:56:28 +0200 Subject: Silence some warnings. Mountian Lion causes various different warnings to be given, possibly because a change to clang by default. Fix them here. --- pdf/pdf_annot.c | 2 ++ pdf/pdf_nametree.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'pdf') diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c index d6b5096e..427ad964 100644 --- a/pdf/pdf_annot.c +++ b/pdf/pdf_annot.c @@ -198,6 +198,8 @@ pdf_parse_action(pdf_document *xref, pdf_obj *action) pdf_obj *obj, *dest; fz_context *ctx = xref->ctx; + UNUSED(ctx); + ld.kind = FZ_LINK_NONE; if (!action) diff --git a/pdf/pdf_nametree.c b/pdf/pdf_nametree.c index 7d8ac319..d163dc08 100644 --- a/pdf/pdf_nametree.c +++ b/pdf/pdf_nametree.c @@ -118,6 +118,8 @@ pdf_load_name_tree_imp(pdf_obj *dict, pdf_document *xref, pdf_obj *node) pdf_obj *names = pdf_dict_gets(node, "Names"); int i; + UNUSED(ctx); + if (kids && !pdf_dict_mark(node)) { int len = pdf_array_len(kids); -- cgit v1.2.3 From 25552e9f2ec3f17a0ce1cbd8d7818170d132959a Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Fri, 17 Aug 2012 14:52:47 +0200 Subject: Rename fz_new_name to pdf_new_name. Should have been pdf_new_name ever since the pre 1.0 rename, but evidently we missed it. --- pdf/mupdf.h | 2 +- pdf/pdf_object.c | 4 ++-- pdf/pdf_parse.c | 12 ++++++------ pdf/pdf_write.c | 4 ++-- pdf/pdf_xobject.c | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) (limited to 'pdf') diff --git a/pdf/mupdf.h b/pdf/mupdf.h index 59302951..6ebe4437 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -17,7 +17,7 @@ pdf_obj *pdf_new_null(fz_context *ctx); pdf_obj *pdf_new_bool(fz_context *ctx, int b); pdf_obj *pdf_new_int(fz_context *ctx, int i); pdf_obj *pdf_new_real(fz_context *ctx, float f); -pdf_obj *fz_new_name(fz_context *ctx, char *str); +pdf_obj *pdf_new_name(fz_context *ctx, char *str); pdf_obj *pdf_new_string(fz_context *ctx, char *str, int len); pdf_obj *pdf_new_indirect(fz_context *ctx, int num, int gen, void *doc); pdf_obj *pdf_new_array(fz_context *ctx, int initialcap); diff --git a/pdf/pdf_object.c b/pdf/pdf_object.c index 35291fc9..9c6e0e9a 100644 --- a/pdf/pdf_object.c +++ b/pdf/pdf_object.c @@ -117,7 +117,7 @@ pdf_new_string(fz_context *ctx, char *str, int len) } pdf_obj * -fz_new_name(fz_context *ctx, char *str) +pdf_new_name(fz_context *ctx, char *str) { pdf_obj *obj; obj = Memento_label(fz_malloc(ctx, offsetof(pdf_obj, u.n) + strlen(str) + 1), "pdf_obj(name)"); @@ -945,7 +945,7 @@ pdf_dict_put(pdf_obj *obj, pdf_obj *key, pdf_obj *val) void pdf_dict_puts(pdf_obj *obj, char *key, pdf_obj *val) { - pdf_obj *keyobj = fz_new_name(obj->ctx, key); + pdf_obj *keyobj = pdf_new_name(obj->ctx, key); pdf_dict_put(obj, keyobj, val); pdf_drop_obj(keyobj); } diff --git a/pdf/pdf_parse.c b/pdf/pdf_parse.c index dd710891..542b1af7 100644 --- a/pdf/pdf_parse.c +++ b/pdf/pdf_parse.c @@ -165,7 +165,7 @@ pdf_obj * pdf_to_utf8_name(fz_context *ctx, pdf_obj *src) { char *buf = pdf_to_utf8(ctx, src); - pdf_obj *dst = fz_new_name(ctx, buf); + pdf_obj *dst = pdf_new_name(ctx, buf); fz_free(ctx, buf); return dst; } @@ -258,7 +258,7 @@ pdf_parse_array(pdf_document *xref, fz_stream *file, pdf_lexbuf *buf) break; case PDF_TOK_NAME: - obj = fz_new_name(ctx, buf->scratch); + obj = pdf_new_name(ctx, buf->scratch); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; @@ -341,7 +341,7 @@ pdf_parse_dict(pdf_document *xref, fz_stream *file, pdf_lexbuf *buf) if (tok != PDF_TOK_NAME) fz_throw(ctx, "invalid key in dict"); - key = fz_new_name(ctx, buf->scratch); + key = pdf_new_name(ctx, buf->scratch); tok = pdf_lex(file, buf); @@ -355,7 +355,7 @@ pdf_parse_dict(pdf_document *xref, fz_stream *file, pdf_lexbuf *buf) val = pdf_parse_dict(xref, file, buf); break; - case PDF_TOK_NAME: val = fz_new_name(ctx, buf->scratch); break; + case PDF_TOK_NAME: val = pdf_new_name(ctx, buf->scratch); break; case PDF_TOK_REAL: val = pdf_new_real(ctx, buf->f); break; case PDF_TOK_STRING: val = pdf_new_string(ctx, buf->scratch, buf->len); break; case PDF_TOK_TRUE: val = pdf_new_bool(ctx, 1); break; @@ -424,7 +424,7 @@ pdf_parse_stm_obj(pdf_document *xref, fz_stream *file, pdf_lexbuf *buf) return pdf_parse_array(xref, file, buf); case PDF_TOK_OPEN_DICT: return pdf_parse_dict(xref, file, buf); - case PDF_TOK_NAME: return fz_new_name(ctx, buf->scratch); break; + case PDF_TOK_NAME: return pdf_new_name(ctx, buf->scratch); break; case PDF_TOK_REAL: return pdf_new_real(ctx, buf->f); break; case PDF_TOK_STRING: return pdf_new_string(ctx, buf->scratch, buf->len); break; case PDF_TOK_TRUE: return pdf_new_bool(ctx, 1); break; @@ -475,7 +475,7 @@ pdf_parse_ind_obj(pdf_document *xref, obj = pdf_parse_dict(xref, file, buf); break; - case PDF_TOK_NAME: obj = fz_new_name(ctx, buf->scratch); break; + case PDF_TOK_NAME: obj = pdf_new_name(ctx, buf->scratch); break; case PDF_TOK_REAL: obj = pdf_new_real(ctx, buf->f); break; case PDF_TOK_STRING: obj = pdf_new_string(ctx, buf->scratch, buf->len); break; case PDF_TOK_TRUE: obj = pdf_new_bool(ctx, 1); break; diff --git a/pdf/pdf_write.c b/pdf/pdf_write.c index 6a07894a..c2ca3541 100644 --- a/pdf/pdf_write.c +++ b/pdf/pdf_write.c @@ -1054,7 +1054,7 @@ add_linearization_objs(pdf_document *xref, pdf_write_options *opts) /* FIXME: Do we have document information? Do an I entry */ /* FIXME: Do we have logical structure heirarchy? Do a C entry */ /* FIXME: Do L, Page Label hint table */ - o = fz_new_name(ctx, "FlateDecode"); + o = pdf_new_name(ctx, "FlateDecode"); pdf_dict_puts(hint_obj, "Filter", o); pdf_drop_obj(o); o = NULL; @@ -1426,7 +1426,7 @@ static void addhexfilter(pdf_document *xref, pdf_obj *dict) pdf_obj *ahx, *nullobj; fz_context *ctx = xref->ctx; - ahx = fz_new_name(ctx, "ASCIIHexDecode"); + ahx = pdf_new_name(ctx, "ASCIIHexDecode"); nullobj = pdf_new_null(ctx); newf = newdp = NULL; diff --git a/pdf/pdf_xobject.c b/pdf/pdf_xobject.c index c5fc2a83..f9a5793f 100644 --- a/pdf/pdf_xobject.c +++ b/pdf/pdf_xobject.c @@ -153,11 +153,11 @@ pdf_new_xobject(pdf_document *xref, fz_rect *bbox, fz_matrix *mat) res = pdf_new_dict(ctx, 0); procset = pdf_new_array(ctx, 2); - obj = fz_new_name(ctx, "PDF"); + obj = pdf_new_name(ctx, "PDF"); pdf_array_push(procset, obj); pdf_drop_obj(obj); obj = NULL; - obj = fz_new_name(ctx, "Text"); + obj = pdf_new_name(ctx, "Text"); pdf_array_push(procset, obj); pdf_drop_obj(obj); obj = NULL; @@ -166,12 +166,12 @@ pdf_new_xobject(pdf_document *xref, fz_rect *bbox, fz_matrix *mat) procset = NULL; pdf_dict_puts(dict, "Resources", res); - obj = fz_new_name(ctx, "Form"); + obj = pdf_new_name(ctx, "Form"); pdf_dict_puts(dict, "Subtype", obj); pdf_drop_obj(obj); obj = NULL; - obj = fz_new_name(ctx, "XObject"); + obj = pdf_new_name(ctx, "XObject"); pdf_dict_puts(dict, "Type", obj); pdf_drop_obj(obj); obj = NULL; -- cgit v1.2.3