[tor-commits] [stegotorus/master] changed pdfwrap and pdfunwrap to use zlib to encode data in stream objects
zwol at torproject.org
zwol at torproject.org
Fri Jul 20 23:17:08 UTC 2012
commit e1024c2d7e14fad7f832454326a4a9ea94e1e736
Author: Steven Cheung <steven.cheung at sri.com>
Date: Sun Jun 10 06:49:45 2012 -0700
changed pdfwrap and pdfunwrap to use zlib to encode data in stream objects
---
src/steg/pdfSteg.cc | 180 ++++++++++++++++++++++++++++++++------------------
1 files changed, 115 insertions(+), 65 deletions(-)
diff --git a/src/steg/pdfSteg.cc b/src/steg/pdfSteg.cc
index 658c319..2f67051 100644
--- a/src/steg/pdfSteg.cc
+++ b/src/steg/pdfSteg.cc
@@ -7,19 +7,21 @@
#include "connections.h"
#include "payloads.h"
#include <event2/buffer.h>
+#include "compression.h"
/* pdfSteg: A PDF-based steganography module */
#define PDF_DELIMITER '?'
#define PDF_DELIMITER2 '.'
-#define STREAM_BEGIN ">>stream"
-#define STREAM_BEGIN_SIZE 8
+#define STREAM_BEGIN "stream"
+#define STREAM_BEGIN_SIZE 6
#define STREAM_END "endstream"
#define STREAM_END_SIZE 9
#define DEBUG
+
/*
* pdf_add_delimiter processes the input buffer (inbuf) of length
* inbuflen, copies it to output buffer (outbuf) of size outbufsize,
@@ -158,6 +160,38 @@ pdf_remove_delimiter(const char *inbuf, size_t inbuflen,
return cnt;
}
+
+/*
+ * strInBinaryRewind looks for char array pattern of length patternLen
+ * in a char array blob of length blobLen in the *reverse* direction
+ *
+ * return a pointer for the first occurrence of pattern in blob,
+ * starting from the end of blob, if found; otherwise, return NULL
+ *
+ */
+char *
+strInBinaryRewind (const char *pattern, unsigned int patternLen,
+ const char *blob, unsigned int blobLen) {
+ int found = 0;
+ char *cp;
+
+ if (patternLen < 1 || blobLen < 1) return 0;
+ cp = (char *) blob + blobLen - 1;
+ while (cp >= blob) {
+ if (cp - (patternLen-1) < blob) break;
+ if (*cp == pattern[patternLen-1]) {
+ if (memcmp(cp-(patternLen-1), pattern, patternLen-1) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ cp--;
+ }
+ if (found) return (cp-(patternLen-1));
+ else return NULL;
+}
+
+
/*
* pdf_wrap embeds data of length dlen inside the stream objects of the PDF
* document (length plen) that appears in the body of a HTTP msg, and
@@ -172,29 +206,30 @@ pdf_wrap(const char *data, size_t dlen,
const char *pdfTemplate, size_t plen,
char *outbuf, size_t outbufsize)
{
- char data2[dlen*2+2];
- const char *tp, *dp, *plimit;
- char *op, *streamStart, *streamEnd;
- size_t data2len, cnt, size, size2;
- ssize_t rv;
+ int data2size = 2*dlen+10;
+ // see rfc 1950 for zlib format, in addition to compressed data, we have
+ // 2-byte compression method and flags +
+ // 4-byte dict ID +
+ // 4-byte ADLER32 checksum
+ char data2[data2size];
+ const char *tp, *plimit;
+ char *op, *streamStart, *streamEnd, *filterStart;
+ size_t data2len, size;
+ int np;
if (dlen > SIZE_T_CEILING || plen > SIZE_T_CEILING ||
outbufsize > SIZE_T_CEILING)
return -1;
- // assumption: pdf_wrap is length-preserving
- if (outbufsize < plen) return -1;
-
- rv = pdf_add_delimiter(data, dlen, data2, HTTP_MSG_BUF_SIZE,
- PDF_DELIMITER, PDF_DELIMITER2);
- if (rv < 1)
+ data2len = compress((const uint8_t *)data, dlen,
+ (uint8_t *)data2, data2size, c_format_zlib);
+ if ((int)data2len < 0) {
+ log_warn("compress failed and returned %lu", data2len);
return -1;
- data2len = rv;
+ }
op = outbuf; // current pointer for output buffer
tp = pdfTemplate; // current pointer for http msg template
- dp = data2; // current pointer for data2
- cnt = 0; // number of data char encoded
plimit = pdfTemplate+plen;
while (tp < plimit) {
@@ -205,43 +240,47 @@ pdf_wrap(const char *data, size_t dlen,
return -1;
}
- // copy everything between tp and "stream" (inclusive) to outbuf
- size = streamStart - tp + STREAM_BEGIN_SIZE;
- memcpy(op, tp, size);
- op += size;
- tp = streamStart + STREAM_BEGIN_SIZE;
-
streamEnd = strInBinary(STREAM_END, STREAM_END_SIZE, tp, plimit-tp);
if (streamEnd == NULL) {
log_warn("Cannot find endstream in pdf");
return -1;
}
- // count the number of usable char between tp and streamEnd
- size = streamEnd-tp;
-
- // encoding data in the stream obj
- if (size > 0) {
- size2 = data2len - cnt;
- if (size < size2) {
- memcpy(op, dp, size);
- op += size; tp += size; dp += size;
- memcpy(op, tp, STREAM_END_SIZE);
- op += STREAM_END_SIZE; tp += STREAM_END_SIZE;
- cnt += size;
- } else { // done encoding data
- memcpy(op, dp, size2);
- op += size2; tp += size2; dp += size2;
- cnt += size2;
- break;
- }
- log_debug("Encoded %lu bytes in pdf", (unsigned long)size);
- } else { // empty stream
- memcpy(op, tp, STREAM_END_SIZE);
- op += STREAM_END_SIZE; tp += STREAM_END_SIZE;
+ filterStart = strInBinaryRewind(" obj", 4, tp, streamStart-tp);
+ if (filterStart == NULL) {
+ log_warn("Cannot find obj\n");
+ return -1;
+ } else {
+ // copy everything between tp and up and and including "obj" to outbuf
+ size = filterStart - tp + 4;
+ memcpy(op, tp, size);
+ op[size] = 0;
+ op += size;
+
+ // write meta-data for stream object
+ np = sprintf(op, " <<\n/Length %d\n/Filter /FlateDecode\n>>\nstream\n", (int)data2len);
+ if (np < 0) {
+ log_warn("sprintf failed\n");
+ return -1;
+ }
+ op += np;
+
+ // copy compressed data to outbuf
+ memcpy(op, data2, data2len);
+ op += data2len;
+
+ // write endstream to outbuf
+ np = sprintf(op, "\nendstream");
+ if (np < 0) {
+ log_warn("sprintf failed\n");
+ return -1;
+ }
+ op += np;
}
- if (cnt >= data2len) break; // this shouldn't happen ...
+ // done with encoding data
+ tp = streamEnd+STREAM_END_SIZE;
+ break;
}
// copy the rest of pdfTemplate to outbuf
@@ -261,9 +300,11 @@ pdf_unwrap(const char *data, size_t dlen,
char *outbuf, size_t outbufsize)
{
const char *dp, *dlimit;
- char *op, *streamStart, *streamEnd, *olimit;
+ char *op, *streamStart, *streamEnd;
size_t cnt, size, size2;
- bool endFlag, escape = false;
+
+ int streamObjStartSkip=0;
+ int streamObjEndSkip=0;
if (dlen > SIZE_T_CEILING || outbufsize > SIZE_T_CEILING)
return -1;
@@ -272,8 +313,8 @@ pdf_unwrap(const char *data, size_t dlen,
op = outbuf; // current pointer for outbuf
cnt = 0; // number of char decoded
dlimit = data+dlen;
- olimit = outbuf+outbufsize;
+
while (dp < dlimit) {
// find the next stream obj
streamStart = strInBinary(STREAM_BEGIN, STREAM_BEGIN_SIZE, dp, dlimit-dp);
@@ -283,31 +324,40 @@ pdf_unwrap(const char *data, size_t dlen,
}
dp = streamStart + STREAM_BEGIN_SIZE;
+
+ // streamObjStartSkip = size of end-of-line (EOL) char(s) after ">>stream"
+ if ( *dp == '\r' && *(dp+1) == '\n' ) { // Windows-style EOL
+ streamObjStartSkip = 2;
+ } else if ( *dp == '\n' ) { // Unix-style EOL
+ streamObjStartSkip = 1;
+ }
+
+ dp = dp + streamObjStartSkip;
+
streamEnd = strInBinary(STREAM_END, STREAM_END_SIZE, dp, dlimit-dp);
if (streamEnd == NULL) {
log_warn("Cannot find endstream in pdf");
return -1;
}
- // count the number of usable char between tp and streamEnd
- size = streamEnd-dp;
+ // streamObjEndSkip = size of end-of-line (EOL) char(s) at the end of stream obj
+ if (*(streamEnd-2) == '\r' && *(streamEnd-1) == '\n') {
+ streamObjEndSkip = 2;
+ } else if (*(streamEnd-1) == '\n') {
+ streamObjEndSkip = 1;
+ }
- if (size > 0) {
- ssize_t rv = pdf_remove_delimiter(dp, size, op, olimit-op, PDF_DELIMITER,
- &endFlag, &escape);
- if (rv < 0)
- return -1;
+ // compute the size of stream obj payload
+ size = (streamEnd-streamObjEndSkip) - dp;
- size2 = rv;
- cnt += size2;
- if (endFlag) { // Done decoding
- break;
- } else { // Continue decoding
- op += size2;
- dp = streamEnd + STREAM_END_SIZE;
- }
- } else { // empty stream obj
- dp = streamEnd + STREAM_END_SIZE;
+ size2 = decompress((const uint8_t *)dp, size, (uint8_t *)op, outbufsize);
+ if ((int)size2 < 0) {
+ log_warn("decompress failed; size2 = %d\n", (int)size2);
+ return -1;
+ } else {
+ op += size2;
+ cnt = size2;
+ break; // done decoding
}
}
More information about the tor-commits
mailing list