mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-02-18 18:02:51 +01:00
Do some reorganization and start the implementation of decryption.
This commit is contained in:
parent
b7ecaeee07
commit
234c3a7381
17
FAQ.md
17
FAQ.md
@ -1,17 +0,0 @@
|
|||||||
Frequently Asked Questions
|
|
||||||
==========================
|
|
||||||
|
|
||||||
Why Don't You Support Writing a PDF File with Encryption?
|
|
||||||
---------------------------------------------------------
|
|
||||||
|
|
||||||
PDF encryption offers very little protection:
|
|
||||||
|
|
||||||
- PDF encryption keys are reused and derived from the user password (padded
|
|
||||||
with a standard base string) and the object numbers in the file.
|
|
||||||
- RC4 encryption (40- and 128-bit) was broken years ago.
|
|
||||||
- AES encryption (128- and 256-bit) is better, but PDF uses Cipher Block
|
|
||||||
Chaining (CBC) which enables attacks that allow the original encryption key
|
|
||||||
to be recovered.
|
|
||||||
|
|
||||||
In addition, PDF usage controls (no print, no copy, etc.) are tied to this
|
|
||||||
encryption, making them trivial to bypass.
|
|
356
pdfio-crypto.c
356
pdfio-crypto.c
@ -23,6 +23,228 @@
|
|||||||
#endif // __has_include
|
#endif // __has_include
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Local globals...
|
||||||
|
//
|
||||||
|
|
||||||
|
static uint8_t pdf_passpad[32] = // Padding for passwords
|
||||||
|
{
|
||||||
|
0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
|
||||||
|
0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
|
||||||
|
0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
|
||||||
|
0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioCryptoLock()' - Lock a PDF file by generating the encryption object and keys.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` otherwise
|
||||||
|
_pdfioCryptoLock(
|
||||||
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_permission_t permissions, // I - Use permissions
|
||||||
|
pdfio_encryption_t encryption, // I - Type of encryption to use
|
||||||
|
const char *owner_password, // I - Owner password, if any
|
||||||
|
const char *user_password) // I - User password, if any
|
||||||
|
{
|
||||||
|
pdfio_dict_t *dict; // Encryption dictionary
|
||||||
|
size_t i, j; // Looping vars
|
||||||
|
_pdfio_md5_t md5; // MD5 context
|
||||||
|
uint8_t digest[16]; // 128-bit MD5 digest
|
||||||
|
_pdfio_rc4_t rc4; // RC4 encryption context
|
||||||
|
size_t len; // Length of password
|
||||||
|
uint8_t owner_pad[32], // Padded owner password
|
||||||
|
user_pad[32], // Padded user password
|
||||||
|
perm_bytes[4], // Permissions bytes
|
||||||
|
*file_id; // File ID bytes
|
||||||
|
size_t file_id_len; // Length of file ID
|
||||||
|
pdfio_dict_t *cf_dict, // CF dictionary
|
||||||
|
*filter_dict; // CryptFilter dictionary
|
||||||
|
|
||||||
|
|
||||||
|
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to create encryption dictionary.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioDictSetName(dict, "Filter", "Standard");
|
||||||
|
|
||||||
|
switch (encryption)
|
||||||
|
{
|
||||||
|
case PDFIO_ENCRYPTION_RC4_128 :
|
||||||
|
case PDFIO_ENCRYPTION_AES_128 :
|
||||||
|
// Create the 128-bit encryption keys...
|
||||||
|
if (user_password)
|
||||||
|
{
|
||||||
|
// Use the specified user password
|
||||||
|
if ((len = strlen(user_password)) > sizeof(user_pad))
|
||||||
|
len = sizeof(user_pad);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No user password
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
memcpy(user_pad, user_password, len);
|
||||||
|
if (len < sizeof(user_pad))
|
||||||
|
memcpy(user_pad + len, pdf_passpad, sizeof(user_pad) - len);
|
||||||
|
|
||||||
|
if (owner_password)
|
||||||
|
{
|
||||||
|
// Use the specified owner password...
|
||||||
|
if ((len = strlen(owner_password)) > sizeof(owner_pad))
|
||||||
|
len = sizeof(owner_pad);
|
||||||
|
}
|
||||||
|
else if (user_password && *user_password)
|
||||||
|
{
|
||||||
|
// Generate a random owner password...
|
||||||
|
_pdfioCryptoMakeRandom(owner_pad, sizeof(owner_pad));
|
||||||
|
len = sizeof(owner_pad);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No owner password
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
memcpy(owner_pad, owner_password, len);
|
||||||
|
if (len < sizeof(owner_pad))
|
||||||
|
memcpy(owner_pad + len, pdf_passpad, sizeof(owner_pad) - len);
|
||||||
|
|
||||||
|
// Compute the owner key...
|
||||||
|
_pdfioCryptoMD5Init(&md5);
|
||||||
|
_pdfioCryptoMD5Append(&md5, owner_pad, 32);
|
||||||
|
_pdfioCryptoMD5Finish(&md5, digest);
|
||||||
|
|
||||||
|
for (i = 0; i < 50; i ++)
|
||||||
|
{
|
||||||
|
_pdfioCryptoMD5Init(&md5);
|
||||||
|
_pdfioCryptoMD5Append(&md5, digest, 16);
|
||||||
|
_pdfioCryptoMD5Finish(&md5, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy and encrypt the padded user password...
|
||||||
|
memcpy(pdf->owner_key, user_pad, sizeof(pdf->owner_key));
|
||||||
|
|
||||||
|
for (i = 0; i < 20; i ++)
|
||||||
|
{
|
||||||
|
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 ++)
|
||||||
|
encrypt_key[j] = (uint8_t)(digest[j] ^ i);
|
||||||
|
|
||||||
|
_pdfioCryptoRC4Init(&rc4, encrypt_key, sizeof(encrypt_key));
|
||||||
|
_pdfioCryptoRC4Crypt(&rc4, pdf->owner_key, pdf->owner_key, sizeof(pdf->owner_key));
|
||||||
|
}
|
||||||
|
pdf->owner_keylen = 32;
|
||||||
|
|
||||||
|
// Generate the encryption key
|
||||||
|
perm_bytes[0] = (uint8_t)permissions;
|
||||||
|
perm_bytes[1] = (uint8_t)(permissions >> 8);
|
||||||
|
perm_bytes[2] = (uint8_t)(permissions >> 16);
|
||||||
|
perm_bytes[3] = (uint8_t)(permissions >> 24);
|
||||||
|
|
||||||
|
file_id = pdfioArrayGetBinary(pdf->id_array, 0, &file_id_len);
|
||||||
|
|
||||||
|
_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);
|
||||||
|
|
||||||
|
// MD5 the result 50 times..
|
||||||
|
for (i = 0; i < 50; i ++)
|
||||||
|
{
|
||||||
|
_pdfioCryptoMD5Init(&md5);
|
||||||
|
_pdfioCryptoMD5Append(&md5, digest, 16);
|
||||||
|
_pdfioCryptoMD5Finish(&md5, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pdf->encryption_key, digest, 16);
|
||||||
|
pdf->encryption_keylen = 16;
|
||||||
|
|
||||||
|
// Generate the user key...
|
||||||
|
_pdfioCryptoMD5Init(&md5);
|
||||||
|
_pdfioCryptoMD5Append(&md5, pdf_passpad, 32);
|
||||||
|
_pdfioCryptoMD5Append(&md5, file_id, file_id_len);
|
||||||
|
_pdfioCryptoMD5Finish(&md5, pdf->user_key);
|
||||||
|
|
||||||
|
memset(pdf->user_key + 16, 0, 16);
|
||||||
|
|
||||||
|
// Encrypt the result 20 times...
|
||||||
|
for (i = 0; i < 20; i ++)
|
||||||
|
{
|
||||||
|
// XOR each byte in the key with the loop counter...
|
||||||
|
for (j = 0; j < 16; j ++)
|
||||||
|
digest[j] = (uint8_t)(pdf->encryption_key[j] ^ i);
|
||||||
|
|
||||||
|
_pdfioCryptoRC4Init(&rc4, digest, 16);
|
||||||
|
_pdfioCryptoRC4Crypt(&rc4, pdf->user_key, pdf->user_key, sizeof(pdf->user_key));
|
||||||
|
}
|
||||||
|
pdf->user_keylen = 32;
|
||||||
|
|
||||||
|
// Save everything in the dictionary...
|
||||||
|
pdfioDictSetNumber(dict, "Length", 128);
|
||||||
|
pdfioDictSetBinary(dict, "O", pdf->owner_key, sizeof(pdf->owner_key));
|
||||||
|
pdfioDictSetNumber(dict, "P", (int)permissions);
|
||||||
|
pdfioDictSetNumber(dict, "R", encryption == PDFIO_ENCRYPTION_RC4_128 ? 3 : 4);
|
||||||
|
pdfioDictSetNumber(dict, "V", encryption == PDFIO_ENCRYPTION_RC4_128 ? 2 : 4);
|
||||||
|
pdfioDictSetBinary(dict, "U", pdf->user_key, sizeof(pdf->user_key));
|
||||||
|
|
||||||
|
if (encryption == PDFIO_ENCRYPTION_AES_128)
|
||||||
|
{
|
||||||
|
if ((cf_dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to create Encryption CF dictionary.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((filter_dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to create Encryption CryptFilter dictionary.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioDictSetName(filter_dict, "Type", "CryptFilter");
|
||||||
|
pdfioDictSetName(filter_dict, "CFM", encryption == PDFIO_ENCRYPTION_RC4_128 ? "V2" : "AESV2");
|
||||||
|
pdfioDictSetDict(cf_dict, "PDFio", filter_dict);
|
||||||
|
pdfioDictSetDict(dict, "CF", cf_dict);
|
||||||
|
pdfioDictSetName(dict, "StmF", "PDFio");
|
||||||
|
pdfioDictSetName(dict, "StrF", "PDFio");
|
||||||
|
pdfioDictSetBoolean(dict, "EncryptMetadata", true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDFIO_ENCRYPTION_AES_256 :
|
||||||
|
// TODO: Implement AES-256 (/V 6 /R 6)
|
||||||
|
|
||||||
|
default :
|
||||||
|
_pdfioFileError(pdf, "Encryption mode %d not supported for writing.", (int)encryption);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pdf->encrypt_obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to create encryption object.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioObjClose(pdf->encrypt_obj);
|
||||||
|
|
||||||
|
pdf->encryption = encryption;
|
||||||
|
pdf->permissions = permissions;
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// '_pdfioCryptoMakeRandom()' - Fill a buffer with good random numbers.
|
// '_pdfioCryptoMakeRandom()' - Fill a buffer with good random numbers.
|
||||||
//
|
//
|
||||||
@ -323,3 +545,137 @@ _pdfio_crypto_cb_t // O - Encryption callback or `NULL` for none
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// '_pdfioCryptoUnlock()' - Unlock an encrypted PDF.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` on success, `false` otherwise
|
||||||
|
_pdfioCryptoUnlock(
|
||||||
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_password_cb_t password_cb, // I - Password callback or `NULL` for none
|
||||||
|
void *password_data) // I - Password callback data, if any
|
||||||
|
{
|
||||||
|
int tries; // Number of tries
|
||||||
|
const char *password = NULL; // Password to try
|
||||||
|
pdfio_dict_t *encrypt_dict; // Encrypt objection dictionary
|
||||||
|
int version, // Version value
|
||||||
|
revision, // Revision value
|
||||||
|
length; // Key length value
|
||||||
|
const char *handler, // Security handler name
|
||||||
|
*stream_filter, // Stream encryption filter
|
||||||
|
*string_filter; // String encryption filter
|
||||||
|
pdfio_dict_t *cf_dict; // CryptFilters dictionary
|
||||||
|
unsigned char *owner_key, // Owner key
|
||||||
|
*user_key, // User key
|
||||||
|
*file_id; // File ID value
|
||||||
|
size_t owner_keylen, // Length of owner key
|
||||||
|
user_keylen, // Length of user key
|
||||||
|
file_idlen; // Length of file ID
|
||||||
|
|
||||||
|
|
||||||
|
// See if we support the type of encryption specified by the Encrypt object
|
||||||
|
// dictionary...
|
||||||
|
if ((encrypt_dict = pdfioObjGetDict(pdf->encrypt_obj)) == NULL)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unable to get encryption dictionary.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler = pdfioDictGetName(encrypt_dict, "Filter");
|
||||||
|
version = pdfioDictGetNumber(encrypt_dict, "V");
|
||||||
|
revision = pdfioDictGetNumber(encrypt_dict, "R");
|
||||||
|
length = pdfioDictGetNumber(encrypt_dict, "Length");
|
||||||
|
stream_filter = pdfioDictGetName(encrypt_dict, "StmF");
|
||||||
|
string_filter = pdfioDictGetName(encrypt_dict, "StrF");
|
||||||
|
cf_dict = pdfioDictGetDict(encrypt_dict, "CF");
|
||||||
|
|
||||||
|
if (!handler || strcmp(handler, "Standard"))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unsupported security handler '%s'.", handler ? handler : "(null)");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version == 4 && revision == 4)
|
||||||
|
{
|
||||||
|
// Lookup crypt filter to see if we support it...
|
||||||
|
pdfio_dict_t *filter; // Crypt Filter
|
||||||
|
const char *cfm; // Crypt filter method
|
||||||
|
|
||||||
|
if ((filter = pdfioDictGetDict(cf_dict, stream_filter)) != NULL && (cfm = pdfioDictGetName(filter, "CFM")) != NULL)
|
||||||
|
{
|
||||||
|
if (!strcmp(cfm, "V2"))
|
||||||
|
{
|
||||||
|
pdf->encryption = PDFIO_ENCRYPTION_RC4_128;
|
||||||
|
if (length < 40 || length > 128)
|
||||||
|
length = 128;
|
||||||
|
}
|
||||||
|
if (!strcmp(cfm, "AESV2"))
|
||||||
|
{
|
||||||
|
pdf->encryption = PDFIO_ENCRYPTION_AES_128;
|
||||||
|
length = 128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (version == 2)
|
||||||
|
{
|
||||||
|
if (revision == 2)
|
||||||
|
{
|
||||||
|
pdf->encryption = PDFIO_ENCRYPTION_RC4_40;
|
||||||
|
length = 40;
|
||||||
|
}
|
||||||
|
else if (revision == 3)
|
||||||
|
{
|
||||||
|
pdf->encryption = PDFIO_ENCRYPTION_RC4_128;
|
||||||
|
if (length < 40 || length > 128)
|
||||||
|
length = 128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Implement AES-256 - V6 R6
|
||||||
|
|
||||||
|
if (pdf->encryption == PDFIO_ENCRYPTION_NONE)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Unsupported encryption V%d R%d.", version, revision);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the remaining values we need to unlock the PDF...
|
||||||
|
pdf->encryption_keylen = length / 8;
|
||||||
|
pdf->permissions = pdfioDictGetNumber(encrypt_dict, "P");
|
||||||
|
|
||||||
|
owner_key = pdfioDictGetBinary(encrypt_dict, "O", &owner_keylen);
|
||||||
|
user_key = pdfioDictGetBinary(encrypt_dict, "U", &user_keylen);
|
||||||
|
|
||||||
|
if (!owner_key || owner_keylen < 32 || owner_keylen > sizeof(pdf->owner_key))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Missing or bad owner key, unable to unlock file.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pdf->owner_key, owner_key, owner_keylen);
|
||||||
|
pdf->owner_keylen = owner_keylen;
|
||||||
|
|
||||||
|
if (!user_key || user_keylen < 32 || user_keylen > sizeof(pdf->user_key))
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Missing or bad user key, unable to unlock file.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pdf->user_key, user_key, user_keylen);
|
||||||
|
pdf->user_keylen = user_keylen;
|
||||||
|
|
||||||
|
if ((file_id = pdfioArrayGetBinary(pdf->id_array, 0, &file_idlen)) == NULL || file_idlen < 16)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Missing or bad file ID, unable to unlock file.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now try to unlock the PDF...
|
||||||
|
for (tries = 0; tries < 4; tries ++)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
302
pdfio-file.c
302
pdfio-file.c
@ -26,7 +26,7 @@ static int compare_objmaps(_pdfio_objmap_t *a, _pdfio_objmap_t *b);
|
|||||||
static int compare_objs(pdfio_obj_t **a, pdfio_obj_t **b);
|
static int compare_objs(pdfio_obj_t **a, pdfio_obj_t **b);
|
||||||
static bool load_obj_stream(pdfio_obj_t *obj);
|
static bool load_obj_stream(pdfio_obj_t *obj);
|
||||||
static bool load_pages(pdfio_file_t *pdf, pdfio_obj_t *obj);
|
static bool load_pages(pdfio_file_t *pdf, pdfio_obj_t *obj);
|
||||||
static bool load_xref(pdfio_file_t *pdf, off_t xref_offset);
|
static bool load_xref(pdfio_file_t *pdf, off_t xref_offset, pdfio_password_cb_t password_cb, void *password_data);
|
||||||
static bool write_catalog(pdfio_file_t *pdf);
|
static bool write_catalog(pdfio_file_t *pdf);
|
||||||
static bool write_pages(pdfio_file_t *pdf);
|
static bool write_pages(pdfio_file_t *pdf);
|
||||||
static bool write_trailer(pdfio_file_t *pdf);
|
static bool write_trailer(pdfio_file_t *pdf);
|
||||||
@ -221,13 +221,14 @@ pdfioFileCreate(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf->filename = strdup(filename);
|
pdf->filename = strdup(filename);
|
||||||
pdf->version = strdup(version);
|
pdf->version = strdup(version);
|
||||||
pdf->mode = _PDFIO_MODE_WRITE;
|
pdf->mode = _PDFIO_MODE_WRITE;
|
||||||
pdf->error_cb = error_cb;
|
pdf->error_cb = error_cb;
|
||||||
pdf->error_data = error_data;
|
pdf->error_data = error_data;
|
||||||
pdf->bufptr = pdf->buffer;
|
pdf->permissions = PDFIO_PERMISSION_ALL;
|
||||||
pdf->bufend = pdf->buffer + sizeof(pdf->buffer);
|
pdf->bufptr = pdf->buffer;
|
||||||
|
pdf->bufend = pdf->buffer + sizeof(pdf->buffer);
|
||||||
|
|
||||||
if (media_box)
|
if (media_box)
|
||||||
{
|
{
|
||||||
@ -496,13 +497,14 @@ pdfioFileCreateOutput(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf->filename = strdup("output.pdf");
|
pdf->filename = strdup("output.pdf");
|
||||||
pdf->version = strdup(version);
|
pdf->version = strdup(version);
|
||||||
pdf->mode = _PDFIO_MODE_WRITE;
|
pdf->mode = _PDFIO_MODE_WRITE;
|
||||||
pdf->error_cb = error_cb;
|
pdf->error_cb = error_cb;
|
||||||
pdf->error_data = error_data;
|
pdf->error_data = error_data;
|
||||||
pdf->bufptr = pdf->buffer;
|
pdf->permissions = PDFIO_PERMISSION_ALL;
|
||||||
pdf->bufend = pdf->buffer + sizeof(pdf->buffer);
|
pdf->bufptr = pdf->buffer;
|
||||||
|
pdf->bufend = pdf->buffer + sizeof(pdf->buffer);
|
||||||
|
|
||||||
if (media_box)
|
if (media_box)
|
||||||
{
|
{
|
||||||
@ -834,6 +836,35 @@ pdfioFileGetPage(pdfio_file_t *pdf, // I - PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioFileGetPermissions()' - Get the access permissions of a PDF file.
|
||||||
|
//
|
||||||
|
// This function returns the access permissions of a PDF file and (optionally)
|
||||||
|
// the type of encryption that has been used.
|
||||||
|
//
|
||||||
|
|
||||||
|
pdfio_permission_t // O - Permission bits
|
||||||
|
pdfioFileGetPermissions(
|
||||||
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
|
pdfio_encryption_t *encryption) // O - Type of encryption used or `NULL` to ignore
|
||||||
|
{
|
||||||
|
// Range check input...
|
||||||
|
if (!pdf)
|
||||||
|
{
|
||||||
|
if (encryption)
|
||||||
|
*encryption = PDFIO_ENCRYPTION_NONE;
|
||||||
|
|
||||||
|
return (PDFIO_PERMISSION_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return values...
|
||||||
|
if (encryption)
|
||||||
|
*encryption = pdf->encryption;
|
||||||
|
|
||||||
|
return (pdf->permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'pdfioFileGetProducer()' - Get the producer string for a PDF file.
|
// 'pdfioFileGetProducer()' - Get the producer string for a PDF file.
|
||||||
//
|
//
|
||||||
@ -910,9 +941,6 @@ pdfioFileOpen(
|
|||||||
off_t xref_offset; // Offset to xref table
|
off_t xref_offset; // Offset to xref table
|
||||||
|
|
||||||
|
|
||||||
(void)password_cb;
|
|
||||||
(void)password_data;
|
|
||||||
|
|
||||||
// Range check input...
|
// Range check input...
|
||||||
if (!filename)
|
if (!filename)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@ -935,10 +963,11 @@ pdfioFileOpen(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf->filename = strdup(filename);
|
pdf->filename = strdup(filename);
|
||||||
pdf->mode = _PDFIO_MODE_READ;
|
pdf->mode = _PDFIO_MODE_READ;
|
||||||
pdf->error_cb = error_cb;
|
pdf->error_cb = error_cb;
|
||||||
pdf->error_data = error_data;
|
pdf->error_data = error_data;
|
||||||
|
pdf->permissions = PDFIO_PERMISSION_ALL;
|
||||||
|
|
||||||
// Open the file...
|
// Open the file...
|
||||||
if ((pdf->fd = open(filename, O_RDONLY | O_BINARY)) < 0)
|
if ((pdf->fd = open(filename, O_RDONLY | O_BINARY)) < 0)
|
||||||
@ -985,7 +1014,7 @@ pdfioFileOpen(
|
|||||||
|
|
||||||
xref_offset = (off_t)strtol(ptr + 9, NULL, 10);
|
xref_offset = (off_t)strtol(ptr + 9, NULL, 10);
|
||||||
|
|
||||||
if (!load_xref(pdf, xref_offset))
|
if (!load_xref(pdf, xref_offset, password_cb, password_data))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
return (pdf);
|
return (pdf);
|
||||||
@ -1074,28 +1103,6 @@ pdfioFileSetPermissions(
|
|||||||
const char *owner_password, // I - Owner password, if any
|
const char *owner_password, // I - Owner password, if any
|
||||||
const char *user_password) // I - User password, if any
|
const char *user_password) // I - User password, if any
|
||||||
{
|
{
|
||||||
pdfio_dict_t *dict; // Encryption dictionary
|
|
||||||
size_t i, j; // Looping vars
|
|
||||||
_pdfio_md5_t md5; // MD5 context
|
|
||||||
uint8_t digest[16]; // 128-bit MD5 digest
|
|
||||||
_pdfio_rc4_t rc4; // RC4 encryption context
|
|
||||||
size_t len; // Length of password
|
|
||||||
uint8_t owner_pad[32], // Padded owner password
|
|
||||||
user_pad[32], // Padded user password
|
|
||||||
perm_bytes[4], // Permissions bytes
|
|
||||||
*file_id; // File ID bytes
|
|
||||||
size_t file_id_len; // Length of file ID
|
|
||||||
pdfio_dict_t *cf_dict, // CF dictionary
|
|
||||||
*filter_dict; // CryptFilter dictionary
|
|
||||||
static uint8_t pad[32] = // Padding for passwords
|
|
||||||
{
|
|
||||||
0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
|
|
||||||
0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
|
|
||||||
0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
|
|
||||||
0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
if (!pdf)
|
if (!pdf)
|
||||||
return (false);
|
return (false);
|
||||||
|
|
||||||
@ -1108,182 +1115,7 @@ pdfioFileSetPermissions(
|
|||||||
if (encryption == PDFIO_ENCRYPTION_NONE)
|
if (encryption == PDFIO_ENCRYPTION_NONE)
|
||||||
return (true);
|
return (true);
|
||||||
|
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
return (_pdfioCryptoLock(pdf, permissions, encryption, owner_password, user_password));
|
||||||
{
|
|
||||||
_pdfioFileError(pdf, "Unable to create encryption dictionary.");
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioDictSetName(dict, "Filter", "Standard");
|
|
||||||
|
|
||||||
switch (encryption)
|
|
||||||
{
|
|
||||||
case PDFIO_ENCRYPTION_RC4_128 :
|
|
||||||
case PDFIO_ENCRYPTION_AES_128 :
|
|
||||||
// Create the 128-bit encryption keys...
|
|
||||||
if (user_password)
|
|
||||||
{
|
|
||||||
// Use the specified user password
|
|
||||||
if ((len = strlen(user_password)) > sizeof(user_pad))
|
|
||||||
len = sizeof(user_pad);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No user password
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
// Use the specified owner password...
|
|
||||||
if ((len = strlen(owner_password)) > sizeof(owner_pad))
|
|
||||||
len = sizeof(owner_pad);
|
|
||||||
}
|
|
||||||
else if (user_password && *user_password)
|
|
||||||
{
|
|
||||||
// Generate a random owner password...
|
|
||||||
_pdfioCryptoMakeRandom(owner_pad, sizeof(owner_pad));
|
|
||||||
len = sizeof(owner_pad);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
for (i = 0; i < 50; i ++)
|
|
||||||
{
|
|
||||||
_pdfioCryptoMD5Init(&md5);
|
|
||||||
_pdfioCryptoMD5Append(&md5, digest, 16);
|
|
||||||
_pdfioCryptoMD5Finish(&md5, digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy and encrypt the padded user password...
|
|
||||||
memcpy(pdf->owner_key, user_pad, sizeof(pdf->owner_key));
|
|
||||||
|
|
||||||
for (i = 0; i < 20; i ++)
|
|
||||||
{
|
|
||||||
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 ++)
|
|
||||||
encrypt_key[j] = (uint8_t)(digest[j] ^ i);
|
|
||||||
|
|
||||||
_pdfioCryptoRC4Init(&rc4, encrypt_key, sizeof(encrypt_key));
|
|
||||||
_pdfioCryptoRC4Crypt(&rc4, pdf->owner_key, pdf->owner_key, sizeof(pdf->owner_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate the encryption key
|
|
||||||
perm_bytes[0] = (uint8_t)permissions;
|
|
||||||
perm_bytes[1] = (uint8_t)(permissions >> 8);
|
|
||||||
perm_bytes[2] = (uint8_t)(permissions >> 16);
|
|
||||||
perm_bytes[3] = (uint8_t)(permissions >> 24);
|
|
||||||
|
|
||||||
file_id = pdfioArrayGetBinary(pdf->id_array, 0, &file_id_len);
|
|
||||||
|
|
||||||
_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);
|
|
||||||
|
|
||||||
// MD5 the result 50 times..
|
|
||||||
for (i = 0; i < 50; i ++)
|
|
||||||
{
|
|
||||||
_pdfioCryptoMD5Init(&md5);
|
|
||||||
_pdfioCryptoMD5Append(&md5, digest, 16);
|
|
||||||
_pdfioCryptoMD5Finish(&md5, digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(pdf->encryption_key, digest, 16);
|
|
||||||
|
|
||||||
// Generate the user key...
|
|
||||||
_pdfioCryptoMD5Init(&md5);
|
|
||||||
_pdfioCryptoMD5Append(&md5, pad, 32);
|
|
||||||
_pdfioCryptoMD5Append(&md5, file_id, file_id_len);
|
|
||||||
_pdfioCryptoMD5Finish(&md5, pdf->user_key);
|
|
||||||
|
|
||||||
memset(pdf->user_key + 16, 0, 16);
|
|
||||||
|
|
||||||
// Encrypt the result 20 times...
|
|
||||||
for (i = 0; i < 20; i ++)
|
|
||||||
{
|
|
||||||
// XOR each byte in the key with the loop counter...
|
|
||||||
for (j = 0; j < 16; j ++)
|
|
||||||
digest[j] = (uint8_t)(pdf->encryption_key[j] ^ i);
|
|
||||||
|
|
||||||
_pdfioCryptoRC4Init(&rc4, digest, 16);
|
|
||||||
_pdfioCryptoRC4Crypt(&rc4, pdf->user_key, pdf->user_key, sizeof(pdf->user_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save everything in the dictionary...
|
|
||||||
pdfioDictSetNumber(dict, "Length", 128);
|
|
||||||
pdfioDictSetBinary(dict, "O", pdf->owner_key, sizeof(pdf->owner_key));
|
|
||||||
pdfioDictSetNumber(dict, "P", (int)permissions);
|
|
||||||
pdfioDictSetNumber(dict, "R", encryption == PDFIO_ENCRYPTION_RC4_128 ? 3 : 4);
|
|
||||||
pdfioDictSetNumber(dict, "V", encryption == PDFIO_ENCRYPTION_RC4_128 ? 2 : 4);
|
|
||||||
pdfioDictSetBinary(dict, "U", pdf->user_key, sizeof(pdf->user_key));
|
|
||||||
|
|
||||||
if (encryption == PDFIO_ENCRYPTION_AES_128)
|
|
||||||
{
|
|
||||||
if ((cf_dict = pdfioDictCreate(pdf)) == NULL)
|
|
||||||
{
|
|
||||||
_pdfioFileError(pdf, "Unable to create Encryption CF dictionary.");
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((filter_dict = pdfioDictCreate(pdf)) == NULL)
|
|
||||||
{
|
|
||||||
_pdfioFileError(pdf, "Unable to create Encryption CryptFilter dictionary.");
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioDictSetName(filter_dict, "Type", "CryptFilter");
|
|
||||||
pdfioDictSetName(filter_dict, "CFM", encryption == PDFIO_ENCRYPTION_RC4_128 ? "V2" : "AESV2");
|
|
||||||
pdfioDictSetDict(cf_dict, "PDFio", filter_dict);
|
|
||||||
pdfioDictSetDict(dict, "CF", cf_dict);
|
|
||||||
pdfioDictSetName(dict, "StmF", "PDFio");
|
|
||||||
pdfioDictSetName(dict, "StrF", "PDFio");
|
|
||||||
pdfioDictSetBoolean(dict, "EncryptMetadata", true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PDFIO_ENCRYPTION_AES_256 :
|
|
||||||
// TODO: Implement AES-256 (/V 6 /R 6)
|
|
||||||
|
|
||||||
default :
|
|
||||||
_pdfioFileError(pdf, "Encryption mode %d not supported for writing.", (int)encryption);
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((pdf->encrypt_obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
|
||||||
{
|
|
||||||
_pdfioFileError(pdf, "Unable to create encryption object.");
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioObjClose(pdf->encrypt_obj);
|
|
||||||
|
|
||||||
pdf->encryption = encryption;
|
|
||||||
pdf->permissions = permissions;
|
|
||||||
|
|
||||||
return (true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1567,8 +1399,11 @@ load_pages(pdfio_file_t *pdf, // I - PDF file
|
|||||||
//
|
//
|
||||||
|
|
||||||
static bool // O - `true` on success, `false` on failure
|
static bool // O - `true` on success, `false` on failure
|
||||||
load_xref(pdfio_file_t *pdf, // I - PDF file
|
load_xref(
|
||||||
off_t xref_offset) // I - Offset to xref
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
|
off_t xref_offset, // I - Offset to xref
|
||||||
|
pdfio_password_cb_t password_cb, // I - Password callback or `NULL` for none
|
||||||
|
void *password_data) // I - Password callback data, if any
|
||||||
{
|
{
|
||||||
bool done = false; // Are we done?
|
bool done = false; // Are we done?
|
||||||
char line[1024], // Line from file
|
char line[1024], // Line from file
|
||||||
@ -1668,13 +1503,6 @@ load_xref(pdfio_file_t *pdf, // I - PDF file
|
|||||||
_pdfioFileError(pdf, "Cross-reference stream does not have a dictionary.");
|
_pdfioFileError(pdf, "Cross-reference stream does not have a dictionary.");
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
else if (_pdfioDictGetValue(pdf->trailer_dict, "Encrypt"))
|
|
||||||
{
|
|
||||||
// TODO: Fix me
|
|
||||||
// Encryption not yet supported...
|
|
||||||
_pdfioFileError(pdf, "Sorry, PDFio currently does not support encrypted PDF files.");
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->value = trailer;
|
obj->value = trailer;
|
||||||
|
|
||||||
@ -1809,6 +1637,10 @@ load_xref(pdfio_file_t *pdf, // I - PDF file
|
|||||||
|
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
|
// If the trailer contains an Encrypt key, try unlocking the file...
|
||||||
|
if ((pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt")) != NULL && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
||||||
|
return (false);
|
||||||
|
|
||||||
// Load any object streams that are left...
|
// Load any object streams that are left...
|
||||||
PDFIO_DEBUG("load_xref: %lu compressed object streams to load.\n", (unsigned long)num_sobjs);
|
PDFIO_DEBUG("load_xref: %lu compressed object streams to load.\n", (unsigned long)num_sobjs);
|
||||||
|
|
||||||
@ -1916,12 +1748,6 @@ load_xref(pdfio_file_t *pdf, // I - PDF file
|
|||||||
_pdfioFileError(pdf, "Trailer is not a dictionary.");
|
_pdfioFileError(pdf, "Trailer is not a dictionary.");
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
else if (_pdfioDictGetValue(pdf->trailer_dict, "Encrypt"))
|
|
||||||
{
|
|
||||||
// Encryption not yet supported...
|
|
||||||
_pdfioFileError(pdf, "Sorry, PDFio currently does not support encrypted PDF files.");
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_pdfioTokenFlush(&tb);
|
_pdfioTokenFlush(&tb);
|
||||||
}
|
}
|
||||||
@ -1941,6 +1767,10 @@ load_xref(pdfio_file_t *pdf, // I - PDF file
|
|||||||
// Save the trailer dictionary and grab the root (catalog) and info
|
// Save the trailer dictionary and grab the root (catalog) and info
|
||||||
// objects...
|
// objects...
|
||||||
pdf->trailer_dict = trailer.value.dict;
|
pdf->trailer_dict = trailer.value.dict;
|
||||||
|
|
||||||
|
// If the trailer contains an Encrypt key, try unlocking the file...
|
||||||
|
if ((pdf->encrypt_obj = pdfioDictGetObj(pdf->trailer_dict, "Encrypt")) != NULL && !_pdfioCryptoUnlock(pdf, password_cb, password_data))
|
||||||
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((xref_offset = (off_t)pdfioDictGetNumber(trailer.value.dict, "Prev")) <= 0)
|
if ((xref_offset = (off_t)pdfioDictGetNumber(trailer.value.dict, "Prev")) <= 0)
|
||||||
|
@ -259,6 +259,9 @@ struct _pdfio_file_s // PDF file structure
|
|||||||
uint8_t encryption_key[16], // Object encryption key
|
uint8_t encryption_key[16], // Object encryption key
|
||||||
owner_key[32], // Owner encryption key
|
owner_key[32], // Owner encryption key
|
||||||
user_key[32]; // User encryption key
|
user_key[32]; // User encryption key
|
||||||
|
size_t encryption_keylen, // Length of encryption key
|
||||||
|
owner_keylen, // Length of owner encryption key
|
||||||
|
user_keylen; // Length of user encryption key
|
||||||
|
|
||||||
// Active file data
|
// Active file data
|
||||||
int fd; // File descriptor
|
int fd; // File descriptor
|
||||||
@ -344,6 +347,7 @@ extern bool _pdfioArrayWrite(pdfio_array_t *a, pdfio_obj_t *obj) _PDFIO_INTERNA
|
|||||||
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;
|
||||||
extern size_t _pdfioCryptoAESEncrypt(_pdfio_aes_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len) _PDFIO_INTERNAL;
|
extern size_t _pdfioCryptoAESEncrypt(_pdfio_aes_t *ctx, uint8_t *outbuffer, const uint8_t *inbuffer, size_t len) _PDFIO_INTERNAL;
|
||||||
|
extern bool _pdfioCryptoLock(pdfio_file_t *pdf, pdfio_permission_t permissions, pdfio_encryption_t encryption, const char *owner_password, const char *user_password) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioCryptoMakeRandom(uint8_t *buffer, size_t bytes) _PDFIO_INTERNAL;
|
extern void _pdfioCryptoMakeRandom(uint8_t *buffer, size_t bytes) _PDFIO_INTERNAL;
|
||||||
extern _pdfio_crypto_cb_t _pdfioCryptoMakeReader(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_crypto_ctx_t *ctx, uint8_t *iv, size_t *ivlen) _PDFIO_INTERNAL;
|
extern _pdfio_crypto_cb_t _pdfioCryptoMakeReader(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_crypto_ctx_t *ctx, uint8_t *iv, size_t *ivlen) _PDFIO_INTERNAL;
|
||||||
extern _pdfio_crypto_cb_t _pdfioCryptoMakeWriter(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_crypto_ctx_t *ctx, uint8_t *iv, size_t *ivlen) _PDFIO_INTERNAL;
|
extern _pdfio_crypto_cb_t _pdfioCryptoMakeWriter(pdfio_file_t *pdf, pdfio_obj_t *obj, _pdfio_crypto_ctx_t *ctx, uint8_t *iv, size_t *ivlen) _PDFIO_INTERNAL;
|
||||||
@ -355,6 +359,7 @@ extern size_t _pdfioCryptoRC4Crypt(_pdfio_rc4_t *ctx, uint8_t *outbuffer, const
|
|||||||
extern void _pdfioCryptoSHA256Append(_pdfio_sha256_t *, const uint8_t *bytes, size_t bytecount) _PDFIO_INTERNAL;
|
extern void _pdfioCryptoSHA256Append(_pdfio_sha256_t *, const uint8_t *bytes, size_t bytecount) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioCryptoSHA256Init(_pdfio_sha256_t *ctx) _PDFIO_INTERNAL;
|
extern void _pdfioCryptoSHA256Init(_pdfio_sha256_t *ctx) _PDFIO_INTERNAL;
|
||||||
extern void _pdfioCryptoSHA256Finish(_pdfio_sha256_t *ctx, uint8_t *Message_Digest) _PDFIO_INTERNAL;
|
extern void _pdfioCryptoSHA256Finish(_pdfio_sha256_t *ctx, uint8_t *Message_Digest) _PDFIO_INTERNAL;
|
||||||
|
extern bool _pdfioCryptoUnlock(pdfio_file_t *pdf, pdfio_password_cb_t password_cb, void *password_data) _PDFIO_INTERNAL;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -121,7 +121,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
|
|||||||
uint8_t temp[8192]; // Temporary buffer
|
uint8_t temp[8192]; // Temporary buffer
|
||||||
size_t outbytes; // Output bytes
|
size_t outbytes; // Output bytes
|
||||||
|
|
||||||
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, st->buffer, (size_t)(st->bufptr - st->buffer));
|
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, (uint8_t *)st->buffer, (size_t)(st->bufptr - st->buffer));
|
||||||
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
|
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
|
||||||
{
|
{
|
||||||
ret = false;
|
ret = false;
|
||||||
@ -423,6 +423,24 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj->pdf->encryption)
|
||||||
|
{
|
||||||
|
uint8_t iv[64]; // Initialization vector
|
||||||
|
size_t ivlen; // Length of initialization vector, if any
|
||||||
|
|
||||||
|
ivlen = _pdfioFilePeek(st->pdf, iv, sizeof(iv));
|
||||||
|
|
||||||
|
if ((st->crypto_cb = _pdfioCryptoMakeReader(st->pdf, obj, &st->crypto_ctx, iv, &ivlen)) == NULL)
|
||||||
|
{
|
||||||
|
// TODO: Add error message?
|
||||||
|
free(st);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ivlen > 0)
|
||||||
|
_pdfioFileConsume(st->pdf, ivlen);
|
||||||
|
}
|
||||||
|
|
||||||
if (decode)
|
if (decode)
|
||||||
{
|
{
|
||||||
// Try to decode/decompress the contents of this object...
|
// Try to decode/decompress the contents of this object...
|
||||||
@ -537,6 +555,9 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (st->crypto_cb)
|
||||||
|
rbytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, rbytes);
|
||||||
|
|
||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
|
|
||||||
@ -810,7 +831,7 @@ pdfioStreamWrite(
|
|||||||
if (st->bufptr >= st->bufend)
|
if (st->bufptr >= st->bufend)
|
||||||
{
|
{
|
||||||
// Encrypt and flush
|
// Encrypt and flush
|
||||||
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, st->buffer, sizeof(st->buffer));
|
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, (uint8_t *)st->buffer, sizeof(st->buffer));
|
||||||
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
|
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
|
||||||
return (false);
|
return (false);
|
||||||
|
|
||||||
@ -980,8 +1001,13 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
rbytes = _pdfioFileRead(st->pdf, buffer, bytes);
|
rbytes = _pdfioFileRead(st->pdf, buffer, bytes);
|
||||||
|
|
||||||
if (rbytes > 0)
|
if (rbytes > 0)
|
||||||
|
{
|
||||||
st->remaining -= (size_t)rbytes;
|
st->remaining -= (size_t)rbytes;
|
||||||
|
|
||||||
|
if (st->crypto_cb)
|
||||||
|
(st->crypto_cb)(&st->crypto_ctx, (uint8_t *)buffer, (uint8_t *)buffer, rbytes);
|
||||||
|
}
|
||||||
|
|
||||||
return (rbytes);
|
return (rbytes);
|
||||||
}
|
}
|
||||||
else if (st->filter == PDFIO_FILTER_FLATE)
|
else if (st->filter == PDFIO_FILTER_FLATE)
|
||||||
@ -1005,6 +1031,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
if (rbytes <= 0)
|
if (rbytes <= 0)
|
||||||
return (-1); // End of file...
|
return (-1); // End of file...
|
||||||
|
|
||||||
|
if (st->crypto_cb)
|
||||||
|
rbytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, rbytes);
|
||||||
|
|
||||||
st->remaining -= (size_t)rbytes;
|
st->remaining -= (size_t)rbytes;
|
||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
@ -1058,6 +1087,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
if (rbytes <= 0)
|
if (rbytes <= 0)
|
||||||
return (-1); // End of file...
|
return (-1); // End of file...
|
||||||
|
|
||||||
|
if (st->crypto_cb)
|
||||||
|
rbytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, rbytes);
|
||||||
|
|
||||||
st->remaining -= (size_t)rbytes;
|
st->remaining -= (size_t)rbytes;
|
||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
@ -1122,6 +1154,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
|
|||||||
if (rbytes <= 0)
|
if (rbytes <= 0)
|
||||||
return (-1); // End of file...
|
return (-1); // End of file...
|
||||||
|
|
||||||
|
if (st->crypto_cb)
|
||||||
|
rbytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, rbytes);
|
||||||
|
|
||||||
st->remaining -= (size_t)rbytes;
|
st->remaining -= (size_t)rbytes;
|
||||||
st->flate.next_in = (Bytef *)st->cbuffer;
|
st->flate.next_in = (Bytef *)st->cbuffer;
|
||||||
st->flate.avail_in = (uInt)rbytes;
|
st->flate.avail_in = (uInt)rbytes;
|
||||||
|
2
pdfio.h
2
pdfio.h
@ -196,7 +196,7 @@ extern size_t pdfioFileGetNumObjs(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
|||||||
extern size_t pdfioFileGetNumPages(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
extern size_t pdfioFileGetNumPages(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileGetObj(pdfio_file_t *pdf, size_t n) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileGetObj(pdfio_file_t *pdf, size_t n) _PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileGetPage(pdfio_file_t *pdf, size_t n) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileGetPage(pdfio_file_t *pdf, size_t n) _PDFIO_PUBLIC;
|
||||||
extern pdfio_permission_t pdfioFileGetPermissions(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
extern pdfio_permission_t pdfioFileGetPermissions(pdfio_file_t *pdf, pdfio_encryption_t *encryption) _PDFIO_PUBLIC;
|
||||||
extern const char *pdfioFileGetProducer(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
extern const char *pdfioFileGetProducer(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||||
extern const char *pdfioFileGetSubject(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
extern const char *pdfioFileGetSubject(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||||
extern const char *pdfioFileGetTitle(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
extern const char *pdfioFileGetTitle(pdfio_file_t *pdf) _PDFIO_PUBLIC;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user