Need object when reading/writing encrypted PDFs (to decrypt/encrypt strings),

RC4 writing is now working, AES-128 needs work, AES-256 hasn't been done yet.
This commit is contained in:
Michael R Sweet 2021-10-23 18:08:16 -04:00
parent 3af39d5d1f
commit dd56317635
No known key found for this signature in database
GPG Key ID: 999559A027815955
8 changed files with 175 additions and 62 deletions

View File

@ -560,6 +560,7 @@ _pdfioArrayGetValue(pdfio_array_t *a, // I - Array
pdfio_array_t * // O - New array pdfio_array_t * // O - New array
_pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file _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_token_t *tb) // I - Token buffer/stack
{ {
pdfio_array_t *array; // New array pdfio_array_t *array; // New array
@ -584,7 +585,7 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
// Push the token and decode the value... // Push the token and decode the value...
_pdfioTokenPush(tb, token); _pdfioTokenPush(tb, token);
if (!_pdfioValueRead(pdf, tb, &value)) if (!_pdfioValueRead(pdf, obj, tb, &value))
break; break;
// PDFIO_DEBUG("_pdfioArrayRead(%p): Appending ", (void *)array); // PDFIO_DEBUG("_pdfioArrayRead(%p): Appending ", (void *)array);
@ -603,7 +604,8 @@ _pdfioArrayRead(pdfio_file_t *pdf, // I - PDF file
// //
bool // O - `true` on success, `false` otherwise 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 pdfio_file_t *pdf = a->pdf; // PDF file
size_t i; // Looping var size_t i; // Looping var
@ -617,7 +619,7 @@ _pdfioArrayWrite(pdfio_array_t *a) // I - Array
// Write each value... // Write each value...
for (i = a->num_values, v = a->values; i > 0; i --, v ++) 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); return (false);
} }

View File

@ -244,6 +244,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
// Initialize the RC4/AES context using the digest... // Initialize the RC4/AES context using the digest...
if (pdf->encryption == PDFIO_ENCRYPTION_RC4_128) if (pdf->encryption == PDFIO_ENCRYPTION_RC4_128)
{ {
*ivlen = 0;
_pdfioCryptoRC4Init(&ctx->rc4, digest, sizeof(digest)); _pdfioCryptoRC4Init(&ctx->rc4, digest, sizeof(digest));
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt); return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
} }
@ -305,6 +306,7 @@ _pdfio_crypto_cb_t // O - Encryption callback or `NULL` for none
// Initialize the RC4/AES context using the digest... // Initialize the RC4/AES context using the digest...
if (pdf->encryption == PDFIO_ENCRYPTION_RC4_128) if (pdf->encryption == PDFIO_ENCRYPTION_RC4_128)
{ {
*ivlen = 0;
_pdfioCryptoRC4Init(&ctx->rc4, digest, sizeof(digest)); _pdfioCryptoRC4Init(&ctx->rc4, digest, sizeof(digest));
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt); return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
} }

View File

@ -420,6 +420,7 @@ _pdfioDictGetValue(pdfio_dict_t *dict, // I - Dictionary
pdfio_dict_t * // O - New dictionary pdfio_dict_t * // O - New dictionary
_pdfioDictRead(pdfio_file_t *pdf, // I - PDF file _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_token_t *tb) // I - Token buffer/stack
{ {
pdfio_dict_t *dict; // New dictionary pdfio_dict_t *dict; // New dictionary
@ -448,7 +449,7 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
} }
// Then get the next value... // Then get the next value...
if (!_pdfioValueRead(pdf, tb, &value)) if (!_pdfioValueRead(pdf, obj, tb, &value))
{ {
_pdfioFileError(pdf, "Missing value for dictionary key."); _pdfioFileError(pdf, "Missing value for dictionary key.");
break; break;
@ -850,6 +851,7 @@ _pdfioDictSetValue(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
_pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary _pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
pdfio_obj_t *obj, // I - Object, if any
off_t *length) // I - Offset to length value off_t *length) // I - Offset to length value
{ {
pdfio_file_t *pdf = dict->pdf; // PDF file pdfio_file_t *pdf = dict->pdf; // PDF file
@ -877,7 +879,7 @@ _pdfioDictWrite(pdfio_dict_t *dict, // I - Dictionary
if (!_pdfioFilePuts(pdf, " 9999999999")) if (!_pdfioFilePuts(pdf, " 9999999999"))
return (false); return (false);
} }
else if (!_pdfioValueWrite(pdf, &pair->value, NULL)) else if (!_pdfioValueWrite(pdf, obj, &pair->value, NULL))
return (false); return (false);
} }

View File

@ -193,6 +193,7 @@ pdfioFileCreate(
pdfio_file_t *pdf; // PDF file pdfio_file_t *pdf; // PDF file
pdfio_dict_t *dict; // Dictionary for pages object pdfio_dict_t *dict; // Dictionary for pages object
pdfio_dict_t *info_dict; // Dictionary for information object pdfio_dict_t *info_dict; // Dictionary for information object
unsigned char id_value[16]; // File ID value
// Range check input... // Range check input...
@ -303,6 +304,15 @@ pdfioFileCreate(
return (NULL); 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); return (pdf);
} }
@ -458,6 +468,7 @@ pdfioFileCreateOutput(
pdfio_file_t *pdf; // PDF file pdfio_file_t *pdf; // PDF file
pdfio_dict_t *dict; // Dictionary for pages object pdfio_dict_t *dict; // Dictionary for pages object
pdfio_dict_t *info_dict; // Dictionary for information object pdfio_dict_t *info_dict; // Dictionary for information object
unsigned char id_value[16]; // File ID value
// Range check input... // Range check input...
@ -558,6 +569,15 @@ pdfioFileCreateOutput(
return (NULL); 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); return (pdf);
} }
@ -1099,51 +1119,51 @@ pdfioFileSetPermissions(
case PDFIO_ENCRYPTION_RC4_128 : case PDFIO_ENCRYPTION_RC4_128 :
case PDFIO_ENCRYPTION_AES_128 : case PDFIO_ENCRYPTION_AES_128 :
// Create the 128-bit encryption keys... // 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)) if ((len = strlen(user_password)) > sizeof(user_pad))
len = 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 else
{ {
// Use default (pad) password // No user password
memcpy(user_pad, pad, sizeof(user_pad)); 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)) if ((len = strlen(owner_password)) > sizeof(owner_pad))
len = 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) else if (user_password && *user_password)
{ {
// Generate a random owner password... // Generate a random owner password...
_pdfioCryptoMakeRandom(owner_pad, sizeof(owner_pad)); _pdfioCryptoMakeRandom(owner_pad, sizeof(owner_pad));
len = sizeof(owner_pad);
} }
else else
{ {
// Use default (pad) password // No owner password
memcpy(owner_pad, pad, sizeof(owner_pad)); 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... // Compute the owner key...
_pdfioCryptoMD5Init(&md5); _pdfioCryptoMD5Init(&md5);
_pdfioCryptoMD5Append(&md5, owner_pad, 32); _pdfioCryptoMD5Append(&md5, owner_pad, 32);
_pdfioCryptoMD5Finish(&md5, digest); _pdfioCryptoMD5Finish(&md5, digest);
// MD5 the result 50 more times...
for (i = 0; i < 50; i ++) for (i = 0; i < 50; i ++)
{ {
_pdfioCryptoMD5Init(&md5); _pdfioCryptoMD5Init(&md5);
@ -1151,13 +1171,12 @@ pdfioFileSetPermissions(
_pdfioCryptoMD5Finish(&md5, digest); _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)); memcpy(pdf->owner_key, user_pad, sizeof(pdf->owner_key));
// Encrypt the result 20 times...
for (i = 0; i < 20; i ++) 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... // XOR each byte in the digest with the loop counter to make a key...
for (j = 0; j < sizeof(encrypt_key); j ++) for (j = 0; j < sizeof(encrypt_key); j ++)
@ -1178,7 +1197,6 @@ pdfioFileSetPermissions(
_pdfioCryptoMD5Init(&md5); _pdfioCryptoMD5Init(&md5);
_pdfioCryptoMD5Append(&md5, user_pad, 32); _pdfioCryptoMD5Append(&md5, user_pad, 32);
_pdfioCryptoMD5Append(&md5, pdf->owner_key, 32); _pdfioCryptoMD5Append(&md5, pdf->owner_key, 32);
_pdfioCryptoMD5Append(&md5, perm_bytes, 4); _pdfioCryptoMD5Append(&md5, perm_bytes, 4);
_pdfioCryptoMD5Append(&md5, file_id, file_id_len); _pdfioCryptoMD5Append(&md5, file_id, file_id_len);
_pdfioCryptoMD5Finish(&md5, digest); _pdfioCryptoMD5Finish(&md5, digest);
@ -1437,7 +1455,7 @@ load_obj_stream(pdfio_obj_t *obj) // I - Object to load
// Read the objects themselves... // Read the objects themselves...
for (cur_obj = 0; cur_obj < num_objs; cur_obj ++) 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); pdfioStreamClose(st);
return (false); return (false);
@ -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); _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."); _pdfioFileError(pdf, "Unable to read cross-reference stream dictionary.");
return (false); return (false);
@ -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); _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."); _pdfioFileError(pdf, "Unable to read trailer dictionary.");
return (false); return (false);
@ -1982,7 +2000,6 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
bool ret = true; // Return value bool ret = true; // Return value
off_t xref_offset; // Offset to xref table off_t xref_offset; // Offset to xref table
size_t i; // Looping var size_t i; // Looping var
unsigned char id_values[2][16]; // ID array values
// Write the xref table... // Write the xref table...
@ -2016,15 +2033,6 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
goto done; 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) if ((pdf->trailer_dict = pdfioDictCreate(pdf)) == NULL)
{ {
_pdfioFileError(pdf, "Unable to create trailer."); _pdfioFileError(pdf, "Unable to create trailer.");
@ -2040,7 +2048,7 @@ write_trailer(pdfio_file_t *pdf) // I - PDF file
pdfioDictSetObj(pdf->trailer_dict, "Root", pdf->root_obj); pdfioDictSetObj(pdf->trailer_dict, "Root", pdf->root_obj);
pdfioDictSetNumber(pdf->trailer_dict, "Size", pdf->num_objs + 1); 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."); _pdfioFileError(pdf, "Unable to write trailer.");
ret = false; ret = false;

View File

@ -409,7 +409,7 @@ _pdfioObjLoad(pdfio_obj_t *obj) // I - Object
// Then grab the object value... // Then grab the object value...
_pdfioTokenInit(&tb, obj->pdf, (_pdfio_tconsume_cb_t)_pdfioFileConsume, (_pdfio_tpeek_cb_t)_pdfioFilePeek, obj->pdf); _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); _pdfioFileError(obj->pdf, "Unable to read value for object %lu.", (unsigned long)obj->number);
return (false); return (false);
@ -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)) if (!_pdfioFilePrintf(obj->pdf, "%lu %u obj\n", (unsigned long)obj->number, obj->generation))
return (false); return (false);
if (!_pdfioValueWrite(obj->pdf, &obj->value, &obj->length_offset)) if (!_pdfioValueWrite(obj->pdf, obj, &obj->value, &obj->length_offset))
return (false); return (false);
return (_pdfioFilePuts(obj->pdf, "\n")); return (_pdfioFilePuts(obj->pdf, "\n"));

View File

@ -338,8 +338,8 @@ struct _pdfio_stream_s // Stream
extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL; extern void _pdfioArrayDebug(pdfio_array_t *a, FILE *fp) _PDFIO_INTERNAL;
extern void _pdfioArrayDelete(pdfio_array_t *a) _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_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 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_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 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; extern size_t _pdfioCryptoAESDecrypt(_pdfio_aes_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len) _PDFIO_INTERNAL;
@ -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 _pdfioDictDebug(pdfio_dict_t *dict, FILE *fp) _PDFIO_INTERNAL;
extern void _pdfioDictDelete(pdfio_dict_t *dict) _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_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 _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 _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; extern bool _pdfioFileAddPage(pdfio_file_t *pdf, pdfio_obj_t *obj) _PDFIO_INTERNAL;
@ -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 _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 _pdfioValueDebug(_pdfio_value_t *v, FILE *fp) _PDFIO_INTERNAL;
extern void _pdfioValueDelete(_pdfio_value_t *v) _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 _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_value_t *v, off_t *length) _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 #endif // !PDFIO_PRIVATE_H

View File

@ -194,6 +194,7 @@ _pdfioValueDelete(_pdfio_value_t *v) // I - Value
_pdfio_value_t * // O - Value or `NULL` on error/EOF _pdfio_value_t * // O - Value or `NULL` on error/EOF
_pdfioValueRead(pdfio_file_t *pdf, // I - PDF file _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
pdfio_obj_t *obj, // I - Object, if any
_pdfio_token_t *tb, // I - Token buffer/stack _pdfio_token_t *tb, // I - Token buffer/stack
_pdfio_value_t *v) // I - Value _pdfio_value_t *v) // I - Value
{ {
@ -216,7 +217,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
#endif // DEBUG #endif // DEBUG
PDFIO_DEBUG("_pdfioValueRead(pdf=%p, v=%p)\n", pdf, v); PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v);
(void)obj; // TODO: Implement decryption
if (!_pdfioTokenGet(tb, token, sizeof(token))) if (!_pdfioTokenGet(tb, token, sizeof(token)))
return (NULL); return (NULL);
@ -225,14 +227,14 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
{ {
// Start of array // Start of array
v->type = PDFIO_VALTYPE_ARRAY; v->type = PDFIO_VALTYPE_ARRAY;
if ((v->value.array = _pdfioArrayRead(pdf, tb)) == NULL) if ((v->value.array = _pdfioArrayRead(pdf, obj, tb)) == NULL)
return (NULL); return (NULL);
} }
else if (!strcmp(token, "<<")) else if (!strcmp(token, "<<"))
{ {
// Start of dictionary // Start of dictionary
v->type = PDFIO_VALTYPE_DICT; v->type = PDFIO_VALTYPE_DICT;
if ((v->value.dict = _pdfioDictRead(pdf, tb)) == NULL) if ((v->value.dict = _pdfioDictRead(pdf, obj, tb)) == NULL)
return (NULL); return (NULL);
} }
else if (!strncmp(token, "(D:", 3)) else if (!strncmp(token, "(D:", 3))
@ -474,6 +476,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
_pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
pdfio_obj_t *obj, // I - Object, if any
_pdfio_value_t *v, // I - Value _pdfio_value_t *v, // I - Value
off_t *length)// O - Offset to /Length value, if any off_t *length)// O - Offset to /Length value, if any
{ {
@ -483,23 +486,47 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
return (false); return (false);
case PDFIO_VALTYPE_ARRAY : case PDFIO_VALTYPE_ARRAY :
return (_pdfioArrayWrite(v->value.array)); return (_pdfioArrayWrite(v->value.array, obj));
case PDFIO_VALTYPE_BINARY : case PDFIO_VALTYPE_BINARY :
{ {
size_t i; // Looping var size_t databytes; // Bytes to write
unsigned char *dataptr; // Pointer into data uint8_t temp[32768], // Temporary buffer for encryption
*dataptr; // Pointer into data
if (obj && pdf->encryption)
{
// Write encrypted string...
_pdfio_crypto_ctx_t ctx; // Encryption context
_pdfio_crypto_cb_t cb; // Encryption callback
size_t ivlen; // Number of initialization vector bytes
if (v->value.binary.datalen > (sizeof(temp) - 32))
{
_pdfioFileError(pdf, "Unable to write encrypted binary string - too long.");
return (false);
}
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
databytes = (cb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen;
dataptr = temp;
}
else
{
dataptr = v->value.binary.data;
databytes = v->value.binary.datalen;
}
if (!_pdfioFilePuts(pdf, "<")) if (!_pdfioFilePuts(pdf, "<"))
return (false); return (false);
for (i = v->value.binary.datalen, dataptr = v->value.binary.data; i > 1; i -= 2, dataptr += 2) for (; databytes > 1; databytes -= 2, dataptr += 2)
{ {
if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1])) if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1]))
return (false); return (false);
} }
if (i > 0) if (databytes > 0)
return (_pdfioFilePrintf(pdf, "%02X>", dataptr[0])); return (_pdfioFilePrintf(pdf, "%02X>", dataptr[0]));
else else
return (_pdfioFilePuts(pdf, ">")); return (_pdfioFilePuts(pdf, ">"));
@ -514,6 +541,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
case PDFIO_VALTYPE_DATE : case PDFIO_VALTYPE_DATE :
{ {
struct tm date; // Date values struct tm date; // Date values
char datestr[32]; // Formatted date value
#ifdef _WIN32 #ifdef _WIN32
gmtime_s(&date, &v->value.date); gmtime_s(&date, &v->value.date);
@ -521,11 +549,45 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
gmtime_r(&v->value.date, &date); gmtime_r(&v->value.date, &date);
#endif // _WIN32 #endif // _WIN32
return (_pdfioFilePrintf(pdf, "(D:%04d%02d%02d%02d%02d%02dZ)", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec)); snprintf(datestr, sizeof(datestr), "D:%04d%02d%02d%02d%02d%02dZ", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec);
if (obj && pdf->encryption)
{
// Write encrypted string...
uint8_t temp[32768], // Encrypted bytes
*tempptr; // Pointer into encrypted bytes
_pdfio_crypto_ctx_t ctx; // Encryption context
_pdfio_crypto_cb_t cb; // Encryption callback
size_t len = strlen(datestr),
// Length of value
ivlen, // Number of initialization vector bytes
tempbytes; // Number of output bytes
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)datestr, len) + ivlen;
if (!_pdfioFilePuts(pdf, "<"))
return (false);
for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2)
{
if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1]))
return (false);
}
if (tempbytes > 0)
return (_pdfioFilePrintf(pdf, "%02X>", *tempptr));
else
return (_pdfioFilePuts(pdf, ">"));
}
else
{
return (_pdfioFilePrintf(pdf, "(%s)", datestr));
}
} }
case PDFIO_VALTYPE_DICT : case PDFIO_VALTYPE_DICT :
return (_pdfioDictWrite(v->value.dict, length)); return (_pdfioDictWrite(v->value.dict, obj, length));
case PDFIO_VALTYPE_INDIRECT : case PDFIO_VALTYPE_INDIRECT :
return (_pdfioFilePrintf(pdf, " %lu %u R", (unsigned long)v->value.indirect.number, v->value.indirect.generation)); return (_pdfioFilePrintf(pdf, " %lu %u R", (unsigned long)v->value.indirect.number, v->value.indirect.generation));
@ -540,7 +602,44 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
return (_pdfioFilePrintf(pdf, " %g", v->value.number)); return (_pdfioFilePrintf(pdf, " %g", v->value.number));
case PDFIO_VALTYPE_STRING : case PDFIO_VALTYPE_STRING :
if (obj && pdf->encryption)
{ {
// Write encrypted string...
uint8_t temp[32768], // Encrypted bytes
*tempptr; // Pointer into encrypted bytes
_pdfio_crypto_ctx_t ctx; // Encryption context
_pdfio_crypto_cb_t cb; // Encryption callback
size_t len = strlen(v->value.string),
// Length of value
ivlen, // Number of initialization vector bytes
tempbytes; // Number of output bytes
if (len > (sizeof(temp) - 32))
{
_pdfioFileError(pdf, "Unable to write encrypted string - too long.");
return (false);
}
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen;
if (!_pdfioFilePuts(pdf, "<"))
return (false);
for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2)
{
if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1]))
return (false);
}
if (tempbytes > 0)
return (_pdfioFilePrintf(pdf, "%02X>", *tempptr));
else
return (_pdfioFilePuts(pdf, ">"));
}
else
{
// Write unencrypted string...
const char *start, // Start of fragment const char *start, // Start of fragment
*end; // End of fragment *end; // End of fragment

View File

@ -970,7 +970,7 @@ do_unit_tests(void)
fputs("_pdfioValueRead(complex_dict): ", stdout); fputs("_pdfioValueRead(complex_dict): ", stdout);
s = complex_dict; s = complex_dict;
_pdfioTokenInit(&tb, inpdf, (_pdfio_tconsume_cb_t)token_consume_cb, (_pdfio_tpeek_cb_t)token_peek_cb, (void *)&s); _pdfioTokenInit(&tb, inpdf, (_pdfio_tconsume_cb_t)token_consume_cb, (_pdfio_tpeek_cb_t)token_peek_cb, (void *)&s);
if (_pdfioValueRead(inpdf, &tb, &value)) if (_pdfioValueRead(inpdf, NULL, &tb, &value))
{ {
// TODO: Check value... // TODO: Check value...
fputs("PASS: ", stdout); fputs("PASS: ", stdout);
@ -984,7 +984,7 @@ do_unit_tests(void)
fputs("_pdfioValueRead(cid_dict): ", stdout); fputs("_pdfioValueRead(cid_dict): ", stdout);
s = cid_dict; s = cid_dict;
_pdfioTokenInit(&tb, inpdf, (_pdfio_tconsume_cb_t)token_consume_cb, (_pdfio_tpeek_cb_t)token_peek_cb, (void *)&s); _pdfioTokenInit(&tb, inpdf, (_pdfio_tconsume_cb_t)token_consume_cb, (_pdfio_tpeek_cb_t)token_peek_cb, (void *)&s);
if (_pdfioValueRead(inpdf, &tb, &value)) if (_pdfioValueRead(inpdf, NULL, &tb, &value))
{ {
// TODO: Check value... // TODO: Check value...
fputs("PASS: ", stdout); fputs("PASS: ", stdout);