Skip to content

Commit

Permalink
Need object when reading/writing encrypted PDFs (to decrypt/encrypt s…
Browse files Browse the repository at this point in the history
…trings),

RC4 writing is now working, AES-128 needs work, AES-256 hasn't been done yet.
  • Loading branch information
michaelrsweet committed Oct 23, 2021
1 parent 3af39d5 commit dd56317
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 62 deletions.
8 changes: 5 additions & 3 deletions pdfio-array.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ _pdfioArrayGetValue(pdfio_array_t *a, // I - Array

pdfio_array_t * // O - New array
_pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
pdfio_obj_t *obj, // I - Object, if any
_pdfio_token_t *tb) // I - Token buffer/stack
{
pdfio_array_t *array; // New array
Expand All @@ -584,7 +585,7 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file

// Push the token and decode the value...
_pdfioTokenPush(tb, token);
if (!_pdfioValueRead(pdf, tb, &value))
if (!_pdfioValueRead(pdf, obj, tb, &value))
break;

// PDFIO_DEBUG("_pdfioArrayRead(%p): Appending ", (void *)array);
Expand All @@ -603,7 +604,8 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
//

bool // O - `true` on success, `false` otherwise
_pdfioArrayWrite(pdfio_array_t *a) // I - Array
_pdfioArrayWrite(pdfio_array_t *a, // I - Array
pdfio_obj_t *obj) // I - Object, if any
{
pdfio_file_t *pdf = a->pdf; // PDF file
size_t i; // Looping var
Expand All @@ -617,7 +619,7 @@ _pdfioArrayWrite(pdfio_array_t *a) // I - Array
// Write each value...
for (i = a->num_values, v = a->values; i > 0; i --, v ++)
{
if (!_pdfioValueWrite(pdf, v, NULL))
if (!_pdfioValueWrite(pdf, obj, v, NULL))
return (false);
}

Expand Down
2 changes: 2 additions & 0 deletions pdfio-crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
// Initialize the RC4/AES context using the digest...
if (pdf->encryption == PDFIO_ENCRYPTION_RC4_128)
{
*ivlen = 0;
_pdfioCryptoRC4Init(&ctx->rc4, digest, sizeof(digest));
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
}
Expand Down Expand Up @@ -305,6 +306,7 @@ _pdfio_crypto_cb_t // O - Encryption callback or `NULL` for none
// Initialize the RC4/AES context using the digest...
if (pdf->encryption == PDFIO_ENCRYPTION_RC4_128)
{
*ivlen = 0;
_pdfioCryptoRC4Init(&ctx->rc4, digest, sizeof(digest));
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
}
Expand Down
6 changes: 4 additions & 2 deletions pdfio-dict.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ _pdfioDictGetValue(pdfio_dict_t *dict, // I - Dictionary

pdfio_dict_t * // O - New dictionary
_pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
pdfio_obj_t *obj, // I - Object, if any
_pdfio_token_t *tb) // I - Token buffer/stack
{
pdfio_dict_t *dict; // New dictionary
Expand Down Expand Up @@ -448,7 +449,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
}

// Then get the next value...
if (!_pdfioValueRead(pdf, tb, &value))
if (!_pdfioValueRead(pdf, obj, tb, &value))
{
_pdfioFileError(pdf, "Missing value for dictionary key.");
break;
Expand Down Expand Up @@ -850,6 +851,7 @@ _pdfioDictSetValue(

bool // O - `true` on success, `false` on failure
_pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
pdfio_obj_t *obj, // I - Object, if any
off_t *length) // I - Offset to length value
{
pdfio_file_t *pdf = dict->pdf; // PDF file
Expand Down Expand Up @@ -877,7 +879,7 @@ _pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
if (!_pdfioFilePuts(pdf, " 9999999999"))
return (false);
}
else if (!_pdfioValueWrite(pdf, &pair->value, NULL))
else if (!_pdfioValueWrite(pdf, obj, &pair->value, NULL))
return (false);
}

Expand Down
82 changes: 45 additions & 37 deletions pdfio-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ pdfioFileCreate(
pdfio_file_t *pdf; // PDF file
pdfio_dict_t *dict; // Dictionary for pages object
pdfio_dict_t *info_dict; // Dictionary for information object
unsigned char id_value[16]; // File ID value


// Range check input...
Expand Down Expand Up @@ -303,6 +304,15 @@ pdfioFileCreate(
return (NULL);
}

// Create random file ID values...
_pdfioCryptoMakeRandom(id_value, sizeof(id_value));

if ((pdf->id_array = pdfioArrayCreate(pdf)) != NULL)
{
pdfioArrayAppendBinary(pdf->id_array, id_value, sizeof(id_value));
pdfioArrayAppendBinary(pdf->id_array, id_value, sizeof(id_value));
}

return (pdf);
}

Expand Down Expand Up @@ -458,6 +468,7 @@ pdfioFileCreateOutput(
pdfio_file_t *pdf; // PDF file
pdfio_dict_t *dict; // Dictionary for pages object
pdfio_dict_t *info_dict; // Dictionary for information object
unsigned char id_value[16]; // File ID value


// Range check input...
Expand Down Expand Up @@ -558,6 +569,15 @@ pdfioFileCreateOutput(
return (NULL);
}

// Create random file ID values...
_pdfioCryptoMakeRandom(id_value, sizeof(id_value));

if ((pdf->id_array = pdfioArrayCreate(pdf)) != NULL)
{
pdfioArrayAppendBinary(pdf->id_array, id_value, sizeof(id_value));
pdfioArrayAppendBinary(pdf->id_array, id_value, sizeof(id_value));
}

return (pdf);
}

Expand Down Expand Up @@ -1099,65 +1119,64 @@ pdfioFileSetPermissions(
case PDFIO_ENCRYPTION_RC4_128 :
case PDFIO_ENCRYPTION_AES_128 :
// Create the 128-bit encryption keys...
if (user_password && *user_password)
if (user_password)
{
// Copy the user password and pad it with the special PDF pad bytes
// Use the specified user password
if ((len = strlen(user_password)) > sizeof(user_pad))
len = sizeof(user_pad);

if (len > 0)
memcpy(user_pad, user_password, len);
if (len < sizeof(user_pad))
memcpy(user_pad + len, pad, sizeof(user_pad) - len);
}
else
{
// Use default (pad) password
memcpy(user_pad, pad, sizeof(user_pad));
// No user password
len = 0;
}

if (owner_password && *owner_password)
if (len > 0)
memcpy(user_pad, user_password, len);
if (len < sizeof(user_pad))
memcpy(user_pad + len, pad, sizeof(user_pad) - len);

if (owner_password)
{
// Copy the owner password and pad it with the special PDF pad bytes
// Use the specified owner password...
if ((len = strlen(owner_password)) > sizeof(owner_pad))
len = sizeof(owner_pad);

if (len > 0)
memcpy(owner_pad, owner_password, len);
if (len < sizeof(owner_pad))
memcpy(owner_pad + len, pad, sizeof(owner_pad) - len);
}
else if (user_password && *user_password)
{
// Generate a random owner password...
_pdfioCryptoMakeRandom(owner_pad, sizeof(owner_pad));
len = sizeof(owner_pad);
}
else
{
// Use default (pad) password
memcpy(owner_pad, pad, sizeof(owner_pad));
// No owner password
len = 0;
}

if (len > 0)
memcpy(owner_pad, owner_password, len);
if (len < sizeof(owner_pad))
memcpy(owner_pad + len, pad, sizeof(owner_pad) - len);

// Compute the owner key...
_pdfioCryptoMD5Init(&md5);
_pdfioCryptoMD5Append(&md5, owner_pad, 32);
_pdfioCryptoMD5Finish(&md5, digest);

// MD5 the result 50 more times...
for (i = 0; i < 50; i ++)
{
_pdfioCryptoMD5Init(&md5);
_pdfioCryptoMD5Append(&md5, digest, 16);
_pdfioCryptoMD5Finish(&md5, digest);
}

// Copy the padded user password...
// Copy and encrypt the padded user password...
memcpy(pdf->owner_key, user_pad, sizeof(pdf->owner_key));

// Encrypt the result 20 times...
for (i = 0; i < 20; i ++)
{
uint8_t encrypt_key[16];// RC4 encryption key
uint8_t encrypt_key[16]; // RC4 encryption key

// XOR each byte in the digest with the loop counter to make a key...
for (j = 0; j < sizeof(encrypt_key); j ++)
Expand All @@ -1178,7 +1197,6 @@ pdfioFileSetPermissions(
_pdfioCryptoMD5Init(&md5);
_pdfioCryptoMD5Append(&md5, user_pad, 32);
_pdfioCryptoMD5Append(&md5, pdf->owner_key, 32);

_pdfioCryptoMD5Append(&md5, perm_bytes, 4);
_pdfioCryptoMD5Append(&md5, file_id, file_id_len);
_pdfioCryptoMD5Finish(&md5, digest);
Expand Down Expand Up @@ -1437,7 +1455,7 @@ load_obj_stream(pdfio_obj_t *obj) // I - Object to load
// Read the objects themselves...
for (cur_obj = 0; cur_obj < num_objs; cur_obj ++)
{
if (!_pdfioValueRead(obj->pdf, &tb, &(objs[cur_obj]->value)))
if (!_pdfioValueRead(obj->pdf, obj, &tb, &(objs[cur_obj]->value)))
{
pdfioStreamClose(st);
return (false);
Expand Down Expand Up @@ -1615,7 +1633,7 @@ load_xref(pdfio_file_t *pdf, // I - PDF file

_pdfioTokenInit(&tb, pdf, (_pdfio_tconsume_cb_t)_pdfioFileConsume, (_pdfio_tpeek_cb_t)_pdfioFilePeek, pdf);

if (!_pdfioValueRead(pdf, &tb, &trailer))
if (!_pdfioValueRead(pdf, obj, &tb, &trailer))
{
_pdfioFileError(pdf, "Unable to read cross-reference stream dictionary.");
return (false);
Expand Down Expand Up @@ -1863,7 +1881,7 @@ load_xref(pdfio_file_t *pdf, // I - PDF file

_pdfioTokenInit(&tb, pdf, (_pdfio_tconsume_cb_t)_pdfioFileConsume, (_pdfio_tpeek_cb_t)_pdfioFilePeek, pdf);

if (!_pdfioValueRead(pdf, &tb, &trailer))
if (!_pdfioValueRead(pdf, NULL, &tb, &trailer))
{
_pdfioFileError(pdf, "Unable to read trailer dictionary.");
return (false);
Expand Down Expand Up @@ -1982,7 +2000,6 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
bool ret = true; // Return value
off_t xref_offset; // Offset to xref table
size_t i; // Looping var
unsigned char id_values[2][16]; // ID array values


// Write the xref table...
Expand Down Expand Up @@ -2016,15 +2033,6 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
goto done;
}

_pdfioCryptoMakeRandom(id_values[0], sizeof(id_values[0]));
_pdfioCryptoMakeRandom(id_values[1], sizeof(id_values[1]));

if ((pdf->id_array = pdfioArrayCreate(pdf)) != NULL)
{
pdfioArrayAppendBinary(pdf->id_array, id_values[0], sizeof(id_values[0]));
pdfioArrayAppendBinary(pdf->id_array, id_values[1], sizeof(id_values[1]));
}

if ((pdf->trailer_dict = pdfioDictCreate(pdf)) == NULL)
{
_pdfioFileError(pdf, "Unable to create trailer.");
Expand All @@ -2040,7 +2048,7 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
pdfioDictSetObj(pdf->trailer_dict, "Root", pdf->root_obj);
pdfioDictSetNumber(pdf->trailer_dict, "Size", pdf->num_objs + 1);

if (!_pdfioDictWrite(pdf->trailer_dict, NULL))
if (!_pdfioDictWrite(pdf->trailer_dict, NULL, NULL))
{
_pdfioFileError(pdf, "Unable to write trailer.");
ret = false;
Expand Down
4 changes: 2 additions & 2 deletions pdfio-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
// Then grab the object value...
_pdfioTokenInit(&tb, obj->pdf, (_pdfio_tconsume_cb_t)_pdfioFileConsume, (_pdfio_tpeek_cb_t)_pdfioFilePeek, obj->pdf);

if (!_pdfioValueRead(obj->pdf, &tb, &obj->value))
if (!_pdfioValueRead(obj->pdf, obj, &tb, &obj->value))
{
_pdfioFileError(obj->pdf, "Unable to read value for object %lu.", (unsigned long)obj->number);
return (false);
Expand Down Expand Up @@ -479,7 +479,7 @@ write_obj_header(pdfio_obj_t *obj) // I - Object
if (!_pdfioFilePrintf(obj->pdf, "%lu %u obj\n", (unsigned long)obj->number, obj->generation))
return (false);

if (!_pdfioValueWrite(obj->pdf, &obj->value, &obj->length_offset))
if (!_pdfioValueWrite(obj->pdf, obj, &obj->value, &obj->length_offset))
return (false);

return (_pdfioFilePuts(obj->pdf, "\n"));
Expand Down
12 changes: 6 additions & 6 deletions pdfio-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,8 @@ struct _pdfio_stream_s // Stream
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
extern void _pdfioArrayDelete(pdfio_array_t *a) _PDFIO_INTERNAL;
extern _pdfio_value_t *_pdfioArrayGetValue(pdfio_array_t *a, size_t n) _PDFIO_INTERNAL;
extern pdfio_array_t *_pdfioArrayRead(pdfio_file_t *pdf, _pdfio_token_t *ts) _PDFIO_INTERNAL;
extern bool _pdfioArrayWrite(pdfio_array_t *a) _PDFIO_INTERNAL;
extern pdfio_array_t *_pdfioArrayRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts) _PDFIO_INTERNAL;
extern bool _pdfioArrayWrite(pdfio_array_t *a, pdfio_obj_t *obj) _PDFIO_INTERNAL;

extern void _pdfioCryptoAESInit(_pdfio_aes_t *ctx, const uint8_t *key, size_t keylen, const uint8_t *iv) _PDFIO_INTERNAL;
extern size_t _pdfioCryptoAESDecrypt(_pdfio_aes_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len) _PDFIO_INTERNAL;
Expand All @@ -359,9 +359,9 @@ extern void _pdfioCryptoSHA256Finish(_pdfio_sha256_t *ctx, uint8_t *Message_Dig
extern void _pdfioDictDebug(pdfio_dict_t *dict, FILE *fp) _PDFIO_INTERNAL;
extern void _pdfioDictDelete(pdfio_dict_t *dict) _PDFIO_INTERNAL;
extern _pdfio_value_t *_pdfioDictGetValue(pdfio_dict_t *dict, const char *key) _PDFIO_INTERNAL;
extern pdfio_dict_t *_pdfioDictRead(pdfio_file_t *pdf, _pdfio_token_t *ts) _PDFIO_INTERNAL;
extern pdfio_dict_t *_pdfioDictRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts) _PDFIO_INTERNAL;
extern bool _pdfioDictSetValue(pdfio_dict_t *dict, const char *key, _pdfio_value_t *value) _PDFIO_INTERNAL;
extern bool _pdfioDictWrite(pdfio_dict_t *dict, off_t *length) _PDFIO_INTERNAL;
extern bool _pdfioDictWrite(pdfio_dict_t *dict, pdfio_obj_t *obj, off_t *length) _PDFIO_INTERNAL;

extern bool _pdfioFileAddMappedObj(pdfio_file_t *pdf, pdfio_obj_t *dst_obj, pdfio_obj_t *src_obj) _PDFIO_INTERNAL;
extern bool _pdfioFileAddPage(pdfio_file_t *pdf, pdfio_obj_t *obj) _PDFIO_INTERNAL;
Expand Down Expand Up @@ -399,7 +399,7 @@ extern bool _pdfioTokenRead(_pdfio_token_t *tb, char *buffer, size_t bufsize);
extern _pdfio_value_t *_pdfioValueCopy(pdfio_file_t *pdfdst, _pdfio_value_t *vdst, pdfio_file_t *pdfsrc, _pdfio_value_t *vsrc) _PDFIO_INTERNAL;
extern void _pdfioValueDebug(_pdfio_value_t *v, FILE *fp) _PDFIO_INTERNAL;
extern void _pdfioValueDelete(_pdfio_value_t *v) _PDFIO_INTERNAL;
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, _pdfio_token_t *ts, _pdfio_value_t *v) _PDFIO_INTERNAL;
extern bool _pdfioValueWrite(pdfio_file_t *pdf, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;
extern _pdfio_value_t *_pdfioValueRead(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_token_t *ts, _pdfio_value_t *v) _PDFIO_INTERNAL;
extern bool _pdfioValueWrite(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_value_t *v, off_t *length) _PDFIO_INTERNAL;

#endif // !PDFIO_PRIVATE_H
Loading

0 comments on commit dd56317

Please sign in to comment.