Blame SOURCES/qpdf-gnutls-crypto.patch

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