From 7625d3dd03e3254dbe70ac72d8ec441696a5a9ad 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 1/5] Introduce cryptographic functions for cluster encryption.

---
 configure                                    |  15 +-
 src/backend/storage/Makefile                 |   3 +-
 src/backend/storage/encryption/Makefile      |  21 ++
 src/backend/storage/encryption/enc_cipher.c  | 125 ++++++++
 src/backend/storage/encryption/enc_openssl.c | 420 +++++++++++++++++++++++++++
 src/include/pg_config.h.in                   |   6 +
 src/include/storage/enc_cipher.h             |  37 +++
 src/include/storage/enc_common.h             |  32 ++
 src/include/storage/enc_internal.h           |  38 +++
 src/include/storage/encryption.h             |  49 ++++
 10 files changed, 744 insertions(+), 2 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 2c98e80..4ac4c1b 100755
--- a/configure
+++ b/configure
@@ -12113,7 +12113,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"
@@ -12827,6 +12827,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/src/backend/storage/Makefile b/src/backend/storage/Makefile
index 8376cdf..2a6d2ab 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 0000000..50244c3
--- /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 0000000..7f63c22
--- /dev/null
+++ b/src/backend/storage/encryption/enc_cipher.c
@@ -0,0 +1,125 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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
+}
+
+/* Password based key derivation */
+void
+pg_derive_key_passphrase(const char *passphrase, int pass_size,
+						 unsigned char *salt, int salt_size,
+						 int iter_cnt, int derived_size,
+						 unsigned char *derived_key)
+{
+#ifdef USE_OPENSSL
+	ossl_derive_key_passphrase(passphrase, pass_size, salt, salt_size,
+							   iter_cnt, derived_size, derived_key);
+#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
+}
+
+/* Compute HMAC */
+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";
+}
diff --git a/src/backend/storage/encryption/enc_openssl.c b/src/backend/storage/encryption/enc_openssl.c
new file mode 100644
index 0000000..11cdcfd
--- /dev/null
+++ b/src/backend/storage/encryption/enc_openssl.c
@@ -0,0 +1,420 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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);
+typedef struct
+{
+	ossl_EVP_cipher_func cipher_func;
+	int					key_len;
+} cipher_info;
+
+/*
+ * Supported cipher function and its key size. The index of each cipher
+ * is (data_encryption_cipher - 1).
+ */
+cipher_info cipher_info_table[] =
+{
+	{EVP_aes_128_ctr, 16},	/* TDE_ENCRYPTION_AES_128 */
+	{EVP_aes_256_ctr, 32}	/* 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)
+{
+	cipher_info *cipher = &cipher_info_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(cipher->cipher_func,
+											   cipher->key_len, true, false);
+	cctx->dec_ctx = create_ossl_encryption_ctx(cipher->cipher_func,
+											   cipher->key_len, 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;
+	EncryptionKeySize = cipher->key_len;
+
+	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_passphrase(const char *passphrase, int pass_size,
+						   unsigned char *salt, int salt_size,
+						   int iter_cnt, int derived_size,
+						   unsigned char *derived_key)
+{
+	int rc;
+
+	/* Derive KEK from passphrase */
+	rc = PKCS5_PBKDF2_HMAC(passphrase, pass_size, salt, salt_size, iter_cnt,
+						   EVP_sha256(), derived_size, derived_key);
+
+	if (rc != 1)
+		ereport(ERROR,
+				(errmsg("could not derive key from passphrase"),
+				 (errdetail("openssl error string: %s",
+							ERR_error_string(ERR_get_error(), NULL)))));
+}
+
+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 unwrapping 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 512213a..ac5334b 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -416,6 +416,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 0000000..3915047
--- /dev/null
+++ b/src/include/storage/enc_cipher.h
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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_passphrase(const char *passphrase, int pass_size,
+									 unsigned char *salt, int salt_size,
+									 int iter_cnt, int derived_size,
+									 unsigned char *derived_key);
+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 0000000..bea5427
--- /dev/null
+++ b/src/include/storage/enc_common.h
@@ -0,0 +1,32 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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 database_encryption_cipher_kind
+{
+	TDE_ENCRYPTION_OFF = 0,
+	TDE_ENCRYPTION_AES_128,
+	TDE_ENCRYPTION_AES_256
+};
+
+/* GUC parameter */
+extern int data_encryption_cipher;
+
+/* Encrypton keys (TDEK and WDEK) size */
+extern int EncryptionKeySize;
+
+extern char *EncryptionCipherString(int value);
+extern int EncryptionCipherValue(const char *name);
+
+#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 0000000..7726fd6
--- /dev/null
+++ b/src/include/storage/enc_internal.h
@@ -0,0 +1,38 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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_passphrase(const char *passphrase, int pass_size,
+									   unsigned char *salt, int salt_size,
+									   int iter_cnt, int derived_size,
+									   unsigned char *derived_key);
+extern void ossl_derive_key(const unsigned char *base_key, int base_size,
+							unsigned char *info, unsigned char *derived_key,
+							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 0000000..eaf17ab
--- /dev/null
+++ b/src/include/storage/encryption.h
@@ -0,0 +1,49 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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 > 0)
+
+/* Cluster encryption doesn't encrypt VM and FSM */
+#define EncryptForkNum(forknum) \
+	((forknum) == MAIN_FORKNUM || (forknum) == INIT_FORKNUM)
+
+/*
+ * 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
+
+/*
+ * The size for counter of AES-CTR mode in nonce.
+ */
+#define ENC_WAL_AES_COUNTER_SIZE 32
+#define ENC_BUFFER_AES_COUNTER_SIZE 32
+
+/* bufenc.c */
+extern void DecryptBufferBlock(BlockNumber blocknum, Page page);
+extern void EncryptBufferBlock(BlockNumber blocknum, Page page);
+
+#endif							/* ENCRYPTION_H */
-- 
2.10.5

