From 7557acf60f52da4a86fd9f902bab4804c028dd4b Mon Sep 17 00:00:00 2001 From: David Christensen Date: Tue, 31 Oct 2023 15:24:02 -0400 Subject: [PATCH v3 3/5] Backend-related changes --- contrib/basic_archive/basic_archive.c | 2 +- src/backend/Makefile | 17 +- src/backend/access/gist/README | 10 + src/backend/access/gist/gist.c | 64 +-- src/backend/access/gist/gistbuild.c | 25 +- src/backend/access/gist/gistvacuum.c | 20 +- src/backend/access/hash/hashpage.c | 2 + src/backend/access/heap/rewriteheap.c | 11 + src/backend/access/nbtree/nbtsort.c | 4 +- src/backend/access/rmgrdesc/xlogdesc.c | 6 +- src/backend/access/transam/xlog.c | 39 ++ src/backend/access/transam/xloginsert.c | 26 +- src/backend/backup/basebackup.c | 5 + src/backend/bootstrap/bootstrap.c | 29 +- src/backend/catalog/storage.c | 7 +- src/backend/crypto/Makefile | 19 + src/backend/crypto/README | 340 +++++++++++++ src/backend/crypto/bufenc.c | 237 +++++++++ src/backend/crypto/ckey_aws.sh.sample | 53 ++ src/backend/crypto/ckey_direct.sh.sample | 39 ++ src/backend/crypto/ckey_passphrase.sh.sample | 35 ++ src/backend/crypto/ckey_piv_nopin.sh.sample | 68 +++ src/backend/crypto/ckey_piv_pin.sh.sample | 81 ++++ src/backend/crypto/kmgr.c | 442 +++++++++++++++++ src/backend/crypto/meson.build | 14 + src/backend/crypto/ssl_passphrase.sh.sample | 35 ++ src/backend/libpq/be-secure-common.c | 8 +- src/backend/main/main.c | 3 + src/backend/meson.build | 1 + src/backend/postmaster/postmaster.c | 15 +- src/backend/replication/logical/decode.c | 1 + src/backend/storage/buffer/bufmgr.c | 158 ++++-- src/backend/storage/buffer/localbuf.c | 9 + src/backend/storage/file/copydir.c | 43 +- src/backend/storage/file/reinit.c | 2 +- src/backend/storage/ipc/ipci.c | 3 + src/backend/storage/lmgr/lwlocknames.txt | 1 + src/backend/storage/page/bufpage.c | 51 +- src/backend/tcop/postgres.c | 30 +- .../utils/activity/wait_event_names.txt | 3 + src/backend/utils/misc/guc_tables.c | 25 + src/backend/utils/misc/pg_controldata.c | 37 +- src/backend/utils/misc/postgresql.conf.sample | 5 + src/include/access/gist.h | 5 +- src/include/access/xlog.h | 19 +- src/include/access/xloginsert.h | 2 + src/include/catalog/pg_control.h | 7 +- src/include/catalog/pg_proc.dat | 6 +- src/include/crypto/bufenc.h | 37 ++ src/include/crypto/kmgr.h | 25 + src/include/postmaster/postmaster.h | 2 + src/include/storage/bufpage.h | 23 +- src/include/storage/copydir.h | 2 +- src/include/utils/guc_tables.h | 1 + src/test/Makefile | 3 + src/test/README | 3 + src/test/crypto/.gitignore | 4 + src/test/crypto/KWP_AD_128.txt | 35 ++ src/test/crypto/KWP_AD_256.txt | 35 ++ src/test/crypto/KWP_AE_128.txt | 35 ++ src/test/crypto/KWP_AE_256.txt | 35 ++ src/test/crypto/Makefile | 39 ++ src/test/crypto/README | 33 ++ src/test/crypto/gcmDecrypt128.rsp | 129 +++++ src/test/crypto/gcmDecrypt256.rsp | 129 +++++ src/test/crypto/gcmEncryptExtIV128.rsp | 129 +++++ src/test/crypto/gcmEncryptExtIV256.rsp | 129 +++++ src/test/crypto/t/001_testcrypto.pl | 137 ++++++ src/test/crypto/t/002_testkwp.pl | 126 +++++ src/test/crypto/t/003_clusterkey.pl | 93 ++++ src/test/crypto/t/004_buffers.pl | 157 ++++++ src/test/crypto/testcrypto.c | 458 ++++++++++++++++++ src/tools/msvc/Mkvcbuild.pm | 4 +- 73 files changed, 3754 insertions(+), 113 deletions(-) create mode 100644 src/backend/crypto/Makefile create mode 100644 src/backend/crypto/README create mode 100644 src/backend/crypto/bufenc.c create mode 100644 src/backend/crypto/ckey_aws.sh.sample create mode 100644 src/backend/crypto/ckey_direct.sh.sample create mode 100644 src/backend/crypto/ckey_passphrase.sh.sample create mode 100644 src/backend/crypto/ckey_piv_nopin.sh.sample create mode 100644 src/backend/crypto/ckey_piv_pin.sh.sample create mode 100644 src/backend/crypto/kmgr.c create mode 100644 src/backend/crypto/meson.build create mode 100644 src/backend/crypto/ssl_passphrase.sh.sample create mode 100644 src/include/crypto/bufenc.h create mode 100644 src/include/crypto/kmgr.h create mode 100644 src/test/crypto/.gitignore create mode 100644 src/test/crypto/KWP_AD_128.txt create mode 100644 src/test/crypto/KWP_AD_256.txt create mode 100644 src/test/crypto/KWP_AE_128.txt create mode 100644 src/test/crypto/KWP_AE_256.txt create mode 100644 src/test/crypto/Makefile create mode 100644 src/test/crypto/README create mode 100644 src/test/crypto/gcmDecrypt128.rsp create mode 100644 src/test/crypto/gcmDecrypt256.rsp create mode 100644 src/test/crypto/gcmEncryptExtIV128.rsp create mode 100644 src/test/crypto/gcmEncryptExtIV256.rsp create mode 100644 src/test/crypto/t/001_testcrypto.pl create mode 100644 src/test/crypto/t/002_testkwp.pl create mode 100644 src/test/crypto/t/003_clusterkey.pl create mode 100644 src/test/crypto/t/004_buffers.pl create mode 100644 src/test/crypto/testcrypto.c diff --git a/contrib/basic_archive/basic_archive.c b/contrib/basic_archive/basic_archive.c index 4d78c31859..8bed44ccc7 100644 --- a/contrib/basic_archive/basic_archive.c +++ b/contrib/basic_archive/basic_archive.c @@ -301,7 +301,7 @@ basic_archive_file_internal(const char *file, const char *path) * Copy the file to its temporary destination. Note that this will fail * if temp already exists. */ - copy_file(path, temp); + copy_file(path, temp, false); /* * Sync the temporary file to disk and move it to its final destination. diff --git a/src/backend/Makefile b/src/backend/Makefile index 3e275ac759..80959ff91d 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -21,7 +21,7 @@ SUBDIRS = access archive backup bootstrap catalog parser commands executor \ main nodes optimizer partitioning port postmaster \ regex replication rewrite \ statistics storage tcop tsearch utils $(top_builddir)/src/timezone \ - jit + jit crypto include $(srcdir)/common.mk @@ -214,6 +214,12 @@ endif $(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample '$(DESTDIR)$(datadir)/pg_hba.conf.sample' $(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample '$(DESTDIR)$(datadir)/pg_ident.conf.sample' $(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample '$(DESTDIR)$(datadir)/postgresql.conf.sample' + $(INSTALL_DATA) $(srcdir)/crypto/ckey_aws.sh.sample '$(DESTDIR)$(datadir)/auth_commands/ckey_aws.sh.sample' + $(INSTALL_DATA) $(srcdir)/crypto/ckey_direct.sh.sample '$(DESTDIR)$(datadir)/auth_commands/ckey_direct.sh.sample' + $(INSTALL_DATA) $(srcdir)/crypto/ckey_passphrase.sh.sample '$(DESTDIR)$(datadir)/auth_commands/ckey_passphrase.sh.sample' + $(INSTALL_DATA) $(srcdir)/crypto/ckey_piv_nopin.sh.sample '$(DESTDIR)$(datadir)/auth_commands/ckey_piv_nopin.sh.sample' + $(INSTALL_DATA) $(srcdir)/crypto/ckey_piv_pin.sh.sample '$(DESTDIR)$(datadir)/auth_commands/ckey_piv_pin.sh.sample' + $(INSTALL_DATA) $(srcdir)/crypto/ssl_passphrase.sh.sample '$(DESTDIR)$(datadir)/auth_commands/ssl_passphrase.sh.sample' ifeq ($(with_llvm), yes) install-bin: install-postgres-bitcode @@ -233,6 +239,7 @@ endif installdirs: $(MKDIR_P) '$(DESTDIR)$(bindir)' '$(DESTDIR)$(datadir)' + $(MKDIR_P) '$(DESTDIR)$(datadir)' '$(DESTDIR)$(datadir)/auth_commands' ifeq ($(PORTNAME), cygwin) ifeq ($(MAKE_DLL), true) $(MKDIR_P) '$(DESTDIR)$(libdir)' @@ -272,7 +279,13 @@ endif $(MAKE) -C utils uninstall-data rm -f '$(DESTDIR)$(datadir)/pg_hba.conf.sample' \ '$(DESTDIR)$(datadir)/pg_ident.conf.sample' \ - '$(DESTDIR)$(datadir)/postgresql.conf.sample' + '$(DESTDIR)$(datadir)/postgresql.conf.sample' \ + '$(DESTDIR)$(datadir)/auth_commands/ckey_aws.sh.sample' \ + '$(DESTDIR)$(datadir)/auth_commands/ckey_direct.sh.sample' \ + '$(DESTDIR)$(datadir)/auth_commands/ckey_passphrase.sh.sample' \ + '$(DESTDIR)$(datadir)/auth_commands/ckey_piv_nopin.sh.sample' \ + '$(DESTDIR)$(datadir)/auth_commands/ckey_piv_pin.sh.sample' \ + '$(DESTDIR)$(datadir)/auth_commands/ssl_passphrase.sh.sample' ifeq ($(with_llvm), yes) $(call uninstall_llvm_module,postgres) endif diff --git a/src/backend/access/gist/README b/src/backend/access/gist/README index 8015ff19f0..3e916f1c70 100644 --- a/src/backend/access/gist/README +++ b/src/backend/access/gist/README @@ -477,6 +477,16 @@ value. The page is not recycled, until that XID is no longer visible to anyone. That's much more conservative than necessary, but let's keep it simple. +GiST and Encryption +------------------- + +GiST uses LSNs and NSNs for concurrency. This means that unlogged and +temporary relations also need LSNs. GiST has a mechanism to assign LSNs +to such relations, but sometimes uses fixed LSNs and or calls +gistGetFakeLSN(), which can cause duplicate LSNs to be used. Therefore, +when encryption is enabled and fake LSNs are needed, the GiST code calls +LSNForEncryption(). See src/backend/crypto/README for more details. + Authors: Teodor Sigaev diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 8ef5fa0329..12b9341b11 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -502,16 +502,16 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, * we don't need to be able to detect concurrent splits yet.) */ if (is_build) - recptr = GistBuildLSN; + recptr = !FileEncryptionEnabled ? GistBuildLSN : + LSNForEncryption(RelationIsPermanent(rel)); + else if (RelationNeedsWAL(rel)) + recptr = gistXLogSplit(is_leaf, + dist, oldrlink, oldnsn, leftchildbuf, + markfollowright); + else if (FileEncryptionEnabled) + recptr = LSNForEncryption(RelationIsPermanent(rel)); else - { - if (RelationNeedsWAL(rel)) - recptr = gistXLogSplit(is_leaf, - dist, oldrlink, oldnsn, leftchildbuf, - markfollowright); - else - recptr = gistGetFakeLSN(rel); - } + recptr = gistGetFakeLSN(rel); for (ptr = dist; ptr; ptr = ptr->next) PageSetLSN(ptr->page, recptr); @@ -569,27 +569,28 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, MarkBufferDirty(leftchildbuf); if (is_build) - recptr = GistBuildLSN; - else + recptr = !FileEncryptionEnabled ? GistBuildLSN : + LSNForEncryption(RelationIsPermanent(rel)); + else if (RelationNeedsWAL(rel)) { - if (RelationNeedsWAL(rel)) - { - OffsetNumber ndeloffs = 0, - deloffs[1]; + OffsetNumber ndeloffs = 0, + deloffs[1]; - if (OffsetNumberIsValid(oldoffnum)) - { - deloffs[0] = oldoffnum; - ndeloffs = 1; - } - - recptr = gistXLogUpdate(buffer, - deloffs, ndeloffs, itup, ntup, - leftchildbuf); + if (OffsetNumberIsValid(oldoffnum)) + { + deloffs[0] = oldoffnum; + ndeloffs = 1; } - else - recptr = gistGetFakeLSN(rel); + + recptr = gistXLogUpdate(buffer, + deloffs, ndeloffs, itup, ntup, + leftchildbuf); } + else if (FileEncryptionEnabled) + recptr = LSNForEncryption(RelationIsPermanent(rel)); + else + recptr = gistGetFakeLSN(rel); + PageSetLSN(page, recptr); if (newblkno) @@ -1686,6 +1687,8 @@ gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel) if (ndeletable > 0) { + XLogRecPtr recptr; + TransactionId snapshotConflictHorizon = InvalidTransactionId; if (XLogStandbyInfoActive() && RelationNeedsWAL(rel)) @@ -1711,17 +1714,18 @@ gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel) /* XLOG stuff */ if (RelationNeedsWAL(rel)) { - XLogRecPtr recptr; - recptr = gistXLogDelete(buffer, deletable, ndeletable, snapshotConflictHorizon, heapRel); - PageSetLSN(page, recptr); } + else if (FileEncryptionEnabled) + recptr = LSNForEncryption(RelationIsPermanent(rel)); else - PageSetLSN(page, gistGetFakeLSN(rel)); + recptr = gistGetFakeLSN(rel); + + PageSetLSN(page, recptr); END_CRIT_SECTION(); } diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index a45e2fe375..a24307cd0c 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -48,6 +48,8 @@ #include "utils/rel.h" #include "utils/tuplesort.h" +extern XLogRecPtr LSNForEncryption(bool use_wal_lsn); + /* Step of index tuples for check whether to switch to buffering build mode */ #define BUFFERING_MODE_SWITCH_CHECK_STEP 256 @@ -307,7 +309,8 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) GISTInitBuffer(buffer, F_LEAF); MarkBufferDirty(buffer); - PageSetLSN(page, GistBuildLSN); + PageSetLSN(page, !FileEncryptionEnabled ? GistBuildLSN : + LSNForEncryption(RelationIsPermanent(index))); UnlockReleaseBuffer(buffer); @@ -458,7 +461,15 @@ gist_indexsortbuild(GISTBuildState *state) gist_indexsortbuild_flush_ready_pages(state); /* Write out the root */ - PageSetLSN(levelstate->pages[0], GistBuildLSN); + RelationGetSmgr(state->indexrel); + PageSetLSN(levelstate->pages[0], !FileEncryptionEnabled ? GistBuildLSN : + LSNForEncryption(RelationIsPermanent(state->indexrel))); + /* Make sure LSNs are vaild, and if encryption, are not constant. */ + Assert(!XLogRecPtrIsInvalid(PageGetLSN(levelstate->pages[0])) && + (!FileEncryptionEnabled || + PageGetLSN(levelstate->pages[0]) != GistBuildLSN)); + PageEncryptInplace(levelstate->pages[0], MAIN_FORKNUM, RelationIsPermanent(state->indexrel), + GIST_ROOT_BLKNO, state->indexrel->rd_locator.relNumber); PageSetChecksumInplace(levelstate->pages[0], GIST_ROOT_BLKNO); smgrwrite(RelationGetSmgr(state->indexrel), MAIN_FORKNUM, GIST_ROOT_BLKNO, levelstate->pages[0], true); @@ -656,7 +667,15 @@ gist_indexsortbuild_flush_ready_pages(GISTBuildState *state) if (blkno != state->pages_written) elog(ERROR, "unexpected block number to flush GiST sorting build"); - PageSetLSN(page, GistBuildLSN); + PageSetLSN(page, !FileEncryptionEnabled ? GistBuildLSN : + LSNForEncryption(RelationIsPermanent(state->indexrel))); + /* Make sure LSNs are vaild, and if encryption, are not constant. */ + Assert(!XLogRecPtrIsInvalid(PageGetLSN(page)) && + (!FileEncryptionEnabled || + PageGetLSN(page) != GistBuildLSN)); + PageEncryptInplace(page, MAIN_FORKNUM, RelationIsPermanent(state->indexrel), + blkno, state->indexrel->rd_locator.relNumber + ); PageSetChecksumInplace(page, blkno); smgrextend(RelationGetSmgr(state->indexrel), MAIN_FORKNUM, blkno, page, true); diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index 3f60d3274d..35e7ed5b93 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -24,6 +24,8 @@ #include "storage/lmgr.h" #include "utils/memutils.h" +extern XLogRecPtr LSNForEncryption(bool use_wal_lsn); + /* Working state needed by gistbulkdelete */ typedef struct { @@ -180,6 +182,8 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, vstate.callback_state = callback_state; if (RelationNeedsWAL(rel)) vstate.startNSN = GetInsertRecPtr(); + else if (FileEncryptionEnabled) + vstate.startNSN = LSNForEncryption(RelationIsPermanent(rel)); else vstate.startNSN = gistGetFakeLSN(rel); @@ -359,6 +363,8 @@ restart: */ if (ntodelete > 0) { + XLogRecPtr recptr; + START_CRIT_SECTION(); MarkBufferDirty(buffer); @@ -367,16 +373,15 @@ restart: GistMarkTuplesDeleted(page); if (RelationNeedsWAL(rel)) - { - XLogRecPtr recptr; - recptr = gistXLogUpdate(buffer, todelete, ntodelete, NULL, 0, InvalidBuffer); - PageSetLSN(page, recptr); - } + else if (FileEncryptionEnabled) + recptr = LSNForEncryption(RelationIsPermanent(rel)); else - PageSetLSN(page, gistGetFakeLSN(rel)); + recptr = gistGetFakeLSN(rel); + + PageSetLSN(page, recptr); END_CRIT_SECTION(); @@ -663,8 +668,11 @@ gistdeletepage(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, if (RelationNeedsWAL(info->index)) recptr = gistXLogPageDelete(leafBuffer, txid, parentBuffer, downlink); + else if (FileEncryptionEnabled) + recptr = LSNForEncryption(RelationIsPermanent(info->index)); else recptr = gistGetFakeLSN(info->index); + PageSetLSN(parentPage, recptr); PageSetLSN(leafPage, recptr); diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index 0c6e79f1bd..162b1a79d4 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -1029,6 +1029,8 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks) zerobuf.data, true); + PageEncryptInplace(page, MAIN_FORKNUM, RelationIsPermanent(rel), lastblock, + rel->rd_locator.relNumber); PageSetChecksumInplace(page, lastblock); smgrextend(RelationGetSmgr(rel), MAIN_FORKNUM, lastblock, zerobuf.data, false); diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 424958912c..2a079b7aac 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -323,6 +323,11 @@ end_heap_rewrite(RewriteState state) state->rs_buffer, true); + PageEncryptInplace(state->rs_buffer, MAIN_FORKNUM, + RelationIsPermanent(state->rs_new_rel), + state->rs_blockno, + RelationGetSmgr(state->rs_new_rel)->smgr_rlocator.locator.relNumber + ); PageSetChecksumInplace(state->rs_buffer, state->rs_blockno); smgrextend(RelationGetSmgr(state->rs_new_rel), MAIN_FORKNUM, @@ -689,8 +694,14 @@ raw_heap_insert(RewriteState state, HeapTuple tup) * need for smgr to schedule an fsync for this write; we'll do it * ourselves in end_heap_rewrite. */ + PageEncryptInplace(page, MAIN_FORKNUM, + RelationIsPermanent(state->rs_new_rel), + state->rs_blockno, + RelationGetSmgr(state->rs_new_rel)->smgr_rlocator.locator.relNumber + ); PageSetChecksumInplace(page, state->rs_blockno); + /* XXX - is this still needed? */ smgrextend(RelationGetSmgr(state->rs_new_rel), MAIN_FORKNUM, state->rs_blockno, page, true); diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index c2665fce41..f951f4c356 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -663,13 +663,15 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno) wstate->btws_zeropage = (Page) palloc_aligned(BLCKSZ, PG_IO_ALIGN_SIZE, MCXT_ALLOC_ZERO); - /* don't set checksum for all-zero page */ + /* don't set checksum or encryption for all-zero page */ smgrextend(RelationGetSmgr(wstate->index), MAIN_FORKNUM, wstate->btws_pages_written++, wstate->btws_zeropage, true); } + PageEncryptInplace(page, MAIN_FORKNUM, RelationIsPermanent(wstate->index), + blkno, RelationGetSmgr(wstate->index)->smgr_rlocator.locator.relNumber); PageSetChecksumInplace(page, blkno); /* diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index 37f59bda7e..b5cbfa0da5 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -80,7 +80,8 @@ xlog_desc(StringInfo buf, XLogReaderState *record) appendStringInfoString(buf, xlrec->rp_name); } - else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT) + else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT || + info == XLOG_ENCRYPTION_LSN) { /* no further information to print */ } @@ -203,6 +204,9 @@ xlog_identify(uint8 info) case XLOG_CHECKPOINT_REDO: id = "CHECKPOINT_REDO"; break; + case XLOG_ENCRYPTION_LSN: + id = "ENCRYPTION_LSN"; + break; } return id; diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b541be8eec..332885de95 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -69,13 +69,16 @@ #include "catalog/pg_database.h" #include "common/controldata_utils.h" #include "common/file_utils.h" +#include "crypto/kmgr.h" #include "executor/instrument.h" +#include "crypto/bufenc.h" #include "miscadmin.h" #include "pg_trace.h" #include "pgstat.h" #include "port/atomics.h" #include "port/pg_iovec.h" #include "postmaster/bgwriter.h" +#include "postmaster/postmaster.h" #include "postmaster/startup.h" #include "postmaster/walwriter.h" #include "replication/logical.h" @@ -109,6 +112,7 @@ #include "utils/varlena.h" extern uint32 bootstrap_data_checksum_version; +extern int bootstrap_file_encryption_method; /* timeline ID to be used when bootstrapping */ #define BootstrapTimeLineID 1 @@ -3961,6 +3965,7 @@ InitControlFile(uint64 sysidentifier) ControlFile->wal_log_hints = wal_log_hints; ControlFile->track_commit_timestamp = track_commit_timestamp; ControlFile->data_checksum_version = bootstrap_data_checksum_version; + ControlFile->file_encryption_method = bootstrap_file_encryption_method; } static void @@ -4240,6 +4245,12 @@ ReadControlFile(void) /* Make the initdb settings visible as GUC variables, too */ SetConfigOption("data_checksums", DataChecksumsEnabled() ? "yes" : "no", PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT); + + StaticAssertStmt(lengthof(encryption_methods) == NUM_ENCRYPTION_METHODS, + "encryption_methods[] must match NUM_ENCRYPTION_METHODS"); + SetConfigOption("file_encryption_method", + encryption_methods[ControlFile->file_encryption_method].name, + PGC_INTERNAL, PGC_S_OVERRIDE); } /* @@ -4282,6 +4293,21 @@ DataChecksumsEnabled(void) return (ControlFile->data_checksum_version > 0); } +/* + * Is cluster file encryption enabled? + */ +int +GetFileEncryptionMethod(void) +{ + if (IsBootstrapProcessingMode()) + return bootstrap_file_encryption_method; + else + { + Assert(ControlFile != NULL); + return ControlFile->file_encryption_method; + } +} + /* * Returns a fake LSN for unlogged relations. * @@ -4819,6 +4845,9 @@ BootStrapXLOG(void) recptr += sizeof(checkPoint); Assert(recptr - (char *) record == record->xl_tot_len); + BootStrapKmgr(); + InitializeBufferEncryption(bootstrap_file_encryption_method); + INIT_CRC32C(crc); COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord); COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc)); @@ -4871,6 +4900,12 @@ BootStrapXLOG(void) /* some additional ControlFile fields are set in WriteControlFile() */ WriteControlFile(); + if (terminal_fd != -1) + { + close(terminal_fd); + terminal_fd = -1; + } + /* Bootstrap the commit log, too */ BootStrapCLOG(); BootStrapCommitTs(); @@ -8089,6 +8124,10 @@ xlog_redo(XLogReaderState *record) UnlockReleaseBuffer(buffer); } } + else if (info == XLOG_ENCRYPTION_LSN) + { + /* nothing to do here */ + } else if (info == XLOG_BACKUP_END) { /* nothing to do here, handled in xlogrecovery_redo() */ diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index e4aaa551a0..7c2277dd5b 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -553,7 +553,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, XLogRecData *rdt; uint64 total_len = 0; int block_id; - pg_crc32c rdata_crc; + pg_crc32c rdata_crc = 0; registered_buffer *prev_regbuf = NULL; XLogRecData *rdt_datas_last; XLogRecord *rechdr; @@ -1128,6 +1128,30 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std) return recptr; } +/* + * This function returns either a WAL or fake LSN, for use by encryption. + */ +XLogRecPtr +LSNForEncryption(bool use_wal_lsn) +{ + if (use_wal_lsn) + { + int dummy = 0; + + Assert(FileEncryptionEnabled); + /* + * Records other than SWITCH_WAL must have content. We use an integer 0 to + * follow the restriction. + */ + XLogBeginInsert(); + XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT); + XLogRegisterData((char *) &dummy, sizeof(dummy)); + return XLogInsert(RM_XLOG_ID, XLOG_ENCRYPTION_LSN); + } + else + return GetFakeLSNForUnloggedRel(); +} + /* * Write a WAL record containing a full image of a page. Caller is responsible * for writing the page to disk after calling this routine. diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c index b537f46219..8771175018 100644 --- a/src/backend/backup/basebackup.c +++ b/src/backend/backup/basebackup.c @@ -24,6 +24,7 @@ #include "backup/basebackup_target.h" #include "commands/defrem.h" #include "common/compression.h" +#include "common/kmgr_utils.h" #include "common/file_perm.h" #include "common/file_utils.h" #include "lib/stringinfo.h" @@ -139,6 +140,10 @@ struct exclude_list_item */ static const char *const excludeDirContents[] = { + /* Skip temporary crypto key directories */ + NEW_KMGR_DIR, + OLD_KMGR_DIR, + /* * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped * because extensions like pg_stat_statements store data there. diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index e01dca9b7c..5735019d4b 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -29,10 +29,12 @@ #include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "common/link-canary.h" +#include "crypto/bufenc.h" #include "libpq/pqsignal.h" #include "miscadmin.h" #include "nodes/makefuncs.h" #include "pg_getopt.h" +#include "postmaster/postmaster.h" /* TODO: verify we need this still */ #include "storage/bufmgr.h" #include "storage/bufpage.h" #include "storage/condition_variable.h" @@ -47,6 +49,9 @@ uint32 bootstrap_data_checksum_version = 0; /* No checksum */ +int bootstrap_file_encryption_method = DISABLED_ENCRYPTION_METHOD; +char *bootstrap_old_key_datadir = NULL; /* disabled */ + static void CheckerModeMain(void); static void bootstrap_signals(void); @@ -221,7 +226,7 @@ BootstrapModeMain(int argc, char *argv[], bool check_only) argv++; argc--; - while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:X:-:")) != -1) + while ((flag = getopt(argc, argv, "B:c:d:D:e:FkK:r:R:u:X:-:")) != -1) { switch (flag) { @@ -276,9 +281,31 @@ BootstrapModeMain(int argc, char *argv[], bool check_only) case 'k': bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION; break; + case 'K': + { + /* method 0/disabled cannot be specified */ + for (i = DISABLED_ENCRYPTION_METHOD + 1; + i < NUM_ENCRYPTION_METHODS; i++) + if (pg_strcasecmp(optarg, encryption_methods[i].name) == 0) + { + bootstrap_file_encryption_method = i; + break; + } + if (i == NUM_ENCRYPTION_METHODS) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid encryption method specified"))); + } + break; case 'r': strlcpy(OutputFileName, optarg, MAXPGPATH); break; + case 'R': + terminal_fd = atoi(optarg); + break; + case 'u': + bootstrap_old_key_datadir = pstrdup(optarg); + break; case 'X': SetConfigOption("wal_segment_size", optarg, PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT); break; diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 93f07e49b7..a65f9f3b19 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -486,7 +486,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst, smgrread(src, forkNum, blkno, buf.data); - if (!PageIsVerifiedExtended(page, blkno, + if (!PageIsVerifiedExtended(page, forkNum, + relpersistence == RELPERSISTENCE_PERMANENT, + blkno, src->smgr_rlocator.locator.relNumber, PIV_LOG_WARNING | PIV_REPORT_STAT)) { /* @@ -514,6 +516,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst, if (use_wal) log_newpage(&dst->smgr_rlocator.locator, forkNum, blkno, page, false); + PageEncryptInplace(page, forkNum, + relpersistence == RELPERSISTENCE_PERMANENT, blkno, + dst->smgr_rlocator.locator.relNumber); PageSetChecksumInplace(page, blkno); /* diff --git a/src/backend/crypto/Makefile b/src/backend/crypto/Makefile new file mode 100644 index 0000000000..8985a66875 --- /dev/null +++ b/src/backend/crypto/Makefile @@ -0,0 +1,19 @@ +#------------------------------------------------------------------------- +# +# Makefile +# Makefile for src/backend/crypto +# +# IDENTIFICATION +# src/backend/crypto/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/backend/crypto +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/README b/src/backend/crypto/README new file mode 100644 index 0000000000..3569176f2c --- /dev/null +++ b/src/backend/crypto/README @@ -0,0 +1,340 @@ +Cluster File Encryption +======================= + +This directory contains support functions and sample scripts to be used +for cluster file encryption. + +Architecture +------------ + +Fundamentally, cluster file encryption must store data in a file system +in such a way that the keys required to decrypt the file system data can +only be accessed using somewhere outside of the file system itself. The +external requirement can be someone typing in a passphrase, getting a +key from a key management server (KMS), or decrypting a key stored in +the file system using a hardware security module (HSM). The current +architecture supports all of these methods, and includes sample scripts +for them. + +The simplest method for accessing data keys using some external +requirement would be to retrieve all data encryption keys from a KMS. +However, retrieved keys would still need to be verified as valid. This +method also introduces unacceptable complexity for simpler use-cases, +like user-supplied passphrases or HSM usage. External key rotation +would also be very hard since it would require re-encrypting all the +file system data with the new externally-stored keys. + +For these reason, a two-tiered architecture is used, which uses two +types of encryption keys: a key encryption key (KEK) and data encryption +keys (DEK). The KEK should not be present unencrypted in the file system +--- it should be supplied the user, stored externally (e.g., in a KMS) +or stored in the file system encrypted with a HSM (e.g., PIV device). +The DEK is used to encrypt database files and is stored in the same file +system as the database but is encrypted using the KEK. Because the DEK +is encrypted, its storage in the file system is no more of a security +weakness and the storage of the encrypted database files in the same +file system. + +Implementation +-------------- + +To enable cluster file encryption, the initdb option +--cluster-key-command must be used, which specifies a command to +retrieve the KEK. initdb records the cluster_key_command in +postgresql.conf. Every time the KEK is needed, the command is run and +must return 64 hex characters which are decoded into the KEK. The +command is called twice during initdb, and every time the server starts. +initdb also sets the encryption method in controldata during server +bootstrap. + +initdb runs "postgres --boot", which calls function +kmgr.c::BootStrapKmgr(), which calls the cluster key command. The +cluster key command returns a KEK which is used to encrypt random bytes +for each DEK and writes them to the file system by +kmgr.c::KmgrWriteCryptoKeys() (unless --copy-encryption-keys is used). +Currently the DEK files are 0 and 1 and are stored in +$PGDATA/pg_cryptokeys/live. The wrapped DEK files use Key Wrapping with +Padding which verifies the validity of the KEK. + +initdb also does a non-boot backend start which calls +kmgr.c::InitializeKmgr(), which calls the cluster key command a second +time. This decrypts/unwraps the DEK keys and stores them in the shared +memory structure KmgrShmem. This step also happens every time the server +starts. Later patches will use the keys stored in KmgrShmem to +encrypt/decrypt database files. KmgrShmem is erased via +explicit_bzero() on server shutdown. + +Limitations +----------- + +There doesn't seem to be a reasonable way to detect all malicious data +modification or key extraction if a user has write permission on the +files in PGDATA. It might be possible to limit the key extraction risk +if postgresql.auto.conf were able to be moved to a directory outside of +PGDATA, and if postmaster.opts could be moved or ignored when cluster +file encryption is used. (This file is used by pg_ctl restart.) + +It doesn't appear possible to detect all malicious writes --- even if +you add message authentication code (MAC) checks to encrypted files, +modifying non-encrypted files could still affect encrypted ones, e.g., +modifying files in pg_xact could affect how heap rows are interpreted. +Basically you would need to encrypt all files, and at that point you +might as well just use an encrypted file system. There also doesn't seem +to be a way to prevent key extraction if someone has read permission on +postgres process memory. + +Initialization Vector +--------------------- + +Nonce means "number used once". An Initialization Vector (IV) is a +specific type of nonce. That is, unique but not necessarily random or +secret, as specified by the NIST +(https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf). +To generate unique IVs, the NIST recommends two methods: + + The first method is to apply the forward cipher function, under + the same key that is used for the encryption of the plaintext, + to a nonce. The nonce must be a data block that is unique to + each execution of the encryption operation. For example, the + nonce may be a counter, as described in Appendix B, or a message + number. The second method is to generate a random data block + using a FIPS-approved random number generator. + +We will use the first method to generate IVs. That is, select nonce +carefully and use a cipher with the key to make it unique enough to use +as an IV. The nonce selection for buffer encryption and WAL encryption +are described below. + +If the IV was used more than once with the same key (and we only use one +data encryption key), changes in the unencrypted data would be visible +in the encrypted data. + +IV for Heap/Index Encryption +- - - - - - - - - - - - - - + +To create the 16-byte IV needed by AES for each page version, we will +use the page LSN (8 bytes) and page number (4 bytes). In the remaining +four bytes, one bit will be used to indicate if the LSN is WAL (real) or +fake (see below). The LSN is ideal for use in the IV because it is +always increasing, and is changed every time a page is updated. The +same LSN is never used for two relations with different page contents. + +However, the same LSN can be used in multiple pages in the same relation +--- this can happen when a heap update expires an old tuple and adds a +new tuple to another page. By adding the page number to the IV, we keep +the IV unique. + +CREATE DATABASE can be run with two different strategies: FILE_COPY or +WAL_LOG. If using WAL_LOG, the heap/index files are automatically +rewritten with new LSNs as part of the copy operation and will get new +IVs automatically. + +This approach still works with the older FILE_COPY stragegy; by not +using the database id in the IV, CREATE DATABASE can copy the heap/index +files from the old database to a new one without decryption/encryption. +Both page copies are valid. Once a database changes its pages, it gets +new LSNs, and hence new IV. + +As part of WAL logging, every change of a WAL-logged page gets a new +LSN, and therefore a new IV automatically. + +However, the LSN must then be visible on encrypted pages, so we will not +encrypt the LSN on the page. We will also not encrypt the CRC so +pg_checksums can still check pages offline without access to the keys. + +Non-Permanent Relations +- - - - - - - - - - - - + +To avoid the overhead of generating WAL for non-permanent (unlogged and +temporary) relations, we assign fake LSNs that are derived from a +counter via xlog.c::GetFakeLSNForUnloggedRel(). (GiST also uses this +counter for LSNs.) We also set a bit in the IV so the use of the same +value for WAL (real) and fake LSNs will still generate unique IVs. Only +main forks are encrypted, not init, vm, or fsm files. + +In the code, we need to identify if a page uses WAL or fake LSNs in +four places, when: + +1. Reading a page from the file system and decrypting +2. Setting the WAL or fake LSN on a page +3. Hint bits changes requiring new LSNs for the encryption IV +4. Encrypting and writing a page to the file system + +For all these case, we have access to the fork number and either the +relation's persistence state or the buffer state. If it is a "main" +fork and the relation persistence state is RELPERSISTENCE_PERMANENT, or +if it is an "init" fork, we use a real LSN. If it is a main fork and +RELPERSISTENCE_PERMANENT is false, we use a fake LSN. The buffer state +BM_PERMANENT is true if the relation is PERMANENT or is an init fork. + +Init Forks +- - - - - + +Init forks for unlogged relations get permanent LSNs because unlogged +relation creation is WAL logged/crash safe, even though the relation's +contents are not. When the init fork is copied to represent an empty +relation during crash recovery, it becomes a non-permanent page and must +be successfully decrypted as such. Therefore, when it is copied, its +LSN is changed to a fake LSN and then encrypted. This prevents a real +LSN from being encrypted with the fake nonce bit. + +LSN Assignment, GiST, & Non-Permanent Relations +- - - - - - - - - - - - - - - - - - - - - - - - + +LSN assignment has to be slightly modified for encryption. In normal, +non-encryption mode, LSNs are assigned to pages following these rules: + +1. During GiST builds, some pages are assigned fixed LSNs (GistBuildLSN) + +2. During GiST builds, non-permanent pages not assigned fixed LSNs in +#1 are assigned fake LSNs, via gistutil.c::gistGetFakeLSN(). + +3. All other permanent pages are assigned WAL-based LSNs based on the +WAL position of their WAL records. + +4. All other non-permanent pages have LSNs of zero. + +When encryption is enabled: + +1. During GiST builds, permanent pages are assigned WAL-based LSNs +generated by xloginsert.c::LSNForEncryption(). + +2. During GiST builds, non-permanent pages are assigned fake LSNs. +(No constant LSNs are used in #1 or #2.) + +3. same as #3 above + +4. All other non-permanent pages are assigned fake LSNs before page +encryption. + +When switching to an encrypted replica from a non-encrypted primary, +GiST indexes will be using fixed LSNs for permanent tables, so it is +recommended to rebuild GiST indexes. Non-permanent relations are not +replicated, so they are not an issue. + +Hint Bits +- - - - - + +For hint bit changes, the LSN normally doesn't change, which is a +problem. By enabling wal_log_hints, you get full page writes to the WAL +after the first hint bit change of the checkpoint. This is useful for +two reasons. First, it generates a new LSN, which is needed for the IV +to be secure. Second, full page images protect against torn pages, +which is an even bigger requirement for encryption because the new LSN +is re-encrypting the entire page, not just the hint bit changes. You +can safely lose the hint bit changes, but you need to use the same LSN +to decrypt the entire page, so a torn page with an LSN change cannot be +decrypted. To prevent this, wal_log_hints guarantees that the +pre-hint-bit version (and previous LSN version) of the page is restored. + +However, if a hint-bit-modified page is written to the file system +during a checkpoint, and there is a later hint bit change switching the +same page from clean to dirty during the same checkpoint, we need a new +LSN, and wal_log_hints doesn't give us a new LSN here. The fix for this +is to update the page LSN by writing a dummy WAL record via +xloginsert.c::LSNForEncryption() in such cases. + + +Types of Encryption +------------------- + +PostgreSQL will utilize either XTS or GCM encryption, chosen depending on your +specific needs. + + +Why XTS? +- - - - + +XTS encryption provides industry standard AES encryption, however this is +non-authenticated encryption. What this means is that there is no validation +that the decrypted payload or non-encrypted portions of the authenticated data +have not been changed or tampered with. So given that this is not guaranteed, +why would you consider using XTS encryption? + +The major answer here is that you can enable encryption in a new cluster while +using just normal streaming backup tools without needing to resort to logical +replication, so this enables you to easily switch to an encrypted cluster just +by creating a new replica with the target encryption settings, catching up +replication, and faililng over to the new cluster. + + +Setting up with XTS +- - - - - - - - - - + +XTS replication can be at initdb time for a new cluster. If you define a new +standby with XTS encryption, you can then stream changes from PostgreSQL, with +the relation data being encrypted as you go. XXX - mention rekeying the cluster +here? + + +Why GCM? +- - - - + +GCM is the "authenticated encryption" portion, which ensures that encrypted and +non-encryption portions of page data has not been tampered with. This stores a +16-byte tag on each Page which stores the authtag for GCM-encrypted data. If any +of the data is modified, this authtag will no longer match and you will not be +able to decrypt the corresponding data. This ensures that you cannot change +ciphertext or non-encrypted pieces of data on the page in order to leak key +information. + +Since GCM-based encryption needs to store the authtag with the Page itself, this +does mean that we cannot convert existing disk pages to this new format in a way +that is compatible with a different cluster, so moving to a GCM-based cluster +will require Logical Replication or a dump/restore to enable this encryption +method, which definitely is a heavier operation. + +GCM encryption uses a Page Feature to reserve space in the Page structure for +its own usage. Since there are different benefits to either approach, we offer +both. + +When GCM is used, the following data is included as AAD: + - PageHeaderData, up to the pg_special field: + PageXLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog + * record for last change to this page */ + union { + uint16 checksum; /* checksum */ + uint16 features; /* page feature flags */ + } pd_feat; + uint16 pd_flags; /* flag bits, see below */ + LocationIndex pd_lower; /* offset to start of free space */ + LocationIndex pd_upper; /* offset to end of free space */ + +The rest of the page is encrypted. + +"pg_feat" and "pg_flags" need to be unencrypted since they are key to the interpretation of the PageFeature, and hence determine whether the page itself has an encryption tag. + +XXX - should we include pd_lower onward in encrypted data? Why starting with pd_special? + + +Authenticated WAL encryption +- - - - - - - - - - - - - - + +Regardless of whether XTS or GCM is chosen to encrypt the relation files, the +WAL records are encrypted using AES-GCM, storing the authtag for the record +inside the CRC field of the XLogRecordHeader. This is expanded to 64-bits from +32-bit, and said WAL will include as Authenticated Data the following fields: + +IV: +- uses the current TLI and the LSN of the WAL record as the IV + +Authenticated Data: +- the entirety of the XLogRecord header up to the + uint32 xl_tot_len; /* total len of entire record */ + TransactionId xl_xid; /* xact id */ + XLogRecPtr xl_prev; /* ptr to previous record in log */ + uint8 xl_info; /* flag bits, see below */ + RmgrId xl_rmid; /* resource manager for this record */ + char xl_pad[6]; /* explicit padding; should be 0'd */ + +The authtag for the WAL record is stored in the 8-byte xl_integrity.authtag +field. For the purposes of single use IV/key this provides us validation for a +significant number of transactions (XXX: find exact reuse stats), which would +require a rekey to be set only every XXX transactions for the Relation key. + +Encrypted Data: + +- Any additional data in the XLogRecord will be encrypted using the key/IV. For + everything except the XLOG_SWITCH record, this will contain at least 2 bytes + of a payload. This means that there will be xl_tot_len - sizeof(XLogRecord) + bytes of encrypted data following this. diff --git a/src/backend/crypto/bufenc.c b/src/backend/crypto/bufenc.c new file mode 100644 index 0000000000..18a34d9802 --- /dev/null +++ b/src/backend/crypto/bufenc.c @@ -0,0 +1,237 @@ +/*------------------------------------------------------------------------- + * + * 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 "access/gist.h" +#include "access/xlog.h" +#include "crypto/bufenc.h" +#include "storage/bufpage.h" +#include "storage/fd.h" + +extern XLogRecPtr LSNForEncryption(bool use_wal_lsn); + +/* + * We use the page LSN, page number, and permanent-bit to indicate if a fake + * LSN was used to create a nonce for each page. + */ +#define BUFENC_IV_SIZE 16 + +static unsigned char buf_encryption_iv[BUFENC_IV_SIZE]; +static int file_encryption_tag_size = 0; +static int file_encryption_page_size = 0; +static int file_encryption_method = DISABLED_ENCRYPTION_METHOD; + +/* this private struct is used to store additional info about the page used to validate specific other pages */ +typedef struct AdditionalAuthenticatedData { + unsigned char data[PageEncryptOffset]; /* copy the unencrypted page header info */ + RelFileNumber fileno; + BlockNumber blkNo; +} AdditionalAuthenticatedData; + +StaticAssertDecl((MAXALIGN(sizeof(AdditionalAuthenticatedData)) == sizeof(AdditionalAuthenticatedData)), + "AdditionalAuthenticatedData must be fully padded"); + +AdditionalAuthenticatedData auth_data; + +PgCipherCtx *BufEncCtx = NULL; +PgCipherCtx *BufDecCtx = NULL; + +static void set_buffer_encryption_iv(Page page, BlockNumber blkno, + bool relation_is_permanent); +static void +setup_additional_authenticated_data(Page page, BlockNumber blkno, + bool relation_is_permanent, RelFileNumber fileno); + + +void +InitializeBufferEncryption(int init_file_encryption_method) +{ + const CryptoKey *key; + +#ifndef FRONTEND + if (init_file_encryption_method == DISABLED_ENCRYPTION_METHOD) + return; + + key = KmgrGetKey(KMGR_KEY_ID_REL); +#else + return; +#endif + file_encryption_method = init_file_encryption_method; + + BufEncCtx = pg_cipher_ctx_create(EncryptionAlgorithm(file_encryption_method), + (unsigned char *) key->key, + EncryptionBlockLength(file_encryption_method), + true); + if (!BufEncCtx) + my_error("cannot initialize encryption context: method: %d; len: %d", file_encryption_method, key->klen); + + BufDecCtx = pg_cipher_ctx_create(EncryptionAlgorithm(file_encryption_method), + (unsigned char *) key->key, + EncryptionBlockLength(file_encryption_method), + false); + if (!BufDecCtx) + my_error("cannot initialize decryption context"); + + file_encryption_tag_size = SizeOfEncryptionTag(file_encryption_method); + file_encryption_page_size = SizeOfPageEncryption(file_encryption_method); +} + +/* Encrypt the given page with the relation key */ +void +EncryptPage(Page page, bool relation_is_permanent, BlockNumber blkno, RelFileNumber fileno) +{ + unsigned char *ptr = (unsigned char *) page + PageEncryptOffset; + bool is_gist_page_or_similar; + int enclen; + unsigned char *tag = NULL, *aad = NULL; + int aadlen = 0; + + Assert(BufEncCtx != NULL); + + /* + * Permanent pages have valid LSNs, and non-permanent pages usually have + * invalid (not set) LSNs. (One exception are GiST fake LSNs, see below.) + * However, we need valid ones on all pages for encryption. There are too + * many places that set the page LSN for permanent pages to do the same + * for non-permanent pages, so we just set it here. + * + * Also, while permanent relations get new LSNs every time the page is + * modified, for non-permanent relations do not, so we just update the LSN + * here before it is encrypted. + * + * GiST indexes uses LSNs, which are also stored in NSN fields, to detect + * page splits. Therefore, we allow the GiST code to assign LSNs and we + * don't change them here. + */ + + /* Permanent relations should already have valid LSNs. */ + Assert(!XLogRecPtrIsInvalid(PageGetLSN(page)) || !relation_is_permanent); + + /* + * Check if the page has a special size == GISTPageOpaqueData, a valid + * GIST_PAGE_ID, no invalid GiST flag bits are set, and a valid LSN. This + * is true for all GiST pages, and perhaps a few pages that are not. The + * only downside of guessing wrong is that we might not update the LSN for + * some non-permanent relation page changes, and therefore reuse the IV, + * which seems acceptable. + */ + is_gist_page_or_similar = + (PageGetSpecialSize(page) == MAXALIGN(sizeof(GISTPageOpaqueData)) && + GistPageGetOpaque(page)->gist_page_id == GIST_PAGE_ID && + (GistPageGetOpaque(page)->flags & ~GIST_FLAG_BITMASK) == 0 && + !XLogRecPtrIsInvalid(PageGetLSN(page))); + + if (!relation_is_permanent && !is_gist_page_or_similar) + PageSetLSN(page, LSNForEncryption(relation_is_permanent)); + + set_buffer_encryption_iv(page, blkno, relation_is_permanent); + + /* setup tag and AAD */ + if (file_encryption_tag_size > 0) + { + tag = (unsigned char*)page + BLCKSZ - file_encryption_tag_size; + setup_additional_authenticated_data(page, blkno, relation_is_permanent, fileno); + aad = (unsigned char *)&auth_data; + aadlen = sizeof(AdditionalAuthenticatedData); + } + + if (unlikely(!pg_cipher_encrypt(BufEncCtx, EncryptionAlgorithm(file_encryption_method), + (const unsigned char *) ptr, /* input */ + file_encryption_page_size, + ptr, /* length */ + &enclen, /* resulting length */ + buf_encryption_iv, /* iv */ + BUFENC_IV_SIZE, + aad, aadlen, /* AAD */ + tag, file_encryption_tag_size))) + my_error("cannot encrypt page %u", blkno); + + Assert(enclen == file_encryption_page_size); +} + +/* Decrypt the given page with the relation key */ +void +DecryptPage(Page page, bool relation_is_permanent, BlockNumber blkno, RelFileNumber fileno) +{ + unsigned char *ptr = (unsigned char *) page + PageEncryptOffset; + int enclen; + unsigned char *tag = NULL, *aad = NULL; + int aadlen = 0; + + Assert(BufDecCtx != NULL); + + set_buffer_encryption_iv(page, blkno, relation_is_permanent); + + /* setup tag and AAD */ + if (file_encryption_tag_size > 0) + { + tag = (unsigned char*)page + BLCKSZ - file_encryption_tag_size; + setup_additional_authenticated_data(page, blkno, relation_is_permanent, fileno); + aad = (unsigned char *)&auth_data; + aadlen = sizeof(AdditionalAuthenticatedData); + } + + if (unlikely(!pg_cipher_decrypt(BufDecCtx, EncryptionAlgorithm(file_encryption_method), + (const unsigned char *) ptr, /* input */ + file_encryption_page_size, + ptr, /* output */ + &enclen, /* resulting length */ + buf_encryption_iv, /* iv */ + BUFENC_IV_SIZE, + aad, aadlen, /* AAD */ + tag, file_encryption_tag_size))) + my_error("cannot decrypt page %u", blkno); + + Assert(enclen == file_encryption_page_size); +} + +/* Construct iv for the given page */ +static void +set_buffer_encryption_iv(Page page, BlockNumber blkno, + bool relation_is_permanent) +{ + 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); + + /* + * Mark use of fake LSNs in IV so if the real and fake LSN counters + * overlap, the IV will remain unique. XXX Is there a better value? + */ + if (!relation_is_permanent) + *p++ = 0x80; + +} + +/* setup aad for given page; private struct so we don't care */ +static void +setup_additional_authenticated_data(Page page, BlockNumber blkno, + bool relation_is_permanent, RelFileNumber fileno) +{ + /* snarf the existing unencrypted bits of the page header */ + memcpy(&auth_data.data, page, PageEncryptOffset); + auth_data.fileno = fileno; + auth_data.blkNo = blkno; +} diff --git a/src/backend/crypto/ckey_aws.sh.sample b/src/backend/crypto/ckey_aws.sh.sample new file mode 100644 index 0000000000..d9bee53132 --- /dev/null +++ b/src/backend/crypto/ckey_aws.sh.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# This uses the AWS Secrets Manager using the AWS CLI and OpenSSL. +# This stores the AWS secret Id in $DIR. +# Do not create any file with extension "wkey" in $DIR; these are +# reserved for wrapped data key files. + +[ "$#" -ne 1 ] && echo "cluster_key_command usage: $0 \"%d\"" 1>&2 && exit 1 +# No need for %R or -R since we are not prompting + +DIR="$1" +[ ! -e "$DIR" ] && echo "$DIR does not exist" 1>&2 && exit 1 +[ ! -d "$DIR" ] && echo "$DIR is not a directory" 1>&2 && exit 1 + +# File containing the id of the AWS secret +AWS_ID_FILE="$DIR/aws-secret.id" + + +# ---------------------------------------------------------------------- + + +# Create an AWS Secrets Manager secret? +if [ ! -e "$AWS_ID_FILE" ] +then # The 'postgres' operating system user must have permission to + # access the AWS CLI + + # The epoch-time/directory/hostname combination is unique + HASH=$(echo -n "$(date '+%s')$DIR$(hostname)" | sha1sum | cut -d' ' -f1) + AWS_SECRET_ID="Postgres-cluster-key-$HASH" + + # Use stdin to avoid passing the secret on the command line + openssl rand -hex 32 | + aws secretsmanager create-secret \ + --name "$AWS_SECRET_ID" \ + --description "Postgres cluster file encryption on $(hostname)" \ + --secret-string 'file:///dev/stdin' \ + --output text > /dev/null + if [ "$?" -ne 0 ] + then echo 'cluster key generation failed' 1>&2 + exit 1 + fi + + echo "$AWS_SECRET_ID" > "$AWS_ID_FILE" +fi + +if ! aws secretsmanager get-secret-value \ + --secret-id "$(cat "$AWS_ID_FILE")" \ + --output text +then echo 'cluster key retrieval failed' 1>&2 + exit 1 +fi | awk -F'\t' 'NR == 1 {print $4}' + +exit 0 diff --git a/src/backend/crypto/ckey_direct.sh.sample b/src/backend/crypto/ckey_direct.sh.sample new file mode 100644 index 0000000000..492defcffe --- /dev/null +++ b/src/backend/crypto/ckey_direct.sh.sample @@ -0,0 +1,39 @@ +#!/bin/sh + +# This uses a 64-character hex key supplied by the user. +# If OpenSSL is installed, you can generate a pseudo-random key by running: +# openssl rand -hex 32 +# To get a true random key, run: +# wget -q -O - 'https://www.random.org/cgi-bin/randbyte?nbytes=32&format=h' | tr -d ' \n'; echo +# Do not create any fie with extension "wkey" in $DIR; these are +# reserved for wrapped data key files. + +[ "$#" -lt 1 ] && echo "cluster_key_command usage: $0 %R [%p]" 1>&2 && exit 1 +# Supports environment variable PROMPT + +FD="$1" +[ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 + +[ "$2" ] && PROMPT="$2" + + +# ---------------------------------------------------------------------- + +[ ! "$PROMPT" ] && PROMPT='Enter cluster key as 64 hexadecimal characters: ' + +stty -echo <&"$FD" + +echo 1>&"$FD" +echo -n "$PROMPT" 1>&"$FD" +read KEY <&"$FD" + +stty echo <&"$FD" + +if [ "$(expr "$KEY" : '[0-9a-fA-F]*$')" -ne 64 ] +then echo 'invalid; must be 64 hexadecimal characters' 1>&2 + exit 1 +fi + +echo "$KEY" + +exit 0 diff --git a/src/backend/crypto/ckey_passphrase.sh.sample b/src/backend/crypto/ckey_passphrase.sh.sample new file mode 100644 index 0000000000..a5d837b45e --- /dev/null +++ b/src/backend/crypto/ckey_passphrase.sh.sample @@ -0,0 +1,35 @@ +#!/bin/sh + +# This uses a passphrase supplied by the user. +# Do not create any fie with extension "wkey" in $DIR; these are +# reserved for wrapped data key files. + +[ "$#" -lt 1 ] && echo "cluster_key_command usage: $0 %R [\"%p\"]" 1>&2 && exit 1 + +FD="$1" +[ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 +# Supports environment variable PROMPT + +[ "$2" ] && PROMPT="$2" + + +# ---------------------------------------------------------------------- + +[ ! "$PROMPT" ] && PROMPT='Enter cluster passphrase: ' + +stty -echo <&"$FD" + +echo 1>&"$FD" +echo -n "$PROMPT" 1>&"$FD" +read PASS <&"$FD" + +stty echo <&"$FD" + +if [ ! "$PASS" ] +then echo 'invalid: empty passphrase' 1>&2 + exit 1 +fi + +echo "$PASS" | sha256sum | cut -d' ' -f1 + +exit 0 diff --git a/src/backend/crypto/ckey_piv_nopin.sh.sample b/src/backend/crypto/ckey_piv_nopin.sh.sample new file mode 100644 index 0000000000..e90a579dea --- /dev/null +++ b/src/backend/crypto/ckey_piv_nopin.sh.sample @@ -0,0 +1,68 @@ +#!/bin/sh + +# This uses the public/private keys on a PIV device, like a CAC or Yubikey. +# It uses a PIN stored in a file. +# It uses OpenSSL with PKCS11 enabled via OpenSC. +# This stores the cluster encryption key encrypted with the PIV public +# key in $DIR. This is technically a three-level encryption +# architecture, with the third level requiring the PIV and PIN. +# Do not create any fie with extension "wkey" in $DIR; these are +# reserved for wrapped data key files. + +[ "$#" -ne 1 ] && echo "cluster_key_command usage: $0 \"%d\"" 1>&2 && exit 1 +# Supports environment variable PIV_PIN_FILE +# No need for %R or -R since we are not prompting for a PIN + +DIR="$1" +[ ! -e "$DIR" ] && echo "$DIR does not exist" 1>&2 && exit 1 +[ ! -d "$DIR" ] && echo "$DIR is not a directory" 1>&2 && exit 1 + +# Set these here or pass in as environment variables. +# File that stores the PIN to unlock the PIV +#PIV_PIN_FILE='' +# PIV slot 3 is the "Key Management" slot, so we use '0:3' +PIV_SLOT='0:3' + +# File containing the cluster key encrypted with the PIV_SLOT's public key +KEY_FILE="$DIR/pivpass.key" + + +# ---------------------------------------------------------------------- + +[ ! "$PIV_PIN_FILE" ] && echo 'PIV_PIN_FILE undefined' 1>&2 && exit 1 +[ ! -e "$PIV_PIN_FILE" ] && echo "$PIV_PIN_FILE does not exist" 1>&2 && exit 1 +[ -d "$PIV_PIN_FILE" ] && echo "$PIV_PIN_FILE is a directory" 1>&2 && exit 1 + +[ ! "$KEY_FILE" ] && echo 'KEY_FILE undefined' 1>&2 && exit 1 +[ -d "$KEY_FILE" ] && echo "$KEY_FILE is a directory" 1>&2 && exit 1 + +# Create a cluster key encrypted with the PIV_SLOT's public key? +if [ ! -e "$KEY_FILE" ] +then # The 'postgres' operating system user must have permission to + # access the PIV device. + + openssl rand -hex 32 | + if ! openssl rsautl -engine pkcs11 -keyform engine -encrypt \ + -inkey "$PIV_SLOT" -passin file:"$PIV_PIN_FILE" -out "$KEY_FILE" + then echo 'cluster key generation failed' 1>&2 + exit 1 + fi + + # Warn the user to save the cluster key in a safe place + cat 1>&2 <&2 + exit 1 +fi + +exit 0 diff --git a/src/backend/crypto/ckey_piv_pin.sh.sample b/src/backend/crypto/ckey_piv_pin.sh.sample new file mode 100644 index 0000000000..e693ac31ba --- /dev/null +++ b/src/backend/crypto/ckey_piv_pin.sh.sample @@ -0,0 +1,81 @@ +#!/bin/sh + +# This uses the public/private keys on a PIV device, like a CAC or Yubikey. +# It requires a user-entered PIN. +# It uses OpenSSL with PKCS11 enabled via OpenSC. +# This stores the cluster encryption key encrypted with the PIV public +# key in $DIR. This is technically a three-level encryption +# architecture, with the third level requiring the PIV and PIN. +# Do not create any fie with extension "wkey" in $DIR; these are +# reserved for wrapped data key files. + +[ "$#" -lt 2 ] && echo "cluster_key_command usage: $0 \"%d\" %R [\"%p\"]" 1>&2 && exit 1 +# Supports environment variable PROMPT + +DIR="$1" +[ ! -e "$DIR" ] && echo "$DIR does not exist" 1>&2 && exit 1 +[ ! -d "$DIR" ] && echo "$DIR is not a directory" 1>&2 && exit 1 + +FD="$2" +[ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 + +[ "$3" ] && PROMPT="$3" + +# PIV slot 3 is the "Key Management" slot, so we use '0:3' +PIV_SLOT='0:3' + +# File containing the cluster key encrypted with the PIV_SLOT's public key +KEY_FILE="$DIR/pivpass.key" + + +# ---------------------------------------------------------------------- + +[ ! "$PROMPT" ] && PROMPT='Enter PIV PIN: ' + +stty -echo <&"$FD" + +# Create a cluster key encrypted with the PIV_SLOT's public key? +if [ ! -e "$KEY_FILE" ] +then echo 1>&"$FD" + echo -n "$PROMPT" 1>&"$FD" + + # The 'postgres' operating system user must have permission to + # access the PIV device. + + openssl rand -hex 32 | + # 'engine "pkcs11" set.' message confuses prompting + if ! openssl rsautl -engine pkcs11 -keyform engine -encrypt \ + -inkey "$PIV_SLOT" -passin fd:"$FD" -out "$KEY_FILE" 2>&1 + then stty echo <&"$FD" + echo 'cluster key generation failed' 1>&2 + exit 1 + fi | grep -v 'engine "pkcs11" set\.' + + echo 1>&"$FD" + + # Warn the user to save the cluster key in a safe place + cat 1>&"$FD" <&"$FD" +echo -n "$PROMPT" 1>&"$FD" + +# Decrypt the cluster key encrypted with the PIV_SLOT's public key +if ! openssl rsautl -engine pkcs11 -keyform engine -decrypt \ + -inkey "$PIV_SLOT" -passin fd:"$FD" -in "$KEY_FILE" 2>&1 +then stty echo <&"$FD" + echo 'cluster key retrieval failed' 1>&2 + exit 1 +fi | grep -v 'engine "pkcs11" set\.' + +echo 1>&"$FD" + +stty echo <&"$FD" + +exit 0 diff --git a/src/backend/crypto/kmgr.c b/src/backend/crypto/kmgr.c new file mode 100644 index 0000000000..a5b74f990f --- /dev/null +++ b/src/backend/crypto/kmgr.c @@ -0,0 +1,442 @@ +/*------------------------------------------------------------------------- + * + * kmgr.c + * Cluster file encryption routines + * + * Cluster file encryption is enabled if user requests it during initdb. + * During bootstrap, we generate data encryption keys, wrap them with the + * cluster-level key, and store them into each file located at KMGR_DIR. + * During startup, we decrypt all internal keys and load them to the shared + * memory. Internal keys in the shared memory are read-only. The wrapping + * and unwrapping key routines require the OpenSSL library. + * + * Copyright (c) 2021, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/crypto/kmgr.c + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include +#include + +#include "funcapi.h" +#include "miscadmin.h" +#include "pgstat.h" + +#include "access/xlog.h" +#include "common/file_perm.h" +#include "common/kmgr_utils.h" +#include "common/sha2.h" +#include "access/xlog.h" +#include "common/controldata_utils.h" +#include "crypto/kmgr.h" +#include "crypto/bufenc.h" + +#include "postmaster/postmaster.h" +#include "storage/copydir.h" +#include "storage/fd.h" +#include "storage/ipc.h" +#include "storage/shmem.h" +#include "utils/builtins.h" +#include "utils/memutils.h" +/* Struct stores file encryption keys in plaintext format */ +typedef struct KmgrShmemData +{ + CryptoKey intlKeys[KMGR_NUM_DATA_KEYS]; +} KmgrShmemData; +static KmgrShmemData *KmgrShmem; + +/* GUC variables */ +char *cluster_key_command = NULL; + +CryptoKey bootstrap_keys[KMGR_NUM_DATA_KEYS]; + +extern char *bootstrap_old_key_datadir; +extern int bootstrap_file_encryption_method; + +static void bzeroKmgrKeys(int status, Datum arg); +static void KmgrWriteCryptoKeys(const char *dir, unsigned char **keys, int *key_lens); +static CryptoKey *generate_crypto_key(int len); + +/* + * This function must be called ONCE during initdb. It creates the DEK + * files wrapped with the KEK supplied by kmgr_run_cluster_key_command(). + * There is also an option for the keys to be copied from another cluster. + */ +void +BootStrapKmgr(void) +{ + char live_path[MAXPGPATH]; + unsigned char *keys_wrap[KMGR_NUM_DATA_KEYS]; + int key_lens[KMGR_NUM_DATA_KEYS]; + char cluster_key_hex[ALLOC_KMGR_CLUSTER_KEY_MAX_LEN]; + int cluster_key_hex_len; + unsigned char cluster_key[KMGR_CLUSTER_KEY_MAX_LEN]; + + if (!FileEncryptionEnabled) + return; + +#ifndef USE_OPENSSL + ereport(ERROR, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + (errmsg("cluster file encryption is not supported because OpenSSL is not supported by this build"), + errhint("Compile with --with-openssl to use this feature.")))); +#endif + + /* + * There are too many optimizations for wal_level=minimal that don't set + * LSNs for permanent tables, so just disallow it. + */ + if (!XLogIsNeeded()) + ereport(ERROR, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + (errmsg("cluster file encryption is not supported with a wal_level of \"minimal\"")))); + + snprintf(live_path, sizeof(live_path), "%s/%s", DataDir, LIVE_KMGR_DIR); + + /* + * Copy cluster file encryption keys from an old cluster? This is useful + * for pg_upgrade upgrades where the copied database files are already + * encrypted using the old cluster's DEK keys. + */ + if (bootstrap_old_key_datadir != NULL) + { + char old_key_dir[MAXPGPATH]; + + snprintf(old_key_dir, sizeof(old_key_dir), "%s/%s", + bootstrap_old_key_datadir, LIVE_KMGR_DIR); + copydir(old_key_dir, LIVE_KMGR_DIR, true); + } + /* create an empty directory */ + else + { + if (mkdir(LIVE_KMGR_DIR, pg_dir_create_mode) < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not create cluster file encryption directory \"%s\": %m", + LIVE_KMGR_DIR))); + } + + /* + * Get key encryption key (KEK) from the cluster_key command. The cluster + * key command might need to check for the existence of files in the live + * directory, e.g., PIV, so run this _after_ copying the directory in + * place. + */ + cluster_key_hex_len = kmgr_run_cluster_key_command(cluster_key_command, + cluster_key_hex, + ALLOC_KMGR_CLUSTER_KEY_MAX_LEN, + live_path, terminal_fd); + + /* decode supplied hex */ + if (hex_decode(cluster_key_hex, cluster_key_hex_len, + (char *) cluster_key) != + KMGR_KEK_KEY_LEN) + ereport(ERROR, + (errmsg("cluster key must be %d hexadecimal characters", + KMGR_KEK_KEY_LEN * 2))); + + /* We are not in copy mode? Generate new cluster file encryption keys. */ + if (bootstrap_old_key_datadir == NULL) + { + unsigned char *bootstrap_keys_wrap[KMGR_NUM_DATA_KEYS]; + PgCipherCtx *cluster_key_ctx; + + /* Create KEK encryption context */ + cluster_key_ctx = pg_cipher_ctx_create(PG_CIPHER_AES_KWP, cluster_key, + KMGR_KEK_KEY_LEN, true); + if (!cluster_key_ctx) + elog(ERROR, "could not initialize encryption context"); + + /* Wrap data encryption keys (DEK) using the key encryption key (KEK) */ + for (int id = 0; id < KMGR_NUM_DATA_KEYS; id++) + { + CryptoKey *key; + + /* generate a DEK */ + key = generate_crypto_key( + encryption_methods[bootstrap_file_encryption_method].key_length); + + /* output generated random string as hex, for testing */ + { + char str[MAXPGPATH]; + int out_len; + + out_len = hex_encode((char *) (key->key), key->klen, + str); + str[out_len] = '\0'; + } + + bootstrap_keys_wrap[id] = palloc0(KMGR_MAX_KEY_LEN_BYTES + + pg_cipher_blocksize(cluster_key_ctx)); + + /* wrap DEK with KEK */ + if (!kmgr_wrap_data_key(cluster_key_ctx, key, bootstrap_keys_wrap[id], &(key_lens[id]))) + { + pg_cipher_ctx_free(cluster_key_ctx); + elog(ERROR, "failed to wrap data encryption key"); + } + + /* remove DEK from memory */ + explicit_bzero(key, sizeof(CryptoKey)); + } + + /* Write data encryption keys to the disk */ + KmgrWriteCryptoKeys(LIVE_KMGR_DIR, bootstrap_keys_wrap, key_lens); + + pg_cipher_ctx_free(cluster_key_ctx); + } + + /* + * We are either decrypting keys we copied from an old cluster, or + * decrypting keys we just wrote above --- either way, we decrypt them + * here and store them in a file-scoped variable for use in later + * encrypting during bootstrap mode. + */ + + /* Get the crypto keys from the live directory */ + kmgr_read_wrapped_data_keys(LIVE_KMGR_DIR, keys_wrap, key_lens); + + if (!kmgr_verify_cluster_key(cluster_key, keys_wrap, key_lens, bootstrap_keys)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("supplied cluster key does not match expected cluster_key"))); + + /* bzero DEK on exit */ + on_proc_exit(bzeroKmgrKeys, 0); + + /* bzero KEK */ + explicit_bzero(cluster_key_hex, cluster_key_hex_len); + explicit_bzero(cluster_key, KMGR_CLUSTER_KEY_LEN(GetFileEncryptionMethod())); +} + +/* Report shared-memory space needed by KmgrShmem */ +Size +KmgrShmemSize(void) +{ + if (!FileEncryptionEnabled) + return 0; + + return MAXALIGN(sizeof(KmgrShmemData)); +} + +/* Allocate and initialize key manager memory */ +void +KmgrShmemInit(void) +{ + bool found; + + if (!FileEncryptionEnabled) + return; + + KmgrShmem = (KmgrShmemData *) ShmemInitStruct("File encryption key manager", + KmgrShmemSize(), &found); + + /* bzero DEK on exit */ + on_shmem_exit(bzeroKmgrKeys, 0); +} + +/* + * Get cluster key and verify it, then get the data encryption keys. + * This function is called by postmaster at startup time. + */ +void +InitializeKmgr(void) +{ + unsigned char *keys_wrap[KMGR_NUM_DATA_KEYS]; + int key_lens[KMGR_NUM_DATA_KEYS]; + char cluster_key_hex[ALLOC_KMGR_CLUSTER_KEY_MAX_LEN]; + int cluster_key_hex_len; + struct stat buffer; + char live_path[MAXPGPATH]; + unsigned char cluster_key[KMGR_CLUSTER_KEY_MAX_LEN]; + + if (!FileEncryptionEnabled) + return; + +#ifndef USE_OPENSSL + ereport(ERROR, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + (errmsg("cluster file encryption is not supported because OpenSSL is not supported by this build"), + errhint("Compile with --with-openssl to use this feature.")))); +#endif + + /* + * There are too many optimizations for wal_level=minimal that don't set + * LSNs for permanent tables, so just disallow it. + */ + if (!XLogIsNeeded()) + ereport(ERROR, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + (errmsg("cluster file encryption is not supported with a wal_level of \"minimal\"")))); + + elog(DEBUG1, "starting up cluster file encryption manager"); + + if (stat(KMGR_DIR, &buffer) != 0 || !S_ISDIR(buffer.st_mode)) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + (errmsg("cluster file encryption directory %s is missing", KMGR_DIR)))); + + if (stat(KMGR_DIR_PID, &buffer) == 0) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + (errmsg("cluster had a pg_alterckey failure that needs repair or pg_alterckey is running"), + errhint("Run pg_alterckey --repair or wait for it to complete.")))); + + /* + * We want OLD deleted since it allows access to the data encryption keys + * using the old cluster key. If NEW exists, it means either the new + * directory is partly written, or NEW wasn't renamed to LIVE --- in + * either case, it needs to be repaired. See src/bin/pg_alterckey/README + * for more details. + */ + if (stat(OLD_KMGR_DIR, &buffer) == 0 || stat(NEW_KMGR_DIR, &buffer) == 0) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + (errmsg("cluster had a pg_alterckey failure that needs repair"), + errhint("Run pg_alterckey --repair.")))); + + /* If OLD, NEW, and LIVE do not exist, there is a serious problem. */ + if (stat(LIVE_KMGR_DIR, &buffer) != 0 || !S_ISDIR(buffer.st_mode)) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + (errmsg("cluster has no data encryption keys")))); + + /* Get the cluster key (KEK) */ + snprintf(live_path, sizeof(live_path), "%s/%s", DataDir, LIVE_KMGR_DIR); + cluster_key_hex_len = kmgr_run_cluster_key_command(cluster_key_command, + cluster_key_hex, + ALLOC_KMGR_CLUSTER_KEY_MAX_LEN, + live_path, terminal_fd); + + /* decode supplied hex */ + if (hex_decode(cluster_key_hex, cluster_key_hex_len, + (char *) cluster_key) != + KMGR_KEK_KEY_LEN) + ereport(ERROR, + (errmsg("cluster key must be %d hexadecimal characters", + KMGR_KEK_KEY_LEN * 2))); + + /* Load wrapped DEKs from their files into an array */ + kmgr_read_wrapped_data_keys(LIVE_KMGR_DIR, keys_wrap, key_lens); + + /* + * Verify cluster key and store the unwrapped data encryption keys in + * shared memory. + */ + if (!kmgr_verify_cluster_key(cluster_key, keys_wrap, key_lens, KmgrShmem->intlKeys)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("supplied cluster key does not match expected cluster key"))); + + /* Check that retrieved key lengths match controldata length. */ + for (int id = 0; id < KMGR_NUM_DATA_KEYS; id++) + if (KmgrShmem->intlKeys[id].klen != + encryption_methods[GetFileEncryptionMethod()].key_length) + { + char path[MAXPGPATH]; + + CryptoKeyFilePath(path, DataDir, id); + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("data encryption key %s of length %d does not match controldata key length %d", + path, KmgrShmem->intlKeys[id].klen, + encryption_methods[GetFileEncryptionMethod()].key_length))); + } + + /* bzero KEK */ + explicit_bzero(cluster_key_hex, cluster_key_hex_len); + explicit_bzero(cluster_key, KMGR_CLUSTER_KEY_LEN(GetFileEncryptionMethod())); +} + +static void +bzeroKmgrKeys(int status, Datum arg) +{ + if (IsBootstrapProcessingMode()) + explicit_bzero(bootstrap_keys, sizeof(bootstrap_keys)); + else + explicit_bzero(KmgrShmem->intlKeys, sizeof(KmgrShmem->intlKeys)); +} + +/* return requested DEK */ +const CryptoKey * +KmgrGetKey(int id) +{ + Assert(id < KMGR_NUM_DATA_KEYS); + + return (const CryptoKey *) (IsBootstrapProcessingMode() ? + &(bootstrap_keys[id]) : &(KmgrShmem->intlKeys[id])); +} + +/* Generate a DEK inside a CryptoKey */ +static CryptoKey * +generate_crypto_key(int len) +{ + CryptoKey *newkey; + + Assert(len <= KMGR_MAX_KEY_LEN); + newkey = (CryptoKey *) palloc0(sizeof(CryptoKey)); + + newkey->klen = len; + + if (!pg_strong_random(newkey->key, len)) + elog(ERROR, "failed to generate new file encryption key"); + + return newkey; +} + +/* + * Write the DEKs to the disk. + */ +static void +KmgrWriteCryptoKeys(const char *dir, unsigned char **keys, int *key_lens) +{ + elog(DEBUG2, "writing data encryption keys wrapped using the cluster key"); + + for (int i = 0; i < KMGR_NUM_DATA_KEYS; i++) + { + int fd; + char path[MAXPGPATH]; + + CryptoKeyFilePath(path, dir, i); + + if ((fd = BasicOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY)) < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open file \"%s\": %m", + path))); + + errno = 0; + pgstat_report_wait_start(WAIT_EVENT_KEY_FILE_WRITE); + if (write(fd, keys[i], key_lens[i]) != key_lens[i]) + { + /* if write didn't set errno, assume problem is no disk space */ + if (errno == 0) + errno = ENOSPC; + + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not write file \"%s\": %m", + path))); + } + pgstat_report_wait_end(); + + pgstat_report_wait_start(WAIT_EVENT_KEY_FILE_SYNC); + if (pg_fsync(fd) != 0) + ereport(PANIC, + (errcode_for_file_access(), + errmsg("could not fsync file \"%s\": %m", + path))); + pgstat_report_wait_end(); + + if (close(fd) != 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not close file \"%s\": %m", + path))); + } +} diff --git a/src/backend/crypto/meson.build b/src/backend/crypto/meson.build new file mode 100644 index 0000000000..2b72b26ebf --- /dev/null +++ b/src/backend/crypto/meson.build @@ -0,0 +1,14 @@ +backend_sources += files( + 'bufenc.c', + 'kmgr.c', +) + +install_data( + 'ckey_aws.sh.sample', + 'ckey_direct.sh.sample', + 'ckey_passphrase.sh.sample', + 'ckey_piv_nopin.sh.sample', + 'ckey_piv_pin.sh.sample', + 'ssl_passphrase.sh.sample', + install_dir: dir_data / 'auth_commands', +) diff --git a/src/backend/crypto/ssl_passphrase.sh.sample b/src/backend/crypto/ssl_passphrase.sh.sample new file mode 100644 index 0000000000..efbf5c0720 --- /dev/null +++ b/src/backend/crypto/ssl_passphrase.sh.sample @@ -0,0 +1,35 @@ +#!/bin/sh + +# This uses a passphrase supplied by the user. +# Do not create any fie with extension "wkey" in $DIR; these are +# reserved for wrapped data key files. + +[ "$#" -lt 1 ] && echo "ssl_passphrase_command usage: $0 %R [\"%p\"]" 1>&2 && exit 1 + +FD="$1" +[ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 +# Supports environment variable PROMPT + +[ "$2" ] && PROMPT="$2" + + +# ---------------------------------------------------------------------- + +[ ! "$PROMPT" ] && PROMPT='Enter cluster passphrase: ' + +stty -echo <&"$FD" + +echo 1>&"$FD" +echo -n "$PROMPT" 1>&"$FD" +read PASS <&"$FD" + +stty echo <&"$FD" + +if [ ! "$PASS" ] +then echo 'invalid: empty passphrase' 1>&2 + exit 1 +fi + +echo "$PASS" + +exit 0 diff --git a/src/backend/libpq/be-secure-common.c b/src/backend/libpq/be-secure-common.c index ab5e2dfa2b..5244657832 100644 --- a/src/backend/libpq/be-secure-common.c +++ b/src/backend/libpq/be-secure-common.c @@ -23,6 +23,7 @@ #include #include "common/percentrepl.h" +#include "postmaster/postmaster.h" #include "common/string.h" #include "libpq/libpq.h" #include "storage/fd.h" @@ -44,12 +45,17 @@ run_ssl_passphrase_command(const char *prompt, bool is_server_start, char *buf, FILE *fh; int pclose_rc; size_t len = 0; + char fd_str[20]; Assert(prompt); Assert(size > 0); buf[0] = '\0'; - command = replace_percent_placeholders(ssl_passphrase_command, "ssl_passphrase_command", "p", prompt); + fd_str[0] = 0; + if (terminal_fd != -1) + snprintf(fd_str, sizeof(fd_str), "%d", terminal_fd); + + command = replace_percent_placeholders(ssl_passphrase_command, "ssl_passphrase_command", "pR", prompt, fd_str); fh = OpenPipeStream(command, "r"); if (fh == NULL) diff --git a/src/backend/main/main.c b/src/backend/main/main.c index ed11e8be7f..3de07ee9c1 100644 --- a/src/backend/main/main.c +++ b/src/backend/main/main.c @@ -344,6 +344,7 @@ help(const char *progname) #endif printf(_(" -N MAX-CONNECT maximum number of allowed connections\n")); printf(_(" -p PORT port number to listen on\n")); + printf(_(" -R fd prompt for the cluster key\n")); printf(_(" -s show statistics after each query\n")); printf(_(" -S WORK-MEM set amount of memory for sorts (in kB)\n")); printf(_(" -V, --version output version information, then exit\n")); @@ -371,7 +372,9 @@ help(const char *progname) printf(_(" --boot selects bootstrapping mode (must be first argument)\n")); printf(_(" --check selects check mode (must be first argument)\n")); printf(_(" DBNAME database name (mandatory argument in bootstrapping mode)\n")); + printf(_(" -K LEN enable cluster file encryption with specified key bit length\n")); printf(_(" -r FILENAME send stdout and stderr to given file\n")); + printf(_(" -u DATADIR copy encryption keys from datadir\n")); printf(_("\nPlease read the documentation for the complete list of run-time\n" "configuration settings and how to set them on the command line or in\n" diff --git a/src/backend/meson.build b/src/backend/meson.build index 88a35e9676..c6c157e7b6 100644 --- a/src/backend/meson.build +++ b/src/backend/meson.build @@ -13,6 +13,7 @@ subdir('backup') subdir('bootstrap') subdir('catalog') subdir('commands') +subdir('crypto') subdir('executor') subdir('foreign') subdir('jit') diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 7b6b613c4a..4040aee0ec 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -98,6 +98,8 @@ #include "common/ip.h" #include "common/pg_prng.h" #include "common/string.h" +#include "crypto/bufenc.h" +#include "crypto/kmgr.h" #include "lib/ilist.h" #include "libpq/auth.h" #include "libpq/libpq.h" @@ -232,6 +234,7 @@ static pgsocket *ListenSockets = NULL; /* still more option variables */ bool EnableSSL = false; +int terminal_fd = -1; int PreAuthDelay = 0; int AuthenticationTimeout = 60; @@ -688,7 +691,7 @@ PostmasterMain(int argc, char *argv[]) * tcop/postgres.c (the option sets should not conflict) and with the * common help() function in main/main.c. */ - while ((opt = getopt(argc, argv, "B:bC:c:D:d:EeFf:h:ijk:lN:OPp:r:S:sTt:W:-:")) != -1) + while ((opt = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:OPp:r:R:S:sTt:W:-:")) != -1) { switch (opt) { @@ -801,6 +804,10 @@ PostmasterMain(int argc, char *argv[]) /* only used by single-user backend */ break; + case 'R': + terminal_fd = atoi(optarg); + break; + case 'S': SetConfigOption("work_mem", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; @@ -1337,6 +1344,12 @@ PostmasterMain(int argc, char *argv[]) pfree(rawstring); } + InitializeKmgr(); + InitializeBufferEncryption(GetFileEncryptionMethod()); + + if (terminal_fd != -1) + close(terminal_fd); + /* * check that we have some socket to listen on */ diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 1237118e84..c56c5be076 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -191,6 +191,7 @@ xlog_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) case XLOG_FPI: case XLOG_OVERWRITE_CONTRECORD: case XLOG_CHECKPOINT_REDO: + case XLOG_ENCRYPTION_LSN: break; default: elog(ERROR, "unexpected RM_XLOG_ID record type: %u", info); diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index dc504a1ae0..aec6e95978 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -39,6 +39,7 @@ #include "catalog/catalog.h" #include "catalog/storage.h" #include "catalog/storage_xlog.h" +#include "crypto/bufenc.h" #include "executor/instrument.h" #include "lib/binaryheap.h" #include "miscadmin.h" @@ -1127,7 +1128,10 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, IOOP_READ, io_start, 1); /* check for garbage data */ - if (!PageIsVerifiedExtended((Page) bufBlock, blockNum, + if (!PageIsVerifiedExtended((Page) bufBlock, forkNum, + relpersistence == RELPERSISTENCE_PERMANENT, + blockNum, + smgr->smgr_rlocator.locator.relNumber, PIV_LOG_WARNING | PIV_REPORT_STAT)) { if (mode == RBM_ZERO_ON_ERROR || zero_damaged_pages) @@ -3479,12 +3483,26 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, */ bufBlock = BufHdrGetBlock(buf); + if (FileEncryptionEnabled) + { + /* + * Technically BM_PERMANENT could indicate an init fork, but that's + * okay since forkNum would also tell us not to encrypt init forks. + */ + bufToWrite = PageEncryptCopy((Page) bufBlock, buf->tag.forkNum, + buf_state & BM_PERMANENT, buf->tag.blockNum, + reln->smgr_rlocator.locator.relNumber + ); + bufToWrite = PageSetChecksumCopy((Page) bufToWrite, buf->tag.blockNum); + } + else + bufToWrite = PageSetChecksumCopy((Page) bufBlock, 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); io_start = pgstat_prepare_io_time(); @@ -4142,6 +4160,11 @@ FlushRelationBuffers(Relation rel) errcallback.previous = error_context_stack; error_context_stack = &errcallback; + /* XXX should we be writing a copy of the page here? */ + PageEncryptInplace(localpage, bufHdr->tag.forkNum, + RelationIsPermanent(rel), bufHdr->tag.blockNum, + rel->rd_locator.relNumber + ); PageSetChecksumInplace(localpage, bufHdr->tag.blockNum); io_start = pgstat_prepare_io_time(); @@ -4593,11 +4616,12 @@ IncrBufferRefCount(Buffer buffer) * This is essentially the same as MarkBufferDirty, except: * * 1. The caller does not write WAL; so if checksums are enabled, we may need - * to write an XLOG_FPI_FOR_HINT WAL record to protect against torn pages. + * to write an XLOG_FPI_FOR_HINT record to protect against torn pages, or + * XLOG_ENCRYPTION_LSN to generate a new LSN for the page. * 2. The caller might have only share-lock instead of exclusive-lock on the - * buffer's content lock. + * buffer's content lock. * 3. This function does not guarantee that the buffer is always marked dirty - * (due to a race condition), so it cannot be used for important changes. + * (due to a race condition), so it cannot be used for important changes. */ void MarkBufferDirtyHint(Buffer buffer, bool buffer_std) @@ -4643,53 +4667,111 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * If we need to protect hint bit updates from torn writes, WAL-log a * full page image of the page. This full page image is only necessary * if the hint bit update is the first change to the page since the - * last checkpoint. + * last checkpoint. If cluster file encryption is enabled, we also + * need to generate new page LSNs for all other cases of page writes. * * We don't check full_page_writes here because that logic is included * when we call XLogInsert() since the value changes dynamically. */ - if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + if (XLogHintBitIsNeeded()) { /* - * If we must not write WAL, due to a relfilelocator-specific - * condition or being in recovery, don't dirty the page. We can - * set the hint, just not dirty the page as a result so the hint - * is lost when we evict the page or shutdown. + * If we must not write WAL during recovery so don't dirty the page. + * We can set the hint, just not dirty the page as a result so the + * hint is lost when we evict the page or shutdown. * * See src/backend/storage/page/README for longer discussion. */ if (RecoveryInProgress() || - RelFileLocatorSkippingWAL(BufTagGetRelFileLocator(&bufHdr->tag))) + (RelFileLocatorSkippingWAL(BufTagGetRelFileLocator(&bufHdr->tag)) && + !FileEncryptionEnabled)) return; /* - * If the block is already dirty because we either made a change - * or set a hint already, then we don't need to write a full page - * image. Note that aggressive cleaning of blocks dirtied by hint - * bit setting would increase the call rate. Bulk setting of hint - * bits would reduce the call rate... - * - * We must issue the WAL record before we mark the buffer dirty. - * Otherwise we might write the page before we write the WAL. That - * causes a race condition, since a checkpoint might occur between - * writing the WAL record and marking the buffer dirty. We solve - * that with a kluge, but one that is already in use during - * transaction commit to prevent race conditions. Basically, we - * simply prevent the checkpoint WAL record from being written - * until we have marked the buffer dirty. We don't start the - * checkpoint flush until we have marked dirty, so our checkpoint - * must flush the change to disk successfully or the checkpoint - * never gets written, so crash recovery will fix. - * - * It's possible we may enter here without an xid, so it is - * essential that CreateCheckPoint waits for virtual transactions - * rather than full transactionids. + * Non-BM_PERMANENT objects don't need full page images because + * they are not restored. WAL-skipped relfilenodes should never + * have full page images generated. */ - Assert((MyProc->delayChkptFlags & DELAY_CHKPT_START) == 0); - MyProc->delayChkptFlags |= DELAY_CHKPT_START; - delayChkptFlags = true; - lsn = XLogSaveBufferForHint(buffer, buffer_std); + if (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT && + !RelFileLocatorSkippingWAL(BufTagGetRelFileLocator(&bufHdr->tag))) + { + /* + * If the block is already dirty because we either made a change + * or set a hint already, then we don't need to write a full + * page image. Note that aggressive cleaning of blocks dirtied + * by hint bit setting would increase the call rate. Bulk + * setting of hint bits would reduce the call rate... + * + * We must issue the WAL record before we mark the buffer + * dirty. Otherwise we might write the page before we write + * the WAL. That causes a race condition, since a checkpoint + * might occur between writing the WAL record and marking the + * buffer dirty. We solve that with a kluge, but one that is + * already in use during transaction commit to prevent race + * conditions. Basically, we simply prevent the checkpoint WAL + * record from being written until we have marked the buffer + * dirty. We don't start the checkpoint flush until we have + * marked dirty, so our checkpoint must flush the change to disk + * successfully or the checkpoint never gets written, so crash + * recovery will fix. + * + * It's possible we may enter here without an xid, so it + * is essential that CreateCheckpoint waits for virtual + * transactions rather than full transactionids. + */ + MyProc->delayChkptFlags |= DELAY_CHKPT_START; + delayChkptFlags = true; + lsn = XLogSaveBufferForHint(buffer, buffer_std); + } + + /* + * Above, for hint bit changes, we might have generated a new page + * LSN and a full-page WAL record for a page's first-clean-to-dirty + * during a checkpoint for permanent, non-WAL-skipped relfilenodes. + * If we didn't (the lsn variable is invalid), and we are + * doing cluster file encryption, we must generate a new + * page LSN here for either non-permanent relations or page + * non-first-clean-to-dirty during a checkpoint. (Cluster file + * encryption does not support WAL-skip relfilenodes.) We must + * update the page LSN even if the page with the hint bit change is + * later overwritten in the file system with an earlier version of + * the page during crash recovery. + * + * XXX Can we rely on the full page write above with no lock being + * held to avoid torn pages? Above, the LSN and page image are + * tied together, but here is just the page LSN update. + */ + if (XLogRecPtrIsInvalid(lsn) && FileEncryptionEnabled) + { + /* + * For cluster file encryption we need a new page LSN because + * the LSN is used, with the page number and permanent flag, as + * part of the nonce, and the nonce must be unique for every + * page write. If we reencrypt a page with hint bit changes + * using the same nonce as previous writes, it would expose the + * hint bit change locations. To avoid this, we write a simple + * WAL record to advance the lsn, which can then be assigned to + * the page below. + * + * Above we are relying on the full page writes to revert + * any partial pages writes caused by this LSN change for + * permanent, non-WAL-skip relfilenodes. For non-permanent + * relations, they crash recover as empty. For WAL-skip + * relfilenodes, they recover with their original contents, so + * that works too. + */ + /* XXX Do we need the checkpoint delay here? */ + MyProc->delayChkptFlags |= DELAY_CHKPT_START; + delayChkptFlags = true; + /* + * XXX We probably don't need to replay this WAL on the primary + * since the full page image is restored, but do we have + * to replay this on the repicas (for relations that are + * replicated)? + */ + lsn = LSNForEncryption( + pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT); + } } buf_state = LockBufHdr(bufHdr); diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 9f20dca121..e81fe7b76b 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -181,6 +181,12 @@ GetLocalVictimBuffer(void) BufferDesc *bufHdr; ResourceOwnerEnlargeBuffers(CurrentResourceOwner); + +#ifdef LBDEBUG + fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n", + smgr->smgr_rlocator.locator.relNumber, forkNum, blockNum, + -nextFreeLocalBuf - 1); +#endif /* * Need to get a new buffer. We use a clock sweep algorithm (essentially @@ -241,6 +247,9 @@ GetLocalVictimBuffer(void) /* Find smgr relation for buffer */ oreln = smgropen(BufTagGetRelFileLocator(&bufHdr->tag), MyBackendId); + PageEncryptInplace(localpage, bufHdr->tag.forkNum, + buf_state & BM_PERMANENT, bufHdr->tag.blockNum, + bufHdr->tag.relNumber); PageSetChecksumInplace(localpage, bufHdr->tag.blockNum); io_start = pgstat_prepare_io_time(); diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c index e04bc3941a..63a85a68dd 100644 --- a/src/backend/storage/file/copydir.c +++ b/src/backend/storage/file/copydir.c @@ -21,12 +21,15 @@ #include #include +#include "crypto/bufenc.h" #include "common/file_utils.h" #include "miscadmin.h" #include "pgstat.h" #include "storage/copydir.h" #include "storage/fd.h" +extern XLogRecPtr LSNForEncryption(bool use_wal_lsn); + /* * copydir: copy a directory * @@ -71,7 +74,7 @@ copydir(const char *fromdir, const char *todir, bool recurse) copydir(fromfile, tofile, true); } else if (xlde_type == PGFILETYPE_REG) - copy_file(fromfile, tofile); + copy_file(fromfile, tofile, false); } FreeDir(xldir); @@ -114,7 +117,7 @@ copydir(const char *fromdir, const char *todir, bool recurse) * copy one file */ void -copy_file(const char *fromfile, const char *tofile) +copy_file(const char *fromfile, const char *tofile, bool encrypt_init_file) { char *buffer; int srcfd; @@ -122,9 +125,10 @@ copy_file(const char *fromfile, const char *tofile) int nbytes; off_t offset; off_t flush_offset; - /* Size of copy buffer (read and write requests) */ #define COPY_BUF_SIZE (8 * BLCKSZ) + RelFileNumber fileno = 0; + /* * Size of data flush requests. It seems beneficial on most platforms to @@ -185,6 +189,39 @@ copy_file(const char *fromfile, const char *tofile) errmsg("could not read file \"%s\": %m", fromfile))); if (nbytes == 0) break; + /* + * When we copy an init fork page to be part of an empty unlogged + * relation, its real LSN must be replaced with a fake one, and the + * page encrypted. + */ + if (encrypt_init_file) + { + Page page = (Page) buffer; + + /* fileno */ + if (!fileno) + { + /* + * Parse fileno from tofile; if we have hit this routine we + * already know we are an init fork and using a valid + * relfilenumber, so we can just backtrack to the previous + * path separator and just atoi() to get our result. + */ + + char *ptr = strrchr(tofile, '/'); + if (ptr) + fileno = atoi(ptr+1); + else + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not determine relfilenumber for init fork"))); + } + + Assert(nbytes == BLCKSZ); + PageSetLSN(page, LSNForEncryption(false)); + PageEncryptInplace(page, MAIN_FORKNUM, false, offset / BLCKSZ, fileno); + } + errno = 0; pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE); if ((int) write(dstfd, buffer, nbytes) != nbytes) diff --git a/src/backend/storage/file/reinit.c b/src/backend/storage/file/reinit.c index 5df2517b46..824f369efc 100644 --- a/src/backend/storage/file/reinit.c +++ b/src/backend/storage/file/reinit.c @@ -312,7 +312,7 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op) /* OK, we're ready to perform the actual copy. */ elog(DEBUG2, "copying %s to %s", srcpath, dstpath); - copy_file(srcpath, dstpath); + copy_file(srcpath, dstpath, true); } FreeDir(dbspace_dir); diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index a3d8eacb8d..0e836fdd04 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -25,6 +25,7 @@ #include "access/xlogprefetcher.h" #include "access/xlogrecovery.h" #include "commands/async.h" +#include "crypto/kmgr.h" #include "miscadmin.h" #include "pgstat.h" #include "postmaster/autovacuum.h" @@ -143,6 +144,7 @@ CalculateShmemSize(int *num_semaphores) size = add_size(size, AsyncShmemSize()); size = add_size(size, StatsShmemSize()); size = add_size(size, WaitEventExtensionShmemSize()); + size = add_size(size, KmgrShmemSize()); #ifdef EXEC_BACKEND size = add_size(size, ShmemBackendArraySize()); #endif @@ -302,6 +304,7 @@ CreateSharedMemoryAndSemaphores(void) AsyncShmemInit(); StatsShmemInit(); WaitEventExtensionShmemInit(); + KmgrShmemInit(); #ifdef EXEC_BACKEND diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt index f72f2906ce..4c31c3b93f 100644 --- a/src/backend/storage/lmgr/lwlocknames.txt +++ b/src/backend/storage/lmgr/lwlocknames.txt @@ -54,3 +54,4 @@ XactTruncationLock 44 WrapLimitsVacuumLock 46 NotifyQueueTailLock 47 WaitEventExtensionLock 48 +KmgrFileLock 49 diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index 9a302ddc30..b1e0a267ca 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, bool relation_is_permanent, + BlockNumber blkno, RelFileNumber fileno, int flags) { PageHeader p = (PageHeader) page; size_t *pagebytes; @@ -108,6 +110,8 @@ PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags) checksum_failure = true; } + PageDecryptInplace(page, forknum, relation_is_permanent, blkno, fileno); + /* * 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 @@ -1547,3 +1551,48 @@ PageSetChecksumInplace(Page page, BlockNumber blkno) ((PageHeader) page)->pd_checksum = pg_checksum_page((char *) page, blkno); } + +char * +PageEncryptCopy(Page page, ForkNumber forknum, bool relation_is_permanent, + BlockNumber blkno, RelFileNumber fileno) +{ + 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, relation_is_permanent, blkno, fileno); + return pageCopy; +} + +void +PageEncryptInplace(Page page, ForkNumber forknum, bool relation_is_permanent, + BlockNumber blkno, RelFileNumber fileno) +{ + if (PageIsNew(page) || !PageNeedsToBeEncrypted(forknum)) + return; + + EncryptPage(page, relation_is_permanent, blkno, fileno); +} + + +void +PageDecryptInplace(Page page, ForkNumber forknum, bool relation_is_permanent, + BlockNumber blkno, RelFileNumber fileno) +{ + if (PageIsNew(page) || !PageNeedsToBeEncrypted(forknum)) + return; + + DecryptPage(page, relation_is_permanent, blkno, fileno); +} diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6a070b5d8c..ffccb4776c 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -39,6 +39,8 @@ #include "commands/event_trigger.h" #include "commands/prepare.h" #include "common/pg_prng.h" +#include "crypto/bufenc.h" +#include "crypto/kmgr.h" #include "jit/jit.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" @@ -3798,7 +3800,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx, * postmaster/postmaster.c (the option sets should not conflict) and with * the common help() function in main/main.c. */ - while ((flag = getopt(argc, argv, "B:bC:c:D:d:EeFf:h:ijk:lN:nOPp:r:S:sTt:v:W:-:")) != -1) + while ((flag = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:R:S:sTt:v:W:-:")) != -1) { switch (flag) { @@ -3916,6 +3918,19 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx, strlcpy(OutputFileName, optarg, MAXPGPATH); break; + case 'R': + terminal_fd = atoi(optarg); + if (terminal_fd == -1) + { + /* + * Allow file descriptor closing to be bypassed via -1. + * We just duplicate sterr. This is useful for + * single-user mode. + */ + terminal_fd = dup(2); + } + break; + case 'S': SetConfigOption("work_mem", optarg, ctx, gucsource); break; @@ -4135,6 +4150,19 @@ PostgresMain(const char *dbname, const char *username) SetProcessingMode(InitProcessing); + /* + * Initialize kmgr for cluster encryption. Since kmgr needs to attach to + * shared memory the initialization must be called after BaseInit(). + */ + if (!IsUnderPostmaster) + { + InitializeKmgr(); + InitializeBufferEncryption(GetFileEncryptionMethod()); + + if (terminal_fd != -1) + close(terminal_fd); + } + /* * Set up signal handlers. (InitPostmasterChild or InitStandaloneProcess * has already set up BlockSig and made that the active signal mask.) diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt index d7995931bd..535905d2e7 100644 --- a/src/backend/utils/activity/wait_event_names.txt +++ b/src/backend/utils/activity/wait_event_names.txt @@ -195,6 +195,9 @@ DATA_FILE_TRUNCATE "Waiting for a relation data file to be truncated." DATA_FILE_WRITE "Waiting for a write to a relation data file." DSM_ALLOCATE "Waiting for a dynamic shared memory segment to be allocated." DSM_FILL_ZERO_WRITE "Waiting to fill a dynamic shared memory backing file with zeroes." +KEY_FILE_READ "Waiting for a read of the wrapped data encryption keys." +KEY_FILE_WRITE "Waiting for a write of the wrapped data encryption keys." +KEY_FILE_SYNC "Waiting for changes to the wrapped data encryption keys to reach durable storage." LOCK_FILE_ADDTODATADIR_READ "Waiting for a read while adding a line to the data directory lock file." LOCK_FILE_ADDTODATADIR_SYNC "Waiting for data to reach durable storage while adding a line to the data directory lock file." LOCK_FILE_ADDTODATADIR_WRITE "Waiting for a write while adding a line to the data directory lock file." diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index 7605eff9b9..31241b330f 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -44,6 +44,7 @@ #include "commands/vacuum.h" #include "common/file_utils.h" #include "common/scram-common.h" +#include "crypto/kmgr.h" #include "jit/jit.h" #include "libpq/auth.h" #include "libpq/libpq.h" @@ -610,6 +611,7 @@ static char *recovery_target_string; static char *recovery_target_xid_string; static char *recovery_target_name_string; static char *recovery_target_lsn_string; +static char *file_encryption_method_str; /* should be static, but commands/variable.c needs to get at this */ char *role_string; @@ -732,6 +734,8 @@ const char *const config_group_names[] = gettext_noop("Statistics / Monitoring"), /* STATS_CUMULATIVE */ gettext_noop("Statistics / Cumulative Query and Index Statistics"), + /* ENCRYPTION */ + gettext_noop("Encryption"), /* AUTOVACUUM */ gettext_noop("Autovacuum"), /* CLIENT_CONN_STATEMENT */ @@ -4496,6 +4500,27 @@ struct config_string ConfigureNamesString[] = NULL, NULL, NULL }, + { + {"cluster_key_command", PGC_SIGHUP, ENCRYPTION, + gettext_noop("Command to obtain cluster key for cluster file encryption."), + NULL + }, + &cluster_key_command, + "", + NULL, NULL, NULL + }, + + { + {"file_encryption_method", PGC_INTERNAL, PRESET_OPTIONS, + gettext_noop("Shows the cluster file encryption method."), + NULL, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + }, + &file_encryption_method_str, + "", + NULL, NULL, NULL + }, + { {"application_name", PGC_USERSET, LOGGING_WHAT, gettext_noop("Sets the application name to be reported in statistics and logs."), diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index a1003a464d..46637658e8 100644 --- a/src/backend/utils/misc/pg_controldata.c +++ b/src/backend/utils/misc/pg_controldata.c @@ -204,8 +204,8 @@ pg_control_recovery(PG_FUNCTION_ARGS) Datum pg_control_init(PG_FUNCTION_ARGS) { - Datum values[11]; - bool nulls[11]; + Datum values[12]; + bool nulls[12]; TupleDesc tupdesc; HeapTuple htup; ControlFileData *ControlFile; @@ -213,6 +213,36 @@ pg_control_init(PG_FUNCTION_ARGS) if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); + /* + * Construct a tuple descriptor for the result row. This must match this + * function's pg_proc entry! + */ + tupdesc = CreateTemplateTupleDesc(12); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "max_data_alignment", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database_block_size", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "blocks_per_segment", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_block_size", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "bytes_per_wal_segment", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "max_identifier_length", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "max_index_columns", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 8, "max_toast_chunk_size", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 9, "large_object_chunk_size", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 10, "float8_pass_by_value", + BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 11, "data_page_checksum_version", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 12, "file_encryption_method", + INT4OID, -1, 0); + tupdesc = BlessTupleDesc(tupdesc); /* read the control file */ LWLockAcquire(ControlFileLock, LW_SHARED); @@ -255,6 +285,9 @@ pg_control_init(PG_FUNCTION_ARGS) values[10] = Int32GetDatum(ControlFile->data_checksum_version); nulls[10] = false; + values[11] = Int32GetDatum(ControlFile->file_encryption_method); + nulls[11] = false; + htup = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(htup)); diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index e48c066a5b..d3d8347ce6 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -662,6 +662,11 @@ # autovacuum, -1 means use # vacuum_cost_limit +#------------------------------------------------------------------------------ +# ENCRYPTION +#------------------------------------------------------------------------------ + +#cluster_key_command = '' #------------------------------------------------------------------------------ # CLIENT CONNECTION DEFAULTS diff --git a/src/include/access/gist.h b/src/include/access/gist.h index 0235716c06..a83c49b3a4 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -41,7 +41,7 @@ #define GISTNProcs 11 /* - * Page opaque data in a GiST index page. + * Page opaque data flags in a GiST index page. */ #define F_LEAF (1 << 0) /* leaf page */ #define F_DELETED (1 << 1) /* the page has been deleted */ @@ -51,6 +51,9 @@ #define F_HAS_GARBAGE (1 << 4) /* some tuples on the page are dead, * but not deleted yet */ +/* Specifies the bits that can be set in the GiST flags field */ +#define GIST_FLAG_BITMASK 0x1F + /* * NSN (node sequence number) is a special-purpose LSN which is stored on each * index page in GISTPageOpaqueData and updated only during page splits. By diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index a14126d164..3eb8ce2a17 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -13,6 +13,7 @@ #include "access/xlogbackup.h" #include "access/xlogdefs.h" +#include "common/kmgr_utils.h" #include "datatype/timestamp.h" #include "lib/stringinfo.h" #include "nodes/pg_list.h" @@ -109,13 +110,15 @@ extern PGDLLIMPORT int wal_level; /* * Is a full-page image needed for hint bit updates? * - * Normally, we don't WAL-log hint bit updates, but if checksums are enabled, - * we have to protect them against torn page writes. When you only set - * individual bits on a page, it's still consistent no matter what combination - * of the bits make it to disk, but the checksum wouldn't match. Also WAL-log - * them if forced by wal_log_hints=on. + * Normally, we don't WAL-log hint bit updates, but if checksums or encryption + * is enabled, we have to protect them against torn page writes. When you + * only set individual bits on a page, it's still consistent no matter what + * combination of the bits make it to disk, but the checksum wouldn't match. + * Cluster file encryption requires a new LSN for hint bit changes, and can't + * tolerate torn pages. Also WAL-log them if forced by wal_log_hints=on. */ -#define XLogHintBitIsNeeded() (DataChecksumsEnabled() || wal_log_hints) +#define XLogHintBitIsNeeded() \ + (DataChecksumsEnabled() || FileEncryptionEnabled || wal_log_hints) /* Do we need to WAL-log information required only for Hot Standby and logical replication? */ #define XLogStandbyInfoActive() (wal_level >= WAL_LEVEL_REPLICA) @@ -227,6 +230,10 @@ extern XLogRecPtr GetXLogWriteRecPtr(void); extern uint64 GetSystemIdentifier(void); extern char *GetMockAuthenticationNonce(void); extern bool DataChecksumsEnabled(void); + +#define FileEncryptionEnabled (GetFileEncryptionMethod() != DISABLED_ENCRYPTION_METHOD) +extern int GetFileEncryptionMethod(void); + extern XLogRecPtr GetFakeLSNForUnloggedRel(void); extern Size XLOGShmemSize(void); extern void XLOGShmemInit(void); diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h index cace867497..f8908d4563 100644 --- a/src/include/access/xloginsert.h +++ b/src/include/access/xloginsert.h @@ -62,6 +62,8 @@ extern void log_newpage_range(Relation rel, ForkNumber forknum, BlockNumber startblk, BlockNumber endblk, bool page_std); extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std); +extern XLogRecPtr LSNForEncryption(bool use_wal_lsn); + extern void InitXLogInsert(void); #endif /* XLOGINSERT_H */ diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index 2ae72e3b26..36e9e534c5 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -20,9 +20,8 @@ #include "pgtime.h" /* for pg_time_t */ #include "port/pg_crc32c.h" - /* Version identifier for this pg_control format */ -#define PG_CONTROL_VERSION 1300 +#define PG_CONTROL_VERSION 1700 /* Nonce key length, see below */ #define MOCK_AUTH_NONCE_LEN 32 @@ -79,6 +78,7 @@ typedef struct CheckPoint /* 0xC0 is used in Postgres 9.5-11 */ #define XLOG_OVERWRITE_CONTRECORD 0xD0 #define XLOG_CHECKPOINT_REDO 0xE0 +#define XLOG_ENCRYPTION_LSN 0xF0 /* @@ -227,6 +227,9 @@ typedef struct ControlFileData */ char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN]; + /* File encryption method; index into encryption_methods[]. */ + int file_encryption_method; + /* CRC of all above ... MUST BE LAST! */ pg_crc32c crc; } ControlFileData; diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 568aa80d92..de83ca42dd 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -11909,9 +11909,9 @@ descr => 'pg_controldata init state information as a function', proname => 'pg_control_init', provolatile => 'v', prorettype => 'record', proargtypes => '', - proallargtypes => '{int4,int4,int4,int4,int4,int4,int4,int4,int4,bool,int4}', - proargmodes => '{o,o,o,o,o,o,o,o,o,o,o}', - proargnames => '{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float8_pass_by_value,data_page_checksum_version}', + proallargtypes => '{int4,int4,int4,int4,int4,int4,int4,int4,int4,bool,int4,int4}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float8_pass_by_value,data_page_checksum_version,file_encryption_method}', prosrc => 'pg_control_init' }, # subscripting support for built-in types diff --git a/src/include/crypto/bufenc.h b/src/include/crypto/bufenc.h new file mode 100644 index 0000000000..41270ee923 --- /dev/null +++ b/src/include/crypto/bufenc.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * 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" + +/* Cluster encryption encrypts only main forks */ +#define PageNeedsToBeEncrypted(forknum) \ + (FileEncryptionEnabled && (forknum) == MAIN_FORKNUM) + + +#ifdef FRONTEND +#include "common/logging.h" +#define my_error(...) pg_fatal(__VA_ARGS__) +#define LSNForEncryption(a) InvalidXLogRecPtr +#else +extern XLogRecPtr LSNForEncryption(bool use_wal_lsn); +#define my_error(...) elog(ERROR, __VA_ARGS__) +#endif + +extern void InitializeBufferEncryption(int file_encryption_method); +extern void EncryptPage(Page page, bool relation_is_permanent, + BlockNumber blkno, RelFileNumber fileno); +extern void DecryptPage(Page page, bool relation_is_permanent, + BlockNumber blkno, RelFileNumber fileno); + +#endif /* BUFENC_H */ diff --git a/src/include/crypto/kmgr.h b/src/include/crypto/kmgr.h new file mode 100644 index 0000000000..ec341c70b9 --- /dev/null +++ b/src/include/crypto/kmgr.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * kmgr.h + * + * Portions Copyright (c) 2021, PostgreSQL Global Development Group + * + * src/include/crypto/kmgr.h + * + *------------------------------------------------------------------------- + */ +#ifndef KMGR_H +#define KMGR_H + +#include "common/kmgr_utils.h" + +/* GUC parameters */ +extern char *cluster_key_command; + +extern Size KmgrShmemSize(void); +extern void KmgrShmemInit(void); +extern void BootStrapKmgr(void); +extern void InitializeKmgr(void); +extern const CryptoKey *KmgrGetKey(int id); + +#endif /* KMGR_H */ diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h index 3b3889c58c..b667a308a1 100644 --- a/src/include/postmaster/postmaster.h +++ b/src/include/postmaster/postmaster.h @@ -34,6 +34,8 @@ extern PGDLLIMPORT bool remove_temp_files_after_crash; extern PGDLLIMPORT bool send_abort_for_crash; extern PGDLLIMPORT bool send_abort_for_kill; +extern int terminal_fd; + #ifdef WIN32 extern PGDLLIMPORT HANDLE PostmasterHandle; #else diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h index 424ecba028..2988239e03 100644 --- a/src/include/storage/bufpage.h +++ b/src/include/storage/bufpage.h @@ -15,10 +15,12 @@ #define BUFPAGE_H #include "access/xlogdefs.h" +#include "common/relpath.h" #include "storage/block.h" #include "storage/item.h" #include "storage/off.h" + /* * A postgres disk page is an abstraction layered on top of a postgres * disk block (which is simply a unit of i/o, see block.h). @@ -168,6 +170,8 @@ typedef struct PageHeaderData } PageHeaderData; typedef PageHeaderData *PageHeader; +#define PageEncryptOffset offsetof(PageHeaderData, pd_special) +#define SizeOfPageEncryption(m) (BLCKSZ - PageEncryptOffset - SizeOfEncryptionTag(m)) /* * pd_flags contains the following flag bits. Undefined bits are initialized @@ -302,6 +306,7 @@ PageSetPageSizeAndVersion(Page page, Size size, uint8 version) ((PageHeader) page)->pd_pagesize_version = size | version; } + /* ---------------- * page special data functions * ---------------- @@ -471,9 +476,9 @@ do { \ ((overwrite) ? PAI_OVERWRITE : 0) | \ ((is_heap) ? PAI_IS_HEAP : 0)) -#define PageIsVerified(page, blkno) \ - PageIsVerifiedExtended(page, blkno, \ - PIV_LOG_WARNING | PIV_REPORT_STAT) +#define PageIsVerified(page, relation_is_permanent, blkno, fileno) \ + PageIsVerifiedExtended(page, MAIN_FORKNUM, relation_is_permanent, blkno, \ + fileno, PIV_LOG_WARNING | PIV_REPORT_STAT) /* * Check that BLCKSZ is a multiple of sizeof(size_t). In @@ -486,7 +491,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 fork, bool permanent, + BlockNumber blkno, RelFileNumber fileno, int flags); extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size, OffsetNumber offsetNumber, int flags); extern Page PageGetTempPage(Page page); @@ -506,5 +512,14 @@ 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, + bool relation_is_permanent, BlockNumber blkno, + RelFileNumber fileno); +extern void PageEncryptInplace(Page page, ForkNumber forknum, + bool relation_is_permanent, BlockNumber blkno, + RelFileNumber fileno); +extern void PageDecryptInplace(Page page, ForkNumber forknum, + bool relation_is_permanent, BlockNumber blkno, + RelFileNumber fileno); #endif /* BUFPAGE_H */ diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h index a8be5b21e0..2fb5c0377f 100644 --- a/src/include/storage/copydir.h +++ b/src/include/storage/copydir.h @@ -14,6 +14,6 @@ #define COPYDIR_H extern void copydir(const char *fromdir, const char *todir, bool recurse); -extern void copy_file(const char *fromfile, const char *tofile); +extern void copy_file(const char *fromfile, const char *tofile, bool encrypt_init_file); #endif /* COPYDIR_H */ diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h index 1ec9575570..f0b4577ac7 100644 --- a/src/include/utils/guc_tables.h +++ b/src/include/utils/guc_tables.h @@ -86,6 +86,7 @@ enum config_group PROCESS_TITLE, STATS_MONITORING, STATS_CUMULATIVE, + ENCRYPTION, AUTOVACUUM, CLIENT_CONN_STATEMENT, CLIENT_CONN_LOCALE, diff --git a/src/test/Makefile b/src/test/Makefile index dbd3192874..617f1dfa29 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -17,6 +17,9 @@ SUBDIRS = perl regress isolation modules authentication recovery subscription ifeq ($(with_icu),yes) SUBDIRS += icu endif +ifeq ($(with_openssl),yes) +SUBDIRS += crypto +endif ifeq ($(with_gssapi),yes) SUBDIRS += kerberos endif diff --git a/src/test/README b/src/test/README index afdc767651..0955a764e3 100644 --- a/src/test/README +++ b/src/test/README @@ -11,6 +11,9 @@ which tests get run automatically. authentication/ Tests for authentication (but see also below) +crypto/ + Tests for cluster file encryption + examples/ Demonstration programs for libpq that double as regression tests via "make check" diff --git a/src/test/crypto/.gitignore b/src/test/crypto/.gitignore new file mode 100644 index 0000000000..7b92218ad2 --- /dev/null +++ b/src/test/crypto/.gitignore @@ -0,0 +1,4 @@ +# Generated by test suite +/tmp_check/ +/log/ +/testcrypto diff --git a/src/test/crypto/KWP_AD_128.txt b/src/test/crypto/KWP_AD_128.txt new file mode 100644 index 0000000000..d77aeab719 --- /dev/null +++ b/src/test/crypto/KWP_AD_128.txt @@ -0,0 +1,35 @@ +# CAVS 21.4 +# 'NIST SP 800-38F KWP-AD with AES-128 cipher function' information for test-files +# Seed = 0f0c6b6602d959d22ff2305478ea477a85d196d9695abf5b445010b45ce046c501bc04e6ca4faf46137adf6eac452d97314cd91137e33fc30cc6df316117fed3 +# Generated on Fri Apr 6 14:46:45 2018 +[PLAINTEXT LENGTH = 4096] + +COUNT = 0 +K = 1dd51f0d3a0a784174ba81b2c9f89005 +C = e1bde6d2df3b8e48ca127f97b56b5dc2672b3736cc3157c7b80a0316ef1efbdbbce19fea23da831836ccd2e002b2c1dfad206b5cec358446b8434d7f4c39e65b0e0b50897642ffc34bfb3cb3e233aa9c1058ff0d4fd48e98bc8cc3d214c06d514dd97db2278093a308f91f4ae92626d85771fb1447b36a3467fff02ac7e81ddbd0fdbcd02d1acd4f053c989ef3dcc2c01e23bc2f6090f3e8c0ba5f0082341200b1c37b99daa9cb6fec78bce3429aec5badb9fd28fdbdbdc5d53570675a9e39535b4594095658ef950ecd79a162223b60d2eb91765e022dc6e1bbdd86f1bcc280ed9df350da08a801fa16a1bf2701947acfb08f19fdfcaa1d76f466a5de2458a78fb82f6af3e1be68f405a4289f25896f4c9830005c9e895c86e67eceab0ad544856071b8d9585835b5e85a07ab01515f7ab54f98dffb4ca49a15068eefc6a01f7f52fd1adbe3631c59f6f43f79d2b4f2a691e2b30bb1d43a848dc3ee39c7f2e50f0c9deb7ab51e33bf40903ac255bb1510fd61676a6c13c3c776b8aacc6cefb95e24973ebb11192e2692dd0c6a085b58f86e11cc28ee2194988c123e3666da7339c0a4ac6afbacc83f1f100fbb39efff7cc605c9213828224a17c476395aeb9bb0a3150fb8889a8c2a494c8c526203f261642bfa69a94b86de9e6d3d932fe20fffe4bd76d502c0d437a3e1d0d8727b7a8dc0e361967109e93566326b6c517663731c4c9bdd0295d8 +P = 1a4eed4bf5b8d2e2a58f1f1277f164cc32cdadaed848f76fe634034082ff9aa1711870bf3936d01a2aa48de30de5143b9148cf56f4490f9d480dda0b672e8e17a012cd26cec3c68837bd5b2f9beb13e0110f21c6c36343e09e027f39557d1596d4ca406e3e7aa113e9bb8623106bae25f0ea23d46bc29970ba2596f83fe4f73a6f978a4d949fa7c271570a2ae5d2b50792d5ab5c43d455f359fb83c35ca3da37cd73cd66b6adce94d78ecdeabf667daa47ea70799af299e1d898ccf3fca6c42c6fff8cf2ec992f596fed4a0cdb502a00f9b5689302931d15cba691e2f8079a0411332438b714ace5234b91e4aebee8f8dda0e1968c2016fed350430a65d8d206c9436f40b79ce03083b8dc207d6960be1ce97007ed22a388ebb7b3d8f7d2b7d9f8f49731fbcb21e21db0cdd15674c795d5af2b2cd727f83e634e8c47157ed0c6873a5c9419e683f16f4a7827b444967812f9d1adb9201b89a0e66bbcf0591465f5d7036a21cdda0e10099feb819dfc37fdd3105120044dab716882d3971f312e3f4459006fd5a1eab08ff63edf6718f47ddaa37f7f40c9c372995f3aec97bc45e287b64fc8cf5559ab04a4d4d3ed482f5d61d3abd99cc87ee406da3ab9c9cd22ba3b8d191b26754aa94a2412f39e332d77fe72210adb0cbb5c96adebdbde036f1f1aaafad74a7ac2594f81efa734054e2e16dc931d49b970b81756862705fcd4 + +COUNT = 1 +K = b3fa008b5947ce58dfbd354dd01f2d43 +C = 55cd8e45138f477ce0a84f07bd28a93d7d628bb4860207a2f6dc4256bd79843e32c856a4fa831d1603699d49e6c36291b60aa80635900cc6c78cf0a2ddc457beb41782de0de03f08a064df90b41f2e98ce61185d735380403fe56b68f8343a801a14afb8a7ba79684dc2a585110da83e9a836cae1fd9e1a220dd6dc922b4f02b15ca88d43ab61e1da24a9b3cb99c4e5024ce5667f4841ca2a305b1f4c1ae9fb63d1d4dcb83870755a1a646b16c088e612d82ba2bf0e7e2fa0e8035c3baeb595f1ac9bb49b01f6f71392e217c049c0e9bd794b9aa2383cf59ee0a90f965610c65ecd629a17cba2bdf2458e3a8e1a9d219cb66eb9ec8e5226b34f95003064952523920a0b4e94ec8ecd1bdca8a65fe46ed25fd4d076e46fa62a8cde6eabc593045d17cef996ebbeca4b537f65c4f683a10baeb4c42b9867bbb49ca7ea1c5437bc114948c542cffced9bb1ebe3c946eb24ff55be89be004596ba648b264167217d267b881020b905f508e4f0e1a58eca051d56ff30d91891838c574c3de54e3feafcdf514740ddc94ba92cb85fe86033e67f14d90be7a0222e4bd1624cea8894df66a36a8e848dfe9168d8024b7ba5636afbcf6b945a53e6b2778f229af7dc2e59bebbf8bdbdfde1e21465f6b6344b13afa0e5ceac212b3b88932f21b1ae04268476597c92e64ff7c14b9ef678f10a35b56cd70ba03063f94aed97b0a6cf883d1f07facfa37b6e5b070 +P = a067ab39cede4ac6c6cb7630cba48c52a794ac8ebec037125bcd97d1a3c52a8ed64764899f9035a6944d0605a5d977172a55bbf86cd81aef5d6bafb1ac86bfa65da2b3c39bf5da94a98f7b6dbc5df16a7b38061e0665ad16b20fb6aedc9ce7f6d3497c3c55cea92e6343f21251092ef2ea307b35f999683298098bedaea847d1ccbf8bda18dc477e8d49fee4e357273396ad2245703485b97b5a7d97057bad875a3e76b67ad5adbc6ef3b8ba9a1786aa93149f0f8dd166535acbf93f1b9839754d537da3fae1ab02973427c3f353fe9aa6c5a100bf0e6ccb08dc1fdb0fc363a95c77c5758d440db0a70f0340a4c488de51e1ecb932ce2fcb2c95ea28c9f55695d97ba1765c8f11e523ae3e4e1efceb69000a192c047ab197f4840c664c035064ecc12926fd3bca0527a160b5b5a2bbaf5db11437f2c38a1c7535e87f552b9f04f2fdd309a826e4ec7708217022fb075cdfc6cc23e9301e33068caa69ef746f357b09ccc098443a3a2979a225e70be1e722e8d6fbb57d0dded2456c1d47eeb0af2241f769836026fec8fc51d97c4abbe9710a4aa5b95aaac83bee57e1333fa244ccc971b6260a9be16e31cc2fd283fec1b247a7340d149fe5309acb47c9cdb955b7bcc4df277eaf611e8af281ff0bcd64b4534309282d1b5cb14efa93141869d67ce7e418f06bb4c2feebcb7a1151aea2eb8bc2fc4dcee53de9b2fb1803490caf + +COUNT = 2 +K = 4b4c43c9de4fb4a2a7a7adafeabe2dbd +C = 6e4d08b8124f7d3e23303fac1a842014f95e3d71c438f8f1990307842796dc5e404ad81802e35c183fe000390a12c81ee684c5cf26c1d90e414cfffe6931b0f352936fcf0b31429eb5c7612cc359a15371390e518cf5c6a6bff1bb0348d14e2c39b98c9f30672ed2af1d96296df8b5567db25b9510a2083461810e119735490058ed1b46b7fdfa885041d8749f90a072b43ba49f2f51fbcda0dbf3cf99fca1d8f46330e5f6fe079d6679cfa26214c8831b782aaa023a2e0ea91050d277dab876aa6865f2bb3fc1a4a77db52f6179d5e5325993280948b6b7002b572829641d35ed3d735d8423e5b24673c4570ca25064fc2c2ad4840632536bcfaf2a7a814f3eaed92b4d501bc51c1719a0d8d8f420b66db845682bb41c88038cfedf13417143a3a701b521a9bf0bb639875a728c3b5ce6ca7e7a45bc75285c193902e6b5e7a4c6e720493d3937bf485e587bff894f70fd6165a1d0129cc673a992e0a4f5489d228a066b1df60002ec0521924f8d672cd1452fec927e58e75807b2a390256f920743fa4d0fc8f59f2469a595ef65095ca0c80adfc843e9e69b6d4a3f824af47b2bfbf2a7a6c1b650378f096f6f0bfabc752c8f279d4f45d56d09dce97962c119de3a64d83b93ea55066f24d4238a229ae86e6a7857af1d8aba823370a72fe358046049a84a70213ef31d9e77a722def8e21480e79b71299438070946bd459a7251707446c911e381 +FAIL + +COUNT = 3 +K = 96ab719a3d08df2393ebc330e151dab1 +C = d50ae797f6c3418f388a7513d693c6dd665e858767531fbccd3eb1aabe796690ec8fbb757d88b169adf5c136de50ff0f2cfdd8389f812382578aee0b0b61e13c6a2bc500640fe1585f068eee0d1fa3420220e23090e24e3248fe16f4e0c7c0e996a21b4947ddd08fd3ccc1f036651be4f48ee1ffb486cdc05911244480548221d8da1f2bc37dece080e51b2cdd1ddebf37213a4dfa1b252e567243d9cec8c89eb8db544e7c389a2e13f1b91d860df3cbcec3e85c93276c2a9a5fa080efc85e9bad3bfe2d9bb06498dd8b3720456bfabd3c69b345f6954872baa1d43b9f7ceb92ae9ad77b270d0b94c79275a48874dafb136105f5553529687b6aeeaa521790b9376c9f88ace94049235cd52c4387ad210442513dd5e07171519d58b1294fb8ac1f60ac68b8f07b418e1bb0598601ec38b9a9b137dd87d0c8a41089d17ca1c720fd0e7e3b81b85a373753bed0f5e29586f84cb29e1d88c379c965c50f6a803ddfac2e1555beb9c208a3821f53bead8f120f4ef4a1490b730a0b8a2f1869c6b985520d709bdc0e5fce44316b8aa2448a2743761bf77bdbbfdab6a721a8ec79f38f7e7321a80a2cd3a35a912eaac5eace85c4cad3c6685b88be4517cd1c20971b85bd9e8eb6e52869e014831dff7585a163f5a4dbf1d59160104da90a9cfcc8d6a0324942b40fde4319a32442d83ebbf5d7a36e9495be2ffd0e7faec1b66c96f71843750b8a051b7170 +P = 3a3b9e6de537458875e59204ef7565b6dde796e5ab11c83f7a361b8143f0f7a7eadb5b53c6efa6d199f759cad5c029004024eabbaff717bafb95646dc31a8f6063b9f8faaea650dfa8803bfa0c79091f299a55f78611c2e0d015021d6c6d3abf3d85cac306740acc144201516b787421a77c78a566c6eadc88ecdeea4ff861b6db73f7b00f0a8f62faedefa58866fb368424d7267afdf5ff1279916d2f177408d780697e1c45e58a524bb0365858d2b5a42ee2bd9e8904134d04cf071e84db8a31804aa8bebc0b28dd621360385117764178fe74b29da3ac390ac4812fdc7eedf91fce6eaae3d03163435001ce42f55982daeda5cec5deb960b35df231463cbc26267746be628c53b55f4f21ef003816eb7bfc6c710efa03d0994a1b3c8595fc9293a2c101483798034d4ee7e3d5e07bbd897c9de4b8315e53cbd1f81bdecbd59d093c844a0ed1e3e9d238707a7b893ca453745223c67756d9062152b239ceec44c436e0896a59ea9ea8cf79a93b8b759389bb5e73c5f5330e26580d9777817400166d826008be5e8c7184ae2ecf8fb9dba92af3c747c74e1534c05395f9204b5e8481fdcf4dab5ea6224a8e0ee52576d467d930c0899d31a4e288e3eecb8cb7a3be3a66c79ae93033de5d0d422a6d54ab002d1a82f3f60db97834d9fa3782dd64cbec8ddcac2216a393dc263cea2705fd072ec82dfa1ddef9c588c49f17c275 + +COUNT = 4 +K = d8c221e426109cb5911d7d6f0836f4cd +C = d853d57eaacac8096346564eccd33281ee864fb290ce91eb717fa153ca00064e033635178c59860a567215b7320fab4a72ccf716501dbc9a44d5b3d501729674987d2413cad79dece055a9b0d47ec980331f4a236b31984f5d62f9d7f58c0f3afb81fe60f266652da65d06874334be065f56096e98536bd1f2120313b0905ffe2f2c3b6de265ab7800c42be810bed18548c08f9193b02a3981a922b32b618fd9a978439ea382bf2890ad1f30d115b2319276289cf4f7a9917b0c064180e79c8644f9ac880a793b4a8ee424dff32cf2b6ca46f52ff8bd8359ed18ea8aac23e63ae337f5baea9e2ff845a5fdc0b79d5767d47c2a1a536d889f553c52696cbe91ccd2ec671a0644689bdb0f4db7e5d58c854eb539b6b4cd9214e361a216d315b1b124b43c76c703c01d3bc3142f760a399ba4887a6e326a58ecaf56fd49ae128a86cda485eedc3da80b75b171e77cade00c903c1f216eefa845dfaef660fc5ecb6791ed53765683f44da6c4ed8a9ad9e995f7d920cdee8463e79b18e8874b0a2f573b1825f8a480b1ed1245c81f4ec097bf0a0504aab9bdaef27b67d98805a7ec687c8cbcbc92ad3ce58651162a1f57f8af427ea0a111dbd6e3c7f240eb6b2360650a72b9c1c4417b1d541dfcc2a8d6ce3e8c160d8d417e4efbdce809bfe30802696bfd52a0f40be4db9be247dfd867179d82390b55180ebc6ceba0a990e3f6d32eef9dfdb946706371 +P = 92814e18dbe6e83714c4a82ba3ac3baf682a8054eb36666c9546db040d40b8613fc560d97b05265fb19ade180efeb55dfce2cc5981ca222e66b547b78a42401710535b1181674fdd426cf2b0b55e5b7f0505f11307120d495cfb197a3de00569b3d39f93c27270df4725243d314a026549692b0e2b4079c60a8053f0f36e83aaa3494307b175fd40643c1bc264eed1c00f8b565f2a3aeeb78bd94970bd9267d21f5a9a1b07df09ed44a3bd4255a139a328235b921833f92904a74ec202b0eac65df1caed05dc84e52b06c1ecf0f7914324ac4d828b7de7189705308959be42401948e3bf4bdd50ce24101c67ae745a73a67d7e366b6b432ce67b05cefd149a17247010f42dae4de1b2ca42a8e71824cd32c5cb2e2055443ec3ff24339c774dc9207744b84e9203fda1f85595f961987d847ed33867f1ddfce0795e3f2d78c5d749a488a4997392b8c9022c810197c93186894faa55cb0b6775b57a7ba2729c617c9430a44098d5081e3c5c4908ddd1a475cf9211408a8ddbe19ee527ddb2596456e1b1481a09b04e091b1c14b7b2e41bb4434a906736e115cb25ada0950ac5d2845b4a9f1e95f4d80f64440e983324c3aa9f3ec8964f9da0d26aa47e86355aa80ad99d0e573fa9932da70bd65cb1a06d8cb77e455fe7cada4561e027ca1608132c2605b6d0489bba6b29f293951883c451f37bd545f6605364ddc75918df097e + +COUNT = 5 +K = 704eb91dd5ba3d85279cf47c01eca2a5 +C = 51c71fd7778aa3648f3e31e1db0c73cb1479372f2e35f65f00188f08f794993a2ee2bb7e91cd1a2b86e92b8ccca7277207fb525ab17600173fa28844ae27f093e0e5ae00585cc714dac90cbe9b6332cbe4cb689b2cd141c102c6881f5b71ec477c5f4a91f7bdcb5871aadd478f1a9ccc6e069b7283f4d70b26e8748eda6d443ab13804c543a44fe2fb366f90de35d83fbf6354a9a9ab4a93ff7d61cbc0bfe05d6102c9c393273e7d3a04d61eba771f05cee29e5dacb7abf34ec9159e121841e2c39848f604c8f743313cbdca828bfa4635a81136e7a37f230c0d3c814d35c2eaabdd94183312909ab3a09b87cce0c719408f837bf24bfb2dad87630aabc9eab35bdb9cc536198389aceec68e8779f9e1eee84392189823a68195b75bbb6d33addf580564e696a362928e2ac506b79480600bc2f9eaa3e96f323390d1d92cf3c6d4bd4147ada5634cff2bf2d97b259904a335eaf11ec3fc84dcd8e27f7538e0fac1dbe7cb4533f4fa58913535d957b90678fac58aa96694a8047ac774afe488ab429c6807e709351f8159dcfbf83b865aeeb26722ef64a537ce932b2cfa6d53ed6cc1ca8ab58748c06a753515fffc56e294f51ab257585b610d261c6fe12def38a1b5dceaa4681569124c679b20984ed2967740419b342e9010eabd291de026f6e829e4dba5300cb668191358ab58e178c29a0194a639233f9c28c50a609bc42f8fa6cd17bc58eccd +FAIL diff --git a/src/test/crypto/KWP_AD_256.txt b/src/test/crypto/KWP_AD_256.txt new file mode 100644 index 0000000000..6d28f39705 --- /dev/null +++ b/src/test/crypto/KWP_AD_256.txt @@ -0,0 +1,35 @@ +# CAVS 21.4 +# 'NIST SP 800-38F KWP-AD with AES-256 cipher function' information for test-files +# Seed = bf1ba8f321ce0abadb40026686c9d9e7f0c4a55388f2ea7cefc81aeb0e054d40c94f48093f2739580010d6ad6e6ce734f21e7338100b750ec9c7bb06bf46f7f4 +# Generated on Fri Apr 6 14:47:06 2018 +[PLAINTEXT LENGTH = 4096] + +COUNT = 0 +K = 08f5c088acec18e6cf1f03a8f85d772e327e7fb07f8c2939eb554e84c42ab93d +C = dff30fd43647d4be54cf2dfd6187e2ddffb55267313f980fb09c833a9c2bfa558a95861711f0acb2a5c7e731ba22f24a9c4dfdd9e9b0216e9088f817a175b9835b0e17615687a20f68c067205626494cd04fbabc0b3eea7c0a4cd6236bc8b3e52e721dfc357fb8a3722bfcc4c690d8f63dbb864bb6e3a15805aea7270f8eb748deebaa2d066fcda11c2e67221f9a91d2c29a6c79ffae76aa80a2590b4f9e35f623fbf2f8ceb2a205493077556a186e25e5bd52dcff7bcc6909b37a66c1d1431be1b363bb40da25386eaaf5fcabc7be6422a04434a21d1d3105328e7c56770b9f59b03395e4138f5f06fc7e6b80dab87b08caa7bfffc45a095c15263efd3f06c651ded6f58074efc20620d704997fc84721a0a8e9e5b9f5cd330bbb156b31d9d1b1c260e4a24535f30404dc5b2dd6b35d916a1391b25a7d8790be09d85483ed1522074a2785812005bda10dd55acb245b3bd3d9bb777dd23f9b02538ba1a114ba53386d7ca4d9524b2f8a18e0ffb21580b560540bb2146f08f04974b90eb324547d56222df95f44bc6e5f183bef283e4816fb1b2933f9c7c6726a245a495e304d8318d0008c51b0be8090f8f668fbc3f31e073be4b9e97468f4dd8c798e9d682868df493db8a85738b58cfd005190f365849072577772672c6f82555c65046eb34e86fe61103327a063bacbbe33cea7eaa3d1de45471b7269e1b6b38608626e323447a3d5fe0599a6 +P = 8b68f66a3d2f59d419851b94d9a6f2f0e667f8125e11d463a6bc2cea46b12dcc40ce8018b204972c735fdd6d2d05b628f4905c6690f5ac5b1b51e12f3af2dc3ae9b9dab616f0a2a66a1ac197592fd5b15900547f32f54110b58d51a0340aa80e9eeb7b2e0eb97e80aa22ba918f2fe1c678c730ed5c3d8d24774f17d8ab6e01a06243d36e764df1dbb8af1faadbc55281f0242abd7a162c984fd0b05ab8b0bcaedffb2962024f009a8d7c9e71281c09f52ec0707ee3bbeb1ecb918be6ae3e9c1fabbcd3512af928db3ba6c109ff9e9839a616b2a53f092160a48222b84d53cd52490515ef93e1ebb33897263492ab8ec6fad2e633276ae367f76d7f926309478c0205d4f22506a451795dc98f5410d8f5d3e049cbedf381620861e7b4ae08f2d8a71abc1f230248cb636a2d7b4e7717ab2b7b5f2dc6e5b5a18e8043254208b50fd6f8929eaf974c48551233661ad67321b64d69245d536d9a8ca2a6a10966dddb9d2ce36641c9281c460ae524b077867258f638e6ac872cb5f5c6fb216b1ae60a9d0c5ea0dbcd060f255da26111175af4e9935df59ddade6a2a70cddff8cae6a98e4f3843c2dd59d09053b07b648a46f5de0eb21ebb192828279a386ea3eedf2cdc355d73d51111e8c1d522e059752bc56226a4225bcab713bfaaaec78167d7cfd33e913b26fda93ca7524aa8a8b17977c88ff9bc23ea810b4de59eac18d1523b + +COUNT = 1 +K = 94c4d5d70f881e58e10e7246cf812d40e2be258adb2b6c13c6603fc7daf7e85a +C = 6c07b5ffd1b9be182413ef8eae4a6eac657108a46008a0d898727f2711e6fa0ca60fd1d51fad683b57d4202fa2b0eb88b856e08b07155439bdb03890cbb7e0f228172bf297a4e0917dadaa5e89a287bb9ba6441c852c5b0cff5084e6c425aaf866815b3fc45f5f7fb5d14b270343e6a30f402e11d62e433a0d84f65684b2df78d4e7758bc0bf81783316905cdc3c1150ec47f225c966f7f339b2538970eb3b8a2c13f95df1310d6e3b2a1f8aed19105846557d8f0018fc0f17146bf836b654dec98e9ad639c7e4b2f922b4396e82c690cdecb65f5e0ea282dd6262f34346ff9adbc8b2f361ddd4356f0feadf7c750fc0580c4e12c00ee049d06eed2242b14727ef4d58386dc8df279a7bf8131c3befaea2f059ab757826e5e381d49a2f11b8cbc2b0021af4da7a779e5df0083edeb54348cc36ce96a19a3d7ff5bd2f19d05fef6b200e76399a02a991111832173353bff4ce1859ff534ae13290dd176ba8e1384ed24d9702dbff127e15e5c66618f94680271732d19f64552ed03df76dc9d46c3cfdd53a1b253992fbcbea6db006f16e8dd92406f0090ad9100856c6b71f7767fcb895136416b374285efe1c6506941911a380e2bf74ffd0f67e853f9ac7b5df6666b177a2908fda9add0eb798f8ccc52801535b2bdf9507f3fb3b46915aa889d62ac5909040a1a28856105dfe2e10d5cfbb569c380551fc8bbe7d83dc87ef7a92faa3fff4b1e2c2 +P = 85693a16ae69d751cfa6799b95a6396de2eabe7e4da74d734691d992cba353a39f3b9615c1325db5b0563ce1a846bb0f0534a86130ce6657736b9a9b35b0f8d89dd1b3a295131d2f3f57f94deef9606dad76a377d0b24e632b3680e4d3338f3e4484609e8063e9ec621297f55802d7c347e8085ba6e514884b8fc1ae109409c5c3a5bddf4daf034d300e31eccba07a9380f5325666c4a3aa12d60b30ca272fe03534aabe78ba0452a7e4648ebfd4645675629676be6f122a54b6b810cf9cc0c68b7c61470a537a5a664ec24dbb3eb4f9fa8355cc7ae8fef27a0146df5ccc585d8c106a1eeb64ad4c701fd5a54ef18295b07e9e47f7f7dd2f67d38ed776a5f0b28843cc4bb5d7fdbea9cb0088dee849ae232e4e016d8cf3681971e8a45d6b25451538212b91f30e17580a8107a7a95587a06d22d615f5475a5f616fdf2fab79152f2643054d96ba88f50888eb0f2f1f154c6fff53dd44c3613269751dca4fa86f45d6b1af9ad0159685223889529609e7003c8f3cab491fd6c1a020305da8f94ec833d721d9fac7e575c2a1bc26eb4fb5010c35ffbd39b98d857f12584f4ab7de92aa6d7e7148a0120cc6b3f7ae47a291ba1cf55a28d38d3a30dfc3917d663458cf840385ca81cf70acce45a5cd509f8387d450bbdd6fa51830cf9a7387887c620b86809c55a3eb322ca784a51693f1054759804314ae86048f0d9c99650a5a12 + +COUNT = 2 +K = d65338fd3771fd58c07b6b689577378939d439628529b92cd5625edd18afac76 +C = 1c429bf25c144a2cc649fbd60de5c26c31a0c352de99b34b86101c551994f082feffe1db8853de59b3e8593785eca100a71c5392f0c71eca9f411cbd87fc77ea1a96376dc13f6ad460a11e9cd5a829875a7b7dcd2ba4eaac08c5bb48ab5d4c338a6f8bc5e760739edcff2db116b5b1802e35f936d473db168edd12532a992bcc418a759cc9fd3f97f561623078af29d7ab489b7ec564ba981c188f11240dd9354c324f8d0cdf1c74252f0fc75e390e837b8be90a670f5803ee53eb75c3ce95b2853b2342e54f86dd9aeb308eb82ceb2bae7b3e0b364d17105eb61b3843f7206bdb6abb818efe0f0d3b1004e370191e8218cca14947aa8070f7c66fd0422b02ab4a1d94fa46197acd24e272c765667353e819588402feb85d7f00243521d0e7a9d9e70753d8b51d374ea9c8355536594bf05a6960ca7176a4b66086b055b099e315a23e042a7e0807316d7a11a657a6dc9043806e248a9af06570f710af65267d436a5fcb001104fe8a7c564afe075d85bc0a2ce3d33d8d93d5ab1e923f51d4ef26cbb6fd4a935a97cb115aed678e75d5d67fbfcd2362cb3d74ed6b9b9fb0cf82569a474a25e5aa39d22fe5cd301045203d9f93cf5c9e9e9451f1bf3566eec75fbd995cf8c640aa68fb04f5419344057fd1c0e655d750a68c523b0fab24cab03d7393ee3a5735039daed52895dfe7937f55d7ae9a8c0256e9d638a8598452f5329353a20c4bd9958c +P = 58b20979cba48a9dc95a8857f5bce433087ff93470fc62546e86e72dfaaf7b233ffe428802390c1db7cba00b1f23678aace4a16a237b41d26bcd83d471030929a34e8467f85eaef070b9b74a57f13e91b4e95a3c0b8dfea87d026196a10168c152c4ac42718989003b7e688ca43207034b674d3cbab6f57db6513f8883d27f2280c742896a62e7d0f3f20377e98a0688652d270887fdacb86daa086ffda17937e6d20e4a82667f80ac7749a889b0d748e906d653f569b86de2b42b5819ade9c92970d4caeeed8cd5759d56fd38205215bd8401b2a5a000990afe6c9bea8d091171e85ed83f45bb5b9a8d74cae897cc36f1eaf0122693990b1fb57d0025ad6d92c90885accb649368fe237c4cf017787609fb93c9ea5b413847a9fcf2d2ccb6283345a278619abf8dc351682928187bf92551a820939ec73928eb9930c48f7088ed0a367882f4a8b20d754c5f06bc82990da02227923eb8d1cb73c23793ea0d19bed4a9986f0d48d7835733d1ed3396ec3cf15e1854473b05535261251f4f0af8a0743b3298888bec2f7656493d05eb2d9b848e6802845fb9f7835b50d6a0f0e6cfdaf9b1afc6caa6573b3350256e6f23cc4681316705e33eb0a5f664b79be556cb1bbdd0208430cdc95a35f61facbe7ca2a9bd329e4a1fa42aab9bb02f6519a5672346a4cfac1b96a969317480dd995e339af888fc0e43692332d583fec6215d + +COUNT = 3 +K = 1726706350c11e6883955f24ea11ab247ce3b2ab54d05e67ad9770b5564483dd +C = b006f26a67d0e1e2cbeb5c23b6b300adc1526d1f17bbe964fe8237ae244878158e6b04cb488786b5258ac973c3a2eafd7fcf3a7ca6c825155659fbc53d112bc78b3a770cf059fdd5e68f2b4bfa36de3721231102e5041c947fba3d906bff39592ec3901a398da23035f1190e99b58659330cc2e856ee87ad4197dcc7d16e1f062275bced1ed5cd82163ae3e58da7368dc2aadac855385bd4fa0b8baadef608d0a5c27172d12b88c70b136eeccf37f36364361a990dc50815743cab1636e661bff04ca8345520c30b935a060b450526b1d6ac09170e5b0a327b88f42327b85c9a621d2ca745963c2815a2bfcf509d50b6058ed6e67f369b5608d2aa885238b67d1b8e0d83f9464aa473bf109350fcc02e360c2619236cbfbf895b607895530d8d3d2e41450750dad05b1c37ef15db7fb4707597ac252e8e58d4c1ab2713b427643d198164c908b5d8ff36e9700157284009c7b283633d8b27b378bb65eff8aa59b5fe5e6437a1d53a99c106c2c4d033d3d23950e313a10eb31d68524ae9f8e4f56437acf66db3e8f77407a15bbff4b393e5559908993146d93c673d2aeb7d4cb8fc8d0169de7ed6e2bbe6ce9958a0f5d201419e7acb17e47da827ba380d6b3ad3b5a8c2101c5fb501110c727169065f23297947f538ab3ec165d61edc1f6a9e1735e9b7fc06d4d3406cf8f9c6a68b196cf262324a986705fbc802cdd2e6b4ebcf68e6bb9e793ae644 +FAIL + +COUNT = 4 +K = 32e57ccfe7563dc0a20c14ee450837a33606c086ce1467fd7ec58467154338ab +C = 977d9c5f6861a69e13cd854299434e348cd0690b4d04e08e0598b47eea621bcd8a22838dc9c35a72c35fb1a6434718d02fd24cb4b3dd90b0430334a938a218467eeb4c373d446a539810bc3ce1e923b7c20d9f58ea931d4f964c79613bce67b268efc44bdb9bb00a68d60037949aec7a399493defb2a466e33d4831efd63ad1cb89e00b530626d2f0165975ddfc4cc5e0f968d3875de0f674b3a517df26480b02b6236ebb377118268cebb30ff1ddf0e280fe1bff61902a017e8decf60753c642f35faf0565303bfe651ec8f0193cf34d4af010c9925b8871f0f8c934a149d874a3b659f78ad148428aacaeab80b1b25dec8b0f7ce54406287bc802ac2c0cca3db4adcaa8400a8636ea339b62f5e94d5e32fd3d1183b374507a2af620ca1346dccc9f83a4fe855b1c0e91db9e7c532828d0944d9a81b553ebdf35e24119ed8164bd0260627ea011e93bc103f208c76498ddb8bca15fd05324da5473157feedd54592aacaee68852968eb54c69eb1ddf607917c57493ea380de0cc6ae304dc49cab80a31b8b456986dc367c70f144e52dd604c8d5edbce5de5efb30d9470bc883445b34fa4414f44bb94a64362a12b546665721fa6db82f0c947f015978412b2ce136c471c98b1f908315a16c83e9318e64508c7e179a4429195a9b1ccc211a1c1d4e4df15c5ebc7ab90926fcf7da03657159e440e93adea31ee35f72f2399f5fe2f8c560c8826e23 +P = 80de48ff805a88f3b359451bb6df61def9cb3551e64fdd3a3a70a3b6d238a69311a85bc5924e395ce92ef394b1e5dc301233e9a212f7fb86272c42ddf5f4857c38d0dd259dc1d663c0d729e033d9b0f7f01ab1f8f1b7192d40921ee0d4696a3e35663c5ffcff5ed167660bf6b4c00e619512a2e827be33c90eecc539e18acc8c76eb332b28b1cc502af571242342f63d155271da3211352128aa0af70c9ce78dfdf084a13049b7bb6f2bd10dd385b412d60bf1ccc9fae1208f39dc53db471a04d0dcc3703b4f7b95e72ea815b64a1499865a7ccc5b740999e76338e1b251c740d75274150a96def8760a08c5a8a6f58273b079c06ee09f79a976eaacc8a04c365bc61a786b496811121c386d274c413a2fbfae9464db6ea775233193395740fc9a5eca1a3820d33f6f7b38a83ccbacaac16479225e108acdf46ca35e573151963721b73b3e1c9a12effff0c3a622eb9f07bef7ae712c96ee3ba245597fb8d511698d6e819a967e0d1868c0c6055333b7c13a98cf63d6a5d87779a95345ca8b7e9e597ec588e96f8fc2a7f0a0b8f1543d9e362a911dfb1f03132a4e6af71b503c41814d6b684a26b8df00cdc657ae129a1f2a18cf4b78a3981de68296b1268609fe3ecb9928b90df4553be37319fc508096fa54b35e4822328569da60a6c660f30c61f02f4c5ab2527cf36cb7da8d7dade4c714ea3fc2da8f65b4199090e114dd + +COUNT = 5 +K = e3982db2032f2b4ce658fc44b76f5964c45cd31bf803708982ae599186fc3765 +C = 975e49a4b9a770957a1bb2be920a4f39b9cfd69ba46983d2473d631c08132b9bf61c44510b8aa8bd48c70a86276aa1149d8fdefad511d15d2e2037d9e920e640cb71a97663d19eb90d0b74d9764d03e17cda87ebec6e35ac2003cb75bf9192920d910188d78e2e664255fdf6c9190319d34adb858162ff0830f37fe1dd44003d3d5a1f9451949e368f46ad1977ce622daadf8483a1f60359992b9b366e8a81ffbe96cee45d3aef2fd0ad8c17cc34927af77a0d6d0c5deef3b4a25c82ec388667a493bb0599ac492b351246cbad6d283bf1820883afa48bd909eb7304b9fc5b7d960344309133aab7a85c49f7de396926f50bc83c95900cd049eac1b387aae7fcba5345496425f9216e1fd15c20da75fbb26da176149b40a701e15a7bacfe899e3ecc534ab8bc5b7bd081fb825b5f40fa57e363d7bce40020e73f638acfa097b89c50cb9edb0bd6d71d429b8003aa5dcb7d61792eb3bcac795954c625a104209b373c28cf02038c3318916edd2b818e6719ec154cfa56afb2f337d333069f915d0d35edd6c278fae23c4440c40be462a1dcab23758e4a7fbe8436493f58e890092ea71cb8bcf1336e9ee16b852ccc488f21682dc9f02bdf6c56fe8ad04d84a3c69d8d06dee3d126c0a75f142d0c90c256139acd4b719573e588b80b4540024a05a35044cf58d89673923a534c3816492e62379797cd6e6a7464da5eaaf11ee7b9c27b9b03d7b53c03 +P = 43d38ca132545b154995cff07082611cc47a6467a980654d2d1f1ccfb3bcd387e9d7ffa281b0e0b00dc8669207e0d8033e9e36613c98978f8644bb7e505fbf491dcefbe19589254c8abf859dd65cb94dfc99e7b9d3d1f0a31f21285963e1f7b45c7490a522ff887786f7940fb6192f5081ce7181944bdca5c5bfcf2589f9173a682b78fcdf971dd9f4e8529033e15cde560984dcf796914206973dcc13f8c9a24b25dd00c11166ec6ecf33c6ad9b487847abd7bd29b4f3b9c8dc93a6a5a31723dc03245884bfadc12b2fddcc82409d7b14660af808d4e8216157bb6ba03a319193ad4dacbd37ac884550962a4de26ae923f8d74f2f694fcd0aa74f2e809da4689aad9f2820684b3b423ec4a7da0ce4a1b599fc21bd2779653283b0ee81d7b0d9fd3f6d1e75bd71af9620630aa87b73f7b12e68ddbdfa02ae86ae06b0b1aee4a997d34f61b466348b92e36f83652763084a215c47dcf689df17e36b64bae3ca1a2cc22c837b5907236833c2c1e5f3ddb74165fb6f0633990122cbe4af8b5920b1bb6961cdb144ea8d7b245d0128ab76f4fc0189ba97385717e89e0f99c962ee8c2b6e55546a18be0ba3dbebf7e4140eed6aa3558c43115b65b6f6e8e8fb4b9cfbe0b6eac006603667b28cefb4dec037f33568a3c94d9e36539e91b3199d728521a9a6b82b96ff1c29dd1d10366d0510f1b9a9494cd104db2390530be3fb6abdb7 diff --git a/src/test/crypto/KWP_AE_128.txt b/src/test/crypto/KWP_AE_128.txt new file mode 100644 index 0000000000..a682d4bb32 --- /dev/null +++ b/src/test/crypto/KWP_AE_128.txt @@ -0,0 +1,35 @@ +# CAVS 21.4 +# 'NIST SP 800-38F KWP-AE with AES-128 cipher function' information for test-files +# Seed = 7c0f161159cc9e338308ddc59a655450a030832b3d4576c568d63725d57b020073aee9c77d9fec34eab358b83bf5aae4fb52803343bc03d472283edbebbcf75c +# Generated on Fri Apr 6 14:46:12 2018 +[PLAINTEXT LENGTH = 4096] + +COUNT = 0 +K = 0e54956a24c7d4a343f90269fb18a17f +P = 817ddabdc5d215eee233adff97e92193c6beec52a71340477f70243a794ce954af51e356c9940e4ab198f0e68c543355f65ad179cb2d60dd369eaeb9ed141fb18c9e4054ac7fdc83506896990a4d20833d2d6e9a34938796ee67c9d7d23058544a4a35f2954103ce443a95a7e785602075ca0a73da37899e4568106bb2dbf1f901377d4d3380c70fa5175ebc550481ac6f15986a4407fde5c23ff317e37544c0a25f87117506597db5bb79850c86247b73a5d0090417d63e4c257ea0220c2c04db07a34f0ab7954e1dfa2007a1466795c4d0c2aa09ca3986c028185b43a466526594afc9c891c263a7c608304bc1957c9873f544dc71e6f847c48d32026ed03b2333825452ee7e12a50e1cd7d678319264c65f78001996d37fae7f9861fbd21cb506c2f8a3b0ee53c7debe17111b6e3f78a5c5677857b082c2c4943dfd1edf6337fea98a44fc25928361156ef38d865948b979cf6f4b46bd2119f12f0891cef7fc9d0638fd105fc05f9968d16948d1cb820751e82e44cb68e99d4f072ffd1577da6c0631b5827bec7e1b9ec72d18b74cf5f233e85013c1668ceb5d7a1f5e0f016b0ff726a0a9d41e2cea8e14a2f56492b14606d3fafd8ac141335f39f90d56863735628e8f17be90e100ef0785f3cd57db8b9d89a6b2189dc2ea00c285d2657983f8bd7883c215477e67a55556401f1d8b27d4e0d541c7fb7ace370c2e428884 +C = 876f3e53ba9cf4f6a521ac198bc813d0ede0f862ab6082e3e0a06ad82b4f279582f7c43bb63574608446bc2a05f401a68f74086cf2776b4b3df6b3679c2edfb91c024db54c6831e0752ae6f86c7596462de905ee0be908c1b9d043ecafe2ad1cbddb904e18ebc9b7a107031be3a87059516a3d1257812d9c801b0b9f21539e70c47150c128d87c5e58fa6e4371aedde69c7b5cd16b73ac422676328131f3ac48c602bb6e0741805aad9d23b33b3523b86cf0588cdf9dc6c4d5f9fa43d88ca17976eaf48fb37a41a598266da04144373df5631cc5126341c200a0c8499b29ae96e6e6e6c2bdf8d8903da62bf8ddae970569b695240e77f8ac5b191da5034008b6ef21936858e69bac372bbafd8794f6b03711503c1875528a9348681844edb199a0664d740f0f0b1f866c4248c80fe8b5700a3c4134cdddb17676e0cd37d6d81831a0f4adfba071bb0935502480eccd48b28be5954ea6c7d873b51b8bd2b709c5b6132ed31296510915073c18f7012f0eff6a9aad5340a19fd5e372d35260b718d9e4807b1954c24e6a4fd48e4dbb8f395474e99ab577367d2ab5ccaa18c947331047dc3986e213a878b41089aa221019dad4191a4feefd095f8606c2700a46d71cbb13efb6957df925ec26071c04d04d5a94e138e5fc5d1f059236aad76208077dcc607b1dd2086f9c04e33f955822b457eecd68bd5f24836ecedbac675e6ed93d8a787cb57ad68e + +COUNT = 1 +K = 6b8ba9cc9b31068ba175abfcc60c1338 +P = 8af887c58dfbc38ee0423eefcc0e032dcc79dd116638ca65ad75dca2a2459f13934dbe61a62cb26d8bbddbabf9bf52bbe137ef1d3e30eacf0fe456ec808d6798dc29fe54fa1f784aa3c11cf39405009581d3f1d596843813a6685e503fac8535e0c06ecca8561b6a1f22c578eefb691912be2e1667946101ae8c3501e6c66eb17e14f2608c9ce6fbab4a1597ed49ccb3930b1060f98c97d8dc4ce81e35279c4d30d1bf86c9b919a3ce4f0109e77929e58c4c3aeb5de1ec5e0afa38ae896df9121c72c255141f2f5c9a51be5072547cf8a3b067404e62f9615a02479cf8c202e7feb2e258314e0ebe62878a5c4ecd4e9df7dab2e1fa9a7b532c2169acedb7998d5cd8a7118848ce7ee9fb2f68e28c2b279ddc064db70ad73c6dbe10c5e1c56a709c1407f93a727cce1075103a4009ae2f7731b7d71756eee119b828ef4ed61eff164935532a94fa8fe62dc2e22cf20f168ae65f4b6785286c253f365f29453a479dc2824b8bdabd962da3b76ae9c8a720155e158fe389c8cc7fa6ad522c951b5c236bf964b5b1bfb098a39835759b95404b72b17f7dbcda936177ae059269f41ecdac81a49f5bbfd2e801392a043ef06873550a67fcbc039f0b5d30ce490baa979dbbaf9e53d45d7e2dff26b2f7e6628ded694217a39f454b288e7906b79faf4a407a7d207646f93096a157f0d1dca05a7f92e318fc1ff62ce2de7f129b187053 +C = aea19443d7f8ad7d4501c1ecadc6b5e3f1c23c29eca608905f9cabdd46e34a55e1f7ac8308e75c903675982bda99173a2ba57d2ccf2e01a02589f89dfd4b3c7fd229ec91c9d0c46ea5dee3c048cd4611bfeadc9bf26daa1e02cb72e222cf3dab120dd1e8c2dd9bd58bbefa5d14526abd1e8d2170a6ba8283c243ec2fd5ef07030b1ef5f69f9620e4b17a3639341005887b9ffc793533594703e5dcae67bd0ce7a3c98ca65815a4d067f27e6e66d6636cebb789732566a52ac3970e14c37310dc2fcee0e739a16291029fd2b4d534e30445474b26711a8b3e1ee3cc88b09e8b1745b6cc0f067624ecb232db750b01fe5457fdea77b251b10fe95d3eeedb083bdf109c41dba26cc9654f787bf95735ff07070b175cea8b62302e6087b91a0415474605691099f1a9e2b626c4b3bb7aeb8ead9922bc3617cb427c669b88be5f98aea7edb8b0063bec80af4c081f89778d7c7242ddae88e8d3aff1f80e575e1aab4a5d115bc27636fd14d19bc59433f697635ecd870d17e7f5b004dee4001cddc34ab6e377eeb3fb08e9476970765105d93e4558fe3d4fc6fe053aab9c6cf032f1116e70c2d65f7c8cdeb6ad63ac4291f93d467ebbb29ead265c05ac684d20a6bef09b71830f717e08bcb4f9d3773bec928f66eeb64dc451e958e357ebbfef5a342df28707ac4b8e3e8c854e8d691cb92e87c0d57558e44cd754424865c229c9e1abb28e003b6819400b + +COUNT = 2 +K = 5f0f2428ad83ea04642d8f90e31f00ad +P = 05f65580a602fc839c5372778bc495219ab159935acf3caed10958ca0e135cbc44a896aa84b1f6b05d65ac45f5930029a223977ca46c7717809e80d8eb91e7ccbc525e69ca0a85d3e45b2f9bcf0c86980b7f9f9eb20e9b558479aa8c814e6113635a9b8b0e264055da68198303ae91683eb8ed3351dea3b8280a504d163e1cf284834e3641a26868e23fcf460d279d3577115d8c4cf0f54374df26ddfbf0c1df5bf71fe509231177ac531514ed878d3ef44a03685dee906ab394bfb69cb56ff973f19fb466ce550ae7b03008feca7046bae160ad47f28c9004da68e594bcd7f9ca8674a645c50768b5ee0ec2088f66602a429f95492e09dc567c11083eb18da97d85968a86f6ad05054f4a9c4bcd57ece2511bdb38afd78084b0a088112b81b993a4d37674d97e8081795ee055d9c37d2907d859be201e73580ebd439620918e7c4b42243f43a59b475095205c40a1d37c0f87a5df19450ccd5f274f186b0f45f7bc153d30ce3c873d7bba5dea5a8bd348b2f0b4f25461927642a2991c3c4bc3ad34d09c104322bf27e8eaa0ca99c0dd47a3c4c618af02599192e362e75de53db336a68b223567bcddcd7feecde0aba91a1eac0ce6327d3c9c5be36698494b2b67ec0efd36b744d794f521bee251b31dd29852a94e6b95f143a53f93f85ec8c2e86e1026ec949aaf97fc9b8d728c13e1deab628e9624ca966992efae61dcd6e5 +C = efa9d549d0e975789a6c84b99991c98cf20db4de6789be6f9f7ae109e322a6f04a1a1c1fe582e4242a5e2f2b390827d7e52f1bd97a4e745920dda69a25fe93fa5de82c09dce8a2593106667820dfa1f55c8a1152ee02ed0c607ab986e5209859cbb36baf90ca63285c3128fdceb18e5145b9d3efe6bc7b8bac7837637ce5553d634b13fa3888201112248bc31e0785f2dbae1a8eaa7f4ebc0b00d21242f03acd4e4b0f4ad5e9bb1e25301a331a4b5535c1253b9ccc7800cb2e80602ec9ef858865a39e0ba28006da93f9c26c1fb9ee8258dfcd7e79f02ab0d9c2df9ade309fa6c604fcbeb38641b2968ff96349bcc34927cc479c30153125f7ad07068e5a4ffaba903d27488c94bfb694d8277251061a7dcc5b5fbf47ea88065ea1df007cbd4c1bdbc2e3609d53bf99bf2c7de8ef457fd7b85882210fb52c5093415dd2b37084b75f83d2a05a669867143fd95705f241fa794526bc65c5f6422410da4783340497bc54852125e3da579bfabc9ba98ec398487444b3da454f40d8b59d384cdd3454ad77f38d4ce657d10b4708dd4ecb0fcc3238aca57258e082e8cb86d802b9722388284f232811ec35b49ebba151d5b0771feeb6120d8bee8d55fa9c4de45d8f950752b3b9c6526fc4fa8fdd02c645fb053cef8293437111c85b07e98b3b38ccd3de93cd6fd08fdfb8a3a94b619f9acd226be3bd3ff906f14b1dda93cccae783c04ed545db685bf0 + +COUNT = 3 +K = 9b5c2e4a9e53d3e5f5670af2440439db +P = c4c726199cc27b81c90ee59f1f44420abad2a4fe0f24647952116ec46f364a3dad1b48ba5bc6c48c056e34764ed4b4a2da04e7e45ff477df8364ee9f116c82dcff7e9ae2db6a7722f2261b6cee1ef7cc66820184988e002886a6b636264e7704383543817e119ba3582d42aa00aa78dcf84d0ac92ff69f09046f89e7b608143699f9fda37b07d3e2949e935bba230e0a42c2d41d285042feaa480bcc1ef8236d615f449107fad97b5be514ae39d586b98ed45cc39784c30a3a256d62336002b1f7f6cedc3e5418d6f444bacd74d7bc89b3ec65c52191b4a2f3b3c7b682f254e6e909c5dcbc11d5def56792f5d2183e5e7119f268b0395e7f4f25b8574bc921da8419af30113bd35b11c21debb979fb698752264595777be7665419052cf3265117bce96b61f27da4072f828bd9315ef25a9ab9eb4f5319907cdbce6104054c8563a997cf477523478e6d23527f91997dd43ebaf629003530de4b8406bdbfae49c0d97920b745c78a665c438ff064d24803382f79fcc2e24265adaf707394b832685def125b69b1787719aaf92e518645ac22dd94d0dcb03f052c87954854d177e2caa6ab5d9cf3dc4ed4ceca90d2fa0b235efd1b7d17ba9758987d127b11204047f22e75158720feec549f29b67a8158e577325e178d6b757770d56a30b85d12ab5fb164a07a5f613b53d075c44cd3c1e3a311515aeed2427f70b3bc018dd796 +C = 09540dbbe97e983a3420ec1ef7d1195f9cd32acc93e9f31d07e68dd9d963f32bb23565a37d97e857e5e40eae27946ef83a4da10ec29ea001fbe892133a4814b04aa3ebabfa295a19429c7e6b263293d07a48f5b2beea2930aabe6268aec00a8fbcf9f4865d4658905413a0f17bb08bbc6466f8d3e1744d9ffe6132f94ce79bec4ffea05785525eb5e071ecf30081281df58f1b5295842967a486ee262a7c366978140bcb8562abf1a417c7b1ffe07b1748978408cfae4beec8290b312f15d3223fa7447f5a89e52ddfdc4f79cf1d9fe4ecad3e674e98136c457e36748da001970cceed0c61d2ea5f9ee5f9660ad561b9fb808be3d4455fe76ae9778a49526c8461f99dc2c271ff9aa389d3e6a546a82d15967a82e8ec9b64cdf25fb73afccd7cc2fde8d07ef4a1345976970997facd5be16566c7761d23f4a31909a5a31bce35e33596a861e426fb56d9ea13e5f6219aceda2450434e04c454ec8569ef9076856cb48f36618e690a710dfe8717526001c3be7eccb671dbb4430289924ae975a30b6fc7079f8c9cbc8a268f5defc03d94d5bae0474987b7ebd4c9e29eec9080e8d85776c570089fcd235372518dc38e481f8a5edc2105bb4191cd81a19e51c60252a18b3058ac1ff9368af59a2caf82a06357764fb3721287bd28204d77dc2eadb0913cabff7cd63c73488e92c818341563476e69a50fbb781f151e02f2df4a9fe05c8419a3393d67 + +COUNT = 4 +K = f2713273ad5b7add10d2b8d8b61d2f68 +P = 1c189d6d34b57c699dd8c79e30457c6735f3697aa6825e14257906e18413580727d676b6e667cd58e0a47b738abfd91144952940de60b161b0dd261d68af12573820f4f172b32d7c032ed7db3715fc6ceb92ec2d614a2005ea1aed14cc5015de143aaf6dc2db406e0fd31976562250e80eb79140bfc8d14fc79bea4159d66e1013704b474b0b1377220741dc55cecde0eed4e0931e58025e7fb672117a8288587cc91b1a41fb4d1e9e4a7ff59fdb814dbd9521dc148abfe16ab62fa45a3dc361cffb422482f4fd93466320a11d9a5438959947ba51d7761b2a3bb9e0b843ea6a71cba54a96bd14de8360ac8f16ece773d7bfb25df63c1aa67a7bcb587f618f2425bf9aa018eba5aebc2911b9fb6276e48d72dc74836a290fad0f5c545934f1231ed57c6944a464905fb08685e815ecddc8dbe4eeec1355f414fd2ce975c0dbe29bf4369e05c1582cfd9a7ddb7659247a0f6db38ba165f1f46a472760bcd2609ffc8bff49c6f54698063fa81305696f7ce25c95b237c6a4fecb3e48167060f556359609b73e738c5c3021d0e5bc62ed31a2a27f43dc417c0041f8a2402fa7bf76c72e2b290c060efd93ef65d0a893314b03c098a6674d0137f12eba3ebb63b3e65fd0aac89847bf9573d9eff0b1283843bd4edd6d459de6d559e48633d964dccd8b9fb5142596430b2373f9448606f9286157e810dd0f6a72843b0cb28ab452d7 +C = dbeedfe9aede047a07402d23b1b349a3e75490d3c404240c872470aa4f6b5a1723b6a0e455a8961fd25f88a9329b4fdc7d8e6bb2b3d7403bd65418f94b933467d882c1aaca702a47e7bf44916ce5eed0647250d572686c8a8c9f9437f2ceb13b361aef929d428c35cd4cf1d8970d98e75c46b4825c871003eceac2412adb6681f0b8a1d6d6bd7eb41c6e58ebe6909ab061d5e832f7580dce89eccb4ea2546204e895ccb54429fe388b0d9173922e08625d43f0a10743ad76230fa458b0971028b18e0f04f3c1049012a8bbc2f93934e0b51b943efd2fa4a14fdb795a1f21302529653583edcfa3c613ada2bf69a93e5a29a20a6f9d9df7891e3b438be4f9f714806cd57afcabc0d5f5753af804d885ca1ae23bb5fd2593fa361e92e7d12eea0805453056022256410369dab0e2e8d2d4c9ffda1d7df8ba5ee19c5bf62133d1ca9a713fa45157d327bc4e1d8e7a105012036939a5d5ae15a5fe8ef989c8323129b8b4e43402bb4f60f35483685893e9ea0b0dc4a8238148d0220cd9bdd7dc42590cc303f706cd81cc5f6ce761ffdc570c62cf734cfffe0ec7be17c7ae3ab34c65f1a53267b03de4da3a5f921cf01b068c4098c7594a3051bb03940cb6c5bac2aa04f95bd30bd15ccc9edb8e29091047de011ee9591cc4c83244750dceb8c2eedda797965c1243521c19228eb2d799775dd83ceab5aae082cfa743d58544b61b7104f3d10f632994a4 + +COUNT = 5 +K = 8967c8058742169ab39d2d528130df80 +P = cbe7ac6c232b327f7d9154acf334891398fa0a1ea64a4f15243f488ecc784749fec41fab7a447e2a2cc75a44fb548a46a46e51f4c245f64901f3acbf18f468a28367c51060c34762c8a88780044761579846557f285c97bcb9c966aa08d4cf352c26d8a2f308803393155437b91776ee74941da9db39ef64d9ac9261f2c7fb6349e52111a7c146d5a4ef6d5d00717ac93338fea5ff0c90cdefe0d66b039045330877d8596de4c35987ce70f660aa8777276eed1b128002dffd90ce03224d505950eb2c73f5e958df92ee1cd8dee667bbb8cc71f87e4ce880585f004160c798ff2cc195b09921c73951332bd437840bbadcd10730272d46b3f23963a7c0396275407bb8041a6e5ceed4d1dc2a65a70d4843660cc039ce94a4ce96573811d2b8be00e91dec7486484ccb050dfd6e319001ba8b8fef48b03d17902cb91792dc420c79e823616cc79af4e738dc077519015c734c1be0150921657f3139e59ba4ad8e75e0f7b51806a96b7249709faac3cdcd53bfed8f0326d19000ebc1ae05a43e96c1fa02f2cfadefaf871250aff6eade8ce8d4b8d5a686d553e8a66d96412f2f189fb724e67c8acdb229501414e45c430a9533d211a217eae0030ff10db12a399567e94c900ce839157ebee1f4f876675794cb3642ace55fbdb261f1369807f284f4e6f8a2c8330eed88e18b8ff564fb754b96f8c85d28dc7a0b18805ecc3ddffc +C = d29eb0bc54c43081030a3e1169f243eac73f1d0fb2b2f983fb25755684df4331a1932b02e237502c1b73a8d744619f521457b72fcd7401973ec48ee915054e5e12577ef1212d0e642c9dc7341cdaffd344dc480eaf9f29019355b07de2f05897cb91b00b4c53714609dea69f18c7c93429b73373311e0c4a45e2f2b3a6bd393b69f90a4125eb635a794563a68e092cc66730d236909cce6585d34f47a10c2968f161ed79c16c18a6c093c1fc455eb502770ee436dd48c091a4cefeaf449c5b27f2fd2f9150a601bccf8a37cda65b25917728ce3f1f12f55a51d9110c16132bde100b6479eb8a1ae670a9ca396f18a2ff19fb5543dbd3b189e51ba5f12516129071c997044df747f4ed70616e784bfb948a63211b224dfdfc5b9116b869fc5313c761d55c759a6e275e9ac53e83a5386e2cfa50f6c1b541cf752da800ff991ff896b79b9e691d67e96fffd166a06f0c300b7d9bb552f5ec7df6eea384751632ed9357df5a5a9fda931568930fedb0536f5491d4067a3951dc72903d1ca2f5f1b713e24cce5347b056e2f8829d34143032f53edb81a765d2ab3e6cbe12536cd85ac3230fea546ee50d991e13c562bea3d694d3990b1783a373a59fe12cfdb74fa0275e367d76bdef698dd33c30afadbbf0fe0dd7ddf288aec7a397e263a5d537df9f606f5c126565c06ed5e0bd6753d3eaf5002b472a1d7f4d7df7d9a8fe8aa2c595ecef8cfb3da3e7 diff --git a/src/test/crypto/KWP_AE_256.txt b/src/test/crypto/KWP_AE_256.txt new file mode 100644 index 0000000000..66d8523987 --- /dev/null +++ b/src/test/crypto/KWP_AE_256.txt @@ -0,0 +1,35 @@ +# CAVS 21.4 +# 'NIST SP 800-38F KWP-AE with AES-256 cipher function' information for test-files +# Seed = 6eb04695fd5dc2b0038aff221b225c302fc9cde3d6dbf4195d9d4d2756c8303906335e07679fee9a80e5d0d1580f7cdab8f0fdd78c0fa58f34afccdcba4820a5 +# Generated on Fri Apr 6 14:46:23 2018 +[PLAINTEXT LENGTH = 4096] + +COUNT = 0 +K = 20f31cded60b8ed8d9d3fd1e1fa6244e76c7cb7628bfd28a5d63ce8aa2c9494d +P = f07225202842c8dede42215301e44b9bb7e625d3812f74f9b6ddbcd024ebd1f33e2cbf280b9004941f3cbf86c880a2357f88f92a6dcf8dad9da7dddcd00f3635efdff0af4382024e93c2af66b991e565eacca6b886f07178c9b4adad6f0d6ada5ff6aa7cd0712519a947a8089cea5e1e3e40ffe1806010b0149f9ffc7c4dd3c31b3d08d5ae1997c52369393d58611dff9bec501c1ab35e6ed3e7f9445a34e211010a8236686f154e0a5ae3433d6a844eb3884961aa6592216d93952b46bb58a4195aa80966ad0ccd4a7e23823912556a90d5ee9c3bb952ecbb9d895dabd3b11ab4f2e3a6c2582de50403289230ef4dc46e7c0d870a3f0cba9d643a0349503c1b162ddb6350e699589eb47bd563999f55a1adb6b78b52f006901b0427ea7d3394bb0adae4637b4f1ad5d5425e2c8ff3083506d7ad7ba4c7405a778b0a3a11760c96900a5256956cc9710091d073a19f46a985d004651fe2b6448ed761bf9bc81619cf273a6783d868d090753bf01318be21afd88d9f3a961a69f93e9d9fb822c80acc7b48cf14a08b5b7ef15c66975721b7cde9761a145b679155472a44dea8fedc0f86ae7ebf6283ecfde5f2444b51569e6723a7a19e28cdf8dec6791ccc14af95abad018f741575b343cb1a20a2a9adf4248f99728069a1e2e78ad8966c41c9918fb7019ef56c153a183a6247d22d9956564bb03075cbfd1b43d96818b28484 +C = a5b63618fc0c4512960f00a1f226d9837a90480baea75265453b9553b12a58c72153080842d7f8710f317f88fbbbf97caf879ab4bf416ba767ee9aeb34357f4a2d0e8b9571054d98e28804a70bc4d74807f2bfd95ee955bfdbb6f4d6969a0c3c3b541a514647d5cd8c9740ac3496095c3f145c50c97ec98b935158fbdf89705d5330015e48ece89188b8c1bcb2ad6825d865b375a9b9056b743dac720feeac033c9f757f6fe73dd7c4a747661b64cf490a0dd43b547cd791a5d78dac97efcd355f7ebac248fa2a33e4fad640dc34e0d40b0d36588aa32f0864c9446739a6b44ff84666d723bd7d646c5172cda932fec34ddaaba342b02a9604087ef042a2be4774194b5d32cb3fb112438fbf2801050b5424635fa2d3d3fb10332965c73e6669e65195310a3a30602640e9809179cdfc50de585aa1c0072423c626815d281a06eac3b6ffa137716318e288e3f9970e415ef0451bdc557968febf9eb6772c1f77cb8e95701246d9c567048142bb25e340351b87d7391822d9ee7fe51378bc0d08135f9f39cf44b348b87937939dc61f430dfe308cada632722e23aed5a0699e039cf0563ab8025163744b136a13ce3c62c748c89f5e17540f105e7c6ec9ba13515b504342f9e6dc7d65b9a633d8c0b5c9fa858dbb9b3a594406d478a81bb9abfa289730408c1e303c663a61d5caca00f615065312580042862397b9aa8c80ca812887664c439c8c68 + +COUNT = 1 +K = 85c8aa6d9c83cbcb11550c95cb9fa991d49dc89fbe2531e10694269f38e9a309 +P = 58ffd9e73b5f64cb951b7df799a505d842ef0cca6d4b21027680793565a67d47db0bc872a7640691216c044fbfc0be1cd33ffe9fc73c5ad8cf38bcfe6d4b7b76639ef4200ced0eff2d361e9c948075f09398fbe5ef24d370a5a16b515c102d415813cbce56f6a8f7b5227db7aab33c4d8162ac3c178e2344f3c7e123f0e60142112b960137c0176c450248167e9714db8566e2d4af731a7ef3f88730a4be4cb99bf46eba39527ff279be67aee1f4af25b3396aef5883fe7086fed7285af5216c7945d9bd61d907a84095d6fad383a7a90ad4061f7241a84358cf9fbc7048c010c7652bf47f9ff58f1c0cfd62a5fef92b02074ecbf4762af71eeda9aeb8497d7b33beeb4fdbd80b72f2c6dc9a12409cf7ee3716fc07515970411ed7e113b7ad9865d822a502976bba1d2ef254dda4acdf6f55a04c4ac5f6a5e011375af4cfd405d1220a10465a4cd01d160d179fc7ce614ef4023d55dad363e3639f1eb8fec716f21d267ca21b0587186d162b4a3cd23f80e33ca330a8c3bd756e70c2d457306cd54be9e0433bd9416efd861ed42fcde10ccc98389652b5c14cff6c73341320c93ee457f9e3f320c5c5564fe50eeecf2d7a62a85639ddac4abdad7495e8926111b18f7866e6b3f95c788d9124ab9788210b1e25524427e86049726200052404d9b3585477bfc11f12c4fa761ed86b7449a5471ce18f964acee913946c0997980f +C = d4112af26f37a7e2e9cdc0fd460cf4cf4f3985fc820348e63a095751ce30b2fa5d6e89a8d37b8ddd3dc2af8fa64e0db729f526bab89562ad7f2bbb9ba02668033ebf6eb742904f37fbf1d87b4d23b1dfc815529a6e3f24bb31ba1d4354820a47e0d7b0acb4e495a50912824715d24cdeab0be3597dc535326ee073eb39b925c7699115dfdffd4162b84afc61048c7802a76ddafec243b91791a26138f202bf365a0b0863555d48c953c50cce5e09fede4a97571d3ebf0582c57c39680714750fd2227a632274adece8a4bd13413825b51969b3e965ad417c96415f4041d8f0d0a3df04cbb24fcfbeb95b401be7ea840da43606cd5bd56bfde26034fe94aadc78bedfaa4eed77e64cdc3d059e3765ff6346e9344f0e0a183085d78711b13d4ddc356a669693d2ad090bb67e8013403c51c81951f8a6241269d3423a739b44215bfa403f8927fc1d100587d602a7efc505f28edfe51ae8df407361fa06c09d06c7e960cb7b7041f3603faa6b4767a8a3c3d1c8ab05f75143a3061396c7289503ec29237eea7a364eedb77f66da308fe8e194c9b1784364072dbcc8aa1145db1a03f3862c38cc1a08b569f8576623915a644700ab43f7eff7e59684eea5595c31b13778824704b4aaa9c1b5d2acc4a6cd2ae21c5b0b32bc1433d536e8bd7a4e6c5e6d1ceb70dcd2ac215bd4619aa1ea8c184033b3279cc9fd094336c5e6f5112bd9f36fbebf304ab04f + +COUNT = 2 +K = 5309c5dff8fb03b007c28bda0a219d329080120b430f4b5af9df60ebbe20890c +P = 22b75fa402aa5b665aa71db0e24e76a6796329fea9128dffbbe03764e23d32443cadfbb6d557e833f841ecf5cc7c9200de81b2c58fc72a1a9451ce51c75abde6504b7868d1864a5824d6ef5dbd57c80e488a011102f7a321639fa57c40a5eb8479cbbc7428bb5497dd6295e270b53b00eaff17c2aac199a637e2baabce9c3f5af8d8c4698eea5390d7bdaa92ddf8190361a2452df2f44220b92519449605069661e0360cfef6841b734c8bdac87feeac243693a4e114995e1985d5c93e512d0f2fa27f12db8803e0aafd974d968cfb82cd9f0d4b09f34a440cff85e09a63462fe9820d5f1ba6bc6a489f30ed570e44c06668b6a4d3b977a6b7fdff3e781f0b2c7a1361108eb95f569c3ac5dfb1352cfe0965d9bea70f923d9f65cccfa83a9272947b3563f81c92f7f5caff203137b034af82847de0653bfee01aea476c9112267f97507b6949dd1d0d7510fa280432159a0b3bd67a8e628ef11599be4459238161914520b556fd5d91e92349169bd2ec175a9e728ca78b56eb2bacd56fd2af2696d1b116f5776e9df459c1023180a18f5d6e3718ac402bb0fdb806cd7b1cda6fc107e635f6a756005df79b720f3f274deffb31552cf238ec93182370d0ebe9f0b819e2e7225bc2b77e702d5df2825fe5d42005f1e39d67414ea539810db552049641ca22bd6539f1efefcb90dd479bf93080cb9df86a9aa99048f950297b8343 +C = c6a64b49464f5db516dd39f3d1dbc444528b5da57016b5f2a5649965a4781962264dee68d4c78e987f9446cdc815aabeff2590d3e2679a2583dbfd3aa6b8bd3bcd86d66d598daa6e766a6ab8fc6fe98a1bc89b5a137a342a59dfb52c7e7b2feb2a33d5f936503121476a9eee8d5c60b6c4c9aa7f8c56ddee5b4a9d7908890d3aa98f45cce20a074896aacefb6d7520e84b6675d02b819f37929746298d2c81407c20328a1ff4ee6da8298fd639fa9bba4ba27da5e19520434e27ae4bef59b73c3660aba0353701573d602d8135442a14cea4dbca3732a3fc8e5ac831929ad48ca30d4ee0f068f54faafb50bc7c6a784e81cf86b29225200f985af914ea6ed166e08c04e6324a372550603c98bb6c010ea7219699e76e4cdd9c4b8e6c9200d10c51e93a57f25b0019ae436dde220868596e96ebea3086089ece51b93a812c8120b8ba60435720ed690a2d1ff7c024cd514cf73bc7cb121a83222e4fba2dca65aaafd8cb51ac096511f83327458c53119f2462caf6cde5ae679fafd4f96756aa496ae6657ce417b2963c09463ab810ef51b4942dd1ecd120d69ae76f8928f3bcf20465f68e526beb7cef276533270f08136c4088182dcd626ffb2c3c4a357d09affb6b935e671bc827779ec6f260acf2c01f1faad57b162fb50579ed45909be1cb2a4a4dd07effcae6a2342022e0bad504261bb8d5d3b73eea932b0135fbb76fd6b8f8d3b6435db6d3 + +COUNT = 3 +K = 8027a28b92435ac111a67ba0f4af5cdd50e6bbf965cb9077189143440db0327d +P = 0d8f70b229ad687ab5f55f0b0ade81a4bcff76dba57aef40abb8074b9745ad74efcc8d8f2202b92a9788f8049c864e5973403279dd02e165b772ed7444795ebfdafd8e13a9a22ac1103d0c15d8d279c617dafff98dbdb9bcbea923a00967287ea9accdfcc90b2b4047021115d5454d057cf3a27a44988a8fa71578ab7751a5d3bbabd1a335248564f5e334c3925119a29c219aff6e71b3963f603b0f6e8213219fa56a36e33066f49409c643dfa1ab7478630d623c7b77efe07b0ad4811a522ed81a1c905831689747efb4edab65062cea3724c3f9decad27290c4ca0ee9c68f1ad9ce3981a0b712acbe2de17eefb7f9bfb3efd66aae691e63e5d64233715eae8957bce7924fe2f259309ddfe050cfca3cf76c52f96f8b7608cc833bb3876f35e37f6a83ac0a21f0c0fe859133c17c5f7422c72741137b8c3b5c3ed3e7737d5d8a29c063f1490558982496b7c852ec95bc452113c48bba93394dc1df0eee1f8dadd38715e93a1d7065c528f08525cd84583e250327320405bcf18d8011e3d864978f948b2839bb6d1d7bcef4b5b6871243a5c93a2afc1f7fc7d06c8307a025ebb522cf0fa1e1e9f8163f20854514504f4f873d757faa7938bb1ef91000df4ea64bb985d903136fcb9c4e9467561cd564f61146ac519c08dfa41f22b773cc821cd1252a3ba237c1e8c1c128ba40e0b75e67adf12cc448e47fb4037850b014f9c3 +C = c1e82d374a1d7c07b1f061656fd58b5df0a04c099f3390e98d2cd460b2e2713eb7274b9f646fc453a5d26c3fc0b9203521de72dc78292cf4d61095febeb0748658dc6764fdee4fa498b93a6bc053b3d81e10564cc9681aff2296ae0864fe3db495298ac4174f6ce06ae6b5bf86985c4603700757ef44c82c0e03beb7f2841df2dc4dd8022d5dc7ea2f711daacc1c8d1805798f646f1041146891e88edc4db9904f122c74656a5ea1694f8e6073920481e6cd30b20fac4cad7e03f58183f6b0beff8dde3ab4f781a1dc36ce0905e41e77be65c83dc9b6ab69d5d4c15a1de3cae6b081ea9568578207d678df77e20196483c2e00d2dba604784495949285a623f33e07e20687aadb86d57adb9935865e6467801a10add2ac7dfb6f8ba98e7635d6766eed38ca8fa8101f93018261b872a2a899065918b672423288cdaa417560701600424da6db15e0ebb7a5d1d0a7e1cc8aca714ac6bde51f779033563b49dcaeb8e0330112902b5ff0ebbdd00aa371c902092566244bd9a1e5e978af39adbe13a7067d056d04b718133575e420058529a42ec032cc5fa62035e872cec7acb3c32eb8b02e0cdd81c59afdba65b673c828b980756e8ff6b0160a1e796e221ed40c342863848b76e4390ef730abd3edc73ba975c037e6ba5e58162d7a60cd55b61643e9a8d4f6e5efa2485da7c45991ec4e8d4c6d9432e630e703ad1fc2f644d7577248ef7c7c974ce7 + +COUNT = 4 +K = 1a5b5f43929215da78d1d8c8fd4ba4508a66273be95c85a892da606eed04d6da +P = bd762d13e2385d333e435ecd792b8b3f13936d3b8372466fa7f65aa537bbd0bca184ec570acdb99ce59633bace041fb1374961be99276ff1d4b82cd49d78b89585aaa6cb1bf18498f4d01f2fc5e41e2b4fa56cedf5fe69e39eb1bed303d0795a715bb7eece6b389b3ae81b23b4f053137d54c03c2bdc68c79184fcca1758652c61a5e3c19d49b3af1a8946403b254da0f9ef227d2be6d0c528e1a7b78a55a2e79d79d6e420e9a3e8b40bb3ee74935be7c8e935414209be01532c991a871b90de0b35e963989475fbcfc37d81cbac674b1b29da1d0f9e78a6c3ef55575a8d3d7637b93895bae528d85130d059415d7c456a5c8d94897e567d6d6748e7c2689c98331ee5a7e1e25909901ace55828737e7464cb670399af3f806b996f416550d256f354dcdd1c332b4ca9eaef70114a7bc171efa08b88f1afd0429b2cf15366105cb812596a05e22b06debe1c69b06d904fe6cce284531ebefbae44b9c9eb156dedd01a4a73a1e631fcabc349e07636741580a916b35560d02e1cbbbea0a335b395487df8f972cf8600b48237e7b63bad5f08c85b85043eac0ca93d34df56cc486857d6eb3de0c332ee1ded06927e8acdaa3fce78636eb06c0f805788189c56023c8a1f5a2427c6f0f8b993f517a9b4a3bc3fa9c3e6318256dc49941c1e92973e3ae4814b87135c9ee767348045ef7877027c8ec441c50b1cab98bf556352333aa +C = bed34ebd1c70d52665103651110f847d83e19a551f5156c9720e2d1b038ed5d5ac0be8cd97ad3d725a8fa3c127939cbe1a6946558015bda4c7fffff7e00662c4b0ae3d5477bf61e175f8e4ca14cf53ccc558b8fb5f371748329b6cfbfb277cd0828a2394ec99f943775b4a2c1c285127a2d4677ba3b918154908badde2a74b58f73ac8f92b440214a3cc990f1517372b2e53272db9bb191cc7711ea31ffba2de2b646e8e312f4eedbe9e51e182603cf075ff69bc4d845410bf66d20215c160df05ab007b49a5396bf69d702d193aa0e2a2f9d62b7f9fb46cdf11864314101c7b7072f5ba8262c32b12b14225edba48b440501163d027e7fcf2292c9b06ce19dd0eabc6b6639769544d71bf068b8e03c4834c4a785a6b2b927c077f839f29da61c6c52c39ef4354839eff993068b67438266e10e9a421a90a103835829320fb1ad9e7e0cf73bdd22aa268436f4df0d973c401f8bb20f55585954079b6de5a2707ab5ce3b9f42af09b7c1996a45a15af12d041f5fe0c055b969a9055f7656cc2806745e84836903804799ffcc15580f8a50362f4dab9694e8ebf6f32cacbc3ba3501959ffbf33db0d231722715705e685df9202f0466c3ac0f1361a71905e23b0aa9fcac76b01d6402598861084477338b5d0463a641e2576f76aab2de95016cb31d37d8f4617e3908a179b43e3d50c516bff1e388bfc0ca519430f85a0de5b0e274cd0bd021f20c34 + +COUNT = 5 +K = 2a919617d24baf991779de6c06e68bbc4894a4e9a702214ba3eabfbd0015a7c0 +P = 8d01e11206e3b9285cfc73c2ad6b238536fefbe824f19588685601bf94e1ee2515c4ac281aa04feef877694840d15f2a6722661159a7216548d768b4754d65f1f1c522daf2baebbf88f638fb324b182e61d315f5f12b04c486022749f6a222d87c7d635c52605c7efc1853cbba466d138d3cda22979e7742e4fc8168f5139a72818109d2124c20ddcecc74fb388f34151e96fd33e8b269a7d7e51b6fc6ebb427219163c3d9f7de4a6831a7f8b596b4b490789f1104fa160115b6e8d191d1db885e42812c01724170e765634fdb8e05555cc7a85c3d8cc7a8e299b4f3708a4a5189871037c0d04216dca8e6127b449ec6004e7f076430d1f870f0d2c0c6812c810b4665f7fc07fbb04b56bd956b81267d2408c31be8dabade28a3c40c609eee3458b7340715272ee26df8d875d1139511649b629df067a8994e1fbcf7ec60f565e8da257db1b7ef3b2b765c77124c8120bf26db8c47f493d2afbbf8b89efe2e33c21c2a2a1141c0aa5b9dc1eeae50714304ff35a7cd34da963f5249bdce8e2c2a3026672bcd2ebf311f446cbfb7171fd35b446f0270320b30b554f96573eac72ea0594306d43c5ed48a6c2d01a363e88646a8759117075596fe17f18c0b36d00b7976098fddeb7abc4e34bf6d6b35238f81b59d169db4578a96c2bcfe78bd583fb31fc2e7fc97c6f3460147a5730bdf31ca197482acc341b7a719c4e1716cde56 +C = eb62ee28d9929093e3c6dbc0592c35dd0ffbe8faa37173195da391b84b1ffb342b9bd9f0df0947c33c7c74a071e7d71312f91c8e1f11d680865563f2d9604dea06892f2adaf2028246b74ecc82686bd7c369426a09f23012b69a89e7e66e7cf008b41dbf04f72cf950fd8f6ed63b3392de53b6feb34e45df3153e4aa6fdd685fcd7e3239f0509f474d8f6a58abfbd36bf14f93fecf913b2f9a0f0763c39cb6828651434ef0520cee88f46daef7932e5ce1549774ec106c2aba54cff64067e0202167f5a3ba1cd6396bda08023d2cfa9100043b44b8d90e2862d7d2a7f6e3f5eb6976dac2d5dbd2adeb69858ca391fdd4a582d3cb79a2d9fb57ad5b2cbd157b1e36ed49fb848e9960b0dd1c715b701f1d379027999fe8e35769e27a9ef60a45aeee56c7a3ebb39f6c50796d1236e721cd0e5d931e6a85f28fd87d652c3e5b706e2e97c12c4b33fc7df4585d60d0326267d8d252ab8970a2528be086d7ad18ee4b1531cc13b9c88cb3a9188a47b8a72cd276eb4d7d726a290398a98be0083e9917f349d2c8137a6fcd2232baedb6edf075d8e938319a12bfc31726b13d0e1a6c18ae33e11ad1f451fb9693f1774aec30fa7b473c98cbaf4dad1b3743d118ce69620503a753b87e4ae25f36564c2538d6650291087ae04d181e4fc44b6804b5bb0c6c8a0aa04a49895ea64d13f7d253e62216736a716258bc98c63349b5b19f5ae9aec3a176f98cb298 diff --git a/src/test/crypto/Makefile b/src/test/crypto/Makefile new file mode 100644 index 0000000000..9b5fce5b30 --- /dev/null +++ b/src/test/crypto/Makefile @@ -0,0 +1,39 @@ +#------------------------------------------------------------------------ +# +# Makefile for test crypto programs +# +# Copyright (c) 1998-2021, PostgreSQL Global Development Group +# +# src/test/crypto/Makefile +# +#------------------------------------------------------------------------ + +PGFILEDESC = "testcrypto - test PG crypto routines" +PGAPPICON=win32 + +subdir = src/test/crypto +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +export with_ssl + +OBJS = \ + $(WIN32RES) \ + testcrypto.o + +PROGS = testcrypto + +all: $(PROGS) + +testcrypto: $(OBJS) | submake-libpgport + $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) + +check: temp-install $(PROGS) + $(prove_check) + +installcheck: $(PROGS) + $(prove_installcheck) + +clean distclean maintainer-clean: + rm -f $(PROGS) $(OBJS) + rm -rf tmp_check log diff --git a/src/test/crypto/README b/src/test/crypto/README new file mode 100644 index 0000000000..3750346a83 --- /dev/null +++ b/src/test/crypto/README @@ -0,0 +1,33 @@ +src/test/crypto/README + +Regression tests for cluster file encryption +============================================ + +This directory contains scripts for testing cluster file encryption. +The first two tests test the encryption/decryption using AES128 and +AES256 in GCM mode and the Key Wrap with Padding (KWP) method. + +The third test tests that the data encryption keys can be encrypted and +decrypted, and tests cluster key rotation via pg_alterckey. The fourth +test checks that the database files are encrypted. + +Running the tests +================= + +Run + make check +or + make installcheck +You can use "make installcheck" if you previously did "make install". +In that case, the code in the installation tree is tested. With +"make check", a temporary installation tree is built from the current +sources and then tested. + +Either way, this test initializes, starts, and stops a test Postgres +cluster. + +Requirements +============ + +OpenSSL must be compiled into the server for these test to run; if not +the tests are skipped. diff --git a/src/test/crypto/gcmDecrypt128.rsp b/src/test/crypto/gcmDecrypt128.rsp new file mode 100644 index 0000000000..53f694d37a --- /dev/null +++ b/src/test/crypto/gcmDecrypt128.rsp @@ -0,0 +1,129 @@ +# CAVS 14.0 +# GCM Decrypt with keysize 128 test information +# Generated on Fri Aug 31 11:28:04 2012 + +[Keylen = 128] +[IVlen = 1024] +[PTlen = 408] +[AADlen = 0] +[Taglen = 32] + +Count = 0 +Key = 137f40bc82b01b34047a407f40d5c434 +IV = 1f3de3a272227db8a88ba0cf7b23f7e57f84ce370b289e2f774a0c6184f44f9df9b3e645ae506e3d18cdc819fdc3b31f77d2dae7ee295ba2c776e6f1fefecec740021c4aa1118a6ed3813720411f27ace5c11437a78b3d626b5f421e2f3ffcd0677930e7878110a0cad535c057261c63f0531b538d8bf04f491c16e871f071ac +CT = f6336f2001a5edc519aa64071fabec2fbe4654ff334871e9cb8b12c24ffb7ec9f0d316e43bbdb568b65608f937f24f64eab19b +AAD = +Tag = ea3d8cad +PT = 60881890126afdf881dba4c1a7bd0f9d8c240073517b21c622bfa70c1f05d59544b9dccdd908bd924ca60d23697fe64aab927c + +Count = 1 +Key = 5e49fac6608ee4157a9f0ffde503893c +IV = 53d854bba28eb9d9db71e68b5916f9e73964a0f95c6524411fb18f64977d012d611a15fe8d46ec49bcabf060cfc7989c4a8272567c660c0881f944066b88311992b5d52cd644bf07e9f01d2249e5f9b00ae1af9f2739da627b3a8838e28116b02e7d171d1938edc6dd5d7da3dac63ed148b367961b809bf423510f0a3f44a8d5 +CT = 23bff066410784e0999a3d0fe742ee28ce8095fe822fae0f50b0b17d70c8cdcd705c83e108fcef2d64c5b4db110e9a72d3c4e2 +AAD = +Tag = 01aaf4e6 +FAIL + +Count = 2 +Key = 174b47de82c64196af18214d9d6dce2f +IV = db9653e9ca4ff27f8180f45eaf4861541d30b3b147d2b9b64709983dd08312b5fa709a7bc6afc591fbdd08fa0f21f06a25758ee199a6c6415cffdd9777280e620d7bfaa6d551875c069f5672a730aa68137cf33f86d46cbd548248e68f589c2e699c554ae4680417e9440e5514c1cee03205324f789d953d63518b023f65abe6 +CT = f8b0c1317c5f3550363762dc7fcc847376a7917e1505cddafeb5451ecf4464ef52afd797697f1b0b1e8d3a2376600d6acc1c88 +AAD = +Tag = f6fa70c6 +PT = 523986d433fbcca153af7765d177e2bad72ba52743440250db451e2da643913cb25b33fa364011a8f8d5cb563b461d46952923 + +Count = 3 +Key = 5194e88020a501ddf21a7ba5525bff70 +IV = 444b0037fba6cb9d4f4e33df32289d44f262d8f535564a1921e6a4315611b98a4e1074b37114758b421ca44efda91a48ba8674c695c259649c0bd3c11bcdc8363d3d113a534bd790988a44e72559fa70a5e2deeb9da187e2fa89c7b636a000a38d7bfec2edf2831ddfc9326f0c54956c149e5ffba3f556c8f2a749dc6ed5407a +CT = 31398e58d6e27c50e85c87a4dbfd73134f456ff042c9f869b47a41e3c10db7b24cffc103a2185a696fdc1f2d389cbf41379f04 +AAD = +Tag = 2d28343a +FAIL + +Count = 4 +Key = de250ebe0ea1212480f7193934d1ae84 +IV = 255f658334f1c5258d613ef92da7242079795e9c04c5c4e800aa1c03b6abe77f4dc28cf614278900b52f1de23550fc9c0ace8e8dd91a25d0240281dcd684dcb786839f376496692f3e35a5946bbf7b39cabf7d782f4e77eec53a875d2a5e3106238dae0d048e8b9ec7b05961d9d68489bcbe2805ab0f9cd42b5f8f62b4b28b00 +CT = 6eace8c7c10c713870c676e557c6b49134af26011af157de1e2c6ce0769fab666b9a7844756d6b948ccdf1df77fa98119c83a0 +AAD = +Tag = 87b81d39 +FAIL + +Count = 5 +Key = d0d9c4aa70e5bcad8dd9d72d14c21c54 +IV = da20388ed0709e5af5a52a5293bc4060f02ed6d05d96f9ac3a05c14118a3613ff790b721ff2c888d63c04b9b28a7138ca00d0ebbfcb11b70868f5b90c0dce79c7220fb90d5f3b6e22c6ae3640e7dfaca72ec12813820debdb69f90c8393645d7e96cc36bdf62ecc4c0ec181c64593c65c8f707d6db61b16c6a5c2f05f8851692 +CT = 2f08e5a8027a88f0e223429e6749dbdf91ff9742c7c6130962ae837a434a7247600df8e2004fcf3e81f8ef64e6a23bda002f3e +AAD = +Tag = ef6c0d39 +FAIL + +Count = 6 +Key = 464609f485abe0bf4930102f9637fdee +IV = d0a788fa1494d47bd1cddd55f88515229de5c1a2ca7dca054e08bf35d3c0aba677671d5290c3375fabe40de14e15465138d298edea5efe1ac62452dfee86920fec8e46577bae1c0b43d77cb6b8d1de6ba4557d7410796bede796b8b87b5771e30e05a8bfa55ed92194d506892c33f8ad6038ee8896b98772d1a88a7a40ceb650 +CT = 5e81bd883fbedb3e074ba273751081752c3aeb7a62b08091b768f8f8e6c0913cf633358fc26885150adf65bd1d708d9e45eff2 +AAD = +Tag = 7e715546 +FAIL + +Count = 7 +Key = 018319ad18e5d877dbdd871316fa6610 +IV = 941f8715bbba7b1fdfa98c8c05546a50f86cd02b654862af6c1a70cf4d79618b37abd1f06b7a29bbed74e728a8c78a0ec8ef8312f2552fc4571f48024ec5c6d44c21d69311cb1ba390cda615f246cb175a9e8a522a20b671e6df973b8924fd003c5dab7e59af63f20edf56e9dbc9f98fcac25cc692cd87a3d8fbf8d4b5f150cf +CT = c5a681b2b2e5f68e0cb698150aab9d13e93e900e0e6fb20170a4104839a7e0a5775bb3f20ae814edd109530552ee2b41cf5986 +AAD = +Tag = 75a966e1 +FAIL + +Count = 8 +Key = 3556566a1cdec721469cc86412ade697 +IV = 731a29cc083422da193724a57c8126b587c3817fbc6b76bee106abb3ac48722bfd0cc15deb573ca73f2bc10ad7b60024f297bc52c31a7021bda91c5246c781a95d5d18978c685f096e9310d6f5ed151122262f7d3f5a2b265321683cd72e0693ff608e378199264eea876df44659817997b323e43457e70809c74737d015cf26 +CT = 753174df0aff575fcea79e54e5b8347e69175070a00d58720529b173e9dc64677fdf459ad72385b03244d90810670304129f2e +AAD = +Tag = 41147153 +PT = 7588b757f08b75fc799fc825034ac60585e24c56db94920b6982bbae86030e7a021ddc89a5131e5371e9295e414d3503ec11e3 + +Count = 9 +Key = 2ec96059d1313923fe522bed1e942491 +IV = aafb096a63195cfc959bf93785a48cb7a78b98c60f861c9646129222643d249e50d46f706d670662f60c12a7f0a6ad65b908ede9a56b27c46f07d427754c11549154632e9b5ffa25c9306add4c0b13c7191abd59430a65ccc42c5420ec98093ad6ec6ad1c4d3bb895ca3546236c2c78cd075b4b1f44a6a03d115b91df02b96b9 +CT = 61c6b8bd44c9c6eb075fa9bba7ac0156bc64a6326d32afedb51f35daf232dfd068dbfd0505933519a753bce6de4560b79b31f1 +AAD = +Tag = 26f53f5c +PT = e4b86f8b7684d6a300cdca848ee8185c41fcfe061e61af6f3a563ceccab58751f1884b322019983d99150db217a1e92a8f15bb + +Count = 10 +Key = 48cbb46539dca9faa97b69b32015886f +IV = 1d3152ccf3ff05a81837ac7c55f791c78aba8c95149c80de8724b1126dda847b983a1bfe54ac5206d5915dd0796944e4daf432b14a72c5fcf81822ce1e3e7ade345528641b94a2fdc90afac098b9e4b0b5ad159ba275dcbcc11fec04bba0f12db9b3d1473ea0ed7825d293fd0b5d2d07795b3de922bba5660778adbdb2cf8539 +CT = b2658e897b85d9acf437f9e895189954134c543aaa91fa82c586cb5bb1d96e04b189df64df5bfcb63a567e444f4653aee3fdbf +AAD = +Tag = 48d21620 +PT = ef58f7ad664e36dce523408e497acb871e9a579fe4688be6425adf41c4c41db85e905e9279b93a037648802dfc273b387e7216 + +Count = 11 +Key = c5c2e83c4e5b336e30257c95c8f7f75d +IV = 269c29118eb9cb4ae8fd8ff5b3a5d61f4a63a719416bf2cc5225544cabdae24741239ba7910d1a32364c341169a215264ae62964322b6ac64002d09455f11d9658a9454cc6bafa82dba5b5365b2243e854470dbe74a3043b5f5f82ebefadaca4d468317c83076691c188af6e800dc296cdd941fc1aaed8840874f8cbbf96827e +CT = 891da6e799429c772edfe93d9fc3ad20c25fd5a172d272d0ee6b7063b59b611e4a2805923f182abf99373fbe4a1759339bb13d +AAD = +Tag = 6759d819 +PT = 474a2e7aa4a5422bf17f257b584059fc7abe2d25e7243b434a6f936f5a0eaed692616a43a2aef8b427d83ddf1bece29d96c581 + +Count = 12 +Key = f4d7a0e84b7f024988f0507098415616 +IV = 9d58c03fe45a97d4c556bafa4292766c55bd84d0e467c6c26b0e42162015f3f506c9fa06caac63a3ef6a3f0ea62ca4e122bf453a767b2b00d6277a990329b76073c64ef260421d887eaf89b6deb488a0528608ee8c38faa5f5976b2b71d7e29a08ccbeb2342ec15c46232f3c8867ada7cb8cc8aed0728dc59d706913ba62124a +CT = 11358bd3ea694574c0bde99aafc2621732fcd978626d3a3ef124e98a2c3dcb8261580306b51ffa9557d379952ee31bffd9ade0 +AAD = +Tag = cc46943b +PT = 4a289261f4ced6fbe544fa27d430f04c72ccfdbbe0f93e881fcc1b29a19e706a579a98304cb2b03cfb3aacbe187dc69f923ee5 + +Count = 13 +Key = 31237ffe81db56b9541133156fd0e7d8 +IV = feea389ed83bddb360f42351cfd56321bdd0a8fbbdcc8787725a236365eafe5dbc9c6e9ec8e9ea0f74e623c33a574ea4223a43b1550add0c75d8348315add72ee9561e1750b69defd46214bcc507d4db4c66c6da23612aabc2ebc9b0e6d5aeee270c013a553ddbc7d7d7ac62ecb33a5a6e3db859471ca3d3686203c0c96eed2e +CT = b965d7bb29a8811872c894d535e001d534a7d6e99eea5bd14ebf39c5e79c623a67d549bafbd0dcee1494245c04854f34de677e +AAD = +Tag = e6fac1d4 +FAIL + +Count = 14 +Key = b0e576fd7cc85f7c92d44e4b8c149b3c +IV = 3855af97c5b740baebda1532c196d187b8af0da761489ee9e267fcbeb720bf6f73cd743b69d942f3f44893d68a5c70174a1863dfb831ced0ffbee668a03e1066e8b3dc03dc1471c3a848b3787c0645b20add2fc0cc37e5e0aa57ef08fc69c53897030fcb5579a831ee53c76df2f75d2de5bea93e9ddd8e4e1383bfa1a7c7aa77 +CT = 624aad7fd047a61c09638b8dd5065d7c00960035440303a03ff1b19caac02baa3b6835581f2b66c2381006798c9d5d63d65684 +AAD = +Tag = e6142617 +PT = 0fb24ea93a14e3d76c4d7a991cb55e6bde4083504ac9f3a00d4b0ef53d3929953b53f5ce820c41b9aa75a985e09986d3f4baee diff --git a/src/test/crypto/gcmDecrypt256.rsp b/src/test/crypto/gcmDecrypt256.rsp new file mode 100644 index 0000000000..af72933a60 --- /dev/null +++ b/src/test/crypto/gcmDecrypt256.rsp @@ -0,0 +1,129 @@ +# CAVS 14.0 +# GCM Decrypt with keysize 256 test information +# Generated on Fri Aug 31 11:31:25 2012 + +[Keylen = 256] +[IVlen = 1024] +[PTlen = 408] +[AADlen = 0] +[Taglen = 32] + +Count = 0 +Key = 60c9f83fb0ddbdc727e70bf9eb1acc13b1b63e3056e64db7c2ac55c4f2068273 +IV = c33d34a3673b93bb78dd1e00f877c4e6e4cf628438b9effa61cfe81e159155cc9ca7c1418917527ed3f0a51daf2bedbdaca20fad687a7dd086ae086c8ff5094e9b31fd71bd6f8f1f1adbf96bb2690663386c37d7bce891137897aeef70be10a453cef7e31c1b8c0a24ac1baeaf08a46aac445ad5a8103804825fde86dd4720b4 +CT = df6586921250aacd9d25f432977e92b09ddf89a9403c83a80890ff15ce9c4559145ecd85d86f1573bbc1b48992859d22fc13b6 +AAD = +Tag = b0dc70f0 +FAIL + +Count = 1 +Key = 8d7db520bf88c96d46778991a4f0b6de9aa7fd5d35cb6188a6f355499072af5c +IV = 488a50706bfd8ec7fb4c508511bf4c897c8566ef289b5e58a4c59bcbf16b5ae85fbccaee4a1cc0d1ec74156ae911d36d497f5ee71f1fa51649819c9cb88cf65d62d2abb65d621c202bcb33d8d68018a858d04e79deb62b3486658730735a1c87829acb49e73301902c116c9b6ce110f23a6b1a4dd657e47a328e017c19f0ee52 +CT = 497e1a39ba1b38d263bcbf19cc2900ca4070ad37ec12bfdd30139a7068a889825eaac5012cb5c2dcc710a220cc658dcf069f60 +AAD = +Tag = f20b9885 +FAIL + +Count = 2 +Key = 1ae1e42ee656973f5628e3cd11f0494dc8a563cbf5fbc5880cc2dc6d787bc9b9 +IV = 23e3c948cac6eba2ed11d667783557917f066ff6b93ab9409df9c7c84b27d26817dbdebb9fa9d0a64bbc572bfb2c7ef7f0c836528c9bd692505c8c5e522f57aecf6b479723449398e5b1f45cadd81264c5aca8059562d69deba26395034b4b01325d072dce92e540c159dba92d3e41e2d0947d873ad48f9f0b00f4807d420aac +CT = 3839fae7008b88250b602cbdf295e932e3c4e3710d397a2b9a37289104efde75f73302b2820f14664c064e8dec45ae49a74036 +AAD = +Tag = bce334cd +FAIL + +Count = 3 +Key = 8af302bc8684cb91b4d7a6088cf8c94f9f6e027ba046c2b508956ba3c88f2d65 +IV = 3218736e931392e6510b91210a6a6a27680740ba8924062ea176048d6b42f44ed04a46ce31843b735ef4f63dd1d85643f28fb335d21fc2e3c673e97e6b845e363362d32844c9054a165f40658267bb177b74797a8828b1eea723d51b571d93748c758ea5c328103612b109e008f743f9505034ed3c42ab3dc310c20938f8627c +CT = 1f1b133a1a7b58625fc77021f8ad1751bfa2b8addc0a9837dd5c44632cffe5ecc2e9e54b90cafb6cf8b652a8d2da116ecda3f5 +AAD = +Tag = a673129d +FAIL + +Count = 4 +Key = 13a7942b5a5cecb2bdc0e8b0348d4db5a98572544ee31918ea625b0691c10779 +IV = d92b4d05a549b296e18c90a8da55ec5bff3547a679697c489a1d49dc02bfe2dd85c8f050b32c389c4f857eb4b663f53354bcfe9c3a7e30019f2e3994421bcf3a3d1cc093768eed71bad5139f3f3078514d80a4a41d1284b5dc43ce07efac9c475d6ba2acb66dee50cdc62c463a05ca396e72d189f50d44ffb70d2c6112c6ef0e +CT = afe058cf694d64706302b405243db77c7ae2fe4f33c6427416f8992ba92754c69d4e7c1a89e9b6987f2bc0a7b568dca9c9d273 +AAD = +Tag = e0bfbdb0 +PT = d544d114e3d9ab8aa2b9ec588a112f780a6df74d637be3cd34fdefe14506f26281cacd2b98c26fc4adff837a7bd72173b962a2 + +Count = 5 +Key = 7272e6ca6d6d76c483df9a55c6d07bd54fd8fad50b529ed52154959acf01b64a +IV = 5c55bb8f4fe797ce34c0e281c3b04ba0bce8689493451ea569ba8cbacc74ea36ccf319776f77cb4d7f901fd0ff23cd28ff0ca77ad9d4adb0329fb68a60ff004a1c5b12111d2dd705ab1f7734178f14dbb356cfc0c5c208b91c277235f35afe8c2d46ebf43bd5e0a653e67e0c086ebcfca32a56d56dd5f810f562f769cce2794c +CT = 7f378bc30cf2774f21078f42b5d6b66aa355c8c073d3a70f06775f3c7e5948539ec08a2cc50cae6f2ad9680ba47bac190c3068 +AAD = +Tag = e612f4b2 +FAIL + +Count = 6 +Key = 82b1d2ffb53fc79f5ef88742a28eabcf404074836fe28b5b202ce7d5c68f6ebe +IV = 33f834fe23b9639d30de763faf7c1a71568c5dea9d5d253f28723ccb3306a3cac3cac3beca638067a3485ff743b5133577633ec88dae0aec4fec08e894ab5d61c411f0939772df2fa66d5775f74b3ff36ee61695d7cd2726b9be4df80750011477705948b1276db0cafede5d7ac73ccdf01b73a5492a02c43b89632a501f6694 +CT = d9d92b33a10f4252fff828b57ca5f5f118885df0825be80ea5725a874b7e8721af40bd221e7f5c2c8b005d77af6266cd36ddd2 +AAD = +Tag = 86e48fa3 +FAIL + +Count = 7 +Key = 5264831eaebdde1eadf741dbfd585cb0ef6437d1365bd5848d9cb3a22f57d420 +IV = ede74a8f53eac5dac276bc72518255831b616c9fb50a617eacdcdfa50e197d2941004f785f00f8c600e239cda77c8c06088793a674efb8759c98604dc0143e06665dc7e21d5031fd4751a7cd1b947304645e0987ec7e765db80a743122fbcaef9ec83849e8eee8d011dab67fb54317caddcfc472f585e93df91b1edce9695908 +CT = 9ad126b39dc2066542dd30c8fe81cd750b72123d74aa162113c6b0cf10a9cdb217d921e8f03b400f1ff719fc704f44e26ad463 +AAD = +Tag = 5d7bed4e +FAIL + +Count = 8 +Key = 6c2a43ce5610eab9dc40f43f035f7eed6651789dfdd166d4f106c95cef2a67ec +IV = 60e3a8ddb899108c11550a461720bdbf9adef26c300f098c73c3767621b06eac4f5619b9855d96e4d972ddd38f4538f8e25b7524b46c6341e8780e22c3b42ccf43f41fddfc5680432b64fb4025b378204045bb2d7ea56f4340a4018a4c99eb8b91012b28024d1b2bdb603fa10a28130e84bce38384fbb7c43548c0072c5c657d +CT = e073e948ddfc414948b12b4540d43dfeb9cbfa525b3cacccd21da89ecfb254c840722b9179057cb3ee69358f05e4ad0e41a543 +AAD = +Tag = ac0497a5 +FAIL + +Count = 9 +Key = 7c36a9bb3033bc6f7395155eadf0e07c8e5b3441d0ad66b21625d4950760386c +IV = c8393fb1d80ce92801a4fd906a568f7f404a82b02096e859e70e46d1ca5e231a073c5acbaa4cb4c33581e6887c402753bd55f95c76e68bfcbb1cb21bd37ab7a226e03d03e9dca6589c3020f5f916c50676e8c387f9b1710579a728ba7e7b60955ee5e383bb75d2b9d0f2abc72c02edd925bb32dc5a994f032e9a856931eb1ca3 +CT = 559b2ff3f5fd147b9889146f9fdea6758e5e0c716395cf1caf577dc2707764833099bda0910626c62bbb1ca010b66c54114982 +AAD = +Tag = cd2ed4fc +PT = 178745b297a23a897ec5cfe3a9e373befbdb840d9eb657885ad0423628c4a18f934e6fb57974a52436c517f4463cc5f9370c54 + +Count = 10 +Key = 981afbf7e7b74f08d186616d1f71b682bccc3cff6c5560696d267ad455d111f6 +IV = a2d07ac3ef29978c44ebbd83e1ad330a8fcfad8213fe2e924390015bc966a944a0a76831189a011094ec4ef98535efeb56b871e7e1aa36748e639dd5f9d1bf3286a1b2965bfc029faa0f855622c30cad67331bd11dbcea51e397185cbc4f0f0341fd8e744d2f09b2e3c2bd03af15850dbe2a701855ed4247f97acf9754f5e4f9 +CT = cbb1f9a5bd84c4b1b8df2714f87db878f7d2658cc7c37f75d784e2157687398a391ecdfd1119e087bd12f6af79db50ae7711bc +AAD = +Tag = ad794c97 +PT = 06ea96ad8e6044978ea676056df8c647b7bdfce3923750983cdca875089841612737e6fe078496d77906b9606532b309851cdd + +Count = 11 +Key = 03183678896e28b84e16ac41ebb14f4f436efe386ee6df4e8ad2a7aaf11f17d6 +IV = 718ec99fa1b9b1d29a06ca3973d9c0323b14a2cc34cfa2816481aa2da97b435b0a075a2ed6412bb482bea23df9deddd16944492b1756c65138c3d189b8d2d695150667f46edce88755e868a2d90bf13f170d9b6bb29d9210f3c9f507663756866ede0b362aa5c859e15cd96da4f8c7f7852b3924bdf35ff3a515ba5150e1b017 +CT = 6ecd41a492ae5d6295e9c18290c9a36999c79c87f8b69ff20cb42ccb7c6678baaf159c75ecfb15cb87db99a3236734001545d2 +AAD = +Tag = cad99689 +FAIL + +Count = 12 +Key = 2ca8b01d1cbb8d392bae40bd8a51205a9020be27a23533da51dfe1ad0c4c1d41 +IV = 5b5edcc2f17942afb9577c3d2ed7d5ecaf009ac3ebac985fcf1e0fac0dfdfe747fdfe3d05795337baf41cea3b26e4f35caee1c13fc52d1192da145f376b4ea810ce7dc94845a9ca9184203c3b8e803e7a9bfcbf4a310c85b28b04a007e8e9bd14ff0ae28a1966918a6e22ae8415334e7df0d530b0507a24f755f70f117581820 +CT = c420656fb66e89d5b10fbe3ec0929286683ddc4a34cbaca638493f5c09673609814127709b6b1bb765902f6857761a8d57d98f +AAD = +Tag = 23f1dc74 +FAIL + +Count = 13 +Key = 25cb38a4b7ff73bb632ecae5f75d46e45a108ffaf3ec2d6ad39d3af4b3c64ca5 +IV = 372510e18f877e0f74c1cc54b19d265b27a452cbe91339bb720aa1bdfaf9bbe5365c571ce8f01d2e96aef8bf089c3f4402f186213be72b46b200337c9ebf943bf3d2db1f68c8e655534d9198825737e623745c26f6b0a82585660a7cc3985a271dea9b20f93653701a8d383bbf3155864809decc03ffefc9ce018379d12d8bfc +CT = ea01ae67abee8f8552ad260ca9d08ea5b35b53667a3455718545e007e5ac0c62c1ff0c5b06f8c031079fce5f2367889a6a068e +AAD = +Tag = c6a365f1 +PT = 3bc70116886ed9b4ef795e45c6ec8ea65f6285b3449174f89ceb1294ea73dae9b2f037107f57355be7242abb7da818c98d2755 + +Count = 14 +Key = 19bb98022f5d140cdbb5b1c02aae8eeec1e96dc6eb489d70967588b6f414330a +IV = 6d7b41c7f949f8ff3e9e18ff7af3d67eff5ddaa62eefdbc0b0a49dfb6fb07582998250d1c8e609d57510c859333a268f7e89bca06adf1646cdeb2e592bc86769aba402410cbd71f572dbe065beb37d8766ac61c12e7ac322d213407e073d4bb3c28848c42959cab21f9e39d7f4ff8debd50f40bfff96cbf81af07fbffb6bb2b0 +CT = 60a77e3d27fcea5e505221382d82e9ee39c2bfaa01d7d6ce0d293e7fc7bd0d7f900afa9a7f080c33c04cedd76573a914409e39 +AAD = +Tag = b561ee30 +FAIL diff --git a/src/test/crypto/gcmEncryptExtIV128.rsp b/src/test/crypto/gcmEncryptExtIV128.rsp new file mode 100644 index 0000000000..69c74ca6c5 --- /dev/null +++ b/src/test/crypto/gcmEncryptExtIV128.rsp @@ -0,0 +1,129 @@ +# CAVS 14.0 +# GCM Encrypt with keysize 128 test information +# Generated on Fri Aug 31 11:23:06 2012 + +[Keylen = 128] +[IVlen = 1024] +[PTlen = 408] +[AADlen = 0] +[Taglen = 32] + +Count = 0 +Key = f8fe56171fa546a34b1b28e0b1d31cfb +IV = 960d57f1336271e069c12f11044dd5a5bea996fc0290d37b5b2f47c8df3ae3ee37214a6871d963b830aec266026364984cfe31eb88c2a6229f5594ca9d3b6d26c7fadb91a0282cdd0a321714b745dd5e161e7cd192420cf2eacd552c4df5cee8fb5f0e06b7c353017b4b9523ce56899db770c344da720327817ba823a8f71382 +PT = fd229158f18f5b8c2a96c86fa3d8084014660eb2314bbab4ca09fa72c3a98b6faa2ebb83a1809de9ccbc8973d23af34014fb27 +AAD = +CT = 4dc0fd07c86ec84c264f0544456bfee14f688af2109455d73aa1e58a3354727e05387c94568edf352f8342a6156c64d87c44d7 +Tag = ac350afd + +Count = 1 +Key = 803007b69146363999afad4433c0f3b5 +IV = 2fc7688faf0b3783094294526ac07c38a73ff961ab41f20deb66edcabfe68e094aa0f1fc52318706a0e2f9b3901a768346494e846cf17b662d05a3788d77c1468408a49ffe5c0cf68b3b8b26193dfd84c63c4631eebf0c7974283e05e39494d9aaad038018a6e999912b1f92681375214e634f5937cb32ccc4face42d013980c +PT = bb311134866deba57fe506445c5a312ea1ba1ba16469731c1647c6a482bc84fa8349d82bbd01d3edb6cfe8f25b37ff8ec9d621 +AAD = +CT = aa1d6ae4151aaec1030a6f0297c48e67b84d1c397e9eaf0c5c8c3d252bf8638bf8591342c5c20c7f88f41140b0334f55cb7b04 +Tag = 30076c5b + +Count = 2 +Key = bfb96f58535443205ce281e03bdc5c38 +IV = 3961f47e9e800f1c72526d73fe372cd6e69a7eb1d2692c58bf4297bb05503edf95e074a7cf2644981f72421f229d93866a6e1fcf5c13953b39bf36b56fcbd4c09b505e550b5ba0e9bc26efbe0b9621a47b81842caa8c945fa5bb606f0dab824a4bb5a2625668a916e47f0a0d8a995bcae6940e120724f6d53629545da5456008 +PT = 2c07d76ceac2a77809906bebd3452e2f898ea5467d47be1f17573b3f7fc7d11c9b868d1d1a24010b63dabe9c6c6b4e123df559 +AAD = +CT = ca443acf08d121e1ae4221013ec40dca2237d035e89ae67040602132972417e07a7c770d75d96fbb5b8a38e048abb15bb978d2 +Tag = f61f75ee + +Count = 3 +Key = f3a44f15d104f81b4bb263eecf806737 +IV = bbf1b0646991c2b9735066dad5860fcc08a6b92944a5e90dfb120acf2a75403d3175f5e61a1d84b89a0c1bdd3b3414450faf6ffb8820ab1ea01a2b3cc05f1cd1de9bd48ee1308ddc7d87e6db33d3a171e7f63fce6b8e0417359afa833f6b5f293195bedf444ac56103ee0c8706a69c08fe59a95c8474f28a4a12661905f8781c +PT = 62d05ea0b0ddff1c0418b01a21267230ebbf23b63a6c14caa769c9148150c2454c055cbe4a72a08e7cd8dcb456e1ec17bc3a63 +AAD = +CT = df08c4d223a168d4dea9445f5b88d40ef0a796de3e77a6a116bfed840ccbe7b988345d070640f62f5757878420b5c50dd9f567 +Tag = 1518c2d1 + +Count = 4 +Key = ccd58a6017ac344ce5f8ebebdbe03593 +IV = b2c53f013021f494f6637876f62ce5b5dec6d548ffe58d0952aa8fd8fd5c8d2b835165e1b0ca01e72c19f962e38cd4458229a3415d7b4f9afddf5bb63215999b750c07a080677ba4e40f6c5e42038882503c9923a6eb2cf0d3b82f9f94e624f9938830fc22430f16f6c93c362cb3c11cb05d63becdb4c572f03431e7108369c2 +PT = 0b89a455a2470b3b2b7e04afac15c45a0742061494b78f88c57f2505e1f5804f35c0a829f8b6443e427fb6ecd374642217b6f7 +AAD = +CT = a8b6203b914391c61dbc123efc6902b892107ea9724341a22ecdd0deb16c48d885d606f68724cb43a956c07ef9ef654c042906 +Tag = 02aeaa63 + +Count = 5 +Key = 50bcf114df40a431c0e1e88033154a25 +IV = 0ffcd9b14c6bf5f630c86b41cb3cf96004f3fa4fd48ee87b7235d34be0be1fdddeaa79abb3c0c9198a1eea0ccf04e8cfc8d24e4badbf438c59a70b435fbf07d44f55b75e5e48fa0f3d7714aaf9e34b430640614646d0008014ad432a464a252c66584c922b29a90cb2c2e4237c8545f913cd2ed3910a4f075062a55b71228411 +PT = 9f5206b2afe824ac4303d58a97255dea6f026b8531651105db9695f09acb16afd9488928060219307fd41edc16e49f01b7d646 +AAD = +CT = 0143c0a035ce29d1418acb2561dfe88c74f24a9808a8672427797cc0ba01693c2d66c0e365961cfd58fd039bf08fb4c2b1be29 +Tag = 552e27c7 + +Count = 6 +Key = 8dbf11f923374b8e8be93788de939806 +IV = 2fcb130962ba3e3eb8e31a7a26e2082a643f39d67cce11d8b2ba8a782f63d4df375b21b1fedaf67bd8d73b2208937ae941afc99420ebbe328214fe6a456bf00979d5ebfb22b79fd3cdea81056747bf4e4ded33f2f26f2d228965128a3d0a32696db44e4aff6ca5467d3c749830a5d2e9a41b4ffa3a422e5bb870cee84f4b64af +PT = 1c57186740c4901e022e63b2e7b085f9cb60c83763e357a591c1968277920ade1987334e88ed9c3c96665e37fe492a975153d0 +AAD = +CT = ce4c7e5fb87ed02424a13cd2cfcfaacf67f1072198dedc594db26d6453991821861ba6cc843c6d2750e846e162415123b7e01e +Tag = ab10b040 + +Count = 7 +Key = 6e88bed99ebe380c1f8297f46019d8a0 +IV = 80fb82c0016d054491f396a7722217b0a07bfd0fc954a7141bc1e2e7958cb24541a21492ec85d3c744489f93ae3abb9af101a78f2366226080389d29eef564d5205f377ab0902043bbf7ba64c30c9d2c945cd6f29654738106dd282194fa02344ec177b5547531061b31cebfac4a2b0f46b68e44c8c89f6942f9c9c13e50c58e +PT = 6c90ea3dad3e172ae6784cf1b7c08fc04d0f9b4372f1103d11393a8f02e2f495b53c57cf46f1df6f55b2fdb184fd2b7d590402 +AAD = +CT = f55d67b524b8e633019e9b1736f3db1a254e53cd71fecb48f2dceffa62256a0bfc3775f6506db52db6c6eb91971f5bb5688325 +Tag = b4585815 + +Count = 8 +Key = 99de57ce03d1db62a751c3b2c7d38f3c +IV = 2e74c283e216ab5ac9a1b214dd9280431d7ff942a17715fadc3a22978fa1ccc0743f969358baea3d79abe93388a7db82d82ad6a917bf67795fb4360543d7f22f7ee49f41029ebb87573ac03ddb7e279f1846f4a88b85bea63e2c9b9ecf6f91777434b3def0d4a42d3e025eb43a666a28d5f6c834c7e7991897bf051915e646c6 +PT = 72dc7e5533e862efe0d23c62095506b11c9b256d8d18d11511aa1ed4eae67b0017ec74e322f3a7a18e7d199e7093cadf26680a +AAD = +CT = af31d880d1820a35c9248ee0b1aa0da31339f90182e60451493bec8d4dec3baf922268741c2717831b8365bebf072aa7931ab4 +Tag = b1700396 + +Count = 9 +Key = acdc98a8baa0f003c130ce196135334d +IV = b7c9885d302842c41a2880b9382584806e8cb55b49183b80bc50403c82cfaf0d28a00fef813ba5b7e35b80dc1f0b7c3b0669a3bc739f499d77ed9cc47a467ca62fc34c5bf4c374ff396c01a472c3dfdab394e6926545a1c20363960c72dfad3eebf9a970e6579e3eff7a38f6bcf0373a8494d450d12445f9ff62c233dc1d2379 +PT = 30f1c7fb5fc152dad6911623ca4af1eb495e108ed94b6e6cc19eabeaa7b85262ea3cc4dc5297aa6f7cf504ac6e07db5db550e6 +AAD = +CT = b2cbae4df8898ca223213824a5c08e16eda81f063916e813bf2d0d8c7e8a75b2d0a9f6de91e08d5422970534331cf1dd53fa8e +Tag = 8ef08260 + +Count = 10 +Key = 75d651a377ccdc0e743d73b8205fb38c +IV = c7296796ef031d372284f7b1481a13862aec243792ca73f40e11bfe39da28984f11d591d3294c833babf05a1f19b603f4f4a9ca1102f201c1405b6cb45facc8ef408541963abcafa907b2eb8e5c1c404b0e4884a48bbb2d43add4dc1c44c526295bcfbd8f2b7041ed49189e835cdf4ed00dcbb450eef4070482f5e8b52360966 +PT = 13ab743d9db511857f0f79a84742c225b3692a9aee8a63697d42fe50d74fe028ccf95e18a2dd2d9b778392ee7a5d2f23b399eb +AAD = +CT = 09c3f153ef712fcb3b5fca2b9bf7f25740fb748bec64bc35576ed01682030ae2728d4282140264819e8c4dedd48e29199a6236 +Tag = ae374dd4 + +Count = 11 +Key = 15414fda594aa87a3e7af69df769adbf +IV = 7f021a78293e7cb4dd0af221efda3149b0cab87241b597865267cbab5aad530ea4aa4b10815ba9318a45fcb22fd0e6d692d7beecc2042fa2791f6cca5f9916b0bbae79e9d91133aa54d15a1397f8b063695a3d36b8e573a866fc94964f39016e9490c37189cbb0638db09548a91688d73e2c0d4542f5bd08e03ac0d75e36f519 +PT = bc8263ccf50d0224d088546bc16e2577925567ca52d98ec45cb43b190159bbd5f0326d4498a8a88c0ea0b0a79420b906cd5115 +AAD = +CT = 34b07942793b066b74b7fb8a4ce71a04f9b29e40dca351f5b6e0939bc2819cd95e69bd58163a4df9729e3d6220a6df60a4ba9e +Tag = bcf4aed9 + +Count = 12 +Key = 4d73cae96ded98e1688104a63f462c76 +IV = 331b51fd88cd4731e0eca051717b642f86ea6d6941f9a7331ff361e0edc3f9ea4c013d585f3eff70004a696c4b51d7c589ca97e5fd30f4b2f99c0f3ac83769c2397e10669b7b83aef714a2388638b8941efde8e631098dd78742772f484edd568fefe26b9d981b437e4e4f3ad25445e1aa8c8608c655a5090d2cac158ee67e98 +PT = bf55d48ae5015c39bb167782cab391510d7b7d698e9d3faacd7d409fe4d86fea0a6f61128b6aa305ac0fe4cee4d582dd30e717 +AAD = +CT = 3cf29f4d50feac5cda4c7cef91d563b2573096b7f32c723355d8d59b8e1a0e229dc2f6114f1db6bdc26212043d153709597c1d +Tag = 76fcb529 + +Count = 13 +Key = 7045a9d7caae2c0a39f58998720974ec +IV = a9028008f708ae19dd28e75a02c6e84a05096779781ce0a908047152208468cc4b2a57d25608767f936cf70fbe82dd8a61497a180e1fc967caf4e6310ed850082e6919c922e021ec070dc64b040ed9edbbf5883676630d69e48953068b2bd006bd6d5417038604ee5aed04980c9ed2316c531ce6a3a73dfad90c04c58596d5e9 +PT = 635b946047c38533bb2cb4c9799b44f6eae0e63626901b0741f6dcf3c2bb02270343c7708a72dfe303b20f7805cb732386b341 +AAD = +CT = aebb8c1e914ea9bc1ada9b01f84cc8dbbc611f2cd386d5fc89497d37e5a469b28fe2fdf0ab0f1c882dcce50620b1b18a2d8343 +Tag = 27bcaf06 + +Count = 14 +Key = 79d2a35efbf03f57b66e875c232e10d5 +IV = 7cc96b48afff401adf4bab2ebedd021377b18a819f3c3af39fda42e24c5d62e67ec30f8bcab00263dc5a9bb06cbfe1750c98555901d34d775fdcc86841bd08fbeb44ba68ee794dc351a29a1a9de576d83c17a730d50db79cab88d538a441bb9ff6aa073a2a976de820ab5cc61f834753220d4e472a275dcd13db3e51a23a84a5 +PT = d91e1b2811b3e3894b46c563e6ea0b4a33990ba4fce8a354c941e1effc5691671de5d97c4c1a35e3730b43584944695f00544a +AAD = +CT = 6a45beb05c0dba6c38c997f8c37ef07c7cf78eacff6ff4dd6fa000e745e8053d2d270a746994f29c8628f41fc7fecdac158655 +Tag = 36caee75 diff --git a/src/test/crypto/gcmEncryptExtIV256.rsp b/src/test/crypto/gcmEncryptExtIV256.rsp new file mode 100644 index 0000000000..3faa8956bb --- /dev/null +++ b/src/test/crypto/gcmEncryptExtIV256.rsp @@ -0,0 +1,129 @@ +# CAVS 14.0 +# GCM Encrypt with keysize 256 test information +# Generated on Fri Aug 31 11:26:26 2012 + +[Keylen = 256] +[IVlen = 1024] +[PTlen = 408] +[AADlen = 0] +[Taglen = 32] + +Count = 0 +Key = 0df25c2bc9444b4a01e26d357a3ac0635fb6ff2e65ce1e759aae491a17772243 +IV = 54652573ba189cffed3bcfa60efbfb417eb4b0e8de80c7e53765d018cbddfae74617269eb35f29faf628d28c40737f9d9e1eb0b8757c984d94340ecc5ddd108f0a5a0e96335ea805950d378fea7569b98693e88bc1cfd9f6eb8d25de177122fc774a5b1957bcb80e92230c12fe401a8e00d0c04897e234644bda36ae761ea619 +PT = b29af460c6a5dbe56f1d67751346d7182c93413a6c328c6d85176cd8dea8ecce1cad3063c8708c0be9ae73d42bbb10421e73f1 +AAD = +CT = 3c786a3d0c8945bf320a21ca63f3b8bf5c6bf56a8412f836d7894e42c9e0695a8e41bf59b23fc52d17f8b341183f1cdce02e22 +Tag = 0b31bffe + +Count = 1 +Key = 1b6b7b8d00e543f0a17bd0bf595319a4a1f8a55ff41ce2380381d4e83c83243b +IV = 791d9546f180b838b50bb7b66b68f7f1aa09a2cef411a1dbf2e64c5ed026613200ac8f0e5b961925853621a1d4339322ea4b7bbc4adcbc008efeaaee0dc948a916b22ff8693a7d441620d0ff67680b23567f9582e22eec529408c6d0a00de1bd1ee5a11ed7fa29b7567f990e412ce90ee12d5b1d8ba8c2b528d0d9963fdc49a5 +PT = 0a76090de676d71d9f5ee8511864f0c9440a0fa12b5155a5bffc36127bc957b293d4fb624af3b956385783124f28f6f3c0f0e8 +AAD = +CT = fdaa9ef2c65d7666b61367f843863a3b273249192551b5633cfaf84a5ab9ecba42916395177f9a16c1ad385e77393cd93d71b3 +Tag = fd854d63 + +Count = 2 +Key = 261a0382c739093634502303d60dd0d2a568b5155147d661e7789f7bd70de82c +IV = e22330a2981b9b60354a740c49dcd17c9016cff50423977f7fc8500fc36a81610c979eb37a1f9c4d54d11b790906492205263178dca6d269a230a595ee95edeb60e45d92a2d6169877dfe5514b23db143dbcf3ca44e13cf5b7402e4f95a9e6760451be2d57d1d5fefb015ffe4b69456d87338865ee8775d1cce238f75c345dad +PT = 42c8c79988c52bcf38865a6f341a5165294af0947bc4fa597c6f648a1172070851c4ee154604d9a21c8d53f7eba77fbb72cf2b +AAD = +CT = 0fb368563c6ad0c097207239a791bc685274d434c4a54cb0ea97a98b4cee9eb100c4cd626ba82c338a3f51cb29391b1da3a44f +Tag = a9607e42 + +Count = 3 +Key = 5f3d6b5c76cb7ad0be3d771f1f7d1bafd88c8c7c7c84922f89f45f3b7453eb44 +IV = 7072d302e4acb642090c5d48e4549a8823725be1389316df0152e68c41f77937eadc4ee1d164101717cdcdd3bc9be3c2669c0b1394953090ac787fb117500b6275122f608e70a3f5063b21fae42ca4b00724b21c50e27c37a77d4befb118018ada7999888442e1271410f6b804c36a27a41e95a438792de4f06fd7122b177cc3 +PT = 00d82cc00c07d3cf0fd9b31ddc091d351aab9b58af07d2c59f3e28c7202ef6e3ec35726cbdd14f8f1985a770d092470f115be7 +AAD = +CT = 0aab0dbb31c113b33b116659294e0af5497c987af870ae8ce55288d48e8a4f1b3e8377cb34d06460daf3cc99fbefb90724a39f +Tag = 26e56b13 + +Count = 4 +Key = 1d4b6b6ba43269d46ca5c0fab38b61f1d2bf3d24dae46181fac73420a8e6194f +IV = 01c283a90c588dafc585f437dc111e94dd8ea98a622a5d2e554a87086ec10e8dac9b205fae70be3c024b3f9fbdc26208a6e44d082ad92a51a7fa1f861d0e93e7e74d4e41426e70b2e7ef7fbcbc5a302aed4bc8a42963ca53334259f1924e74225c3bf9aa2ffdf97a2be6474c72f6dedba7c454e36fbc3537596a63b61a4cf3ce +PT = 4eb036d945c14de26c4e0c83d446dacb57e91b5bdec2ef612bbed8135e57ce62b28843fbac555580ef23c74959eb869a017872 +AAD = +CT = 24d67f2e94294255b9fd90c16b67c7a8b3a47a42782954aa15e80ffe732d64342b1ec65aa66fc4d6b8fe9dfcdbf4d4c1a979e7 +Tag = 37358e86 + +Count = 5 +Key = cbfbb15a4fae4af3de55ffcaa4b8cdbd515ecc72fd50060b22acc8fad57a5f4b +IV = 86e47ba98d8ed360262f94afc364df373d1e44c788b4ee5ed7542822858aaeca2b3c07b5464d6f7edefca9759107bbb64c086d526cc4c9a6b9a7cd6dbb50acec2297597612fd436d8c8ddbc83664305b214cf2c3b6fab3e545c499c7f1cbba1897041475f94952d8a4fc10110986b5ccc7a10c1d9e6427dabba8d942ada9290a +PT = 5470a60f2818ffef374be3cc591084096a4a8caa0dac0024c12d304382c301264526b02efb674dfbcc3be5c818a1d88a7c19f1 +AAD = +CT = a6a8ebadfe5c5ac754e4a2a9cdc25fdf3588c69a287b0f9aba2347bfcdc110a1134426a45c62d577e52a8d61fae39ea38bad51 +Tag = 97406b4b + +Count = 6 +Key = 3ced5c63078a36f6b02d3bec0debacd19021c8dbc501a9d86f556c4ad2cdef8a +IV = b9629801cba22f7493b4f6394620d49a76ec686e524f5ebcb3a76b5a189473484060cbb01bcbf10048427ef21527626085c8a75aa5264b6338abbc26171c2c3a44f6b3b5c3fd05a892c8290a8f99be962deea48d7ae4e626c45a45ffda5efaad6e54e98ba876b039a5dde3d6061f217e57da4774acfaf1f5da9495083aad4dad +PT = c29788107799077ac6dbccad29a346727f263676a8510fbcadb9b5bf53df978b3382fdfc1b5c3312eaa0f7621b6efdaeebe1c0 +AAD = +CT = 5811d4a96169b39cd8f8ff3f931efdda68550f17558b48de8bb5adf455af5179c8c5ff4a73f363f8819daf846427132daf6a17 +Tag = 06e8e7fa + +Count = 7 +Key = 39ae4fdfe56b74a71325a1a685a6593b44936892890cd05d2719a420c97a7c64 +IV = 8f110d0fd20ece7f35c35b2eed32316fd742ae9346fc6907bd749361a4436427f80185b376b16a36fb95429cfaf2e22e46c210442fe5efc14985a9d9d847c3ceb5db02e0d999acbc3ba0afdfecbfaf65024258cc7f6fc8e3f568cbedec1c7eabe3ff3ab3c7331722b6400429d46b54820bd1f88ac03cfba5cbd0812d91342c4b +PT = 8b086d11be7ff55312addad86b49585ea38ea1ee7c4200964cd269a4bb5cfe0f518e6f9b733efb4ba3ce35ce2e803b0ad47d24 +AAD = +CT = be46d6e61dc11b2fc8ac4c9c5f49ceca0fb6fe1fc7221c7cc5d8ba254a92282500b1b31528314035cd125578de960b3bafb69d +Tag = 7c00aa14 + +Count = 8 +Key = c244e9afd90ec810acb7e586cf7a06386e6892e01c7d111d5c1455fc95250d1b +IV = 6ff9103f9751ff4743d856c5cd54491e1a537384260fbfe076f772ad0d66ff6ddd0aaff57023885b0a4d60d2b25c80b1cdc54802607770a61a2503c23cf26f1fe529573c8d4745b19dedaff5769a6a796c01540776d4fa99be9057ad87cdc973e7938640f9497753e88c4cdc358c1cfa06f1ddd826c33f44c55e2d183927baaa +PT = cd1296133cefe6f5cf6f8ec68b37172bfb793a8582d92a539f24f3582569bfcfebb706fe9f276716b185558fbfd6fe8ea99a1b +AAD = +CT = dd1694b178f15612c454885b3100c576c7b68206c57898161d4fdc51e75a428840c5cfee104c3d85fcbd92edbd1d80f22d8e64 +Tag = 741953f5 + +Count = 9 +Key = 785ea9cd2403ecaeec3e4940dce7c41ec012203a2610c780bca5d15af64748c5 +IV = fbc177ec9d47f69e2fcaba9fef7de30735e46a5d20dc66bf66c8a76a382051d780f58dccae8e2054bbe437a5bc0814381bac2b0efa99202aa1f1bf7f51b842907dc9b60f83987c31eae086e26e2018243bdd47a291b523ac6905b40dfb442ba239c876cdfaa581b2ef0683456ac944829a97b663ecd48c116d06f1f054ddfcdb +PT = a3465ad9a4009e26c39acb1d424b7ba6556a74dcc2b78a5ab65b5d07c2a97f382aadb7415395fa6fc90bd137f6894a75f70907 +AAD = +CT = 2b3eb5ab251282da1795a25f9b43ccaa5a27643d042fc315ad662947b0c5cddeb5848e6c69869ae5e81f5c76729bbaceda9889 +Tag = 64173526 + +Count = 10 +Key = 0becf9c7a069db5b9a25f2871fb0594e452126262ec1c48bca3d3024d85d0c51 +IV = e05643a72ab0b1fc42a6f17302d6446fc507bbb4f0ad59178f5084530f02534df2e673e92e67802629f93221bba545a13fb9143eb2a2ee4bce047be621a9d96a450a19951d93c527eb698ac7e132e4f00985dff91e079ae791549d37da3105c77ef5d8cb7649f1aa761b5a5fbc9e0d7dfb5aade98f3df4a641cca02f33eed55c +PT = 70ba9822801760e5ec647a41e27cf6069978be6a28be0b1da0f3661e124847823dec7ec6af737d6dea597ce5bd5baa5d6f2651 +AAD = +CT = 0d45b5ad77226524374a3bca3680528787cefd9978b3f1407688886ce28fea86e7d9005d7d6acde2a7c2fb158479918c06bba4 +Tag = 43dfd859 + +Count = 11 +Key = d1f374702b4481b83e7c7783853c1850e887b0c80cd28c0686b4cab6adc744c2 +IV = 5e15c44cef36c1c89e02b2979f4e7d275fe5973a80580753f6fd51ea477ba84346a030b90b22a9adfff02096bc0b1691c37ee21cdc1b5f4862696d195859cd2bf0b423f5d19da5e1475bcc99f96b8c7c51fe85930aea0e97304d4c025b52bd386666d0537036360e939a6fbdfd6ce3b012e551d333fa74f3cbb9d33a59477364 +PT = 996428a232b1b9ac81ff5260eb77938f0d531a4a0ed3bd774c72c18128af72e964f8d05fb7ec4e0ac8e37056a48c85713a3a01 +AAD = +CT = aa9c103ae51bf556f7c57f9948d28c859f458a74e22f039fea183e9e262b023bdac9bb5a2f167b34cde4a694c555eb0c905f34 +Tag = d1ed9cf0 + +Count = 12 +Key = a6a69524d66f015b4afb746ad0942410baf06d1aba18ef1a8b40e35633f04ce1 +IV = 5e1df758c63728b1269a1d3f610b6e3724bc7ff797dcb4a7aca9dfe1c8e1717ce4281d1c5b4b33d0aafcee342a4f4eb30089eeab2b0470d3f9b709622bde4654d41b3bbc6bf59c11edea28f26b099d83d4fefdc63ab7218221238fe1c230b1290235465b445f60eaa9822eaa8da2c08f6f2fdaaef87dacf74c7e5d6cea191c74 +PT = 0ffc6c3090817fc1a0e6f3802269e263e40d17772fabf5cbee905962878d77c8bc4223e5671bd9f310d8db56ceaebae41fc79e +AAD = +CT = f24537db3fe27eb07f1d2b9b7059dfae97df86d4e609930491c4ec3154462df308ba1c85204dd754521d8de9619603f90f8c44 +Tag = 360adc36 + +Count = 13 +Key = ff0007317f9ecc43c1601708614eb8d443a407318cbf3c085c0a9a7c67faafa8 +IV = 8186f92bd394ecfbf4bcbb9e7e442bd6faa1e59f8785d9aec82551fee38aa10212a8477be3055927379a906902c153598d50c63e316c4e4f3956ef04ce40e5b6f1901fb5d08a23b913e5ad53512b02bb75ce96f8c50a2cebdfa058ded996fe1dc5370ee50c6d90e948129d544dc89c2f28dda8429bb338d6aed0d9557f96889e +PT = e7f4063319fd31e07192a5fc9e486fc0a2a3470671a46356ab0d32989803259c0dae103a4033c533fbde585866fc2af5eba151 +AAD = +CT = 8f86644614e4f6483f28eec02fab33e7cbbd56381a8f878522c2015b91d48652472e356f608c62361939dc983e1cd364a28665 +Tag = 83335b3a + +Count = 14 +Key = 43646d9ddebec23447febe71596e6f9b2387965db1faf3f06feec8bc5c808342 +IV = 0d3774607261b07427dc77f0dcf57b026226dbd2c1df1b9d74598582da44c677af36a6bd80b6bc1f000632c84c5dfa701f8b51b4da228d340d8b4ccc4d2f5d7b5fad00809133eae9250ecd18d7a8741bb57c394396feb81c20bec23de8520f883b8e22b362dde6e6bd9dad73e8919695384a04c09a28bdb6de2fa356b0d259b1 +PT = 2aab9a484b817b759bd9d876967c90160a18208cfa753e7bccd4f73a715aaa6acc6ce666e97bc22fbcf11f263dfed332418707 +AAD = +CT = dd80974e31ad15ba26ec8a8dacfa5f57f0bc69f7113cc6c39fb038ddce37ffeee3f789a02cd86b0418fe16ca104b5fbdb26432 +Tag = 75c35f4c diff --git a/src/test/crypto/t/001_testcrypto.pl b/src/test/crypto/t/001_testcrypto.pl new file mode 100644 index 0000000000..586a37c5bd --- /dev/null +++ b/src/test/crypto/t/001_testcrypto.pl @@ -0,0 +1,137 @@ +# Reads and parses .rsp files and runs them through testcrypto +# +# Test vectors downloaded from: +# +# https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/cavp-testing-block-cipher-modes +# +# Specifically GCM Test Vectors (SP 800-38D): +# +# https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/gcmtestvectors.zip +# +# Note that the AADlen > 0 cases were removed from our set, since we don't support that and +# the test code will just skip them currently, and we also don't bother testing 192-bit, +# but one could download the full set and run all of the files through if they wished and +# all should pass (they did when this test suite was written originally). + +use strict; +use warnings; +use TestLib; +use Test::More; + +if ($ENV{with_ssl} eq 'openssl') +{ + plan tests => 56; +} +else +{ + plan skip_all => 'SSL not supported by this build'; +} + + +# XXX add CTR tests here + +my $algo = "AES-GCM"; +my @rspfiles = ( + "gcmDecrypt128.rsp", "gcmDecrypt256.rsp", + "gcmEncryptExtIV128.rsp", "gcmEncryptExtIV256.rsp"); + +note "running tests"; + +foreach my $rspfile (@rspfiles) +{ + open(my $in_rspfile, '<', $rspfile) || die; + my %testrun; + my %lengths; + + while (my $line = <$in_rspfile>) + { + + chomp($line); + + # Remove CR, if it's there. + $line =~ s/\r$//; + + # Skip comments + if ($line =~ /^[[:space:]]*#/) { next; } + + # If we hit a blank, time to run a test + if ($line =~ /^[[:space:]]*$/) + { + if (%testrun) + { + my @testargs; + + # Set up the command to run + push(@testargs, ("$ENV{TESTDIR}/testcrypto", '-a', $algo)); + + if ($testrun{'Key'}) + { + push(@testargs, ('-k', $testrun{'Key'})); + } + + if ($testrun{'IV'}) + { + push(@testargs, ('-i', $testrun{'IV'})); + } + + if ($testrun{'CT'}) + { + push(@testargs, ('-c', $testrun{'CT'})); + } + + if ($testrun{'AAD'}) + { + # Don't currently support AAD + undef(%testrun); + next; + } + + if ($testrun{'Tag'}) + { + push(@testargs, ('-t', $testrun{'Tag'})); + } + + if ($testrun{'PT'}) + { + push(@testargs, ('-p', $testrun{'PT'})); + } + + if ($testrun{fail}) + { + command_exit_is(\@testargs, 1, + "Run $testrun{Count} of Keylen: $lengths{Keylen}, IVlen: $lengths{IVlen}, PTlen: $lengths{PTlen}, AADlen: $lengths{AADlen}, Taglen: $lengths{Taglen}" + ); + } + else + { + command_ok(\@testargs, + "Run $testrun{Count} of Keylen: $lengths{Keylen}, IVlen: $lengths{IVlen}, PTlen: $lengths{PTlen}, AADlen: $lengths{AADlen}, Taglen: $lengths{Taglen}" + ); + } + undef(%testrun); + undef(%lengths); + } + else + { + next; + } + } + + # Grab length information, just to have. + if ($line =~ /^\[([A-Za-z]*) = ([0-9]*)]$/) + { + $lengths{$1} = $2; + next; + } + + if ($line =~ /^([A-Za-z]*) = ([a-f0-9]*)$/) + { + $testrun{$1} = $2; + } + + if ($line =~ /^FAIL$/) + { + $testrun{fail} = 1; + } + } +} diff --git a/src/test/crypto/t/002_testkwp.pl b/src/test/crypto/t/002_testkwp.pl new file mode 100644 index 0000000000..25911cfd9f --- /dev/null +++ b/src/test/crypto/t/002_testkwp.pl @@ -0,0 +1,126 @@ +# Reads and parses .rsp files and runs them through testcrypto +# +# (Partial) Test vectors downloaded from: +# +# https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/cavp-testing-block-cipher-modes +# +# Specifically Key Wrap Test Vectors (SP 800-38F): +# +# https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/kwtestvectors.zip +# +# We don't include the 192-bit tests, though they all worked when this test suite was written. +# We also don't include the _inv tests as those aren't supported in OpenSSL yet. + +use strict; +use warnings; +use TestLib; +use Test::More; + +if ($ENV{with_ssl} eq 'openssl') +{ + plan tests => 20; +} +else +{ + plan skip_all => 'SSL not supported by this build'; +} + + +my $algo; +# my @txtfiles = ("KWP_AD_128.txt", "KWP_AD_192.txt", "KWP_AD_256.txt", "KWP_AE_128.txt", "KWP_AE_192.txt", "KWP_AE_256.txt"); +my @txtfiles = + ("KWP_AD_128.txt", "KWP_AD_256.txt", "KWP_AE_128.txt", "KWP_AE_256.txt"); + +note "running tests"; + +foreach my $txtfile (@txtfiles) +{ + open(my $in_txtfile, '<', $txtfile) || die; + my %testrun; + my %lengths; + + if ($txtfile =~ /^KWP_/) + { + $algo = 'AES-KWP'; + } + + while (my $line = <$in_txtfile>) + { + + chomp($line); + + # Remove CR, if it's there. + $line =~ s/\r$//; + + # Skip comments + if ($line =~ /^[[:space:]]*#/) { next; } + + # If we hit a blank, time to run a test + if ($line =~ /^[[:space:]]*$/) + { + if (%testrun) + { + my @testargs; + + # Set up the command to run + push(@testargs, ("$ENV{TESTDIR}/testcrypto", '-a', $algo)); + + if ($testrun{'K'}) + { + push(@testargs, ('-k', $testrun{'K'})); + } + + if ($testrun{'C'}) + { + push(@testargs, ('-c', $testrun{'C'})); + } + + if ($testrun{'P'}) + { + push(@testargs, ('-p', $testrun{'P'})); + } + + if ($testrun{fail}) + { + command_exit_is(\@testargs, 1, + "Run $testrun{COUNT} of Plaintext Length: $lengths{'PLAINTEXT LENGTH'}" + ); + } + else + { + command_ok(\@testargs, + "Run $testrun{COUNT} of Plaintext Length: $lengths{'PLAINTEXT LENGTH'}" + ); + } + undef(%testrun); + undef(%lengths); + } + else + { + next; + } + } + + # Grab length information, just to have. + if ($line =~ /^\[([A-Za-z ]*) = ([0-9]*)]$/) + { + $lengths{$1} = $2; + next; + } + + if ($line =~ /^([A-Z]) = ([a-f0-9]*)$/) + { + $testrun{$1} = $2; + } + + if ($line =~ /^COUNT = ([0-9]*)$/) + { + $testrun{COUNT} = $1; + } + + if ($line =~ /^FAIL$/) + { + $testrun{fail} = 1; + } + } +} diff --git a/src/test/crypto/t/003_clusterkey.pl b/src/test/crypto/t/003_clusterkey.pl new file mode 100644 index 0000000000..5b8a255ace --- /dev/null +++ b/src/test/crypto/t/003_clusterkey.pl @@ -0,0 +1,93 @@ +# Test cluster file encryption key managment +# + +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More; + +if ($ENV{with_ssl} eq 'openssl') +{ + plan tests => 6; +} +else +{ + plan skip_all => "tests cannot run without OpenSSL"; +} + +# generate two cluster file encryption keys of random hex digits +my ($rand_hex, $rand_hex2); +$rand_hex .= sprintf("%x", rand 16) for 1 .. 64; +$rand_hex2 .= sprintf("%x", rand 16) for 1 .. 64; + +# initialize cluster using the first cluster key +my $node = get_new_node('node'); +$node->init( + extra => [ + '--file-encryption-method', 'AES256', + '--cluster-key-command', "echo $rand_hex" + ]); + +# Set wal_level to 'replica'; encryption can't use 'minimal' +$node->append_conf('postgresql.conf', 'wal_level=replica'); + +$node->start; + +# check encryption method +my $file_encryption_method = + $node->safe_psql('postgres', 'SHOW file_encryption_method;'); +ok($file_encryption_method eq 'AES256', 'file_encryption_method is valid'); + +# record pg_proc count +my $old_pg_proc_count = + $node->safe_psql('postgres', 'SELECT COUNT(*) FROM pg_proc;'); +ok($old_pg_proc_count > 0, 'pg_proc count is valid'); + +# create permanent table +$node->safe_psql('postgres', + 'CREATE TABLE perm_table (x) AS SELECT * FROM generate_series(1, 100);'); + +# create unlogged table +# Non-permanent tables like unlogged tables use a special nonce bit, so test those here. +$node->safe_psql('postgres', + 'CREATE UNLOGGED TABLE unlog_table (x) AS SELECT * FROM generate_series(1, 200);' +); + +# We can run pg_alterckey and change the cluster_key_command here +# without affecting the running server. +system_or_bail( + 'pg_alterckey', + "echo $rand_hex", + "echo $rand_hex2", + $node->data_dir); + +$node->safe_psql('postgres', + "ALTER SYSTEM SET cluster_key_command TO 'echo $rand_hex2'"); + +$node->stop; + +# start/stop with new cluster key +$node->start; + +# check encryption method +$file_encryption_method = + $node->safe_psql('postgres', 'SHOW file_encryption_method;'); +ok($file_encryption_method eq 'AES256', 'file_encryption_method is valid'); + +# check pg_proc count +my $new_pg_proc_count = + $node->safe_psql('postgres', 'SELECT COUNT(*) FROM pg_proc;'); +ok($new_pg_proc_count == $old_pg_proc_count, 'old/new pg_proc counts match'); + +# check permanent table count +my $perm_table_count = + $node->safe_psql('postgres', 'SELECT COUNT(*) FROM perm_table;'); +ok($perm_table_count == 100, 'perm_table_count count matches'); + +# check unlogged table count +my $unlog_table_count = + $node->safe_psql('postgres', 'SELECT COUNT(*) FROM unlog_table;'); +ok($unlog_table_count == 200, 'unlog_table_count count matches'); + +$node->stop; diff --git a/src/test/crypto/t/004_buffers.pl b/src/test/crypto/t/004_buffers.pl new file mode 100644 index 0000000000..a1379b4772 --- /dev/null +++ b/src/test/crypto/t/004_buffers.pl @@ -0,0 +1,157 @@ +# Test cluster file encryption buffer management + +# This tests that an encrypted server actually encrypts the database +# files. It does this by checking for strings in the database files in +# both non-encrypted and encrypted clusters. We test a system table, a +# permanent relation, and a unlogged/non-permanent table. +# (Non-permanent relations use a special nonce bit, which is why we test +# it here.) + +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More; + +if ($ENV{with_ssl} eq 'openssl') +{ + plan tests => 17; +} +else +{ + plan skip_all => "tests cannot run without OpenSSL"; +} + +my %file_match_count; + +sub get_cluster_file_contents +{ + my $node = shift(); + my %relnode; + + # get postgres database oid + my $postgres_db_oid = $node->safe_psql('postgres', + "SELECT oid FROM pg_database WHERE datname = 'postgres';"); + ok($postgres_db_oid != 0, 'retrieving postgres database oid'); + + # get pg_proc relfilenode + $relnode{pg_proc} = + $node->safe_psql('postgres', "SELECT pg_relation_filenode('pg_proc');"); + ok($relnode{pg_proc} != 0, 'retrieving pg_proc relfilenode'); + + # create permanent table + $node->safe_psql('postgres', + "CREATE TABLE perm_table (x) AS SELECT 'aaaaaaaa' FROM generate_series(1, 100);" + ); + + # get permanent table relfilenode + $relnode{perm} = $node->safe_psql('postgres', + "SELECT pg_relation_filenode('perm_table');"); + ok($relnode{perm} != 0, 'retrieving permanent table relfilenode'); + + # create unlogged table + $node->safe_psql('postgres', + "CREATE UNLOGGED TABLE unlog_table (x) AS SELECT 'bbbbbbbb' FROM generate_series(1, 200);" + ); + + # get unlogged table relfilenode + $relnode{unlog} = $node->safe_psql('postgres', + "SELECT pg_relation_filenode('unlog_table');"); + ok($relnode{unlog} != 0, 'retrieving unlogged table relfilenode'); + + my $file_contents = + slurp_file($node->basedir . + '/pgdata/base/' . $postgres_db_oid . '/' . $relnode{pg_proc}); + # () converts to list context + $file_match_count{pg_proc} = () = $file_contents =~ m/pg_[a-z]{3,}/g; + + $file_contents = + slurp_file($node->basedir . + '/pgdata/base/' . $postgres_db_oid . '/' . $relnode{perm}); + $file_match_count{perm} = () = $file_contents =~ m/a{8,}/g; + + $file_contents = + slurp_file($node->basedir . + '/pgdata/base/' . $postgres_db_oid . '/' . $relnode{unlog}); + $file_match_count{unlog} = () = $file_contents =~ m/b{8,}/g; +} + +# +# Test with disabled encryption +# + +# initialize cluster +my $non_encrypted_node = get_new_node('non_encrypted_node'); +$non_encrypted_node->init(); + +$non_encrypted_node->start; + +# check encryption is disabled +my $file_encryption_method = + $non_encrypted_node->safe_psql('postgres', 'SHOW file_encryption_method;'); +ok($file_encryption_method eq '', 'file_encryption_method is valid'); + +get_cluster_file_contents($non_encrypted_node); + +# record pg_proc count +my $query_pg_proc_count = $non_encrypted_node->safe_psql('postgres', + "SELECT COUNT(*) FROM pg_proc WHERE proname ~ '^pg_[a-z]{3,}';"); +ok($query_pg_proc_count > 0, 'pg_proc count is valid'); + +# check pg_proc count +ok($file_match_count{pg_proc} != $query_pg_proc_count, + 'SQL/file pg_proc counts match'); + +# check permanent table count +ok($file_match_count{perm} != 100, 'perm_table count matches'); + +# check unlogged table count +ok($file_match_count{unlog} != 200, 'unlog_table count matches'); + +$non_encrypted_node->stop; + + +#--------------------------------------------------------------------------- + +# +# Test with enabled encryption +# + +my $rand_hex; +$rand_hex .= sprintf("%x", rand 16) for 1 .. 64; + +# initialize cluster using a cluster key +my $encrypted_node = get_new_node('encrypted_node'); +$encrypted_node->init( + extra => [ + # We tested AES256 in 003, so use AES128 + '--file-encryption-method', 'AES128', + '--cluster-key-command', "echo $rand_hex" + ]); + +# Set wal_level to 'replica'; encryption can't use 'minimal' +$encrypted_node->append_conf('postgresql.conf', 'wal_level=replica'); + +$encrypted_node->start; + +# check encryption method +$file_encryption_method = + $encrypted_node->safe_psql('postgres', 'SHOW file_encryption_method;'); +ok($file_encryption_method eq 'AES128', 'file_encryption_method is valid'); + +get_cluster_file_contents($encrypted_node); + +# Because the files are encrypted, we should get zero matches for all +# comparisons below. However, technically the encrypted data might +# match the desired string, so we allow one such match. + +# check pg_proc +ok($file_match_count{pg_proc} <= 1, 'pg_proc is encrypted'); + +# check permanent table +ok($file_match_count{perm} <= 1, 'perm_table is encrypted'); + +# check unlogged table +ok($file_match_count{unlog} <= 1, 'unlog_table is encrypted'); + +$encrypted_node->stop; diff --git a/src/test/crypto/testcrypto.c b/src/test/crypto/testcrypto.c new file mode 100644 index 0000000000..85bf921c09 --- /dev/null +++ b/src/test/crypto/testcrypto.c @@ -0,0 +1,458 @@ +/*------------------------------------------------------------------------- + * + * testcrypto.c + * A utility to test our encryption / decryption routines. + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/test/crypto/testcrypto.c + * + *------------------------------------------------------------------------- + */ + +#define FRONTEND 1 + +#define EXITSUCCESS 0 +#define EXITDECRYPTFAIL 1 +#define EXITFAILURE 2 + +#include "postgres_fe.h" + +#include +#include +#include +#include + +#include "common/hex.h" +#include "common/cipher.h" +#include "common/logging.h" +#include "getopt_long.h" +#include "pg_getopt.h" + +static const char *progname; + +static void +usage(const char *progname) +{ + printf(_("%s tests encryption/decryption routines in PG common library.\n\n"), progname); + printf(_("Usage:\n")); + printf(_(" %s [OPTION]\n"), progname); + printf("\n"); + printf(_(" Performs one encryption and one decryption run.\n")); + printf("\n"); + printf(_(" Encrypts the provided plaintext (or the empty string if none given) and generates a tag, if using AES-GCM, using the key and IV given.\n")); + printf(_(" After encryption, compares provided ciphertext to resulting ciphertext.\n")); + printf(_(" Compares provided tag, if any, to resulting tag.\n")); + printf(_(" If no tag is provided, then the tag created during encryption is used during decryption.\n")); + printf("\n"); + printf(_(" Decrypts the provided ciphertext (or the empty string if none given) using the key, and IV + tag given if using AES-GCM.\n")); + printf(_(" After successful decryption (requires tag to match for AES-GCM), compares provided plaintext to resulting plaintext.\n")); + printf(_(" Exits with '1' if decryption fails.\n")); + printf("\n"); + printf(_(" Exits with '2' for any other failure.\n")); + printf("\n"); + printf(_(" Key is always required, IV is required for AES-GCM mode.\n")); + printf("\n"); + printf(_(" Algorithms supported are AES-GCM and AES-KWP.\n")); + printf("\n"); + printf(_("\nOptions:\n")); + printf(_(" -a, --algorithm=ALG Crypto algorithm to use\n")); + printf(_(" -i, --init-vector=IV Initialization vector to use\n")); + printf(_(" -k, --key=KEY Key to use, in hex\n")); + printf(_(" -p, --plain-text=PT Plain text to encrypt\n")); + printf(_(" -c, --cipher-text=CT Cipher text to decrypt\n")); + printf(_(" -t, --tag=TAG Tag to use for decryption\n")); + printf(_(" -T, --tag-length=LEN Length of tag to use for encryption\n")); + printf(_(" -v, --verbose verbose output\n")); + printf(_(" -V, --version output version information, then exit\n")); + printf(_(" -?, --help show this help, then exit\n")); + printf("\n"); + printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT); +} + + +int +main(int argc, char *argv[]) +{ + char *algorithm = NULL, + *iv_hex = NULL, + *key_hex = NULL, + *plaintext_hex = NULL, + *ciphertext_hex = NULL, + *tag_hex = NULL; + + unsigned char *plaintext = NULL, + *ciphertext = NULL, + *key = NULL, + *iv = NULL, + *tag = NULL, + *tag_result = NULL, + *result = NULL; + + int verbose = 0, + plaintext_len = 0, + ciphertext_len = 0, + key_len = 0, + iv_len = 0, + tag_len = 16, + result_len = 0, + blocksize = 0, + cipher = PG_CIPHER_AES_GCM; + + PgCipherCtx *ctx = NULL; + + static struct option long_options[] = { + {"algorithm", required_argument, NULL, 'a'}, + {"init-vector", required_argument, NULL, 'i'}, + {"key", required_argument, NULL, 'k'}, + {"plain-text", required_argument, NULL, 'p'}, + {"cipher-text", required_argument, NULL, 'c'}, + {"tag", required_argument, NULL, 't'}, + {"tag-length", required_argument, NULL, 'T'}, + {"verbose", required_argument, NULL, 'v'}, + {NULL, 0, NULL, 0} + }; + + int c; + + pg_logging_init(argv[0]); + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("testcrypto")); + progname = get_progname(argv[0]); + + if (argc > 1) + { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) + { + usage(progname); + exit(EXITSUCCESS); + } + if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) + { + puts("testcrypto (PostgreSQL) " PG_VERSION); + exit(EXITSUCCESS); + } + } + + /* Process command-line argument */ + + while ((c = getopt_long(argc, argv, "a:i:k:p:c:t:T:v", long_options, NULL)) != -1) + { + switch (c) + { + case 'a': + algorithm = pg_strdup(optarg); + break; + + case 'i': + iv_hex = pg_strdup(optarg); + break; + + case 'k': + key_hex = pg_strdup(optarg); + break; + + case 'p': + plaintext_hex = pg_strdup(optarg); + break; + + case 'c': + ciphertext_hex = pg_strdup(optarg); + break; + + case 't': + tag_hex = pg_strdup(optarg); + break; + + case 'T': + tag_len = atoi(optarg); + break; + + case 'v': + verbose = 1; + break; + + default: + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + exit(EXITFAILURE); + } + } + + /* Complain if any arguments remain */ + if (optind < argc) + { + pg_log_error("too many command-line arguments (first is \"%s\")", + argv[optind]); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(EXITFAILURE); + } + + /* Check options passed in */ + if (algorithm) + { + if (strcmp(algorithm, "AES-GCM") == 0) + cipher = PG_CIPHER_AES_GCM; + else if (strcmp(algorithm, "AES-KWP") == 0) + cipher = PG_CIPHER_AES_KWP; + else + { + pg_log_error("Unsupported algorithm selected."); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(EXITFAILURE); + } + } + + if (key_hex == NULL) + { + pg_log_error("Key must be provided"); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(EXITFAILURE); + } + else + { + size_t key_hex_len = strlen(key_hex); + + key_len = pg_hex_dec_len(key_hex_len); + + key = pg_malloc0(key_len); + pg_hex_decode(key_hex, key_hex_len, (char *) key, key_len); + } + + if (cipher == PG_CIPHER_AES_GCM && iv_hex == NULL) + { + pg_log_error("Initialization vector must be provided"); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(EXITFAILURE); + } + else if (cipher == PG_CIPHER_AES_GCM) + { + size_t iv_hex_len = strlen(iv_hex); + + iv_len = pg_hex_dec_len(iv_hex_len); + + iv = pg_malloc0(iv_len); + pg_hex_decode(iv_hex, iv_hex_len, (char *) iv, iv_len); + } + + if (plaintext_hex) + { + size_t plaintext_hex_len = strlen(plaintext_hex); + + plaintext_len = pg_hex_dec_len(plaintext_hex_len); + + plaintext = pg_malloc0(plaintext_len); + pg_hex_decode(plaintext_hex, plaintext_hex_len, (char *) plaintext, + plaintext_len); + } + + /* + * OpenSSL 1.1.1d and earlier crashes on some zero-length plaintext and + * ciphertext strings. It crashes on an encryption call to + * EVP_EncryptFinal_ex(() in GCM mode of zero-length strings if plaintext + * is NULL, even though plaintext_len is zero. Setting plaintext to + * non-NULL allows it to work. In KWP mode, zero-length strings fail if + * plaintext_len = 0 and plaintext is non-NULL (the opposite). OpenSSL + * 1.1.1e+ is fine with all options. + */ + else if (cipher == PG_CIPHER_AES_GCM) + { + plaintext_len = 0; + plaintext = pg_malloc0(1); + } + + if (ciphertext_hex) + { + size_t ciphertext_hex_len = strlen(ciphertext_hex); + + ciphertext_len = pg_hex_dec_len(ciphertext_hex_len); + + ciphertext = pg_malloc0(ciphertext_len); + pg_hex_decode(ciphertext_hex, ciphertext_hex_len, + (char *) ciphertext, ciphertext_len); + } + /* see OpenSSL 1.1.1d item above, though crash only happens in GCM mode */ + else if (cipher == PG_CIPHER_AES_GCM) + { + ciphertext_len = 0; + ciphertext = pg_malloc0(1); + } + + if (cipher == PG_CIPHER_AES_GCM) + tag_result = pg_malloc0(tag_len); + + if (tag_hex) + { + size_t tag_hex_len = strlen(tag_hex); + + tag_len = pg_hex_dec_len(tag_hex_len); + + tag = pg_malloc0(tag_len); + pg_hex_decode(tag_hex, tag_hex_len, (char *) tag, tag_len); + } + else + tag = tag_result; + + if (verbose) + { + printf("Alrogithm: %d\n", cipher); + printf("Key length: %d (%d bits)\n", key_len, key_len * 8); + printf("IV length: %d (%d bits)\n", iv_len, iv_len * 8); + printf("Tag length: %d (%d bits)\n", tag_len, tag_len * 8); + printf("Plaintext length: %d\n", plaintext_len); + printf("Ciphertext length: %d\n", ciphertext_len); + } + + /* + * Encryption + * + * We run through the encryption even if there wasn't a plaintext + * provided- in that case we just encrypt the empty string. + */ + ctx = pg_cipher_ctx_create(cipher, key, key_len, true); + if (!ctx) + { + pg_log_error("Error creating encryption context, be sure key is of supported length"); + exit(EXITFAILURE); + } + + blocksize = pg_cipher_blocksize(ctx); + + /* If we were provided with a plaintext input */ + if (plaintext_len != 0) + { + /* Encryption might result in as much as input length + blocksize */ + result_len = plaintext_len + blocksize; + result = palloc0(result_len); + + if (ciphertext_hex == NULL) + { + ciphertext = result; + ciphertext_len = plaintext_len; + } + } + + if (cipher == PG_CIPHER_AES_GCM) + { + if (!pg_cipher_encrypt(ctx, cipher, + plaintext, plaintext_len, + result, &result_len, + iv, iv_len, + tag_result, tag_len)) + { + pg_log_error("Error during encryption."); + exit(EXITFAILURE); + } + } + else if (cipher == PG_CIPHER_AES_KWP) + { + if (!pg_cipher_keywrap(ctx, + plaintext, plaintext_len, + result, &result_len)) + { + pg_log_error("Error during encryption."); + exit(EXITFAILURE); + } + } + + if (verbose || ciphertext == NULL) + { + uint64 result_hex_len = pg_hex_enc_len(result_len); + char *result_hex = palloc0(result_hex_len + 1); + + pg_hex_encode((char *) result, result_len, result_hex, result_hex_len); + result_hex[result_hex_len] = '\0'; + + printf("ciphertext: %s\n", result_hex); + + if (cipher == PG_CIPHER_AES_GCM) + { + result_hex_len = pg_hex_enc_len(tag_len); + result_hex = palloc0(result_hex_len + 1); + + pg_hex_encode((char *) tag_result, tag_len, result_hex, result_hex_len); + result_hex[result_hex_len] = '\0'; + + printf("tag: %s\n", result_hex); + } + } + + /* + * Report on non-matching results, but still go through the decryption + * routine to make sure that we get the correct result, and then error + * out. + */ + if (plaintext_len != 0 && ciphertext != NULL && memcmp(ciphertext, result, plaintext_len) != 0) + pg_log_error("Provided ciphertext does not match"); + + if (cipher == PG_CIPHER_AES_GCM && tag != tag_result && memcmp(tag, tag_result, tag_len) != 0) + pg_log_error("Provided tag does not match"); + + /* + * If a ciphertext was provided then use that as the max size of our + * plaintext result. We shouldn't ever get a result larger. + */ + if (ciphertext_len != 0) + { + result_len = ciphertext_len; + result = palloc0(result_len); + } + + /* + * Decryption + * + * We run through the decryption even if there wasn't a ciphertext + * provided- in that case we just decrypt the empty string. + */ + ctx = pg_cipher_ctx_create(cipher, key, key_len, false); + if (!ctx) + { + pg_log_error("Error creating decryption context, be sure key is of supported length"); + exit(EXITFAILURE); + } + + if (cipher == PG_CIPHER_AES_GCM) + { + if (!pg_cipher_decrypt(ctx, cipher, + ciphertext, ciphertext_len, + result, &result_len, + iv, iv_len, + tag, tag_len)) + { + pg_log_error("Error during decryption."); + exit(EXITDECRYPTFAIL); + } + } + else if (cipher == PG_CIPHER_AES_KWP) + { + if (!pg_cipher_keyunwrap(ctx, + ciphertext, ciphertext_len, + result, &result_len)) + { + pg_log_error("Error during decryption."); + exit(EXITDECRYPTFAIL); + } + } + + if (verbose || plaintext == NULL) + { + uint64 result_hex_len = pg_hex_enc_len(result_len); + char *result_hex = palloc0(result_hex_len + 1); + + pg_hex_encode((char *) result, result_len, result_hex, result_hex_len); + result_hex[result_hex_len] = '\0'; + + printf("plaintext: %s\n", result_hex); + } + + if (ciphertext_len != 0 && plaintext != NULL && memcmp(plaintext, result, plaintext_len) != 0) + { + pg_log_error("Provided plaintext does not match"); + exit(EXITFAILURE); + } + + exit(EXITSUCCESS); +} diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index b057ecbd38..db57515bfe 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -138,19 +138,21 @@ sub mkvcbuild archive.c base64.c binaryheap.c checksum_helper.c compression.c config_info.c controldata_utils.c d2s.c encnames.c exec.c f2s.c file_perm.c file_utils.c hashfn.c ip.c jsonapi.c - keywords.c kwlookup.c link-canary.c md5_common.c percentrepl.c + keywords.c kmgr_utils.c kwlookup.c link-canary.c md5_common.c percentrepl.c pg_get_line.c pg_lzcompress.c pg_prng.c pgfnames.c psprintf.c relpath.c rmtree.c saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c wait_error.c wchar.c); if ($solution->{options}->{openssl}) { + push(@pgcommonallfiles, 'cipher_openssl.c'); push(@pgcommonallfiles, 'cryptohash_openssl.c'); push(@pgcommonallfiles, 'hmac_openssl.c'); push(@pgcommonallfiles, 'protocol_openssl.c'); } else { + push(@pgcommonallfiles, 'cipher.c'); push(@pgcommonallfiles, 'cryptohash.c'); push(@pgcommonallfiles, 'hmac.c'); push(@pgcommonallfiles, 'md5.c'); -- 2.40.1