v2-0001-Introduce-cryptographic-functions-for-cluster-enc.patch
application/octet-stream
Filename: v2-0001-Introduce-cryptographic-functions-for-cluster-enc.patch
Type: application/octet-stream
Part: 3
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v2-0001
Subject: Introduce cryptographic functions for cluster encryption.
| File | + | − |
|---|---|---|
| configure | 14 | 1 |
| configure.in | 8 | 1 |
| src/backend/storage/encryption/enc_cipher.c | 129 | 0 |
| src/backend/storage/encryption/enc_openssl.c | 397 | 0 |
| src/backend/storage/encryption/Makefile | 21 | 0 |
| src/backend/storage/Makefile | 2 | 1 |
| src/include/pg_config.h.in | 6 | 0 |
| src/include/storage/enc_cipher.h | 33 | 0 |
| src/include/storage/enc_common.h | 34 | 0 |
| src/include/storage/enc_internal.h | 34 | 0 |
| src/include/storage/encryption.h | 39 | 0 |
From 1902246af4fefa6e9a6754b229c2f90d8026966f Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Thu, 15 Aug 2019 13:08:56 +0900
Subject: [PATCH v2 1/5] Introduce cryptographic functions for cluster
encryption.
---
configure | 15 +-
configure.in | 9 +-
src/backend/storage/Makefile | 3 +-
src/backend/storage/encryption/Makefile | 21 +
src/backend/storage/encryption/enc_cipher.c | 129 ++++++
src/backend/storage/encryption/enc_openssl.c | 397 +++++++++++++++++++
src/include/pg_config.h.in | 6 +
src/include/storage/enc_cipher.h | 33 ++
src/include/storage/enc_common.h | 34 ++
src/include/storage/enc_internal.h | 34 ++
src/include/storage/encryption.h | 39 ++
11 files changed, 717 insertions(+), 3 deletions(-)
create mode 100644 src/backend/storage/encryption/Makefile
create mode 100644 src/backend/storage/encryption/enc_cipher.c
create mode 100644 src/backend/storage/encryption/enc_openssl.c
create mode 100644 src/include/storage/enc_cipher.h
create mode 100644 src/include/storage/enc_common.h
create mode 100644 src/include/storage/enc_internal.h
create mode 100644 src/include/storage/encryption.h
diff --git a/configure b/configure
index 6b1c779ee3..b41fc519c7 100755
--- a/configure
+++ b/configure
@@ -12058,7 +12058,7 @@ done
# defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
# doesn't have these OpenSSL 1.1.0 functions. So check for individual
# functions.
- for ac_func in OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data
+ for ac_func in OPENSSL_init_ssl OPENSSL_init_crypto BIO_get_data BIO_meth_new ASN1_STRING_get0_data EVP_PKEY_derive
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -12772,6 +12772,19 @@ fi
done
+# check for <openssl/kdf.h>
+for ac_header in netinet/tcp.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "openssl/kdf.h" "ac_cv_header_openssl_kdf_h" "$ac_includes_default"
+if test "x$ac_cv_header_openssl_kdf_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_OPENSSL_KDF 1
+_ACEOF
+
+fi
+
+done
+
if expr x"$pgac_cv_check_readline" : 'x-lreadline' >/dev/null ; then
for ac_header in readline/readline.h
diff --git a/configure.in b/configure.in
index 2b9025cac3..3e0b3f937d 100644
--- a/configure.in
+++ b/configure.in
@@ -1190,7 +1190,7 @@ if test "$with_openssl" = yes ; then
# defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
# doesn't have these OpenSSL 1.1.0 functions. So check for individual
# functions.
- AC_CHECK_FUNCS([OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data])
+ AC_CHECK_FUNCS([OPENSSL_init_ssl OPENSSL_init_crypto BIO_get_data BIO_meth_new ASN1_STRING_get0_data])
# OpenSSL versions before 1.1.0 required setting callback functions, for
# thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
# function was removed.
@@ -1322,6 +1322,13 @@ AC_CHECK_HEADERS(netinet/tcp.h, [], [],
#include <netinet/in.h>
])
+if test "$with_openssl" = yes ; then
+ AC_CHECK_HEADERS(openssl/kdf.h, [], [],
+[AC_INCLUDES_DEFAULT
+#include <openssl/kdf.h>
+])
+fi
+
if expr x"$pgac_cv_check_readline" : 'x-lreadline' >/dev/null ; then
AC_CHECK_HEADERS(readline/readline.h, [],
[AC_CHECK_HEADERS(readline.h, [],
diff --git a/src/backend/storage/Makefile b/src/backend/storage/Makefile
index 8376cdfca2..2a6d2aba8c 100644
--- a/src/backend/storage/Makefile
+++ b/src/backend/storage/Makefile
@@ -8,6 +8,7 @@ subdir = src/backend/storage
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
-SUBDIRS = buffer file freespace ipc large_object lmgr page smgr sync
+SUBDIRS = buffer file freespace ipc large_object lmgr page smgr sync \
+ encryption
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/storage/encryption/Makefile b/src/backend/storage/encryption/Makefile
new file mode 100644
index 0000000000..50244c30e7
--- /dev/null
+++ b/src/backend/storage/encryption/Makefile
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for storage/encryption
+#
+# IDENTIFICATION
+# src/backend/storage/encryption/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/storage/encryption/
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+OBJS = kmgr.o bufenc.o walenc.o enc_cipher.o
+
+ifeq ($(with_openssl),yes)
+OBJS += enc_openssl.o
+endif
+
+include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/storage/encryption/enc_cipher.c b/src/backend/storage/encryption/enc_cipher.c
new file mode 100644
index 0000000000..046e531556
--- /dev/null
+++ b/src/backend/storage/encryption/enc_cipher.c
@@ -0,0 +1,129 @@
+/*-------------------------------------------------------------------------
+ *
+ * enc_openssl.c
+ * This code handles encryption and decryption using OpenSSL
+ *
+ * Copyright (c) 2019, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/storage/encryption/enc_openssl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "storage/enc_cipher.h"
+#include "storage/enc_common.h"
+#include "storage/enc_internal.h"
+
+/* GUC parameter */
+int data_encryption_cipher;
+int EncryptionKeySize;
+
+/* Data encryption */
+void
+pg_encrypt(const char *input, char *output, int size,
+ const char *key, const char *iv)
+{
+#ifdef USE_OPENSSL
+ ossl_encrypt_data(input, output, size, key, iv);
+#endif
+}
+
+/* Data decryption */
+void
+pg_decrypt(const char *input, char *output, int size,
+ const char *key, const char *iv)
+{
+#ifdef USE_OPENSSL
+ ossl_decrypt_data(input, output, size, key, iv);
+#endif
+}
+
+/* Key derivation */
+void
+pg_derive_key(const unsigned char *base_key, int base_size, unsigned char *info,
+ unsigned char *derived_key, Size derived_size)
+{
+#ifdef USE_OPENSSL
+ ossl_derive_key(base_key, base_size, info, derived_key, derived_size);
+#endif
+}
+
+/* HMAC computation */
+void
+pg_compute_hmac(const unsigned char *hmac_key, int key_size, unsigned char *data,
+ int data_size, unsigned char *hmac)
+{
+#ifdef USE_OPENSSL
+ ossl_compute_hmac(hmac_key, key_size, data, data_size, hmac);
+#endif
+}
+
+/* Key wrap */
+void
+pg_wrap_key(const unsigned char *key, int key_size, unsigned char *in,
+ int in_size, unsigned char *out, int *out_size)
+{
+#ifdef USE_OPENSSL
+ ossl_wrap_key(key, key_size, in, in_size, out, out_size);
+#endif
+}
+
+/* Key unwrap */
+void
+pg_unwrap_key(const unsigned char *key, int key_size, unsigned char *in,
+ int in_size, unsigned char *out, int *out_size)
+{
+#ifdef USE_OPENSSL
+ ossl_unwrap_key(key, key_size, in, in_size, out, out_size);
+#endif
+}
+
+/* Convert cipher name string to integer value */
+int
+EncryptionCipherValue(const char *name)
+{
+ if (strcmp(name, "aes-128") == 0)
+ return TDE_ENCRYPTION_AES_128;
+ else if (strcmp(name, "aes-256") == 0)
+ return TDE_ENCRYPTION_AES_256;
+ else
+ return TDE_ENCRYPTION_OFF;
+}
+
+/* Convert integer value to cipher name string */
+char *
+EncryptionCipherString(int value)
+{
+ switch (value)
+ {
+ case TDE_ENCRYPTION_OFF :
+ return "off";
+ case TDE_ENCRYPTION_AES_128:
+ return "aes-128";
+ case TDE_ENCRYPTION_AES_256:
+ return "aes-256";
+ }
+
+ return "unknown";
+}
+
+void
+assign_data_encryption_cipher(int new_encryption_cipher, void *extra)
+{
+ switch (new_encryption_cipher)
+ {
+ case TDE_ENCRYPTION_OFF:
+ EncryptionKeySize = 0;
+ break;
+ case TDE_ENCRYPTION_AES_128:
+ EncryptionKeySize = 16;
+ break;
+ case TDE_ENCRYPTION_AES_256:
+ EncryptionKeySize = 32;
+ break;
+ }
+}
diff --git a/src/backend/storage/encryption/enc_openssl.c b/src/backend/storage/encryption/enc_openssl.c
new file mode 100644
index 0000000000..95f165f695
--- /dev/null
+++ b/src/backend/storage/encryption/enc_openssl.c
@@ -0,0 +1,397 @@
+/*-------------------------------------------------------------------------
+ *
+ * enc_openssl.c
+ * This code handles encryption and decryption using OpenSSL
+ *
+ * Copyright (c) 2019, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/storage/encryption/enc_openssl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <unistd.h>
+
+#include "storage/enc_internal.h"
+#include "storage/enc_common.h"
+#include "utils/memutils.h"
+
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/hmac.h>
+#ifdef HAVE_OPENSSL_KDF
+#include <openssl/kdf.h>
+#endif
+
+/*
+ * prototype for the EVP functions that return an algorithm, e.g.
+ * EVP_aes_128_cbc().
+ */
+typedef const EVP_CIPHER *(*ossl_EVP_cipher_func) (void);
+
+/*
+ * Supported cipher function and its key size. The index of each cipher
+ * is (data_encryption_cipher - 1).
+ */
+ossl_EVP_cipher_func cipher_func_table[] =
+{
+ EVP_aes_128_ctr, /* TDE_ENCRYPTION_AES_128 */
+ EVP_aes_256_ctr /* TDE_ENCRYPTION_AES_256 */
+};
+
+typedef struct CipherCtx
+{
+ /* Encryption context */
+ EVP_CIPHER_CTX *enc_ctx;
+
+ /* Decryption context */
+ EVP_CIPHER_CTX *dec_ctx;
+
+ /* Key wrap context */
+ EVP_CIPHER_CTX *wrap_ctx;
+
+ /* Key unwrap context */
+ EVP_CIPHER_CTX *unwrap_ctx;
+
+ /* Key derivation context */
+ EVP_PKEY_CTX *derive_ctx;
+} CipherCtx;
+
+CipherCtx *MyCipherCtx = NULL;
+MemoryContext EncMemoryCtx;
+
+static void createCipherContext(void);
+static EVP_CIPHER_CTX *create_ossl_encryption_ctx(ossl_EVP_cipher_func func,
+ int klen, bool isenc,
+ bool iswrap);
+static EVP_PKEY_CTX *create_ossl_derive_ctx(void);
+static void setup_encryption_ossl(void);
+static void setup_encryption(void) ;
+
+static void
+createCipherContext(void)
+{
+ ossl_EVP_cipher_func cipherfunc = cipher_func_table[data_encryption_cipher - 1];
+ MemoryContext old_ctx;
+ CipherCtx *cctx;
+
+ if (MyCipherCtx != NULL)
+ return;
+
+ if (EncMemoryCtx == NULL)
+ EncMemoryCtx = AllocSetContextCreate(TopMemoryContext,
+ "db encryption context",
+ ALLOCSET_DEFAULT_SIZES);
+
+ old_ctx = MemoryContextSwitchTo(EncMemoryCtx);
+
+ cctx = (CipherCtx *) palloc(sizeof(CipherCtx));
+
+ /* Create encryption/decryption contexts */
+ cctx->enc_ctx = create_ossl_encryption_ctx(cipherfunc,
+ EncryptionKeySize,
+ true, false);
+ cctx->dec_ctx = create_ossl_encryption_ctx(cipherfunc,
+ EncryptionKeySize,
+ false, false);
+
+ /* Create key wrap/unwrap contexts */
+ cctx->wrap_ctx = create_ossl_encryption_ctx(EVP_aes_256_wrap,
+ 32, true, true);
+ cctx->unwrap_ctx = create_ossl_encryption_ctx(EVP_aes_256_wrap,
+ 32, false, true);
+
+ /* Create key derivation context */
+ cctx->derive_ctx = create_ossl_derive_ctx();
+
+ /* Set my cipher context and key size */
+ MyCipherCtx = cctx;
+
+ MemoryContextSwitchTo(old_ctx);
+}
+
+/* Create openssl's key derivation context */
+static EVP_PKEY_CTX *
+create_ossl_derive_ctx(void)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+
+#ifdef HAVE_OPENSSL_KDF
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+
+ if (EVP_PKEY_derive_init(pctx) <= 0)
+ ereport(ERROR,
+ (errmsg("openssl encountered error during initializing derive context"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0)
+ ereport(ERROR,
+ (errmsg("openssl encountered error during setting HKDF context"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+#endif
+
+ return pctx;
+}
+
+/* Create openssl's encryption context */
+static EVP_CIPHER_CTX *
+create_ossl_encryption_ctx(ossl_EVP_cipher_func func, int klen, bool isenc,
+ bool iswrap)
+{
+ EVP_CIPHER_CTX *ctx;
+ int ret;
+
+ /* Create new openssl cipher context */
+ ctx = EVP_CIPHER_CTX_new();
+
+ /* Enable key wrap algorithm */
+ if (iswrap)
+ EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
+
+ if (ctx == NULL)
+ ereport(ERROR,
+ (errmsg("openssl encountered error during creating context"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (isenc)
+ ret = EVP_EncryptInit_ex(ctx, (const EVP_CIPHER *) func(), NULL,
+ NULL, NULL);
+ else
+ ret = EVP_DecryptInit_ex(ctx, (const EVP_CIPHER *) func(), NULL,
+ NULL, NULL);
+
+ if (ret != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered error during initializing context"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (!EVP_CIPHER_CTX_set_key_length(ctx, klen))
+ ereport(ERROR,
+ (errmsg("openssl encountered error during setting key length"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ return ctx;
+}
+
+/*
+ * Initialize encryption subsystem for use. Must be called before any
+ * encryptable data is read from or written to data directory.
+ */
+static void
+setup_encryption(void)
+{
+ setup_encryption_ossl();
+ createCipherContext();
+}
+
+static void
+setup_encryption_ossl(void)
+{
+#ifndef HAVE_OPENSSL_KDF
+ /*
+ * We can initialize openssl even with openssl is 1.0.0 or older, but
+ * since AES key wrap algorithms have introduced in openssl 1.1.0
+ * we require 1.1.0 or higher version for cluster encryption.
+ */
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ (errmsg("openssl 1.1.0 or higher is required for cluster encryption"))));
+#endif
+
+#ifdef HAVE_OPENSSL_INIT_CRYPTO
+ /* Setup OpenSSL */
+ OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+#endif
+}
+
+void
+ossl_encrypt_data(const char *input, char *output, int size,
+ const char *key, const char *iv)
+{
+ int out_size;
+ EVP_CIPHER_CTX *ctx;
+
+ /* Ensure encryption has setup */
+ if (MyCipherCtx == NULL)
+ setup_encryption();
+
+ ctx = MyCipherCtx->enc_ctx;
+
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, (unsigned char *) key,
+ (unsigned char *) iv) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered initialization error during encryption"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (EVP_EncryptUpdate(ctx, (unsigned char *) output,
+ &out_size, (unsigned char *) input, size) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered error during encryption"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ Assert(out_size == size);
+}
+
+void
+ossl_decrypt_data(const char *input, char *output, int size,
+ const char *key, const char *iv)
+{
+ int out_size;
+ EVP_CIPHER_CTX *ctx;
+
+ /* Ensure encryption has setup */
+ if (MyCipherCtx == NULL)
+ setup_encryption();
+
+ ctx = MyCipherCtx->dec_ctx;
+
+ if (EVP_DecryptInit_ex(ctx, NULL, NULL, (unsigned char *) key,
+ (unsigned char *) iv) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered initialization error during decryption"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (EVP_DecryptUpdate(ctx, (unsigned char *) output,
+ &out_size, (unsigned char *) input, size) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered error during decryption"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ Assert(out_size == size);
+}
+
+void
+ossl_derive_key(const unsigned char *base_key, int base_size, unsigned char *info,
+ unsigned char *derived_key, Size derived_size)
+{
+#ifdef HAVE_OPENSSL_KDF
+ EVP_PKEY_CTX *pctx;
+
+ pctx = MyCipherCtx->derive_ctx;
+
+ if (EVP_PKEY_CTX_set1_hkdf_key(pctx, base_key, base_size) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered setting key error during key derivation"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ /*
+ * we don't need to set salt since the input key is already present
+ * as cryptographically strong.
+ */
+
+ if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *) info,
+ strlen((char *) info)) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered setting info error during key derivation"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ /*
+ * The 'derivedkey_size' should contain the length of the 'derivedkey'
+ * buffer, if the call got successful the derived key is written to
+ * 'derivedkey' and the amount of data written to 'derivedkey_size'
+ */
+ if (EVP_PKEY_derive(pctx, derived_key, &derived_size) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered error during key derivation"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+#endif
+}
+
+void
+ossl_compute_hmac(const unsigned char *hmac_key, int key_size,
+ unsigned char *data, int data_size, unsigned char *hmac)
+{
+ unsigned char *h;
+ uint32 hmac_size;
+
+ Assert(hmac != NULL);
+
+ h = HMAC(EVP_sha256(), hmac_key, key_size, data, data_size, hmac, &hmac_size);
+
+ if (h == NULL)
+ ereport(ERROR,
+ (errmsg("could not compute HMAC"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ memcpy(hmac, h, hmac_size);
+}
+
+void
+ossl_wrap_key(const unsigned char *key, int key_size, unsigned char *in,
+ int in_size, unsigned char *out, int *out_size)
+{
+ EVP_CIPHER_CTX *ctx;
+
+ /* Ensure encryption has setup */
+ if (MyCipherCtx == NULL)
+ setup_encryption();
+
+ ctx = MyCipherCtx->wrap_ctx;
+
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered initialization error during unwrapping key"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (!EVP_CIPHER_CTX_set_key_length(ctx, key_size))
+ ereport(ERROR,
+ (errmsg("openssl encountered setting key length error during wrapping key"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (!EVP_EncryptUpdate(ctx, out, out_size, in, in_size))
+ ereport(ERROR,
+ (errmsg("openssl encountered error during wrapping key"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+}
+
+void
+ossl_unwrap_key(const unsigned char *key, int key_size, unsigned char *in,
+ int in_size, unsigned char *out, int *out_size)
+{
+ EVP_CIPHER_CTX *ctx;
+
+ /* Ensure encryption has setup */
+ if (MyCipherCtx == NULL)
+ setup_encryption();
+
+ ctx = MyCipherCtx->unwrap_ctx;
+
+ if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, NULL) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered initialization error during unwrapping key"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (!EVP_CIPHER_CTX_set_key_length(ctx, key_size))
+ ereport(ERROR,
+ (errmsg("openssl encountered setting key length error during unwrapping key"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+
+ if (EVP_DecryptUpdate(ctx, out, out_size, in, in_size) != 1)
+ ereport(ERROR,
+ (errmsg("openssl encountered error during unwrapping key"),
+ (errdetail("openssl error string: %s",
+ ERR_error_string(ERR_get_error(), NULL)))));
+}
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 939245db39..f2e248d9ca 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -419,6 +419,12 @@
/* Define to 1 if you have the `OPENSSL_init_ssl' function. */
#undef HAVE_OPENSSL_INIT_SSL
+/* Define to 1 if you have the `OPENSSL_init_crypto' function. */
+#undef HAVE_OPENSSL_INIT_CRYPTO
+
+/* Define to 1 if you have the <openssl/kdf.h> header file. */
+#undef HAVE_OPENSSL_KDF
+
/* Define to 1 if you have the <ossp/uuid.h> header file. */
#undef HAVE_OSSP_UUID_H
diff --git a/src/include/storage/enc_cipher.h b/src/include/storage/enc_cipher.h
new file mode 100644
index 0000000000..b78862fb57
--- /dev/null
+++ b/src/include/storage/enc_cipher.h
@@ -0,0 +1,33 @@
+/*-------------------------------------------------------------------------
+ *
+ * enc_cipher.h
+ * This file contains definitions for structures and externs for
+ * functions used by data encryption.
+ *
+ * Portions Copyright (c) 2019, PostgreSQL Global Development Group
+ *
+ * src/include/storage/enc_cipher.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef ENC_CIPHER_H
+#define ENC_CIPHER_H
+
+extern void pg_encrypt(const char *input, char *output, int size,
+ const char *key, const char *iv);
+extern void pg_decrypt(const char *input, char *output, int size,
+ const char *key, const char *iv);
+extern void pg_derive_key(const unsigned char *base_key, int base_size,
+ unsigned char *info, unsigned char *derived_key,
+ Size derived_size);
+extern void pg_compute_hmac(const unsigned char *hmac_key, int key_size,
+ unsigned char *data, int data_size,
+ unsigned char *hmac);
+extern void pg_wrap_key(const unsigned char *key, int key_size,
+ unsigned char *in, int in_size, unsigned char *out,
+ int *out_size);
+extern void pg_unwrap_key(const unsigned char *key, int key_size,
+ unsigned char *in, int in_size, unsigned char *out,
+ int *out_size);
+
+#endif /* ENC_CIPHER_H */
diff --git a/src/include/storage/enc_common.h b/src/include/storage/enc_common.h
new file mode 100644
index 0000000000..09adc4d540
--- /dev/null
+++ b/src/include/storage/enc_common.h
@@ -0,0 +1,34 @@
+/*-------------------------------------------------------------------------
+ *
+ * enc_common.h
+ * This file contains common definitions for cluster encryption.
+ *
+ * Portions Copyright (c) 2019, PostgreSQL Global Development Group
+ *
+ * src/include/storage/enc_common.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef ENC_COMMON_H
+#define ENC_COMMON_H
+
+/* Value of data_encryption_cipher */
+enum
+{
+ TDE_ENCRYPTION_OFF = 0,
+ TDE_ENCRYPTION_AES_128,
+ TDE_ENCRYPTION_AES_256
+};
+
+/* GUC parameter */
+extern PGDLLIMPORT int data_encryption_cipher;
+
+/* Encryption keys (TDEK and WDEK) size */
+extern int EncryptionKeySize;
+
+extern char *EncryptionCipherString(int value);
+extern int EncryptionCipherValue(const char *name);
+extern void assign_data_encryption_cipher(int new_encryption_cipher,
+ void *extra);
+
+#endif /* ENC_COMMON_H */
diff --git a/src/include/storage/enc_internal.h b/src/include/storage/enc_internal.h
new file mode 100644
index 0000000000..bcc60fe2b1
--- /dev/null
+++ b/src/include/storage/enc_internal.h
@@ -0,0 +1,34 @@
+/*-------------------------------------------------------------------------
+ *
+ * enc_internal.h
+ * This file contains internal definitions of encryption cipher
+ * functions.
+ *
+ * Portions Copyright (c) 2019, PostgreSQL Global Development Group
+ *
+ * src/include/storage/enc_internal.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef ENC_INTERNAL_H
+#define ENC_INTERNAL_H
+
+/* enc_openssl.h */
+extern void ossl_encrypt_data(const char *input, char *output, int size,
+ const char *key, const char *iv);
+extern void ossl_decrypt_data(const char *input, char *output, int size,
+ const char *key, const char *iv);
+extern void ossl_derive_key(const unsigned char *base_key, int base_size,
+ unsigned char *info, unsigned char *derived_keyen,
+ Size derived_size);
+extern void ossl_compute_hmac(const unsigned char *hmac_key, int key_size,
+ unsigned char *data, int data_size,
+ unsigned char *hmac);
+extern void ossl_wrap_key(const unsigned char *kek, int key_size,
+ unsigned char *in, int in_size, unsigned char *out,
+ int *out_size);
+extern void ossl_unwrap_key(const unsigned char *key, int key_size,
+ unsigned char *in, int in_size, unsigned char *out,
+ int *out_size);
+
+#endif /* ENC_INTERNAL_H */
diff --git a/src/include/storage/encryption.h b/src/include/storage/encryption.h
new file mode 100644
index 0000000000..a7dcd9282f
--- /dev/null
+++ b/src/include/storage/encryption.h
@@ -0,0 +1,39 @@
+/*-------------------------------------------------------------------------
+ *
+ * encryption.h
+ * Cluster encryption functions.
+ *
+ * Portions Copyright (c) 2019, PostgreSQL Global Development Group
+ *
+ * src/include/storage/encryption.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef ENCRYPTION_H
+#define ENCRYPTION_H
+
+#include "access/xlogdefs.h"
+#include "storage/bufpage.h"
+#include "storage/enc_cipher.h"
+#include "storage/enc_common.h"
+
+#define DataEncryptionEnabled() \
+ (data_encryption_cipher > TDE_ENCRYPTION_OFF)
+
+/*
+ * The encrypted data is a series of blocks of size ENCRYPTION_BLOCK.
+ * Initialization vector(IV) is the same size of cipher block.
+ */
+#define ENC_BLOCK_SIZE 16
+#define ENC_IV_SIZE (ENC_BLOCK_SIZE)
+
+/*
+ * Maximum encryption key size is used by AES-256.
+ */
+#define ENC_MAX_ENCRYPTION_KEY_SIZE 32
+
+/* bufenc.c */
+extern void DecryptBufferBlock(BlockNumber blocknum, Page page);
+extern void EncryptBufferBlock(BlockNumber blocknum, Page page);
+
+#endif /* ENCRYPTION_H */
--
2.23.0