You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1143 lines
27 KiB
1143 lines
27 KiB
diff --git a/configure.ac b/configure.ac
|
|
index a9f0316..6ff59ef 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -348,6 +348,36 @@ AC_ARG_ENABLE(show-failed-test-output,
|
|
fi],
|
|
[SHOW_FAILED_TEST_OUTPUT=0])
|
|
|
|
+AC_PATH_TOOL(PKGCONFIG, pkg-config)
|
|
+
|
|
+AC_MSG_CHECKING(if cryptography will be supplied by GNU TLS)
|
|
+AC_ARG_ENABLE(gnutls,
|
|
+ AS_HELP_STRING([--enable-gnutls],
|
|
+ [enable cryptography by GNUTLS]),
|
|
+ [if test "$enableval" = "yes"; then
|
|
+ if test "x$PKGCONFIG" != x ; then
|
|
+ AC_TRY_COMPILE([
|
|
+ #include <gnutls/crypto.h>], , , AC_MSG_ERROR([GNU TLS development headers are needed.]))
|
|
+ GNUTLSFLAGS=`pkg-config --cflags gnutls`
|
|
+ GNUTLSLIBS=`pkg-config --libs gnutls`
|
|
+ LIBS="$LIBS $GNUTLSLIBS"
|
|
+ CPPFLAGS="$CPPFLAGS $GNUTLSFLAGS"
|
|
+ AC_DEFINE([HAVE_GNUTLS], [1], [If cryptography will be supplied by GNU TLS])
|
|
+ HAVE_GNUTLS=1
|
|
+ else
|
|
+ HAVE_GNUTLS=0
|
|
+ AC_MSG_ERROR([pkg-config is needed to configure compilation with GNU TLS.])
|
|
+ fi
|
|
+ else
|
|
+ HAVE_GNUTLS=0
|
|
+ fi],
|
|
+ [HAVE_GNUTLS=0])
|
|
+if test "$HAVE_GNUTLS" = "1" ; then
|
|
+ AC_MSG_RESULT(yes)
|
|
+else
|
|
+ AC_MSG_RESULT(no)
|
|
+fi
|
|
+
|
|
AC_ARG_WITH(docbook-xsl,
|
|
AS_HELP_STRING([--with-docbook-xsl=DIR],
|
|
[location of docbook 4.x xml stylesheets]),
|
|
diff --git a/libqpdf/MD5-gnutls.cc b/libqpdf/MD5-gnutls.cc
|
|
new file mode 100644
|
|
index 0000000..5611b3e
|
|
--- /dev/null
|
|
+++ b/libqpdf/MD5-gnutls.cc
|
|
@@ -0,0 +1,61 @@
|
|
+#include <gnutls/crypto.h>
|
|
+#include <qpdf/MD5.hh>
|
|
+#include <qpdf/QUtil.hh>
|
|
+
|
|
+
|
|
+// MD5 initialization. Begins an MD5 operation, writing a new context.
|
|
+void MD5::init()
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = gnutls_hash_init(&ctx, GNUTLS_DIG_MD5);
|
|
+ if (ret < 0) {
|
|
+ QUtil::throw_system_error(
|
|
+ std::string("GNU TLS: MD5 error:") + std::string(gnutls_strerror(ret)));
|
|
+ ctx = nullptr;
|
|
+ }
|
|
+
|
|
+ finalized = false;
|
|
+ memset(digest_val, 0, sizeof(digest_val));
|
|
+}
|
|
+
|
|
+// MD5 block update operation. Continues an MD5 message-digest
|
|
+// operation, processing another message block, and updating the
|
|
+// context.
|
|
+
|
|
+void MD5::update(unsigned char *input,
|
|
+ unsigned int inputLen)
|
|
+{
|
|
+ if (ctx != nullptr && input != nullptr)
|
|
+ gnutls_hash(ctx, input, inputLen);
|
|
+}
|
|
+
|
|
+// MD5 finalization. Ends an MD5 message-digest operation, writing the
|
|
+// the message digest and zeroizing the context.
|
|
+void MD5::final()
|
|
+{
|
|
+ if (finalized)
|
|
+ return;
|
|
+
|
|
+ if (ctx != nullptr)
|
|
+ {
|
|
+ gnutls_hash_deinit(ctx, digest_val);
|
|
+ ctx = nullptr;
|
|
+ }
|
|
+
|
|
+ finalized = true;
|
|
+}
|
|
+
|
|
+// MD5 basic transformation. Transforms state based on block.
|
|
+void MD5::transform(UINT4 state[4], unsigned char block[64])
|
|
+{}
|
|
+
|
|
+// Encodes input (UINT4) into output (unsigned char). Assumes len is a
|
|
+// multiple of 4.
|
|
+void MD5::encode(unsigned char *output, UINT4 *input, unsigned int len)
|
|
+{}
|
|
+
|
|
+// Decodes input (unsigned char) into output (UINT4). Assumes len is a
|
|
+// multiple of 4.
|
|
+void MD5::decode(UINT4 *output, unsigned char *input, unsigned int len)
|
|
+{}
|
|
diff --git a/libqpdf/MD5.cc b/libqpdf/MD5.cc
|
|
index 0504e2d..19dce79 100644
|
|
--- a/libqpdf/MD5.cc
|
|
+++ b/libqpdf/MD5.cc
|
|
@@ -36,6 +36,10 @@
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include "MD5-gnutls.cc"
|
|
+#else
|
|
+
|
|
int const S11 = 7;
|
|
int const S12 = 12;
|
|
int const S13 = 17;
|
|
@@ -294,6 +298,8 @@ void MD5::decode(UINT4 *output, unsigned char *input, unsigned int len)
|
|
(static_cast<UINT4>(input[j+3]) << 24);
|
|
}
|
|
|
|
+#endif /* HAVE_GNUTLS */
|
|
+
|
|
// Public functions
|
|
|
|
MD5::MD5()
|
|
diff --git a/libqpdf/Pl_AES_PDF-gnutls.cc b/libqpdf/Pl_AES_PDF-gnutls.cc
|
|
new file mode 100644
|
|
index 0000000..7704e6d
|
|
--- /dev/null
|
|
+++ b/libqpdf/Pl_AES_PDF-gnutls.cc
|
|
@@ -0,0 +1,246 @@
|
|
+#include <qpdf/Pl_AES_PDF.hh>
|
|
+#include <gnutls/crypto.h>
|
|
+#include <qpdf/rijndael-gnutls.h>
|
|
+
|
|
+bool Pl_AES_PDF::use_static_iv = false;
|
|
+
|
|
+Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next,
|
|
+ bool encrypt, unsigned char const* key,
|
|
+ unsigned int key_bytes) :
|
|
+ Pipeline(identifier, next),
|
|
+ encrypt(encrypt),
|
|
+ cbc_mode(true),
|
|
+ first(true),
|
|
+ offset(0),
|
|
+ nrounds(0),
|
|
+ use_zero_iv(false),
|
|
+ use_specified_iv(false),
|
|
+ disable_padding(false)
|
|
+{
|
|
+ unsigned int keybits = 8 * key_bytes;
|
|
+ this->keylen = key_bytes;
|
|
+ this->ctx = nullptr;
|
|
+ assert(key_bytes == KEYLENGTH(keybits));
|
|
+ this->key = new unsigned char[key_bytes];
|
|
+ this->rk = new uint32_t[RKLENGTH(keybits)];
|
|
+ unsigned int rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t);
|
|
+ std::memcpy(this->key, key, key_bytes);
|
|
+ std::memset(this->rk, 0, rk_bytes);
|
|
+ std::memset(this->inbuf, 0, this->buf_size);
|
|
+ std::memset(this->outbuf, 0, this->buf_size);
|
|
+ std::memset(this->cbc_block, 0, this->buf_size);
|
|
+}
|
|
+
|
|
+Pl_AES_PDF::~Pl_AES_PDF()
|
|
+{
|
|
+ delete [] this->key;
|
|
+ delete [] this->rk;
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::useZeroIV()
|
|
+{
|
|
+ this->use_zero_iv = true;
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::disablePadding()
|
|
+{
|
|
+ this->disable_padding = true;
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::setIV(unsigned char const* iv, size_t bytes)
|
|
+{
|
|
+ if (bytes != this->buf_size)
|
|
+ {
|
|
+ throw std::logic_error(
|
|
+ "Pl_AES_PDF: specified initialization vector"
|
|
+ " size in bytes must be " + QUtil::int_to_string(bytes));
|
|
+ }
|
|
+ this->use_specified_iv = true;
|
|
+ memcpy(this->specified_iv, iv, bytes);
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::disableCBC()
|
|
+{
|
|
+ this->cbc_mode = false;
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::useStaticIV()
|
|
+{
|
|
+ use_static_iv = true;
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::write(unsigned char* data, size_t len)
|
|
+{
|
|
+ size_t bytes_left = len;
|
|
+ unsigned char* p = data;
|
|
+
|
|
+ while (bytes_left > 0)
|
|
+ {
|
|
+ if (this->offset == this->buf_size)
|
|
+ {
|
|
+ flush(false);
|
|
+ }
|
|
+
|
|
+ size_t available = this->buf_size - this->offset;
|
|
+ size_t bytes = (bytes_left < available ? bytes_left : available);
|
|
+ bytes_left -= bytes;
|
|
+ std::memcpy(this->inbuf + this->offset, p, bytes);
|
|
+ this->offset += bytes;
|
|
+ p += bytes;
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::finish()
|
|
+{
|
|
+ if (this->encrypt)
|
|
+ {
|
|
+ if (this->offset == this->buf_size)
|
|
+ {
|
|
+ flush(false);
|
|
+ }
|
|
+ if (! this->disable_padding)
|
|
+ {
|
|
+ // Pad as described in section 3.5.1 of version 1.7 of the PDF
|
|
+ // specification, including providing an entire block of padding
|
|
+ // if the input was a multiple of 16 bytes.
|
|
+ unsigned char pad =
|
|
+ static_cast<unsigned char>(this->buf_size - this->offset);
|
|
+ memset(this->inbuf + this->offset, pad, pad);
|
|
+ this->offset = this->buf_size;
|
|
+ flush(false);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (this->offset != this->buf_size)
|
|
+ {
|
|
+ // This is never supposed to happen as the output is
|
|
+ // always supposed to be padded. However, we have
|
|
+ // encountered files for which the output is not a
|
|
+ // multiple of the block size. In this case, pad with
|
|
+ // zeroes and hope for the best.
|
|
+ assert(this->buf_size > this->offset);
|
|
+ std::memset(this->inbuf + this->offset, 0,
|
|
+ this->buf_size - this->offset);
|
|
+ this->offset = this->buf_size;
|
|
+ }
|
|
+ flush(! this->disable_padding);
|
|
+ }
|
|
+
|
|
+ if (this->cbc_mode)
|
|
+ rijndaelFinish(this->ctx);
|
|
+
|
|
+ getNext()->finish();
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::initializeVector()
|
|
+{
|
|
+ if (use_zero_iv)
|
|
+ {
|
|
+ for (unsigned int i = 0; i < this->buf_size; ++i)
|
|
+ {
|
|
+ this->cbc_block[i] = 0;
|
|
+ }
|
|
+ }
|
|
+ else if (use_specified_iv)
|
|
+ {
|
|
+ std::memcpy(this->cbc_block, this->specified_iv, this->buf_size);
|
|
+ }
|
|
+ else if (use_static_iv)
|
|
+ {
|
|
+ for (unsigned int i = 0; i < this->buf_size; ++i)
|
|
+ {
|
|
+ this->cbc_block[i] = 14 * (1 + i);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ QUtil::initializeWithRandomBytes(this->cbc_block, this->buf_size);
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+Pl_AES_PDF::flush(bool strip_padding)
|
|
+{
|
|
+ assert(this->offset == this->buf_size);
|
|
+
|
|
+ if (first)
|
|
+ {
|
|
+ first = false;
|
|
+ if (this->cbc_mode)
|
|
+ {
|
|
+ if (encrypt)
|
|
+ {
|
|
+ // Set cbc_block to the initialization vector, and if
|
|
+ // not zero, write it to the output stream.
|
|
+ initializeVector();
|
|
+ if (! (this->use_zero_iv || this->use_specified_iv))
|
|
+ {
|
|
+ getNext()->write(this->cbc_block, this->buf_size);
|
|
+ }
|
|
+ }
|
|
+ else if (this->use_zero_iv || this->use_specified_iv)
|
|
+ {
|
|
+ // Initialize vector with zeroes; zero vector was not
|
|
+ // written to the beginning of the input file.
|
|
+ initializeVector();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ // Take the first block of input as the initialization
|
|
+ // vector. There's nothing to write at this time.
|
|
+ memcpy(this->cbc_block, this->inbuf, this->buf_size);
|
|
+ this->offset = 0;
|
|
+ rijndaelInit(&(this->ctx), this->key, this->keylen, this->cbc_block, this->buf_size);
|
|
+ return;
|
|
+ }
|
|
+ rijndaelInit(&(this->ctx), this->key, this->keylen, this->cbc_block, this->buf_size);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (this->encrypt)
|
|
+ {
|
|
+ if (this->cbc_mode)
|
|
+ rijndaelCBCEncrypt(this->ctx, this->inbuf, this->outbuf, this->buf_size);
|
|
+ else
|
|
+ rijndaelECBEncrypt(this->key, this->keylen, this->cbc_block, this->inbuf, this->outbuf, this->buf_size);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (this->cbc_mode)
|
|
+ rijndaelCBCDecrypt(this->ctx, this->inbuf, this->outbuf, this->buf_size);
|
|
+ else
|
|
+ rijndaelECBDecrypt(this->key, this->keylen, this->cbc_block, this->inbuf, this->outbuf, this->buf_size);
|
|
+ }
|
|
+ unsigned int bytes = this->buf_size;
|
|
+ if (strip_padding)
|
|
+ {
|
|
+ unsigned char last = this->outbuf[this->buf_size - 1];
|
|
+ if (last <= this->buf_size)
|
|
+ {
|
|
+ bool strip = true;
|
|
+ for (unsigned int i = 1; i <= last; ++i)
|
|
+ {
|
|
+ if (this->outbuf[this->buf_size - i] != last)
|
|
+ {
|
|
+ strip = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (strip)
|
|
+ {
|
|
+ bytes -= last;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ getNext()->write(this->outbuf, bytes);
|
|
+ this->offset = 0;
|
|
+}
|
|
diff --git a/libqpdf/Pl_AES_PDF.cc b/libqpdf/Pl_AES_PDF.cc
|
|
index 5c493cb..ac8bde4 100644
|
|
--- a/libqpdf/Pl_AES_PDF.cc
|
|
+++ b/libqpdf/Pl_AES_PDF.cc
|
|
@@ -3,10 +3,15 @@
|
|
#include <cstring>
|
|
#include <assert.h>
|
|
#include <stdexcept>
|
|
-#include <qpdf/rijndael.h>
|
|
+
|
|
#include <string>
|
|
#include <stdlib.h>
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include "Pl_AES_PDF-gnutls.cc"
|
|
+#else
|
|
+# include <qpdf/rijndael.h>
|
|
+
|
|
bool Pl_AES_PDF::use_static_iv = false;
|
|
|
|
Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next,
|
|
@@ -263,3 +268,4 @@ Pl_AES_PDF::flush(bool strip_padding)
|
|
getNext()->write(this->outbuf, bytes);
|
|
this->offset = 0;
|
|
}
|
|
+#endif
|
|
diff --git a/libqpdf/Pl_SHA2.cc b/libqpdf/Pl_SHA2.cc
|
|
index 17eff7e..9156451 100644
|
|
--- a/libqpdf/Pl_SHA2.cc
|
|
+++ b/libqpdf/Pl_SHA2.cc
|
|
@@ -13,6 +13,12 @@ Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) :
|
|
{
|
|
resetBits(bits);
|
|
}
|
|
+
|
|
+#ifdef HAVE_GNUTLS
|
|
+ this->ctx256 = nullptr;
|
|
+ this->ctx384 = nullptr;
|
|
+ this->ctx512 = nullptr;
|
|
+#endif
|
|
}
|
|
|
|
Pl_SHA2::~Pl_SHA2()
|
|
diff --git a/libqpdf/RC4-gnutls.cc b/libqpdf/RC4-gnutls.cc
|
|
new file mode 100644
|
|
index 0000000..093a5b9
|
|
--- /dev/null
|
|
+++ b/libqpdf/RC4-gnutls.cc
|
|
@@ -0,0 +1,51 @@
|
|
+#include <qpdf/RC4.hh>
|
|
+#include <qpdf/QUtil.hh>
|
|
+#include <gnutls/crypto.h>
|
|
+
|
|
+
|
|
+RC4::RC4(unsigned char const* key_data, int key_len)
|
|
+{
|
|
+ if (key_len == -1)
|
|
+ {
|
|
+ key_len = strlen(reinterpret_cast<char const*>(key_data));
|
|
+ }
|
|
+
|
|
+ int ret;
|
|
+ gnutls_cipher_algorithm_t alg = GNUTLS_CIPHER_ARCFOUR_128;
|
|
+
|
|
+ this->key.data = const_cast<unsigned char*>(key_data);
|
|
+ this->key.size = key_len;
|
|
+
|
|
+ ret = gnutls_cipher_init(&(this->ctx),
|
|
+ alg,
|
|
+ &(this->key),
|
|
+ NULL);
|
|
+ if (ret < 0)
|
|
+ {
|
|
+ QUtil::throw_system_error(
|
|
+ std::string("GNU TLS: RC4 error: ") + std::string(gnutls_strerror(ret)));
|
|
+ this->ctx = nullptr;
|
|
+ }
|
|
+}
|
|
+
|
|
+RC4::~RC4()
|
|
+{
|
|
+ if (this->ctx != nullptr)
|
|
+ {
|
|
+ gnutls_cipher_deinit(this->ctx);
|
|
+ this->ctx = nullptr;
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+RC4::process(unsigned char *in_data, int len, unsigned char* out_data)
|
|
+{
|
|
+ if (out_data == 0)
|
|
+ {
|
|
+ // Convert in place
|
|
+ out_data = in_data;
|
|
+ }
|
|
+
|
|
+ if (this->ctx != nullptr && in_data != nullptr)
|
|
+ gnutls_cipher_encrypt2(this->ctx, in_data, len, out_data, len);
|
|
+}
|
|
diff --git a/libqpdf/RC4.cc b/libqpdf/RC4.cc
|
|
index 7639a36..c1288be 100644
|
|
--- a/libqpdf/RC4.cc
|
|
+++ b/libqpdf/RC4.cc
|
|
@@ -2,6 +2,10 @@
|
|
|
|
#include <string.h>
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include "RC4-gnutls.cc"
|
|
+#else
|
|
+
|
|
static void swap_byte(unsigned char &a, unsigned char &b)
|
|
{
|
|
unsigned char t;
|
|
@@ -53,3 +57,4 @@ RC4::process(unsigned char *in_data, int len, unsigned char* out_data)
|
|
out_data[i] = in_data[i] ^ key.state[xor_index];
|
|
}
|
|
}
|
|
+#endif
|
|
diff --git a/libqpdf/SecureRandomDataProvider.cc b/libqpdf/SecureRandomDataProvider.cc
|
|
index fe9f1d4..d72269e 100644
|
|
--- a/libqpdf/SecureRandomDataProvider.cc
|
|
+++ b/libqpdf/SecureRandomDataProvider.cc
|
|
@@ -11,6 +11,10 @@
|
|
# endif
|
|
#endif
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include <gnutls/crypto.h>
|
|
+#endif
|
|
+
|
|
SecureRandomDataProvider::SecureRandomDataProvider()
|
|
{
|
|
}
|
|
@@ -89,7 +93,19 @@ class WindowsCryptProvider
|
|
void
|
|
SecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len)
|
|
{
|
|
-#if defined(_WIN32)
|
|
+#if defined(HAVE_GNUTLS)
|
|
+
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = gnutls_rnd(GNUTLS_RND_NONCE, data, len);
|
|
+ if (ret < 0)
|
|
+ {
|
|
+ throw std::runtime_error(
|
|
+ "GNU TLS: unable to generate secure random data " +
|
|
+ std::string(gnutls_strerror(ret)));
|
|
+ }
|
|
+
|
|
+#elif defined(_WIN32)
|
|
|
|
// Optimization: make the WindowsCryptProvider static as long as
|
|
// it can be done in a thread-safe fashion.
|
|
diff --git a/libqpdf/qpdf/MD5.hh b/libqpdf/qpdf/MD5.hh
|
|
index 4cfe027..bb9f756 100644
|
|
--- a/libqpdf/qpdf/MD5.hh
|
|
+++ b/libqpdf/qpdf/MD5.hh
|
|
@@ -11,6 +11,10 @@
|
|
#endif
|
|
#include <string>
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include <gnutls/crypto.h>
|
|
+#endif
|
|
+
|
|
class MD5
|
|
{
|
|
public:
|
|
@@ -87,6 +91,9 @@ class MD5
|
|
|
|
bool finalized;
|
|
Digest digest_val;
|
|
+#ifdef HAVE_GNUTLS
|
|
+ gnutls_hash_hd_t ctx;
|
|
+#endif
|
|
};
|
|
|
|
#endif // __MD5_HH__
|
|
diff --git a/libqpdf/qpdf/Pl_AES_PDF.hh b/libqpdf/qpdf/Pl_AES_PDF.hh
|
|
index 9aa73ad..8059e7d 100644
|
|
--- a/libqpdf/qpdf/Pl_AES_PDF.hh
|
|
+++ b/libqpdf/qpdf/Pl_AES_PDF.hh
|
|
@@ -7,6 +7,10 @@
|
|
# include <stdint.h>
|
|
#endif
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include <gnutls/crypto.h>
|
|
+#endif
|
|
+
|
|
// This pipeline implements AES-128 and AES-256 with CBC and block
|
|
// padding as specified in the PDF specification.
|
|
|
|
@@ -64,6 +68,11 @@ class Pl_AES_PDF: public Pipeline
|
|
bool use_zero_iv;
|
|
bool use_specified_iv;
|
|
bool disable_padding;
|
|
+
|
|
+#ifdef HAVE_GNUTLS
|
|
+ gnutls_cipher_hd_t ctx;
|
|
+ unsigned int keylen;
|
|
+#endif
|
|
};
|
|
|
|
#endif // __PL_AES_PDF_HH__
|
|
diff --git a/libqpdf/qpdf/RC4.hh b/libqpdf/qpdf/RC4.hh
|
|
index c26f3d0..1421a08 100644
|
|
--- a/libqpdf/qpdf/RC4.hh
|
|
+++ b/libqpdf/qpdf/RC4.hh
|
|
@@ -1,6 +1,12 @@
|
|
#ifndef __RC4_HH__
|
|
#define __RC4_HH__
|
|
|
|
+#include <qpdf/qpdf-config.h>
|
|
+
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include <gnutls/crypto.h>
|
|
+#endif
|
|
+
|
|
class RC4
|
|
{
|
|
public:
|
|
@@ -10,7 +16,15 @@ class RC4
|
|
// out_data = 0 means to encrypt/decrypt in place
|
|
void process(unsigned char* in_data, int len, unsigned char* out_data = 0);
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+ ~RC4();
|
|
+#endif
|
|
+
|
|
private:
|
|
+#ifdef HAVE_GNUTLS
|
|
+ gnutls_cipher_hd_t ctx;
|
|
+ gnutls_datum_t key;
|
|
+#else
|
|
class RC4Key
|
|
{
|
|
public:
|
|
@@ -20,6 +34,7 @@ class RC4
|
|
};
|
|
|
|
RC4Key key;
|
|
+#endif
|
|
};
|
|
|
|
#endif // __RC4_HH__
|
|
diff --git a/libqpdf/qpdf/rijndael-gnutls.h b/libqpdf/qpdf/rijndael-gnutls.h
|
|
new file mode 100644
|
|
index 0000000..a3e7ff0
|
|
--- /dev/null
|
|
+++ b/libqpdf/qpdf/rijndael-gnutls.h
|
|
@@ -0,0 +1,32 @@
|
|
+#ifdef HAVE_INTTYPES_H
|
|
+# include <inttypes.h>
|
|
+#endif
|
|
+#ifdef HAVE_STDINT_H
|
|
+# include <stdint.h>
|
|
+#endif
|
|
+
|
|
+#include <gnutls/crypto.h>
|
|
+
|
|
+void rijndaelInit(gnutls_cipher_hd_t * context, unsigned char * key,
|
|
+ unsigned int keylen, unsigned char cbc_block[16], unsigned int buf_size);
|
|
+int rijndaelSetupEncrypt(uint32_t *rk, const unsigned char *key,
|
|
+ int keybits);
|
|
+int rijndaelSetupDecrypt(uint32_t *rk, const unsigned char *key,
|
|
+ int keybits);
|
|
+void rijndaelCBCEncrypt(gnutls_cipher_hd_t context,
|
|
+ const unsigned char plaintext[16], unsigned char ciphertext[16],
|
|
+ unsigned int buf_size);
|
|
+void rijndaelCBCDecrypt(gnutls_cipher_hd_t context,
|
|
+ const unsigned char ciphertext[16], unsigned char plaintext[16],
|
|
+ unsigned int buf_size);
|
|
+void rijndaelECBEncrypt(unsigned char * key, unsigned int keylen,
|
|
+ unsigned char cbc_block[16], const unsigned char plaintext[16],
|
|
+ unsigned char ciphertext[16], unsigned int buf_size);
|
|
+void rijndaelECBDecrypt(unsigned char * key, unsigned int keylen,
|
|
+ unsigned char cbc_block[16], const unsigned char ciphertext[16],
|
|
+ unsigned char plaintext[16], unsigned int buf_size);
|
|
+void rijndaelFinish(gnutls_cipher_hd_t context);
|
|
+
|
|
+#define KEYLENGTH(keybits) ((keybits)/8)
|
|
+#define RKLENGTH(keybits) ((keybits)/8+28)
|
|
+#define NROUNDS(keybits) ((keybits)/32+6)
|
|
diff --git a/libqpdf/qpdf/rijndael.h b/libqpdf/qpdf/rijndael.h
|
|
index a9cd71d..9698a8b 100644
|
|
--- a/libqpdf/qpdf/rijndael.h
|
|
+++ b/libqpdf/qpdf/rijndael.h
|
|
@@ -9,6 +9,10 @@
|
|
# include <stdint.h>
|
|
#endif
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include "qpdf/rijndael-gnutls.h"
|
|
+#else
|
|
+
|
|
int rijndaelSetupEncrypt(uint32_t *rk, const unsigned char *key,
|
|
int keybits);
|
|
int rijndaelSetupDecrypt(uint32_t *rk, const unsigned char *key,
|
|
@@ -22,4 +26,6 @@ void rijndaelDecrypt(const uint32_t *rk, int nrounds,
|
|
#define RKLENGTH(keybits) ((keybits)/8+28)
|
|
#define NROUNDS(keybits) ((keybits)/32+6)
|
|
|
|
+#endif /* HAVE_GNUTLS */
|
|
+
|
|
#endif
|
|
diff --git a/libqpdf/rijndael-gnutls.cc b/libqpdf/rijndael-gnutls.cc
|
|
new file mode 100644
|
|
index 0000000..dd3fdb2
|
|
--- /dev/null
|
|
+++ b/libqpdf/rijndael-gnutls.cc
|
|
@@ -0,0 +1,116 @@
|
|
+#include <cstring>
|
|
+#include <gnutls/crypto.h>
|
|
+#include <qpdf/QUtil.hh>
|
|
+#include <qpdf/rijndael-gnutls.h>
|
|
+
|
|
+typedef uint32_t u32;
|
|
+
|
|
+/**
|
|
+ * Init cryptographic context
|
|
+ */
|
|
+void rijndaelInit(gnutls_cipher_hd_t * ctx, unsigned char * key,
|
|
+ unsigned int keylen, unsigned char cbc_block[16],
|
|
+ unsigned int buf_size)
|
|
+{
|
|
+ int ret;
|
|
+ gnutls_cipher_algorithm_t alg;
|
|
+ gnutls_datum_t cipher_key;
|
|
+ gnutls_datum_t iv;
|
|
+
|
|
+ cipher_key.data = key;
|
|
+
|
|
+ switch(keylen) {
|
|
+ case 16:
|
|
+ alg = GNUTLS_CIPHER_AES_128_CBC;
|
|
+ break;
|
|
+ case 32:
|
|
+ alg = GNUTLS_CIPHER_AES_256_CBC;
|
|
+ break;
|
|
+ case 24:
|
|
+ alg = GNUTLS_CIPHER_AES_192_CBC;
|
|
+ break;
|
|
+ default:
|
|
+ alg = GNUTLS_CIPHER_AES_128_CBC;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ cipher_key.size = gnutls_cipher_get_key_size(alg);
|
|
+
|
|
+ iv.data = cbc_block;
|
|
+ iv.size = buf_size;
|
|
+
|
|
+ ret = gnutls_cipher_init(ctx, alg, &cipher_key, &iv);
|
|
+ if (ret < 0)
|
|
+ {
|
|
+ QUtil::throw_system_error(
|
|
+ std::string("GNU TLS: AES error: ") + std::string(gnutls_strerror(ret)));
|
|
+ ctx = NULL;
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Encrypt string by AES CBC by GNU TLS.
|
|
+ */
|
|
+void rijndaelCBCEncrypt(gnutls_cipher_hd_t ctx,
|
|
+ const unsigned char plaintext[16], unsigned char ciphertext[16],
|
|
+ unsigned int buf_size)
|
|
+{
|
|
+ if (ctx != nullptr)
|
|
+ gnutls_cipher_encrypt2(ctx, plaintext, buf_size, ciphertext, buf_size);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Decrypt string by AES CBC by GNU TLS.
|
|
+ */
|
|
+void rijndaelCBCDecrypt(gnutls_cipher_hd_t ctx,
|
|
+ const unsigned char ciphertext[16], unsigned char plaintext[16],
|
|
+ unsigned int buf_size)
|
|
+{
|
|
+ if (ctx != nullptr)
|
|
+ gnutls_cipher_decrypt2(ctx, ciphertext, buf_size, plaintext, buf_size);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Encrypt string by AES ECB by GNU TLS.
|
|
+ */
|
|
+void rijndaelECBEncrypt(unsigned char * key, unsigned int keylen,
|
|
+ unsigned char cbc_block[16], const unsigned char ciphertext[16],
|
|
+ unsigned char plaintext[16], unsigned int buf_size)
|
|
+{
|
|
+ gnutls_cipher_hd_t ctx;
|
|
+
|
|
+ rijndaelInit(&ctx, key, keylen, cbc_block, buf_size);
|
|
+
|
|
+ rijndaelCBCEncrypt(ctx, ciphertext, plaintext, buf_size);
|
|
+
|
|
+ rijndaelFinish(ctx);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Decrypt string by AES ECB by GNU TLS.
|
|
+ */
|
|
+void rijndaelECBDecrypt(unsigned char * key, unsigned int keylen,
|
|
+ unsigned char cbc_block[16], const unsigned char ciphertext[16],
|
|
+ unsigned char plaintext[16], unsigned int buf_size)
|
|
+{
|
|
+ gnutls_cipher_hd_t ctx;
|
|
+
|
|
+ rijndaelInit(&ctx, key, keylen, cbc_block, buf_size);
|
|
+
|
|
+ rijndaelCBCDecrypt(ctx, ciphertext, plaintext, buf_size);
|
|
+
|
|
+ rijndaelFinish(ctx);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Finish cryptography context
|
|
+ */
|
|
+void rijndaelFinish(gnutls_cipher_hd_t ctx)
|
|
+{
|
|
+ if (ctx != nullptr)
|
|
+ {
|
|
+ gnutls_cipher_deinit(ctx);
|
|
+ ctx = nullptr;
|
|
+ }
|
|
+}
|
|
diff --git a/libqpdf/rijndael.cc b/libqpdf/rijndael.cc
|
|
index 7f711df..117c1a1 100644
|
|
--- a/libqpdf/rijndael.cc
|
|
+++ b/libqpdf/rijndael.cc
|
|
@@ -2,6 +2,10 @@
|
|
|
|
#include "qpdf/rijndael.h"
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include "rijndael-gnutls.cc"
|
|
+#else
|
|
+
|
|
typedef uint32_t u32;
|
|
typedef unsigned char u8;
|
|
|
|
@@ -1206,3 +1210,4 @@ void rijndaelDecrypt(const u32 *rk, int nrounds, const u8 ciphertext[16],
|
|
rk[3];
|
|
PUTU32(plaintext + 12, s3);
|
|
}
|
|
+#endif
|
|
diff --git a/libqpdf/sha2-gnutls.c b/libqpdf/sha2-gnutls.c
|
|
new file mode 100644
|
|
index 0000000..29155d5
|
|
--- /dev/null
|
|
+++ b/libqpdf/sha2-gnutls.c
|
|
@@ -0,0 +1,41 @@
|
|
+#include <gnutls/crypto.h>
|
|
+#include <stdio.h>
|
|
+#include "sph/sph_sha2_gnutls.h"
|
|
+
|
|
+
|
|
+/* see sph_sha2.h */
|
|
+void
|
|
+sph_sha256_init(void * cc)
|
|
+{
|
|
+ int ret;
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ ret = gnutls_hash_init(ctx, GNUTLS_DIG_SHA256);
|
|
+ if (ret < 0)
|
|
+ {
|
|
+ fprintf(stderr, "GNU TLS: SHA256 error : %s\n", gnutls_strerror(ret));
|
|
+ cc = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* see sph_sha2.h */
|
|
+void
|
|
+sph_sha256_close(void * cc, void *dst)
|
|
+{
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ if (ctx != NULL)
|
|
+ {
|
|
+ gnutls_hash_deinit(*(ctx), dst);
|
|
+ cc = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* see sph_sha2.h */
|
|
+void sph_sha256(void * cc, const void * data, size_t len)
|
|
+{
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ if (ctx != NULL && data != NULL)
|
|
+ gnutls_hash(*(ctx), data, len);
|
|
+}
|
|
diff --git a/libqpdf/sha2.c b/libqpdf/sha2.c
|
|
index 45fdd7e..e240f9b 100644
|
|
--- a/libqpdf/sha2.c
|
|
+++ b/libqpdf/sha2.c
|
|
@@ -35,6 +35,10 @@
|
|
|
|
#include "sph/sph_sha2.h"
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include "sha2-gnutls.c"
|
|
+#else
|
|
+
|
|
#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_SHA2
|
|
#define SPH_SMALL_FOOTPRINT_SHA2 1
|
|
#endif
|
|
@@ -688,3 +692,5 @@ sph_sha224_comp(const sph_u32 msg[16], sph_u32 val[8])
|
|
SHA2_ROUND_BODY(SHA2_IN, val);
|
|
#undef SHA2_IN
|
|
}
|
|
+
|
|
+#endif /* HAVE_GNUTLS */
|
|
diff --git a/libqpdf/sha2big-gnutls.c b/libqpdf/sha2big-gnutls.c
|
|
new file mode 100644
|
|
index 0000000..494e2b4
|
|
--- /dev/null
|
|
+++ b/libqpdf/sha2big-gnutls.c
|
|
@@ -0,0 +1,80 @@
|
|
+#include <gnutls/crypto.h>
|
|
+#include <stdio.h>
|
|
+#include "sph/sph_sha2_gnutls.h"
|
|
+
|
|
+
|
|
+/* see sph_sha3.h */
|
|
+void
|
|
+sph_sha384_init(void * cc)
|
|
+{
|
|
+ int ret;
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ ret = gnutls_hash_init(ctx, GNUTLS_DIG_SHA384);
|
|
+ if (ret < 0)
|
|
+ {
|
|
+ fprintf(stderr, "GNU TLS: SHA384 error: %s\n", gnutls_strerror(ret));
|
|
+ cc = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* see sph_sha3.h */
|
|
+void
|
|
+sph_sha384_close(void * cc, void *dst)
|
|
+{
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ if (ctx != NULL && dst != NULL)
|
|
+ {
|
|
+ gnutls_hash_deinit(*(ctx), dst);
|
|
+ cc = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* see sph_sha3.h */
|
|
+void
|
|
+sph_sha384(void * cc, const void * data, size_t len)
|
|
+{
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ if (ctx != NULL && data != NULL)
|
|
+ gnutls_hash(*(ctx), data, len);
|
|
+}
|
|
+
|
|
+/* see sph_sha3.h */
|
|
+void
|
|
+sph_sha512_init(void * cc)
|
|
+{
|
|
+ int ret;
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ ret = gnutls_hash_init(ctx, GNUTLS_DIG_SHA512);
|
|
+ if (ret < 0)
|
|
+ {
|
|
+ fprintf(stderr, "GNU TLS: SHA512 error: %s\n", gnutls_strerror(ret));
|
|
+ cc = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* see sph_sha3.h */
|
|
+void
|
|
+sph_sha512_close(void * cc, void * dst)
|
|
+{
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ if (ctx != NULL && dst != NULL)
|
|
+ {
|
|
+ gnutls_hash_deinit(*(ctx), dst);
|
|
+ cc = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* see sph_sha3.h */
|
|
+void
|
|
+sph_sha512(void * cc, const void * data, size_t len)
|
|
+{
|
|
+ gnutls_hash_hd_t * ctx = (gnutls_hash_hd_t*) cc;
|
|
+
|
|
+ if (ctx != NULL && data != NULL)
|
|
+ gnutls_hash(*(ctx), data, len);
|
|
+}
|
|
diff --git a/libqpdf/sha2big.c b/libqpdf/sha2big.c
|
|
index e4aadbd..3194a10 100644
|
|
--- a/libqpdf/sha2big.c
|
|
+++ b/libqpdf/sha2big.c
|
|
@@ -35,6 +35,10 @@
|
|
|
|
#include "sph/sph_sha2.h"
|
|
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include "sha2big-gnutls.c"
|
|
+#else
|
|
+
|
|
#if SPH_64
|
|
|
|
#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
|
|
@@ -245,3 +249,5 @@ sph_sha384_comp(const sph_u64 msg[16], sph_u64 val[8])
|
|
}
|
|
|
|
#endif
|
|
+
|
|
+#endif /* HAVE_GNUTLS */
|
|
diff --git a/libqpdf/sph/sph_sha2.h b/libqpdf/sph/sph_sha2.h
|
|
index 4bff9cd..584c6ab 100644
|
|
--- a/libqpdf/sph/sph_sha2.h
|
|
+++ b/libqpdf/sph/sph_sha2.h
|
|
@@ -47,6 +47,12 @@ extern "C" {
|
|
#include <stddef.h>
|
|
#include "sph_types.h"
|
|
|
|
+#include <qpdf/qpdf-config.h>
|
|
+
|
|
+#ifdef HAVE_GNUTLS
|
|
+# include "sph_sha2_gnutls.h"
|
|
+#else
|
|
+
|
|
/**
|
|
* Output size (in bits) for SHA-224.
|
|
*/
|
|
@@ -371,6 +377,8 @@ void sph_sha512_comp(const sph_u64 msg[16], sph_u64 val[8]);
|
|
|
|
#endif
|
|
|
|
+#endif /* HAVE_GNUTLS */
|
|
+
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
diff --git a/libqpdf/sph/sph_sha2_gnutls.h b/libqpdf/sph/sph_sha2_gnutls.h
|
|
new file mode 100644
|
|
index 0000000..1fb26a4
|
|
--- /dev/null
|
|
+++ b/libqpdf/sph/sph_sha2_gnutls.h
|
|
@@ -0,0 +1,88 @@
|
|
+#include <qpdf/qpdf-config.h>
|
|
+#include <gnutls/crypto.h>
|
|
+
|
|
+typedef gnutls_hash_hd_t sph_sha256_context;
|
|
+typedef gnutls_hash_hd_t sph_sha384_context;
|
|
+typedef gnutls_hash_hd_t sph_sha512_context;
|
|
+
|
|
+/**
|
|
+ * Initialize a SHA-256 context.
|
|
+ *
|
|
+ * @param cc the SHA-256 context (pointer to
|
|
+ * a <code>sph_sha256_context</code>)
|
|
+ */
|
|
+void sph_sha256_init(void *cc);
|
|
+
|
|
+/**
|
|
+ * Process some data bytes, for SHA-256.
|
|
+ *
|
|
+ * @param cc the SHA-224 context
|
|
+ * @param data the input data
|
|
+ * @param len the input data length (in bytes)
|
|
+ */
|
|
+void sph_sha256(void *cc, const void *data, size_t len);
|
|
+
|
|
+/**
|
|
+ * Terminate the current SHA-256 computation and output the result into the
|
|
+ * provided buffer. The destination buffer must be wide enough to
|
|
+ * accomodate the result (32 bytes).
|
|
+ *
|
|
+ * @param cc the SHA-256 context
|
|
+ * @param dst the destination buffer
|
|
+ */
|
|
+void sph_sha256_close(void *cc, void *dst);
|
|
+
|
|
+/**
|
|
+ * Initialize a SHA-384 context.
|
|
+ *
|
|
+ * @param cc the SHA-384 context (pointer to
|
|
+ * a <code>sph_sha384_context</code>)
|
|
+ */
|
|
+void sph_sha384_init(void *cc);
|
|
+
|
|
+/**
|
|
+ * Process some data bytes. It is acceptable that <code>len</code> is zero
|
|
+ * (in which case this function does nothing).
|
|
+ *
|
|
+ * @param cc the SHA-384 context
|
|
+ * @param data the input data
|
|
+ * @param len the input data length (in bytes)
|
|
+ */
|
|
+void sph_sha384(void *cc, const void *data, size_t len);
|
|
+
|
|
+/**
|
|
+ * Terminate the current SHA-384 computation and output the result into the
|
|
+ * provided buffer. The destination buffer must be wide enough to
|
|
+ * accomodate the result (48 bytes).
|
|
+ *
|
|
+ * @param cc the SHA-384 context
|
|
+ * @param dst the destination buffer
|
|
+ */
|
|
+void sph_sha384_close(void *cc, void *dst);
|
|
+
|
|
+/**
|
|
+ * Initialize a SHA-512 context.
|
|
+ *
|
|
+ * @param cc the SHA-512 context (pointer to
|
|
+ * a <code>sph_sha512_context</code>)
|
|
+ */
|
|
+void sph_sha512_init(void *cc);
|
|
+
|
|
+/**
|
|
+ * Process some data bytes, for SHA-512.
|
|
+ *
|
|
+ * @param cc the SHA-384 context
|
|
+ * @param data the input data
|
|
+ * @param len the input data length (in bytes)
|
|
+ */
|
|
+void sph_sha512(void *cc, const void *data, size_t len);
|
|
+
|
|
+/**
|
|
+ * Terminate the current SHA-512 computation and output the result into the
|
|
+ * provided buffer. The destination buffer must be wide enough to
|
|
+ * accomodate the result (64 bytes).
|
|
+ *
|
|
+ * @param cc the SHA-512 context
|
|
+ * @param dst the destination buffer
|
|
+ */
|
|
+void sph_sha512_close(void *cc, void *dst);
|
|
diff --git a/libqpdf/sph/sph_types.h b/libqpdf/sph/sph_types.h
|
|
index eab09a2..36d1ff6 100644
|
|
--- a/libqpdf/sph/sph_types.h
|
|
+++ b/libqpdf/sph/sph_types.h
|
|
@@ -48,6 +48,7 @@
|
|
#define SPH_TYPES_H__
|
|
|
|
#include <limits.h>
|
|
+#include <qpdf/qpdf-config.h>
|
|
|
|
/*
|
|
* All our I/O functions are defined over octet streams. We do not know
|