diff --git a/CHANGES.md b/CHANGES.md index ab4e1b2..80bd736 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,12 @@ v1.6.0 - YYYY-MM-DD memory (Issue #120) +v1.5.3 - YYYY-MM-DD +------------------- + +- Fixed decryption of PDF files "protected" by 40-bit RC4. + + v1.5.2 - 2025-04-12 ------------------- diff --git a/pdfio-crypto.c b/pdfio-crypto.c index 1aef364..0510149 100644 --- a/pdfio-crypto.c +++ b/pdfio-crypto.c @@ -490,20 +490,20 @@ _pdfioCryptoMakeReader( case PDFIO_ENCRYPTION_RC4_40 : // Copy the key data for the MD5 hash. - memcpy(data, file_key, 16); - data[16] = (uint8_t)obj->number; - data[17] = (uint8_t)(obj->number >> 8); - data[18] = (uint8_t)(obj->number >> 16); - data[19] = (uint8_t)obj->generation; - data[20] = (uint8_t)(obj->generation >> 8); + memcpy(data, file_key, 5); + data[5] = (uint8_t)obj->number; + data[6] = (uint8_t)(obj->number >> 8); + data[7] = (uint8_t)(obj->number >> 16); + data[8] = (uint8_t)obj->generation; + data[9] = (uint8_t)(obj->generation >> 8); // Hash it... _pdfioCryptoMD5Init(&md5); - _pdfioCryptoMD5Append(&md5, data, sizeof(data)); + _pdfioCryptoMD5Append(&md5, data, 10); _pdfioCryptoMD5Finish(&md5, digest); - // Initialize the RC4 context using 40 bits of the digest... - _pdfioCryptoRC4Init(&ctx->rc4, digest, 5); + // Initialize the RC4 context using 80 bits of the digest... + _pdfioCryptoRC4Init(&ctx->rc4, digest, 10); *ivlen = 0; return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt); diff --git a/pdfio-value.c b/pdfio-value.c index 28c1eb5..802dfc6 100644 --- a/pdfio-value.c +++ b/pdfio-value.c @@ -172,7 +172,7 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file // Copy the decrypted string back to the value and adjust the length... memcpy(v->value.binary.data, temp, templen); - if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128) + if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128 && temp[templen - 1] <= templen) v->value.binary.datalen = templen - temp[templen - 1]; else v->value.binary.datalen = templen; @@ -183,17 +183,26 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file case PDFIO_VALTYPE_STRING : // Decrypt regular string... templen = strlen(v->value.string); - if (templen > (sizeof(temp) - 33)) + if (templen > (PDFIO_MAX_STRING - 1)) { _pdfioFileError(pdf, "Unable to read encrypted string - too long."); return (false); } + else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL) + { + _pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory."); + return (false); + } ivlen = templen; if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, (uint8_t *)v->value.string, &ivlen)) == NULL) return (false); templen = (cb)(&ctx, temp, (uint8_t *)v->value.string + ivlen, templen - ivlen); + + if (pdf->encryption >= PDFIO_ENCRYPTION_AES_128 && temp[templen - 1] <= templen) + templen -= temp[templen - 1]; + temp[templen] = '\0'; if ((timeval = get_date_time((char *)temp)) != 0) @@ -207,6 +216,8 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file // Copy the decrypted string back to the value... v->value.string = pdfioStringCreate(pdf, (char *)temp); } + + _pdfioStringFreeBuffer(pdf, (char *)temp); break; }