summaryrefslogtreecommitdiff
path: root/pdf/pdf_crypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'pdf/pdf_crypt.c')
-rw-r--r--pdf/pdf_crypt.c212
1 files changed, 111 insertions, 101 deletions
diff --git a/pdf/pdf_crypt.c b/pdf/pdf_crypt.c
index 59423a38..b65786d9 100644
--- a/pdf/pdf_crypt.c
+++ b/pdf/pdf_crypt.c
@@ -1,5 +1,5 @@
-#include "fitz.h"
-#include "mupdf.h"
+#include "fitz-internal.h"
+#include "mupdf-internal.h"
enum
{
@@ -20,11 +20,11 @@ struct pdf_crypt_filter_s
struct pdf_crypt_s
{
- fz_obj *id;
+ pdf_obj *id;
int v;
int length;
- fz_obj *cf;
+ pdf_obj *cf;
pdf_crypt_filter stmf;
pdf_crypt_filter strf;
@@ -40,7 +40,7 @@ struct pdf_crypt_s
fz_context *ctx;
};
-static void pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, fz_obj *dict, char *name, int defaultlength);
+static void pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_obj *dict, char *name, int defaultlength);
/*
* Create crypt object for decrypting strings and streams
@@ -48,31 +48,31 @@ static void pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, fz_obj
*/
pdf_crypt *
-pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id)
+pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id)
{
pdf_crypt *crypt;
- fz_obj *obj;
+ pdf_obj *obj;
crypt = fz_malloc_struct(ctx, pdf_crypt);
/* Common to all security handlers (PDF 1.7 table 3.18) */
- obj = fz_dict_gets(dict, "Filter");
- if (!fz_is_name(obj))
+ obj = pdf_dict_gets(dict, "Filter");
+ if (!pdf_is_name(obj))
{
pdf_free_crypt(ctx, crypt);
fz_throw(ctx, "unspecified encryption handler");
}
- if (strcmp(fz_to_name(obj), "Standard") != 0)
+ if (strcmp(pdf_to_name(obj), "Standard") != 0)
{
pdf_free_crypt(ctx, crypt);
- fz_throw(ctx, "unknown encryption handler: '%s'", fz_to_name(obj));
+ fz_throw(ctx, "unknown encryption handler: '%s'", pdf_to_name(obj));
}
crypt->v = 0;
- obj = fz_dict_gets(dict, "V");
- if (fz_is_int(obj))
- crypt->v = fz_to_int(obj);
+ obj = pdf_dict_gets(dict, "V");
+ if (pdf_is_int(obj))
+ crypt->v = pdf_to_int(obj);
if (crypt->v != 1 && crypt->v != 2 && crypt->v != 4 && crypt->v != 5)
{
pdf_free_crypt(ctx, crypt);
@@ -82,9 +82,9 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id)
crypt->length = 40;
if (crypt->v == 2 || crypt->v == 4)
{
- obj = fz_dict_gets(dict, "Length");
- if (fz_is_int(obj))
- crypt->length = fz_to_int(obj);
+ obj = pdf_dict_gets(dict, "Length");
+ if (pdf_is_int(obj))
+ crypt->length = pdf_to_int(obj);
/* work-around for pdf generators that assume length is in bytes */
if (crypt->length < 40)
@@ -122,10 +122,10 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id)
crypt->strf.method = PDF_CRYPT_NONE;
crypt->strf.length = crypt->length;
- obj = fz_dict_gets(dict, "CF");
- if (fz_is_dict(obj))
+ obj = pdf_dict_gets(dict, "CF");
+ if (pdf_is_dict(obj))
{
- crypt->cf = fz_keep_obj(obj);
+ crypt->cf = pdf_keep_obj(obj);
}
else
{
@@ -134,18 +134,18 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id)
fz_try(ctx)
{
- obj = fz_dict_gets(dict, "StmF");
- if (fz_is_name(obj))
- pdf_parse_crypt_filter(ctx, &crypt->stmf, crypt->cf, fz_to_name(obj), crypt->length);
+ obj = pdf_dict_gets(dict, "StmF");
+ if (pdf_is_name(obj))
+ pdf_parse_crypt_filter(ctx, &crypt->stmf, crypt->cf, pdf_to_name(obj), crypt->length);
- obj = fz_dict_gets(dict, "StrF");
- if (fz_is_name(obj))
- pdf_parse_crypt_filter(ctx, &crypt->strf, crypt->cf, fz_to_name(obj), crypt->length);
+ obj = pdf_dict_gets(dict, "StrF");
+ if (pdf_is_name(obj))
+ pdf_parse_crypt_filter(ctx, &crypt->strf, crypt->cf, pdf_to_name(obj), crypt->length);
}
fz_catch(ctx)
{
pdf_free_crypt(ctx, crypt);
- fz_throw(ctx, "cannot parse string crypt filter (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
+ fz_throw(ctx, "cannot parse string crypt filter (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj));
}
/* in crypt revision 4, the crypt filter determines the key length */
@@ -155,36 +155,46 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id)
/* Standard security handler (PDF 1.7 table 3.19) */
- obj = fz_dict_gets(dict, "R");
- if (fz_is_int(obj))
- crypt->r = fz_to_int(obj);
+ obj = pdf_dict_gets(dict, "R");
+ if (pdf_is_int(obj))
+ crypt->r = pdf_to_int(obj);
+ else if (crypt->v <= 4)
+ {
+ fz_warn(ctx, "encryption dictionary missing revision value, guessing...");
+ if (crypt->v < 2)
+ crypt->r = 2;
+ else if (crypt->v == 2 || crypt->v == 3)
+ crypt->r = 3;
+ else if (crypt->v == 4)
+ crypt->r = 4;
+ }
else
{
pdf_free_crypt(ctx, crypt);
- fz_throw(ctx, "encryption dictionary missing revision value");
+ fz_throw(ctx, "encryption dictionary missing version and revision value");
}
- obj = fz_dict_gets(dict, "O");
- if (fz_is_string(obj) && fz_to_str_len(obj) == 32)
- memcpy(crypt->o, fz_to_str_buf(obj), 32);
+ 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 && fz_is_string(obj) && fz_to_str_len(obj) >= 48)
- memcpy(crypt->o, fz_to_str_buf(obj), 48);
+ 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
{
pdf_free_crypt(ctx, crypt);
fz_throw(ctx, "encryption dictionary missing owner password");
}
- obj = fz_dict_gets(dict, "U");
- if (fz_is_string(obj) && fz_to_str_len(obj) == 32)
- memcpy(crypt->u, fz_to_str_buf(obj), 32);
- else if (fz_is_string(obj) && fz_to_str_len(obj) >= 48 && crypt->r == 5)
- memcpy(crypt->u, fz_to_str_buf(obj), 48);
- else if (fz_is_string(obj) && fz_to_str_len(obj) < 32)
+ 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);
+ else if (pdf_is_string(obj) && pdf_to_str_len(obj) >= 48 && crypt->r == 5)
+ memcpy(crypt->u, pdf_to_str_buf(obj), 48);
+ else if (pdf_is_string(obj) && pdf_to_str_len(obj) < 32)
{
- fz_warn(ctx, "encryption password key too short (%d)", fz_to_str_len(obj));
- memcpy(crypt->u, fz_to_str_buf(obj), fz_to_str_len(obj));
+ fz_warn(ctx, "encryption password key too short (%d)", pdf_to_str_len(obj));
+ memcpy(crypt->u, pdf_to_str_buf(obj), pdf_to_str_len(obj));
}
else
{
@@ -192,46 +202,46 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id)
fz_throw(ctx, "encryption dictionary missing user password");
}
- obj = fz_dict_gets(dict, "P");
- if (fz_is_int(obj))
- crypt->p = fz_to_int(obj);
+ obj = pdf_dict_gets(dict, "P");
+ if (pdf_is_int(obj))
+ crypt->p = pdf_to_int(obj);
else
{
- pdf_free_crypt(ctx, crypt);
- fz_throw(ctx, "encryption dictionary missing permissions value");
+ fz_warn(ctx, "encryption dictionary missing permissions");
+ crypt->p = 0xfffffffc;
}
if (crypt->r == 5)
{
- obj = fz_dict_gets(dict, "OE");
- if (!fz_is_string(obj) || fz_to_str_len(obj) != 32)
+ obj = pdf_dict_gets(dict, "OE");
+ if (!pdf_is_string(obj) || pdf_to_str_len(obj) != 32)
{
pdf_free_crypt(ctx, crypt);
fz_throw(ctx, "encryption dictionary missing owner encryption key");
}
- memcpy(crypt->oe, fz_to_str_buf(obj), 32);
+ memcpy(crypt->oe, pdf_to_str_buf(obj), 32);
- obj = fz_dict_gets(dict, "UE");
- if (!fz_is_string(obj) || fz_to_str_len(obj) != 32)
+ obj = pdf_dict_gets(dict, "UE");
+ if (!pdf_is_string(obj) || pdf_to_str_len(obj) != 32)
{
pdf_free_crypt(ctx, crypt);
fz_throw(ctx, "encryption dictionary missing user encryption key");
}
- memcpy(crypt->ue, fz_to_str_buf(obj), 32);
+ memcpy(crypt->ue, pdf_to_str_buf(obj), 32);
}
crypt->encrypt_metadata = 1;
- obj = fz_dict_gets(dict, "EncryptMetadata");
- if (fz_is_bool(obj))
- crypt->encrypt_metadata = fz_to_bool(obj);
+ obj = pdf_dict_gets(dict, "EncryptMetadata");
+ if (pdf_is_bool(obj))
+ crypt->encrypt_metadata = pdf_to_bool(obj);
/* Extract file identifier string */
- if (fz_is_array(id) && fz_array_len(id) == 2)
+ if (pdf_is_array(id) && pdf_array_len(id) == 2)
{
- obj = fz_array_get(id, 0);
- if (fz_is_string(obj))
- crypt->id = fz_keep_obj(obj);
+ obj = pdf_array_get(id, 0);
+ if (pdf_is_string(obj))
+ crypt->id = pdf_keep_obj(obj);
}
else
fz_warn(ctx, "missing file identifier, may not be able to do decryption");
@@ -242,8 +252,8 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id)
void
pdf_free_crypt(fz_context *ctx, pdf_crypt *crypt)
{
- if (crypt->id) fz_drop_obj(crypt->id);
- if (crypt->cf) fz_drop_obj(crypt->cf);
+ if (crypt->id) pdf_drop_obj(crypt->id);
+ if (crypt->cf) pdf_drop_obj(crypt->cf);
fz_free(ctx, crypt);
}
@@ -252,15 +262,15 @@ pdf_free_crypt(fz_context *ctx, pdf_crypt *crypt)
*/
static void
-pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, fz_obj *cf_obj, char *name, int defaultlength)
+pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_obj *cf_obj, char *name, int defaultlength)
{
- fz_obj *obj;
- fz_obj *dict;
+ pdf_obj *obj;
+ pdf_obj *dict;
int is_identity = (strcmp(name, "Identity") == 0);
int is_stdcf = (!is_identity && (strcmp(name, "StdCF") == 0));
if (!is_identity && !is_stdcf)
- fz_throw(ctx, "Crypt Filter not Identity or StdCF (%d %d R)", fz_to_num(cf_obj), fz_to_gen(cf_obj));
+ fz_throw(ctx, "Crypt Filter not Identity or StdCF (%d %d R)", pdf_to_num(cf_obj), pdf_to_gen(cf_obj));
cf->method = PDF_CRYPT_NONE;
cf->length = defaultlength;
@@ -271,28 +281,28 @@ pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, fz_obj *cf_obj, ch
return;
}
- dict = fz_dict_gets(cf_obj, name);
- if (!fz_is_dict(dict))
- fz_throw(ctx, "cannot parse crypt filter (%d %d R)", fz_to_num(cf_obj), fz_to_gen(cf_obj));
+ dict = pdf_dict_gets(cf_obj, name);
+ if (!pdf_is_dict(dict))
+ fz_throw(ctx, "cannot parse crypt filter (%d %d R)", pdf_to_num(cf_obj), pdf_to_gen(cf_obj));
- obj = fz_dict_gets(dict, "CFM");
- if (fz_is_name(obj))
+ obj = pdf_dict_gets(dict, "CFM");
+ if (pdf_is_name(obj))
{
- if (!strcmp(fz_to_name(obj), "None"))
+ if (!strcmp(pdf_to_name(obj), "None"))
cf->method = PDF_CRYPT_NONE;
- else if (!strcmp(fz_to_name(obj), "V2"))
+ else if (!strcmp(pdf_to_name(obj), "V2"))
cf->method = PDF_CRYPT_RC4;
- else if (!strcmp(fz_to_name(obj), "AESV2"))
+ else if (!strcmp(pdf_to_name(obj), "AESV2"))
cf->method = PDF_CRYPT_AESV2;
- else if (!strcmp(fz_to_name(obj), "AESV3"))
+ else if (!strcmp(pdf_to_name(obj), "AESV3"))
cf->method = PDF_CRYPT_AESV3;
else
- fz_warn(ctx, "unknown encryption method: %s", fz_to_name(obj));
+ fz_warn(ctx, "unknown encryption method: %s", pdf_to_name(obj));
}
- obj = fz_dict_gets(dict, "Length");
- if (fz_is_int(obj))
- cf->length = fz_to_int(obj);
+ obj = pdf_dict_gets(dict, "Length");
+ if (pdf_is_int(obj))
+ cf->length = pdf_to_int(obj);
/* the length for crypt filters is supposed to be in bytes not bits */
if (cf->length < 40)
@@ -346,7 +356,7 @@ pdf_compute_encryption_key(pdf_crypt *crypt, unsigned char *password, int pwlen,
fz_md5_update(&md5, buf, 4);
/* Step 5 - pass first element of ID array */
- fz_md5_update(&md5, (unsigned char *)fz_to_str_buf(crypt->id), fz_to_str_len(crypt->id));
+ fz_md5_update(&md5, (unsigned char *)pdf_to_str_buf(crypt->id), pdf_to_str_len(crypt->id));
/* Step 6 (revision 4 or greater) - if metadata is not encrypted pass 0xFFFFFFFF */
if (crypt->r >= 4)
@@ -455,7 +465,7 @@ pdf_compute_user_password(pdf_crypt *crypt, unsigned char *password, int pwlen,
fz_md5_init(&md5);
fz_md5_update(&md5, padding, 32);
- fz_md5_update(&md5, (unsigned char*)fz_to_str_buf(crypt->id), fz_to_str_len(crypt->id));
+ fz_md5_update(&md5, (unsigned char*)pdf_to_str_buf(crypt->id), pdf_to_str_len(crypt->id));
fz_md5_final(&md5, digest);
fz_arc4_init(&arc4, crypt->key, n);
@@ -608,7 +618,7 @@ pdf_has_permission(pdf_document *xref, int p)
}
unsigned char *
-pdf_get_crypt_key(pdf_document *xref)
+pdf_crypt_key(pdf_document *xref)
{
if (xref->crypt)
return xref->crypt->key;
@@ -616,7 +626,7 @@ pdf_get_crypt_key(pdf_document *xref)
}
int
-pdf_get_crypt_revision(pdf_document *xref)
+pdf_crypt_revision(pdf_document *xref)
{
if (xref->crypt)
return xref->crypt->v;
@@ -624,7 +634,7 @@ pdf_get_crypt_revision(pdf_document *xref)
}
char *
-pdf_get_crypt_method(pdf_document *xref)
+pdf_crypt_method(pdf_document *xref)
{
if (xref->crypt)
{
@@ -641,7 +651,7 @@ pdf_get_crypt_method(pdf_document *xref)
}
int
-pdf_get_crypt_length(pdf_document *xref)
+pdf_crypt_length(pdf_document *xref)
{
if (xref->crypt)
return xref->crypt->length;
@@ -697,18 +707,18 @@ pdf_compute_object_key(pdf_crypt *crypt, pdf_crypt_filter *cf, int num, int gen,
*/
static void
-pdf_crypt_obj_imp(fz_context *ctx, pdf_crypt *crypt, fz_obj *obj, unsigned char *key, int keylen)
+pdf_crypt_obj_imp(fz_context *ctx, pdf_crypt *crypt, pdf_obj *obj, unsigned char *key, int keylen)
{
unsigned char *s;
int i, n;
- if (fz_is_indirect(obj))
+ if (pdf_is_indirect(obj))
return;
- if (fz_is_string(obj))
+ if (pdf_is_string(obj))
{
- s = (unsigned char *)fz_to_str_buf(obj);
- n = fz_to_str_len(obj);
+ s = (unsigned char *)pdf_to_str_buf(obj);
+ n = pdf_to_str_len(obj);
if (crypt->strf.method == PDF_CRYPT_RC4)
{
@@ -736,32 +746,32 @@ pdf_crypt_obj_imp(fz_context *ctx, pdf_crypt *crypt, fz_obj *obj, unsigned char
if (s[n - 17] < 1 || s[n - 17] > 16)
fz_warn(ctx, "aes padding out of range");
else
- fz_set_str_len(obj, n - 16 - s[n - 17]);
+ pdf_set_str_len(obj, n - 16 - s[n - 17]);
}
}
}
- else if (fz_is_array(obj))
+ else if (pdf_is_array(obj))
{
- n = fz_array_len(obj);
+ n = pdf_array_len(obj);
for (i = 0; i < n; i++)
{
- pdf_crypt_obj_imp(ctx, crypt, fz_array_get(obj, i), key, keylen);
+ pdf_crypt_obj_imp(ctx, crypt, pdf_array_get(obj, i), key, keylen);
}
}
- else if (fz_is_dict(obj))
+ else if (pdf_is_dict(obj))
{
- n = fz_dict_len(obj);
+ n = pdf_dict_len(obj);
for (i = 0; i < n; i++)
{
- pdf_crypt_obj_imp(ctx, crypt, fz_dict_get_val(obj, i), key, keylen);
+ pdf_crypt_obj_imp(ctx, crypt, pdf_dict_get_val(obj, i), key, keylen);
}
}
}
void
-pdf_crypt_obj(fz_context *ctx, pdf_crypt *crypt, fz_obj *obj, int num, int gen)
+pdf_crypt_obj(fz_context *ctx, pdf_crypt *crypt, pdf_obj *obj, int num, int gen)
{
unsigned char key[32];
int len;
@@ -812,7 +822,7 @@ pdf_open_crypt_with_filter(fz_stream *chain, pdf_crypt *crypt, char *name, int n
return chain;
}
-void pdf_debug_crypt(pdf_crypt *crypt)
+void pdf_print_crypt(pdf_crypt *crypt)
{
int i;