Implement partial write buffering for AES.

This commit is contained in:
Michael R Sweet 2021-10-23 20:33:12 -04:00
parent 208c3419ff
commit b7ecaeee07
No known key found for this signature in database
GPG Key ID: 999559A027815955

View File

@ -54,8 +54,9 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
while ((status = deflate(&st->flate, Z_FINISH)) != Z_STREAM_END) while ((status = deflate(&st->flate, Z_FINISH)) != Z_STREAM_END)
{ {
size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out; size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out,
// Bytes to write // Bytes to write
outbytes; // Actual bytes written
if (status < Z_OK && status != Z_BUF_ERROR) if (status < Z_OK && status != Z_BUF_ERROR)
{ {
@ -67,17 +68,32 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
if (st->crypto_cb) if (st->crypto_cb)
{ {
// Encrypt it first... // Encrypt it first...
bytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, bytes); outbytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, bytes & ~15);
}
else
{
// No encryption
outbytes = bytes;
} }
if (!_pdfioFileWrite(st->pdf, st->cbuffer, bytes)) if (!_pdfioFileWrite(st->pdf, st->cbuffer, outbytes))
{ {
ret = false; ret = false;
goto done; goto done;
} }
st->flate.next_out = (Bytef *)st->cbuffer; if (bytes > outbytes)
st->flate.avail_out = (uInt)sizeof(st->cbuffer); {
bytes -= outbytes;
memmove(st->cbuffer, st->cbuffer + outbytes, bytes);
}
else
{
bytes = 0;
}
st->flate.next_out = (Bytef *)st->cbuffer + bytes;
st->flate.avail_out = (uInt)sizeof(st->cbuffer) - bytes;
} }
if (st->flate.avail_out < (uInt)sizeof(st->cbuffer)) if (st->flate.avail_out < (uInt)sizeof(st->cbuffer))
@ -99,6 +115,19 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
} }
} }
} }
else if (st->crypto_cb && st->bufptr > st->buffer)
{
// Encrypt and flush
uint8_t temp[8192]; // Temporary buffer
size_t outbytes; // Output bytes
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, st->buffer, (size_t)(st->bufptr - st->buffer));
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
{
ret = false;
goto done;
}
}
// Save the length of this stream... // Save the length of this stream...
st->obj->stream_length = (size_t)(_pdfioFileTell(st->pdf) - st->obj->stream_offset); st->obj->stream_length = (size_t)(_pdfioFileTell(st->pdf) - st->obj->stream_offset);
@ -177,6 +206,8 @@ _pdfioStreamCreate(
st->obj = obj; st->obj = obj;
st->length_obj = length_obj; st->length_obj = length_obj;
st->filter = compression; st->filter = compression;
st->bufptr = st->buffer;
st->bufend = st->buffer + sizeof(st->buffer);
if (obj->pdf->encryption) if (obj->pdf->encryption)
{ {
@ -760,20 +791,47 @@ pdfioStreamWrite(
if (st->crypto_cb) if (st->crypto_cb)
{ {
// Encrypt data before writing... // Encrypt data before writing...
unsigned char temp[8192]; // Temporary buffer uint8_t temp[8192]; // Temporary buffer
size_t cbytes, // Current bytes size_t cbytes, // Current bytes
outbytes; // Output bytes outbytes; // Output bytes
bufptr = (const unsigned char *)buffer; bufptr = (const unsigned char *)buffer;
while (bytes > 0) while (bytes > 0)
{ {
if ((cbytes = bytes) > sizeof(temp)) if (st->bufptr > st->buffer || bytes < 16)
cbytes = sizeof(temp); {
// Write through the stream's buffer...
if ((cbytes = bytes) > (st->bufend - st->bufptr))
cbytes = st->bufend - st->bufptr;
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, bufptr, cbytes); memcpy(st->bufptr, bufptr, cbytes);
if (!_pdfioFileWrite(st->pdf, temp, outbytes)) st->bufptr += cbytes;
return (false); if (st->bufptr >= st->bufend)
{
// Encrypt and flush
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, st->buffer, sizeof(st->buffer));
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
return (false);
st->bufptr = st->buffer;
}
}
else
{
// Write directly up to sizeof(temp) bytes...
if ((cbytes = bytes) > sizeof(temp))
cbytes = sizeof(temp);
if (cbytes & 15)
{
// AES has a 16-byte block size, so save the last few bytes...
cbytes &= ~15;
}
outbytes = (st->crypto_cb)(&st->crypto_ctx, temp, bufptr, cbytes);
if (!_pdfioFileWrite(st->pdf, temp, outbytes))
return (false);
}
bytes -= cbytes; bytes -= cbytes;
bufptr += cbytes; bufptr += cbytes;
@ -1160,19 +1218,34 @@ stream_write(pdfio_stream_t *st, // I - Stream
if (st->flate.avail_out < (sizeof(st->cbuffer) / 8)) if (st->flate.avail_out < (sizeof(st->cbuffer) / 8))
{ {
// Flush the compression buffer... // Flush the compression buffer...
size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out; size_t bytes = sizeof(st->cbuffer) - st->flate.avail_out,
outbytes;
if (st->crypto_cb) if (st->crypto_cb)
{ {
// Encrypt it first... // Encrypt it first...
bytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, bytes); outbytes = (st->crypto_cb)(&st->crypto_ctx, st->cbuffer, st->cbuffer, bytes & ~15);
}
else
{
outbytes = bytes;
} }
if (!_pdfioFileWrite(st->pdf, st->cbuffer, bytes)) if (!_pdfioFileWrite(st->pdf, st->cbuffer, bytes))
return (false); return (false);
st->flate.next_out = (Bytef *)st->cbuffer; if (bytes > outbytes)
st->flate.avail_out = sizeof(st->cbuffer); {
bytes -= outbytes;
memmove(st->cbuffer, st->cbuffer + outbytes, bytes);
}
else
{
bytes = 0;
}
st->flate.next_out = (Bytef *)st->cbuffer + bytes;
st->flate.avail_out = sizeof(st->cbuffer) - bytes;
} }
// Deflate what we can this time... // Deflate what we can this time...