summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2019-11-05 20:32:28 +0100
committerJay Berkenbilt <ejb@ql.org>2019-11-09 15:53:38 +0100
commit88bedb41fe82df312d62e364a5a216b62fc8807c (patch)
tree5ca03a77196d780f4b2d39d93ab1b03e9dd1eeee
parentcc14523440c99ff970e9a002f600133deab4b5dd (diff)
downloadqpdf-88bedb41fe82df312d62e364a5a216b62fc8807c.tar.zst
Implement gnutls crypto provider (fixes #218)
Thanks to Zdenek Dohnal <zdohnal@redhat.com> for contributing the code used for the gnutls crypto provider.
-rw-r--r--autoconf.mk.in1
-rw-r--r--autofiles.sums4
-rwxr-xr-xconfigure135
-rw-r--r--configure.ac48
-rw-r--r--libqpdf/QPDFCryptoProvider.cc6
-rw-r--r--libqpdf/QPDFCrypto_gnutls.cc277
-rw-r--r--libqpdf/build.mk7
-rw-r--r--libqpdf/qpdf/QPDFCrypto_gnutls.hh53
-rw-r--r--libqpdf/qpdf/qpdf-config.h.in3
9 files changed, 531 insertions, 3 deletions
diff --git a/autoconf.mk.in b/autoconf.mk.in
index 85a97aa8..41f51b44 100644
--- a/autoconf.mk.in
+++ b/autoconf.mk.in
@@ -31,6 +31,7 @@ OBJDUMP=@OBJDUMP@
GENDEPS=@GENDEPS@
LIBTOOL=@LIBTOOL@
USE_CRYPTO_NATIVE=@USE_CRYPTO_NATIVE@
+USE_CRYPTO_GNUTLS=@USE_CRYPTO_GNUTLS@
DOCBOOKX_DTD=@DOCBOOKX_DTD@
FOP=@FOP@
XSLTPROC=@XSLTPROC@
diff --git a/autofiles.sums b/autofiles.sums
index 74ee4f26..9b3c766a 100644
--- a/autofiles.sums
+++ b/autofiles.sums
@@ -1,6 +1,6 @@
-2b5c5a808c353b8df9e28e8cfb1e7d37114a2cad37eaede5bfe4354acae804d0 configure.ac
+97f3ed3cd8b491f0ceeb57baa40f4ed9c4be188692da1d13c93ef318c45cc4ae configure.ac
d3f9ee6f6f0846888d9a10fd3dad2e4b1258be84205426cf04d7cef02d61dad7 aclocal.m4
-7fc840fce5d372e92aa676e0040213a0f239cc8c01b6d6ef53c82043ceda571a libqpdf/qpdf/qpdf-config.h.in
+2e4cd495837be1b8454a4d8aef541b000988634be89d9c05a9cf5de67dffef5e libqpdf/qpdf/qpdf-config.h.in
5297971a0ef90bcd5563eb3f7127a032bb76d3ae2af7258bf13479caf8983a60 m4/ax_cxx_compile_stdcxx.m4
35bc5c645dc42d47f2daeea06f8f3e767c8a1aee6a35eb2b4854fd2ce66c3413 m4/ax_random_device.m4
37f8897d5f68d7d484e5457832a8f190ddb7507fa2a467cb7ee2be40a4364643 m4/libtool.m4
diff --git a/configure b/configure
index be0bc3a4..5ea9989c 100755
--- a/configure
+++ b/configure
@@ -643,6 +643,9 @@ DOCBOOK_XHTML
SHOW_FAILED_TEST_OUTPUT
QPDF_SKIP_TEST_COMPARE_IMAGES
DEFAULT_CRYPTO
+USE_CRYPTO_GNUTLS
+pc_gnutls_LIBS
+pc_gnutls_CFLAGS
USE_CRYPTO_NATIVE
CXXWFLAGS
WFLAGS
@@ -780,6 +783,7 @@ enable_werror
enable_int_warnings
enable_implicit_crypto
enable_crypto_native
+enable_crypto_gnutls
with_default_crypto
enable_test_compare_images
enable_show_failed_test_output
@@ -811,7 +815,9 @@ PKG_CONFIG_LIBDIR
pc_zlib_CFLAGS
pc_zlib_LIBS
pc_libjpeg_CFLAGS
-pc_libjpeg_LIBS'
+pc_libjpeg_LIBS
+pc_gnutls_CFLAGS
+pc_gnutls_LIBS'
# Initialize some variables set by options.
@@ -1466,6 +1472,8 @@ Optional Features:
are not explicitly requested; true by default
--enable-crypto-native whether to include support for native crypto
provider
+ --enable-crypto-gnutls whether to include support for gnutls crypto
+ provider
--enable-test-compare-images
whether to compare images in test suite; disabled by
default, enabling requires ghostscript and tiffcmp
@@ -1535,6 +1543,10 @@ Some influential environment variables:
C compiler flags for pc_libjpeg, overriding pkg-config
pc_libjpeg_LIBS
linker flags for pc_libjpeg, overriding pkg-config
+ pc_gnutls_CFLAGS
+ C compiler flags for pc_gnutls, overriding pkg-config
+ pc_gnutls_LIBS
+ linker flags for pc_gnutls, overriding pkg-config
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -17625,6 +17637,122 @@ $as_echo "#define USE_CRYPTO_NATIVE 1" >>confdefs.h
fi
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pc_gnutls" >&5
+$as_echo_n "checking for pc_gnutls... " >&6; }
+
+if test -n "$pc_gnutls_CFLAGS"; then
+ pkg_cv_pc_gnutls_CFLAGS="$pc_gnutls_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "gnutls") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_pc_gnutls_CFLAGS=`$PKG_CONFIG --cflags "gnutls" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$pc_gnutls_LIBS"; then
+ pkg_cv_pc_gnutls_LIBS="$pc_gnutls_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "gnutls") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_pc_gnutls_LIBS=`$PKG_CONFIG --libs "gnutls" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ pc_gnutls_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnutls" 2>&1`
+ else
+ pc_gnutls_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnutls" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$pc_gnutls_PKG_ERRORS" >&5
+
+ GNUTLS_FOUND=0
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ GNUTLS_FOUND=0
+else
+ pc_gnutls_CFLAGS=$pkg_cv_pc_gnutls_CFLAGS
+ pc_gnutls_LIBS=$pkg_cv_pc_gnutls_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ GNUTLS_FOUND=1
+fi
+
+IMPLICIT_GNUTLS=0
+USE_CRYPTO_GNUTLS=0
+
+# Check whether --enable-crypto-gnutls was given.
+if test "${enable_crypto_gnutls+set}" = set; then :
+ enableval=$enable_crypto_gnutls; if test "$enableval" = "yes"; then
+ USE_CRYPTO_GNUTLS=1
+ else
+ USE_CRYPTO_GNUTLS=0
+ fi
+else
+ IMPLICIT_GNUTLS=$IMPLICIT_CRYPTO
+fi
+
+
+if test "$IMPLICIT_GNUTLS" = "1"; then
+ USE_CRYPTO_GNUTLS=$GNUTLS_FOUND
+ if test "$USE_CRYPTO_GNUTLS" = "1"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: enabling gnutls crypto provider since gnutls is available" >&5
+$as_echo "$as_me: enabling gnutls crypto provider since gnutls is available" >&6;}
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not enabling gnutls crypto provider since gnutls was not found" >&5
+$as_echo "$as_me: not enabling gnutls crypto provider since gnutls was not found" >&6;}
+ fi
+fi
+
+if test "$USE_CRYPTO_GNUTLS" = "1" -a "$GNUTLS_FOUND" = "0"; then
+ as_fn_error $? "unable to use requested gnutls crypto provider without gnutls" "$LINENO" 5
+fi
+
+if test "$USE_CRYPTO_GNUTLS" = "1"; then
+ CFLAGS="$CFLAGS $pc_gnutls_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $pc_gnutls_CXXFLAGS"
+ LIBS="$LIBS $pc_gnutls_LIBS"
+
+$as_echo "#define USE_CRYPTO_GNUTLS 1" >>confdefs.h
+
+ DEFAULT_CRYPTO=gnutls
+elif test "$GNUTLS_FOUND" = "1"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not linking with gnutls even though it is available" >&5
+$as_echo "$as_me: not linking with gnutls even though it is available" >&6;}
+fi
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which crypto to use by default" >&5
$as_echo_n "checking which crypto to use by default... " >&6; }
@@ -17650,6 +17778,11 @@ case "$DEFAULT_CRYPTO" in
bad_crypto=1
fi
;;
+ "gnutls")
+ if test "$USE_CRYPTO_GNUTLS" != "1"; then
+ bad_crypto=1
+ fi
+ ;;
*)
bad_crypto=1
;;
diff --git a/configure.ac b/configure.ac
index d7223d06..1f6b151a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -506,6 +506,49 @@ if test "$USE_CRYPTO_NATIVE" = "1"; then
DEFAULT_CRYPTO=native
fi
+dnl If the gnutls provider is explicitly requested, require gnutls. If
+dnl the gnutls provider is not explicitly disabled, enable it if
+dnl gnutls is available. If the gnutls provider is explicitly
+dnl disabled, do not link with gnutls even if present.
+
+PKG_CHECK_MODULES([pc_gnutls], [gnutls], [GNUTLS_FOUND=1], [GNUTLS_FOUND=0])
+
+IMPLICIT_GNUTLS=0
+USE_CRYPTO_GNUTLS=0
+AC_SUBST(USE_CRYPTO_GNUTLS)
+AC_ARG_ENABLE(crypto-gnutls,
+ AS_HELP_STRING([--enable-crypto-gnutls],
+ [whether to include support for gnutls crypto provider]),
+ [if test "$enableval" = "yes"; then
+ USE_CRYPTO_GNUTLS=1
+ else
+ USE_CRYPTO_GNUTLS=0
+ fi],
+ [IMPLICIT_GNUTLS=$IMPLICIT_CRYPTO])
+
+if test "$IMPLICIT_GNUTLS" = "1"; then
+ USE_CRYPTO_GNUTLS=$GNUTLS_FOUND
+ if test "$USE_CRYPTO_GNUTLS" = "1"; then
+ AC_MSG_NOTICE(enabling gnutls crypto provider since gnutls is available)
+ else
+ AC_MSG_NOTICE(not enabling gnutls crypto provider since gnutls was not found)
+ fi
+fi
+
+if test "$USE_CRYPTO_GNUTLS" = "1" -a "$GNUTLS_FOUND" = "0"; then
+ AC_MSG_ERROR(unable to use requested gnutls crypto provider without gnutls)
+fi
+
+if test "$USE_CRYPTO_GNUTLS" = "1"; then
+ CFLAGS="$CFLAGS $pc_gnutls_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $pc_gnutls_CXXFLAGS"
+ LIBS="$LIBS $pc_gnutls_LIBS"
+ AC_DEFINE([USE_CRYPTO_GNUTLS], 1, [Whether to use the gnutls crypto provider])
+ DEFAULT_CRYPTO=gnutls
+elif test "$GNUTLS_FOUND" = "1"; then
+ AC_MSG_NOTICE(not linking with gnutls even though it is available)
+fi
+
dnl Allow the default crypto provider to be specified explicitly.
AC_MSG_CHECKING(which crypto to use by default)
@@ -527,6 +570,11 @@ case "$DEFAULT_CRYPTO" in
bad_crypto=1
fi
;;
+ "gnutls")
+ if test "$USE_CRYPTO_GNUTLS" != "1"; then
+ bad_crypto=1
+ fi
+ ;;
*)
bad_crypto=1
;;
diff --git a/libqpdf/QPDFCryptoProvider.cc b/libqpdf/QPDFCryptoProvider.cc
index 58712f54..133a16f7 100644
--- a/libqpdf/QPDFCryptoProvider.cc
+++ b/libqpdf/QPDFCryptoProvider.cc
@@ -5,6 +5,9 @@
#ifdef USE_CRYPTO_NATIVE
# include <qpdf/QPDFCrypto_native.hh>
#endif
+#ifdef USE_CRYPTO_GNUTLS
+# include <qpdf/QPDFCrypto_gnutls.hh>
+#endif
std::shared_ptr<QPDFCryptoImpl>
QPDFCryptoProvider::getImpl()
@@ -43,6 +46,9 @@ QPDFCryptoProvider::QPDFCryptoProvider() :
#ifdef USE_CRYPTO_NATIVE
registerImpl_internal<QPDFCrypto_native>("native");
#endif
+#ifdef USE_CRYPTO_GNUTLS
+ registerImpl_internal<QPDFCrypto_gnutls>("gnutls");
+#endif
setDefaultProvider_internal(DEFAULT_CRYPTO);
}
diff --git a/libqpdf/QPDFCrypto_gnutls.cc b/libqpdf/QPDFCrypto_gnutls.cc
new file mode 100644
index 00000000..d9383064
--- /dev/null
+++ b/libqpdf/QPDFCrypto_gnutls.cc
@@ -0,0 +1,277 @@
+#include <qpdf/QPDFCrypto_gnutls.hh>
+#include <qpdf/QIntC.hh>
+#include <qpdf/QUtil.hh>
+#include <cstring>
+
+QPDFCrypto_gnutls::QPDFCrypto_gnutls() :
+ hash_ctx(nullptr),
+ cipher_ctx(nullptr),
+ sha2_bits(0),
+ encrypt(false),
+ cbc_mode(false),
+ aes_key_data(nullptr),
+ aes_key_len(0)
+{
+ memset(digest, 0, sizeof(digest));
+}
+
+QPDFCrypto_gnutls::~QPDFCrypto_gnutls()
+{
+ if (this->hash_ctx)
+ {
+ gnutls_hash_deinit(this->hash_ctx, digest);
+ }
+ if (cipher_ctx)
+ {
+ gnutls_cipher_deinit(this->cipher_ctx);
+ }
+ this->aes_key_data = nullptr;
+ this->aes_key_len = 0;
+}
+
+void
+QPDFCrypto_gnutls::MD5_init()
+{
+ MD5_finalize();
+ int code = gnutls_hash_init(&this->hash_ctx, GNUTLS_DIG_MD5);
+ if (code < 0)
+ {
+ this->hash_ctx = nullptr;
+ throw std::runtime_error(
+ std::string("gnutls: MD5 error: ") +
+ std::string(gnutls_strerror(code)));
+ }
+}
+
+void
+QPDFCrypto_gnutls::MD5_update(unsigned char const* data, size_t len)
+{
+ gnutls_hash(this->hash_ctx, data, len);
+}
+
+void
+QPDFCrypto_gnutls::MD5_finalize()
+{
+ if (this->hash_ctx)
+ {
+ gnutls_hash_deinit(this->hash_ctx, this->digest);
+ this->hash_ctx = nullptr;
+ }
+}
+
+void
+QPDFCrypto_gnutls::MD5_digest(MD5_Digest d)
+{
+ memcpy(d, this->digest, sizeof(MD5_Digest));
+}
+
+void
+QPDFCrypto_gnutls::RC4_init(unsigned char const* key_data, int key_len)
+{
+ RC4_finalize();
+ if (key_len == -1)
+ {
+ key_len = QIntC::to_int(
+ strlen(reinterpret_cast<char const*>(key_data)));
+ }
+ gnutls_datum_t key;
+ key.data = const_cast<unsigned char*>(key_data);
+ key.size = QIntC::to_uint(key_len);
+
+ int code = gnutls_cipher_init(
+ &this->cipher_ctx, GNUTLS_CIPHER_ARCFOUR_128, &key, nullptr);
+ if (code < 0)
+ {
+ this->cipher_ctx = nullptr;
+ throw std::runtime_error(
+ std::string("gnutls: RC4 error: ") +
+ std::string(gnutls_strerror(code)));
+ }
+}
+
+void
+QPDFCrypto_gnutls::RC4_process(unsigned char* in_data, size_t len,
+ unsigned char* out_data)
+{
+ if (nullptr == out_data)
+ {
+ out_data = in_data;
+ }
+ gnutls_cipher_encrypt2(this->cipher_ctx, in_data, len, out_data, len);
+}
+
+void
+QPDFCrypto_gnutls::RC4_finalize()
+{
+ if (this->cipher_ctx)
+ {
+ gnutls_cipher_deinit(this->cipher_ctx);
+ this->cipher_ctx = nullptr;
+ }
+}
+
+void
+QPDFCrypto_gnutls::SHA2_init(int bits)
+{
+ SHA2_finalize();
+ gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN;
+ switch (bits)
+ {
+ case 256:
+ alg = GNUTLS_DIG_SHA256;
+ break;
+ case 384:
+ alg = GNUTLS_DIG_SHA384;
+ break;
+ case 512:
+ alg = GNUTLS_DIG_SHA512;
+ break;
+ default:
+ badBits();
+ break;
+ }
+ this->sha2_bits = bits;
+ int code = gnutls_hash_init(&this->hash_ctx, alg);
+ if (code < 0)
+ {
+ this->hash_ctx = nullptr;
+ throw std::runtime_error(
+ std::string("gnutls: SHA") + QUtil::int_to_string(bits) +
+ " error: " + std::string(gnutls_strerror(code)));
+ }
+}
+
+void
+QPDFCrypto_gnutls::SHA2_update(unsigned char const* data, size_t len)
+{
+ gnutls_hash(this->hash_ctx, data, len);
+}
+
+void
+QPDFCrypto_gnutls::SHA2_finalize()
+{
+ if (this->hash_ctx)
+ {
+ gnutls_hash_deinit(this->hash_ctx, this->digest);
+ this->hash_ctx = nullptr;
+ }
+}
+
+std::string
+QPDFCrypto_gnutls::SHA2_digest()
+{
+ std::string result;
+ switch (this->sha2_bits)
+ {
+ case 256:
+ result = std::string(reinterpret_cast<char*>(this->digest), 32);
+ break;
+ case 384:
+ result = std::string(reinterpret_cast<char*>(this->digest), 48);
+ break;
+ case 512:
+ result = std::string(reinterpret_cast<char*>(this->digest), 64);
+ break;
+ default:
+ badBits();
+ break;
+ }
+ return result;
+}
+
+void
+QPDFCrypto_gnutls::rijndael_init(
+ bool encrypt, unsigned char const* key_data, size_t key_len,
+ bool cbc_mode, unsigned char* cbc_block)
+{
+ rijndael_finalize();
+ this->encrypt = encrypt;
+ this->cbc_mode = cbc_mode;
+ if (! cbc_mode)
+ {
+ // Save the key so we can re-initialize.
+ this->aes_key_data = key_data;
+ this->aes_key_len = key_len;
+ }
+
+ gnutls_cipher_algorithm_t alg = GNUTLS_CIPHER_UNKNOWN;
+ gnutls_datum_t cipher_key;
+ gnutls_datum_t iv;
+
+ cipher_key.data = const_cast<unsigned char*>(key_data);
+
+ switch(key_len)
+ {
+ 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 = QIntC::to_uint(gnutls_cipher_get_key_size(alg));
+
+ iv.data = cbc_block;
+ iv.size = rijndael_buf_size;
+
+ int code = gnutls_cipher_init(&this->cipher_ctx, alg, &cipher_key, &iv);
+ if (code < 0)
+ {
+ this->cipher_ctx = nullptr;
+ throw std::runtime_error(
+ std::string("gnutls: AES error: ") +
+ std::string(gnutls_strerror(code)));
+ }
+}
+
+void
+QPDFCrypto_gnutls::rijndael_process(unsigned char* in_data,
+ unsigned char* out_data)
+{
+ if (this->encrypt)
+ {
+ gnutls_cipher_encrypt2(this->cipher_ctx,
+ in_data, rijndael_buf_size,
+ out_data, rijndael_buf_size);
+ }
+ else
+ {
+ gnutls_cipher_decrypt2(this->cipher_ctx,
+ in_data, rijndael_buf_size,
+ out_data, rijndael_buf_size);
+ }
+
+ // Gnutls doesn't support AES in ECB (non-CBC) mode, but the
+ // result is the same as if you just reset the cbc block to all
+ // zeroes each time. We jump through a few hoops here to make this
+ // work.
+ if (! this->cbc_mode)
+ {
+ static unsigned char zeroes[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ rijndael_init(this->encrypt, this->aes_key_data, this->aes_key_len,
+ false, zeroes);
+ }
+}
+
+void
+QPDFCrypto_gnutls::rijndael_finalize()
+{
+ if (this->cipher_ctx)
+ {
+ gnutls_cipher_deinit(this->cipher_ctx);
+ this->cipher_ctx = nullptr;
+ }
+}
+
+void
+QPDFCrypto_gnutls::badBits()
+{
+ throw std::logic_error("SHA2 (gnutls) has bits != 256, 384, or 512");
+}
diff --git a/libqpdf/build.mk b/libqpdf/build.mk
index 7e5f4aa3..ac904174 100644
--- a/libqpdf/build.mk
+++ b/libqpdf/build.mk
@@ -14,6 +14,9 @@ CRYPTO_NATIVE = \
libqpdf/sha2.c \
libqpdf/sha2big.c
+CRYPTO_GNUTLS = \
+ libqpdf/QPDFCrypto_gnutls.cc
+
SRCS_libqpdf = \
libqpdf/BitStream.cc \
libqpdf/BitWriter.cc \
@@ -94,6 +97,10 @@ ifeq ($(USE_CRYPTO_NATIVE), 1)
SRCS_libqpdf += $(CRYPTO_NATIVE)
endif
+ifeq ($(USE_CRYPTO_GNUTLS), 1)
+SRCS_libqpdf += $(CRYPTO_GNUTLS)
+endif
+
# -----
CCSRCS_libqpdf = $(filter %.cc,$(SRCS_libqpdf))
diff --git a/libqpdf/qpdf/QPDFCrypto_gnutls.hh b/libqpdf/qpdf/QPDFCrypto_gnutls.hh
new file mode 100644
index 00000000..e7e21182
--- /dev/null
+++ b/libqpdf/qpdf/QPDFCrypto_gnutls.hh
@@ -0,0 +1,53 @@
+#ifndef QPDFCRYPTO_GNUTLS_HH
+#define QPDFCRYPTO_GNUTLS_HH
+
+#include <qpdf/DLL.h>
+#include <qpdf/QPDFCryptoImpl.hh>
+#include <memory>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+class QPDFCrypto_gnutls: public QPDFCryptoImpl
+{
+ public:
+ QPDFCrypto_gnutls();
+
+ QPDF_DLL
+ virtual ~QPDFCrypto_gnutls();
+
+ virtual void MD5_init();
+ virtual void MD5_update(unsigned char const* data, size_t len);
+ virtual void MD5_finalize();
+ virtual void MD5_digest(MD5_Digest);
+
+ virtual void RC4_init(unsigned char const* key_data, int key_len = -1);
+ virtual void RC4_process(unsigned char* in_data, size_t len,
+ unsigned char* out_data = 0);
+ virtual void RC4_finalize();
+
+ virtual void SHA2_init(int bits);
+ virtual void SHA2_update(unsigned char const* data, size_t len);
+ virtual void SHA2_finalize();
+ virtual std::string SHA2_digest();
+
+ virtual void rijndael_init(
+ bool encrypt, unsigned char const* key_data, size_t key_len,
+ bool cbc_mode, unsigned char* cbc_block);
+ virtual void rijndael_process(
+ unsigned char* in_data, unsigned char* out_data);
+ virtual void rijndael_finalize();
+
+ private:
+ void badBits();
+
+ gnutls_hash_hd_t hash_ctx;
+ gnutls_cipher_hd_t cipher_ctx;
+ int sha2_bits;
+ bool encrypt;
+ bool cbc_mode;
+ char digest[64];
+ unsigned char const* aes_key_data;
+ size_t aes_key_len;
+};
+
+#endif // QPDFCRYPTO_GNUTLS_HH
diff --git a/libqpdf/qpdf/qpdf-config.h.in b/libqpdf/qpdf/qpdf-config.h.in
index 20441efd..75d34c66 100644
--- a/libqpdf/qpdf/qpdf-config.h.in
+++ b/libqpdf/qpdf/qpdf-config.h.in
@@ -84,6 +84,9 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
+/* Whether to use the gnutls crypto provider */
+#undef USE_CRYPTO_GNUTLS
+
/* Whether to use the native crypto provider */
#undef USE_CRYPTO_NATIVE