0003-Poc-buffer-encryption.patch
application/octet-stream
Filename: 0003-Poc-buffer-encryption.patch
Type: application/octet-stream
Part: 0
Message:
Re: Key management with tests
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 0003
Subject: Poc: buffer encryption.
| File | + | − |
|---|---|---|
| contrib/bloom/blinsert.c | 1 | 0 |
| src/backend/access/hash/hashpage.c | 1 | 0 |
| src/backend/access/heap/rewriteheap.c | 1 | 0 |
| src/backend/access/nbtree/nbtree.c | 1 | 0 |
| src/backend/access/nbtree/nbtsort.c | 1 | 0 |
| src/backend/access/spgist/spginsert.c | 3 | 0 |
| src/backend/access/transam/xloginsert.c | 13 | 0 |
| src/backend/bootstrap/bootstrap.c | 3 | 0 |
| src/backend/catalog/storage.c | 1 | 1 |
| src/backend/crypto/bufenc.c | 138 | 0 |
| src/backend/crypto/Makefile | 1 | 0 |
| src/backend/postmaster/postmaster.c | 2 | 0 |
| src/backend/storage/buffer/bufmgr.c | 23 | 2 |
| src/backend/storage/page/bufpage.c | 48 | 1 |
| src/backend/tcop/postgres.c | 2 | 0 |
| src/common/cipher_openssl.c | 26 | 0 |
| src/include/access/xloginsert.h | 1 | 0 |
| src/include/common/cipher.h | 2 | 1 |
| src/include/crypto/bufenc.h | 27 | 0 |
| src/include/crypto/kmgr.h | 2 | 0 |
| src/include/storage/bufpage.h | 9 | 2 |
From fba051add0f0ec73770db415bba5a1c486d41c27 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Mon, 11 Jan 2021 19:37:12 +0900
Subject: [PATCH 3/3] Poc: buffer encryption.
---
contrib/bloom/blinsert.c | 1 +
src/backend/access/hash/hashpage.c | 1 +
src/backend/access/heap/rewriteheap.c | 1 +
src/backend/access/nbtree/nbtree.c | 1 +
src/backend/access/nbtree/nbtsort.c | 1 +
src/backend/access/spgist/spginsert.c | 3 +
src/backend/access/transam/xloginsert.c | 13 +++
src/backend/bootstrap/bootstrap.c | 3 +
src/backend/catalog/storage.c | 2 +-
src/backend/crypto/Makefile | 1 +
src/backend/crypto/bufenc.c | 138 ++++++++++++++++++++++++
src/backend/postmaster/postmaster.c | 2 +
src/backend/storage/buffer/bufmgr.c | 25 ++++-
src/backend/storage/page/bufpage.c | 49 ++++++++-
src/backend/tcop/postgres.c | 2 +
src/common/cipher_openssl.c | 26 +++++
src/include/access/xloginsert.h | 1 +
src/include/common/cipher.h | 3 +-
src/include/crypto/bufenc.h | 27 +++++
src/include/crypto/kmgr.h | 2 +
src/include/storage/bufpage.h | 11 +-
21 files changed, 306 insertions(+), 7 deletions(-)
create mode 100644 src/backend/crypto/bufenc.c
create mode 100644 src/include/crypto/bufenc.h
diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c
index 32b5d62e1f..d474af753c 100644
--- a/contrib/bloom/blinsert.c
+++ b/contrib/bloom/blinsert.c
@@ -177,6 +177,7 @@ blbuildempty(Relation index)
* XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE record. Therefore, we need
* this even when wal_level=minimal.
*/
+ PageEncryptInplace(metapage, INIT_FORKNUM, BLOOM_METAPAGE_BLKNO);
PageSetChecksumInplace(metapage, BLOOM_METAPAGE_BLKNO);
smgrwrite(index->rd_smgr, INIT_FORKNUM, BLOOM_METAPAGE_BLKNO,
(char *) metapage, true);
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 49a9867787..7ee505c6ba 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -1025,6 +1025,7 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
true);
RelationOpenSmgr(rel);
+ PageEncryptInplace(page, MAIN_FORKNUM, lastblock);
PageSetChecksumInplace(page, lastblock);
smgrextend(rel->rd_smgr, MAIN_FORKNUM, lastblock, zerobuf.data, false);
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 29ffe40670..d752331706 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -325,6 +325,7 @@ end_heap_rewrite(RewriteState state)
true);
RelationOpenSmgr(state->rs_new_rel);
+ PageEncryptInplace(state->rs_buffer, MAIN_FORKNUM, state->rs_blockno);
PageSetChecksumInplace(state->rs_buffer, state->rs_blockno);
smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno,
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index ba79a7f3e9..b2969dd07e 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -175,6 +175,7 @@ btbuildempty(Relation index)
* XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE record. Therefore, we need
* this even when wal_level=minimal.
*/
+ PageEncryptInplace(metapage, INIT_FORKNUM, BTREE_METAPAGE);
PageSetChecksumInplace(metapage, BTREE_METAPAGE);
smgrwrite(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE,
(char *) metapage, true);
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index c904fc8ef7..04da2d865b 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -665,6 +665,7 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
true);
}
+ PageEncryptInplace(page, MAIN_FORKNUM, blkno);
PageSetChecksumInplace(page, blkno);
/*
diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c
index 2e1d8a33d1..84187583d2 100644
--- a/src/backend/access/spgist/spginsert.c
+++ b/src/backend/access/spgist/spginsert.c
@@ -168,6 +168,7 @@ spgbuildempty(Relation index)
* of their existing content when the corresponding create records are
* replayed.
*/
+ PageEncryptInplace(page, INIT_FORKNUM, SPGIST_METAPAGE_BLKNO);
PageSetChecksumInplace(page, SPGIST_METAPAGE_BLKNO);
smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_METAPAGE_BLKNO,
(char *) page, true);
@@ -177,6 +178,7 @@ spgbuildempty(Relation index)
/* Likewise for the root page. */
SpGistInitPage(page, SPGIST_LEAF);
+ PageEncryptInplace(page, INIT_FORKNUM, SPGIST_ROOT_BLKNO);
PageSetChecksumInplace(page, SPGIST_ROOT_BLKNO);
smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_ROOT_BLKNO,
(char *) page, true);
@@ -186,6 +188,7 @@ spgbuildempty(Relation index)
/* Likewise for the null-tuples root page. */
SpGistInitPage(page, SPGIST_LEAF | SPGIST_NULLS);
+ PageEncryptInplace(page, INIT_FORKNUM, SPGIST_NULL_BLKNO);
PageSetChecksumInplace(page, SPGIST_NULL_BLKNO);
smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_NULL_BLKNO,
(char *) page, true);
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 7052dc245e..d7738c8834 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -1190,6 +1190,19 @@ log_newpage_range(Relation rel, ForkNumber forkNum,
}
}
+/* Write a no-op dummy xlog */
+XLogRecPtr
+log_noop(void)
+{
+ bool dummy;
+
+ XLogBeginInsert();
+
+ /* register dummy data as the record have to contain data */
+ XLogRegisterData((char *) &dummy, sizeof(bool));
+ return XLogInsert(RM_XLOG_ID, XLOG_NOOP);
+}
+
/*
* Allocate working buffers needed for WAL record construction.
*/
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index e2231f1430..9eba3735a5 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -28,6 +28,7 @@
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/link-canary.h"
+#include "crypto/bufenc.h"
#include "crypto/kmgr.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
@@ -528,6 +529,8 @@ BootstrapModeMain(void)
InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL, false);
+ InitializeBufferEncryption();
+
/* Initialize stuff for bootstrap-file processing */
for (i = 0; i < MAXATTR; i++)
{
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index cba7a9ada0..c876c536a5 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -443,7 +443,7 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
smgrread(src, forkNum, blkno, buf.data);
- if (!PageIsVerifiedExtended(page, blkno,
+ if (!PageIsVerifiedExtended(page, forkNum, blkno,
PIV_LOG_WARNING | PIV_REPORT_STAT))
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
diff --git a/src/backend/crypto/Makefile b/src/backend/crypto/Makefile
index c27362029d..8985a66875 100644
--- a/src/backend/crypto/Makefile
+++ b/src/backend/crypto/Makefile
@@ -13,6 +13,7 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS = \
+ bufenc.o \
kmgr.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/crypto/bufenc.c b/src/backend/crypto/bufenc.c
new file mode 100644
index 0000000000..4401303fe9
--- /dev/null
+++ b/src/backend/crypto/bufenc.c
@@ -0,0 +1,138 @@
+/*-------------------------------------------------------------------------
+ *
+ * bufenc.c
+ *
+ * Copyright (c) 2020, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/crypto/bufenc.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "miscadmin.h"
+#include "lib/stringinfo.h"
+
+#include "storage/bufpage.h"
+#include "storage/fd.h"
+#include "crypto/kmgr.h"
+#include "crypto/bufenc.h"
+
+/*-------------------------------------------------------------------------
+ * We use both page LSN and page number to create a nonce for each page. Page
+ * LSN is 8 byte, page number is 4 byte, and the maximum required counter for
+ * AES-CTR is 2048, which fits in 3 byte. Since the length of IV is 16 byte
+ * it's fine. Using the LSN and page number as part of the nonce has
+ * three benefits:
+ *
+ * 1. We don't need to decrypt/re-encrypt during CREATE DATABASE since the page
+ * contents are the same in both places, and once one database changes its pages,
+ * it gets a new LSN, and hence a new nonce.
+ * 2. For each change of an 8k page, we get a new nonce, so we are not encrypting
+ * different data with the same nonce/IV.
+ * 3. We avoid requiring pg_upgrade to preserve database oids, tablespace oids,
+ * relfilenodes.
+ *
+ * Different two pages could have the same page LSN when heap update expires the
+ * old tuple and add the new tuple to the another page. By using the page number
+ * as a part of nonce we can get an unique nonce even in this case. We assume that
+ * we don't use the same LSN in different relations.
+ *-------------------------------------------------------------------------
+ */
+#define BUFENC_IV_SIZE 16
+
+static unsigned char buf_encryption_iv[BUFENC_IV_SIZE];
+
+PgCipherCtx *BufencCtx = NULL;
+PgCipherCtx *BufdecCtx = NULL;
+
+static void set_buffer_encryption_iv(Page page, BlockNumber blkno);
+
+void
+InitializeBufferEncryption(void)
+{
+ const CryptoKey *key;
+
+ if (!DataEncryptionEnabled())
+ return;
+
+ key = KmgrGetKey(KMGR_KEY_ID_REL);
+
+ BufencCtx = pg_cipher_ctx_create(PG_CIPHER_AES_CTR,
+ (unsigned char *) key->key,
+ (file_encryption_keylen / 8), true);
+ if (!BufencCtx)
+ elog(ERROR, "could not intialize encryption context");
+
+ BufdecCtx = pg_cipher_ctx_create(PG_CIPHER_AES_CTR,
+ (unsigned char *) key->key,
+ (file_encryption_keylen / 8), false);
+ if (!BufdecCtx)
+ elog(ERROR, "could not intialize decryption context");
+}
+
+/* Encrypt the given page with the relation key */
+void
+EncryptPage(Page page, BlockNumber blkno)
+{
+ unsigned char *ptr = (unsigned char *) page + PageEncryptOffset;
+ int enclen;
+
+ Assert(BufencCtx != NULL);
+
+ set_buffer_encryption_iv(page, blkno);
+ if (unlikely(!pg_cipher_encrypt(BufencCtx,
+ (const unsigned char *) ptr, /* input */
+ SizeOfPageEncryption,
+ ptr, /* length */
+ &enclen, /* resulting length */
+ buf_encryption_iv, /* iv */
+ BUFENC_IV_SIZE,
+ NULL, 0)))
+ elog(ERROR, "could not encrypt page %u", blkno);
+ Assert(enclen == SizeOfPageEncryption);
+}
+
+/* Decrypt the given page with the relation key */
+void
+DecryptPage(Page page, BlockNumber blkno)
+{
+ unsigned char *ptr = (unsigned char *) page + PageEncryptOffset;
+ int enclen;
+
+ Assert(BufdecCtx != NULL);
+
+ set_buffer_encryption_iv(page, blkno);
+ if (unlikely(!pg_cipher_decrypt(BufdecCtx,
+ (const unsigned char *) ptr, /* input */
+ SizeOfPageEncryption,
+ ptr, /* output */
+ &enclen, /* resulting length */
+ buf_encryption_iv, /* iv */
+ BUFENC_IV_SIZE,
+ NULL, 0)))
+ elog(ERROR, "could not decrypt page %u", blkno);
+ Assert(enclen == SizeOfPageEncryption);
+}
+
+/* Construct iv for the given page */
+static void
+set_buffer_encryption_iv(Page page, BlockNumber blkno)
+{
+ unsigned char *p = buf_encryption_iv;
+
+ MemSet(buf_encryption_iv, 0, BUFENC_IV_SIZE);
+
+ /* page lsn (8 byte) */
+ memcpy(p, &((PageHeader) page)->pd_lsn, sizeof(PageXLogRecPtr));
+ p += sizeof(PageXLogRecPtr);
+
+ /* block number (4 byte) */
+ memcpy(p, &blkno, sizeof(BlockNumber));
+ p += sizeof(BlockNumber);
+
+ /* remainig 4 bytes are the space for the counter, already set to 0 */
+}
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index e2f8e07c88..c0424f3f36 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -100,6 +100,7 @@
#include "common/file_perm.h"
#include "common/ip.h"
#include "common/string.h"
+#include "crypto/bufenc.h"
#include "crypto/kmgr.h"
#include "lib/ilist.h"
#include "libpq/auth.h"
@@ -1333,6 +1334,7 @@ PostmasterMain(int argc, char *argv[])
RemovePgTempFiles();
InitializeKmgr();
+ InitializeBufferEncryption();
if (terminal_fd != -1)
close(terminal_fd);
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 71b5852224..c86b6ea068 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -37,6 +37,7 @@
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/storage.h"
+#include "crypto/bufenc.h"
#include "executor/instrument.h"
#include "lib/binaryheap.h"
#include "miscadmin.h"
@@ -918,7 +919,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
}
/* check for garbage data */
- if (!PageIsVerifiedExtended((Page) bufBlock, blockNum,
+ if (!PageIsVerifiedExtended((Page) bufBlock, forkNum, blockNum,
PIV_LOG_WARNING | PIV_REPORT_STAT))
{
if (mode == RBM_ZERO_ON_ERROR || zero_damaged_pages)
@@ -2792,12 +2793,15 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln)
*/
bufBlock = BufHdrGetBlock(buf);
+ bufToWrite = PageEncryptCopy((Page) bufBlock, buf->tag.forkNum,
+ buf->tag.blockNum);
+
/*
* Update page checksum if desired. Since we have only shared lock on the
* buffer, other processes might be updating hint bits in it, so we must
* copy the page to private storage if we do checksumming.
*/
- bufToWrite = PageSetChecksumCopy((Page) bufBlock, buf->tag.blockNum);
+ bufToWrite = PageSetChecksumCopy((Page) bufToWrite, buf->tag.blockNum);
if (track_io_timing)
INSTR_TIME_SET_CURRENT(io_start);
@@ -3280,6 +3284,8 @@ FlushRelationBuffers(Relation rel)
errcallback.previous = error_context_stack;
error_context_stack = &errcallback;
+ PageEncryptInplace(localpage, bufHdr->tag.forkNum,
+ bufHdr->tag.blockNum);
PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
smgrwrite(rel->rd_smgr,
@@ -3677,6 +3683,21 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
{
dirtied = true; /* Means "will be dirtied by this action" */
+ /*
+ * We will dirty the page but the page lsn is not changed if we
+ * doesn't write a backup block. We don't want to encrypt the
+ * different bits stream with the same combination of nonce and key
+ * since in buffer encryption the page lsn is a part of nonce.
+ * Therefore we WAL-log no-op record just to move page lsn forward if
+ * we doesn't write a backup block, even when this is not the first
+ * modification in this checkpoint round.
+ */
+ if (XLogRecPtrIsInvalid(lsn) && DataEncryptionEnabled())
+ {
+ lsn = log_noop();
+ Assert(!XLogRecPtrIsInvalid(lsn));
+ }
+
/*
* Set the page LSN if we wrote a backup block. We aren't supposed
* to set this when only holding a share lock but as long as we
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index 9ac556b4ae..3a480e7b82 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -17,6 +17,7 @@
#include "access/htup_details.h"
#include "access/itup.h"
#include "access/xlog.h"
+#include "crypto/bufenc.h"
#include "pgstat.h"
#include "storage/checksum.h"
#include "utils/memdebug.h"
@@ -85,7 +86,8 @@ PageInit(Page page, Size pageSize, Size specialSize)
* to pgstat.
*/
bool
-PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags)
+PageIsVerifiedExtended(Page page, ForkNumber forknum, BlockNumber blkno,
+ int flags)
{
PageHeader p = (PageHeader) page;
size_t *pagebytes;
@@ -108,6 +110,9 @@ PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags)
checksum_failure = true;
}
+ if (DataEncryptionEnabled())
+ PageDecryptInplace(page, forknum, blkno);
+
/*
* The following checks don't prove the header is correct, only that
* it looks sane enough to allow into the buffer pool. Later usage of
@@ -1427,3 +1432,45 @@ PageSetChecksumInplace(Page page, BlockNumber blkno)
((PageHeader) page)->pd_checksum = pg_checksum_page((char *) page, blkno);
}
+
+char *
+PageEncryptCopy(Page page, ForkNumber forknum, BlockNumber blkno)
+{
+ static char *pageCopy = NULL;
+
+ /* If we don't need a checksum, just return the passed-in data */
+ if (PageIsNew(page) || !PageNeedsToBeEncrypted(forknum))
+ return (char *) page;
+
+ /*
+ * We allocate the copy space once and use it over on each subsequent
+ * call. The point of palloc'ing here, rather than having a static char
+ * array, is first to ensure adequate alignment for the checksumming code
+ * and second to avoid wasting space in processes that never call this.
+ */
+ if (pageCopy == NULL)
+ pageCopy = MemoryContextAlloc(TopMemoryContext, BLCKSZ);
+
+ memcpy(pageCopy, (char *) page, BLCKSZ);
+ EncryptPage(pageCopy, blkno);
+ return pageCopy;
+}
+
+void
+PageEncryptInplace(Page page, ForkNumber forknum, BlockNumber blkno)
+{
+ if (PageIsNew(page) || !PageNeedsToBeEncrypted(forknum))
+ return;
+
+ EncryptPage(page, blkno);
+}
+
+
+void
+PageDecryptInplace(Page page, ForkNumber forknum, BlockNumber blkno)
+{
+ if (PageIsNew(page) || PageNeedsToBeEncrypted(forknum))
+ return;
+
+ DecryptPage(page, blkno);
+}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 0463da6d46..36759c0190 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -43,6 +43,7 @@
#include "commands/async.h"
#include "commands/prepare.h"
#include "crypto/kmgr.h"
+#include "crypto/bufenc.h"
#include "executor/spi.h"
#include "jit/jit.h"
#include "libpq/libpq.h"
@@ -3978,6 +3979,7 @@ PostgresMain(int argc, char *argv[],
if (!IsUnderPostmaster)
{
InitializeKmgr();
+ InitializeBufferEncryption();
if (terminal_fd != -1)
close(terminal_fd);
diff --git a/src/common/cipher_openssl.c b/src/common/cipher_openssl.c
index 28f613cecc..9a6b4ddbc1 100644
--- a/src/common/cipher_openssl.c
+++ b/src/common/cipher_openssl.c
@@ -34,6 +34,7 @@ static ossl_EVP_cipher_func get_evp_aes_gcm(int klen);
static ossl_EVP_cipher_func get_evp_aes_kw(int klen);
static EVP_CIPHER_CTX *ossl_cipher_ctx_create(int cipher, unsigned char *key, int klen,
bool enc);
+static ossl_EVP_cipher_func get_evp_aes_ctr(int klen);
/*
* Return a newly created cipher context. 'cipher' specifies cipher algorithm
@@ -343,6 +344,26 @@ get_evp_aes_kwp(int klen)
}
}
+/*
+ * Returns the correct cipher functions for OpenSSL based
+ * on the key length requested.
+ */
+static ossl_EVP_cipher_func
+get_evp_aes_ctr(int klen)
+{
+ switch (klen)
+ {
+ case PG_AES128_KEY_LEN:
+ return EVP_aes_128_ctr;
+ case PG_AES192_KEY_LEN:
+ return EVP_aes_192_ctr;
+ case PG_AES256_KEY_LEN:
+ return EVP_aes_256_ctr;
+ default:
+ return NULL;
+ }
+}
+
/*
* Initialize and return an EVP_CIPHER_CTX. Returns NULL if the given
* cipher algorithm is not supported or on failure.
@@ -389,6 +410,11 @@ ossl_cipher_ctx_create(int cipher, unsigned char *key, int klen, bool enc)
if (!func)
goto failed;
break;
+ case PG_CIPHER_AES_CTR:
+ func = get_evp_aes_ctr(klen);
+ if (!func)
+ goto failed;
+ break;
default:
goto failed;
}
diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h
index f1d8c39edf..43c4f1f611 100644
--- a/src/include/access/xloginsert.h
+++ b/src/include/access/xloginsert.h
@@ -59,6 +59,7 @@ extern void log_newpages(RelFileNode *rnode, ForkNumber forkNum, int num_pages,
extern XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std);
extern void log_newpage_range(Relation rel, ForkNumber forkNum,
BlockNumber startblk, BlockNumber endblk, bool page_std);
+extern XLogRecPtr log_noop(void);
extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std);
extern void InitXLogInsert(void);
diff --git a/src/include/common/cipher.h b/src/include/common/cipher.h
index 7d446e86b6..9c4a630cd6 100644
--- a/src/include/common/cipher.h
+++ b/src/include/common/cipher.h
@@ -27,7 +27,8 @@
#define PG_CIPHER_AES_GCM 0
#define PG_CIPHER_AES_KW 1
#define PG_CIPHER_AES_KWP 2
-#define PG_MAX_CIPHER_ID 3
+#define PG_CIPHER_AES_CTR 3
+#define PG_MAX_CIPHER_ID 4
/* AES128/192/256 various length definitions */
#define PG_AES128_KEY_LEN (128 / 8)
diff --git a/src/include/crypto/bufenc.h b/src/include/crypto/bufenc.h
new file mode 100644
index 0000000000..97302a4f3f
--- /dev/null
+++ b/src/include/crypto/bufenc.h
@@ -0,0 +1,27 @@
+/*-------------------------------------------------------------------------
+ *
+ * bufenc.h
+ *
+ * Portions Copyright (c) 2021, PostgreSQL Global Development Group
+ *
+ * src/include/crypto/bufenc.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef BUFENC_H
+#define BUFENC_H
+
+#include "storage/bufmgr.h"
+#include "crypto/kmgr.h"
+
+#define DataEncryptionEnabled() (file_encryption_keylen > 0)
+
+/* Cluster encryption encrypts only main fork */
+#define PageNeedsToBeEncrypted(forknum) \
+ (DataEncryptionEnabled() && ((forknum) == MAIN_FORKNUM))
+
+extern void InitializeBufferEncryption(void);
+extern void EncryptPage(Page page, BlockNumber blkno);
+extern void DecryptPage(Page page, BlockNumber blkno);
+
+#endif /* BUFENC_H */
diff --git a/src/include/crypto/kmgr.h b/src/include/crypto/kmgr.h
index 386ac1cb4a..6a728ebefc 100644
--- a/src/include/crypto/kmgr.h
+++ b/src/include/crypto/kmgr.h
@@ -16,6 +16,8 @@
#include "storage/relfilenode.h"
#include "storage/bufpage.h"
+#define DataEncryptionEnabled() (file_encryption_keylen > 0)
+
/* GUC parameters */
extern int file_encryption_keylen;
extern char *cluster_key_command;
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index 359b749f7f..fc855cc3b5 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -15,6 +15,7 @@
#define BUFPAGE_H
#include "access/xlogdefs.h"
+#include "common/relpath.h"
#include "storage/block.h"
#include "storage/item.h"
#include "storage/off.h"
@@ -164,6 +165,8 @@ typedef struct PageHeaderData
} PageHeaderData;
typedef PageHeaderData *PageHeader;
+#define PageEncryptOffset offsetof(PageHeaderData, pd_special)
+#define SizeOfPageEncryption (BLCKSZ - PageEncryptOffset)
/*
* pd_flags contains the following flag bits. Undefined bits are initialized
@@ -419,7 +422,7 @@ do { \
((is_heap) ? PAI_IS_HEAP : 0))
#define PageIsVerified(page, blkno) \
- PageIsVerifiedExtended(page, blkno, \
+ PageIsVerifiedExtended(page, MAIN_FORKNUM, blkno, \
PIV_LOG_WARNING | PIV_REPORT_STAT)
/*
@@ -433,7 +436,8 @@ StaticAssertDecl(BLCKSZ == ((BLCKSZ / sizeof(size_t)) * sizeof(size_t)),
"BLCKSZ has to be a multiple of sizeof(size_t)");
extern void PageInit(Page page, Size pageSize, Size specialSize);
-extern bool PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags);
+extern bool PageIsVerifiedExtended(Page page, ForkNumber forknum, BlockNumber blkno,
+ int flags);
extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size,
OffsetNumber offsetNumber, int flags);
extern Page PageGetTempPage(Page page);
@@ -452,5 +456,8 @@ extern bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum,
Item newtup, Size newsize);
extern char *PageSetChecksumCopy(Page page, BlockNumber blkno);
extern void PageSetChecksumInplace(Page page, BlockNumber blkno);
+extern char *PageEncryptCopy(Page page, ForkNumber forknum, BlockNumber blkno);
+extern void PageEncryptInplace(Page page, ForkNumber forknum, BlockNumber blkno);
+extern void PageDecryptInplace(Page page, ForkNumber forknum, BlockNumber blkno);
#endif /* BUFPAGE_H */
--
2.27.0