Skip to content

Proof-of-concept: Protect decrypted relation keys #446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: TDE_REL_17_STABLE
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contrib/pg_tde/Makefile
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ endif

OBJS = src/encryption/enc_tde.o \
src/encryption/enc_aes.o \
src/encryption/tde_keys.o \
src/access/pg_tde_tdemap.o \
src/access/pg_tde_xlog.o \
src/access/pg_tde_xlog_smgr.o \
1 change: 1 addition & 0 deletions contrib/pg_tde/meson.build
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ pg_tde_sources = files(
'src/common/pg_tde_utils.c',
'src/encryption/enc_aes.c',
'src/encryption/enc_tde.c',
'src/encryption/tde_keys.c',
'src/keyring/keyring_api.c',
'src/keyring/keyring_curl.c',
'src/keyring/keyring_file.c',
109 changes: 72 additions & 37 deletions contrib/pg_tde/src/access/pg_tde_tdemap.c
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
#include "catalog/tde_principal_key.h"
#include "encryption/enc_aes.h"
#include "encryption/enc_tde.h"
#include "encryption/tde_keys.h"
#include "keyring/keyring_api.h"

#ifdef FRONTEND
@@ -73,21 +74,67 @@ static void finalize_key_rotation(const char *path_old, const char *path_new);
static int pg_tde_open_file_write(const char *tde_filename, const TDESignedPrincipalKeyInfo *signed_key_info, bool truncate, off_t *curr_pos);

void
pg_tde_save_smgr_key(RelFileLocator rel, const InternalKey *rel_key_data)
pg_tde_save_smgr_key(RelFileLocator rel, const EncryptedTdeKey *encrypted_key)
{
TDEPrincipalKey *principal_key;
LWLock *lock_pk = tde_lwlock_enc_keys();
char db_map_path[MAXPGPATH];
int map_fd;
off_t curr_pos = 0;
TDEMapEntry write_map_entry;
TDESignedPrincipalKeyInfo signed_key_Info;

write_map_entry.spcOid = rel.spcOid;
write_map_entry.relNumber = rel.relNumber;
write_map_entry.type = TDE_KEY_TYPE_SMGR;
memcpy(write_map_entry.enc_key.key, encrypted_key->key_data, TDE_KEY_SIZE);
memcpy(write_map_entry.enc_key.base_iv, encrypted_key->key_iv, TDE_KEY_IV_SIZE);
write_map_entry.enc_key.type = TDE_KEY_TYPE_SMGR;
write_map_entry.enc_key.start_lsn = 0;
memcpy(write_map_entry.entry_iv, encrypted_key->iv, TDE_KEY_ENCRYPTION_IV_SIZE);
memcpy(write_map_entry.aead_tag, encrypted_key->aead_tag, TDE_KEY_ENCRYPTION_AEAD_TAG_SIZE);

pg_tde_set_db_file_path(rel.dbOid, db_map_path);

LWLockAcquire(lock_pk, LW_EXCLUSIVE);

principal_key = GetPrincipalKey(rel.dbOid, LW_EXCLUSIVE);
if (principal_key == NULL)
{
ereport(ERROR,
errmsg("principal key not configured"),
errhint("create one using pg_tde_set_key before using encrypted tables"));

pg_tde_sign_principal_key_info(&signed_key_Info, principal_key);

/* Open and validate file for basic correctness. */
map_fd = pg_tde_open_file_write(db_map_path, &signed_key_Info, false, &curr_pos);

/*
* Read until we find an empty slot. Otherwise, read until end. This seems
* to be less frequent than vacuum. So let's keep this function here
* rather than overloading the vacuum process.
*/
while (1)
{
TDEMapEntry read_map_entry;
off_t prev_pos = curr_pos;

if (!pg_tde_read_one_map_entry(map_fd, &read_map_entry, &curr_pos))
{
curr_pos = prev_pos;
break;
}

if (read_map_entry.type == MAP_ENTRY_EMPTY)
{
curr_pos = prev_pos;
break;
}
}

pg_tde_write_key_map_entry(&rel, rel_key_data, principal_key);
pg_tde_write_one_map_entry(map_fd, &write_map_entry, &curr_pos, db_map_path);

CloseTransientFile(map_fd);
LWLockRelease(lock_pk);
}

@@ -268,7 +315,7 @@ pg_tde_initialize_map_entry(TDEMapEntry *map_entry, const TDEPrincipalKey *princ

AesGcmEncrypt(principal_key->keyData,
map_entry->entry_iv, MAP_ENTRY_IV_SIZE,
(unsigned char *) map_entry, offsetof(TDEMapEntry, enc_key),
(uint8 *) rlocator, sizeof(RelFileLocator),
rel_key_data->key, INTERNAL_KEY_LEN,
map_entry->enc_key.key,
map_entry->aead_tag, MAP_ENTRY_AEAD_TAG_SIZE);
@@ -725,13 +772,19 @@ tde_decrypt_rel_key(TDEPrincipalKey *principal_key, TDEMapEntry *map_entry)
{
InternalKey *rel_key_data = palloc_object(InternalKey);

RelFileLocator rlocator = {
.dbOid = principal_key->keyInfo.databaseId,
.relNumber = map_entry->relNumber,
.spcOid = map_entry->spcOid,
};

Assert(principal_key);

*rel_key_data = map_entry->enc_key;

if (!AesGcmDecrypt(principal_key->keyData,
map_entry->entry_iv, MAP_ENTRY_IV_SIZE,
(unsigned char *) map_entry, offsetof(TDEMapEntry, enc_key),
(uint8 *) &rlocator, sizeof(RelFileLocator),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to uint8 seems very arbitrary. Doesn't PostgreSQL use unsigned char everywhere for this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said I prefer uint8 over unsigned char, but that is not what I think we or PostgreSQL are using. So now you introduced a new way. Also it does seem you have not changed AesGcmDecrypt.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in pg_tde_tdemap.c was just to support the way I calculated aad in the other file, so that rotations wouldn't break everything. They are very PoC.

Copy link
Collaborator Author

@AndersAstrand AndersAstrand Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The postgres code uses uint8 about as commonly as unsigned char. I picked the one I like :D. The type wasn't the point there at all but instead to use the full rlocator as aad.

For WAL keys we currently use a fake rlocator that's the same for all of them so they need something else (probably start_lsn).

EDIT: excluding contrib/ unsigned char seems to be used about 66% of the time.

map_entry->enc_key.key, INTERNAL_KEY_LEN,
rel_key_data->key,
map_entry->aead_tag, MAP_ENTRY_AEAD_TAG_SIZE))
@@ -925,16 +978,15 @@ pg_tde_has_smgr_key(RelFileLocator rel)
}

/*
* Reads the map entry of the relation and decrypts the key.
* Reads the map entry of the relation and returns the encrypted key.
*/
InternalKey *
EncryptedTdeKey *
pg_tde_get_smgr_key(RelFileLocator rel)
{
TDEMapEntry map_entry;
TDEPrincipalKey *principal_key;
LWLock *lock_pk = tde_lwlock_enc_keys();
char db_map_path[MAXPGPATH];
InternalKey *rel_key;
EncryptedTdeKey *encrypted_key;
bool found_map_entry;

Assert(rel.relNumber != InvalidRelFileNumber);

@@ -943,37 +995,20 @@ pg_tde_get_smgr_key(RelFileLocator rel)
if (access(db_map_path, F_OK) == -1)
return NULL;

LWLockAcquire(lock_pk, LW_SHARED);
LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED);
found_map_entry = pg_tde_find_map_entry(&rel, TDE_KEY_TYPE_SMGR, db_map_path, &map_entry);
LWLockRelease(tde_lwlock_enc_keys());

if (!pg_tde_find_map_entry(&rel, TDE_KEY_TYPE_SMGR, db_map_path, &map_entry))
{
LWLockRelease(lock_pk);
if (!found_map_entry)
return NULL;
}

/*
* Get/generate a principal key, create the key for relation and get the
* encrypted key with bytes to write
*
* We should hold the lock until the internal key is loaded to be sure the
* retrieved key was encrypted with the obtained principal key. Otherwise,
* the next may happen: - GetPrincipalKey returns key "PKey_1". - Some
* other process rotates the Principal key and re-encrypt an Internal key
* with "PKey_2". - We read the Internal key and decrypt it with "PKey_1"
* (that's what we've got). As the result we return an invalid Internal
* key.
*/
principal_key = GetPrincipalKey(rel.dbOid, LW_SHARED);
if (principal_key == NULL)
ereport(ERROR,
errmsg("principal key not configured"),
errhint("create one using pg_tde_set_key before using encrypted tables"));

rel_key = tde_decrypt_rel_key(principal_key, &map_entry);

LWLockRelease(lock_pk);
encrypted_key = palloc0_object(EncryptedTdeKey);
memcpy(encrypted_key->key_data, map_entry.enc_key.key, TDE_KEY_SIZE);
memcpy(encrypted_key->key_iv, map_entry.enc_key.base_iv, TDE_KEY_ENCRYPTION_IV_SIZE);
memcpy(encrypted_key->iv, map_entry.entry_iv, TDE_KEY_IV_SIZE);
memcpy(encrypted_key->aead_tag, map_entry.aead_tag, TDE_KEY_ENCRYPTION_AEAD_TAG_SIZE);

return rel_key;
return encrypted_key;
}

/*
168 changes: 168 additions & 0 deletions contrib/pg_tde/src/encryption/tde_keys.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#include "postgres.h"

#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>

#include "utils/resowner.h"

#include "encryption/enc_aes.h"
#include "encryption/tde_keys.h"

#ifdef FRONTEND
#include "pg_tde_fe.h"
#endif

static void ResourceOwnerReleaseDecryptedTdeKey(Datum resource);
static DecryptedTdeKey *tde_keys_alloc_decrypted_key(void);

static const ResourceOwnerDesc tde_keys_resource_owner_desc =
{
.name = "pg_tde decrypted key",
.release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
.release_priority = RELEASE_PRIO_FIRST,
.ReleaseResource = ResourceOwnerReleaseDecryptedTdeKey,
.DebugPrint = NULL,
};

EncryptedTdeKey *
tde_keys_encrypt_key(const DecryptedTdeKey *decrypted_key,
const uint8 *encryption_key,
const uint8 *additional_authentication_data,
int additional_authentication_data_size)
{
EncryptedTdeKey *encrypted_key = palloc0_object(EncryptedTdeKey);

memcpy(encrypted_key->key_iv, decrypted_key->iv, TDE_KEY_IV_SIZE);

if (!RAND_bytes(encrypted_key->iv, TDE_KEY_ENCRYPTION_IV_SIZE))
ereport(ERROR,
errmsg("could not generate iv for key encryption: %s",
ERR_error_string(ERR_get_error(), NULL)));

AesGcmEncrypt(encryption_key,

encrypted_key->iv,
TDE_KEY_ENCRYPTION_IV_SIZE,

additional_authentication_data,
additional_authentication_data_size,

decrypted_key->data,
TDE_KEY_SIZE,

encrypted_key->key_data,

encrypted_key->aead_tag,
TDE_KEY_ENCRYPTION_AEAD_TAG_SIZE);

return encrypted_key;
}

DecryptedTdeKey *
tde_keys_decrypt_key(EncryptedTdeKey *encrypted_key,
const uint8 *decryption_key,
const uint8 *additional_authentication_data,
int additional_authentication_data_size)
{
DecryptedTdeKey *decrypted_key;

Assert(encrypted_key);
Assert(decryption_key);

decrypted_key = tde_keys_alloc_decrypted_key();

if (!AesGcmDecrypt(decryption_key,

encrypted_key->iv,
TDE_KEY_ENCRYPTION_IV_SIZE,

additional_authentication_data,
additional_authentication_data_size,

encrypted_key->key_data,
TDE_KEY_SIZE,

decrypted_key->data,

encrypted_key->aead_tag,
TDE_KEY_ENCRYPTION_AEAD_TAG_SIZE))
{
tde_keys_free_decrypted_key(decrypted_key);
return NULL;
}

memcpy(decrypted_key->iv, encrypted_key->key_iv, TDE_KEY_IV_SIZE);

return decrypted_key;
}

void
tde_keys_free_decrypted_key(DecryptedTdeKey *decrypted_key)
{
Assert(decrypted_key->owner);

ResourceOwnerForget(decrypted_key->owner,
PointerGetDatum(decrypted_key),
&tde_keys_resource_owner_desc);
OPENSSL_secure_clear_free(decrypted_key, sizeof(DecryptedTdeKey));
}

DecryptedTdeKey *
tde_keys_generate_decrypted_key(void)
{
DecryptedTdeKey *decrypted_key = tde_keys_alloc_decrypted_key();

if (!RAND_bytes(decrypted_key->data, TDE_KEY_SIZE))
ereport(ERROR,
errmsg("could not generate key: %s",
ERR_error_string(ERR_get_error(), NULL)));

if (!RAND_bytes(decrypted_key->iv, TDE_KEY_IV_SIZE))
ereport(ERROR,
errmsg("could not generate iv: %s",
ERR_error_string(ERR_get_error(), NULL)));

return decrypted_key;
}

static void
ResourceOwnerReleaseDecryptedTdeKey(Datum resource)
{
OPENSSL_secure_clear_free(DatumGetPointer(resource), sizeof(DecryptedTdeKey));
}

static DecryptedTdeKey *
tde_keys_alloc_decrypted_key(void)
{
DecryptedTdeKey *decrypted_key;

ResourceOwnerEnlarge(CurrentResourceOwner);

decrypted_key = OPENSSL_secure_zalloc(sizeof(DecryptedTdeKey));

decrypted_key->owner = CurrentResourceOwner;
ResourceOwnerRemember(decrypted_key->owner,
PointerGetDatum(decrypted_key),
&tde_keys_resource_owner_desc);

return decrypted_key;
}

EncryptedTdeKey *
tde_keys_new_encrypted_key(const uint8 *encryption_key,
const uint8 *additional_authentication_data,
int additional_authentication_data_size)
{
DecryptedTdeKey *decrypted_key;
EncryptedTdeKey *encrypted_key;

decrypted_key = tde_keys_generate_decrypted_key();
encrypted_key = tde_keys_encrypt_key(decrypted_key,
encryption_key,
additional_authentication_data,
additional_authentication_data_size);
tde_keys_free_decrypted_key(decrypted_key);

return encrypted_key;
}
5 changes: 3 additions & 2 deletions contrib/pg_tde/src/include/access/pg_tde_tdemap.h
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
#include "storage/relfilelocator.h"
#include "catalog/tde_principal_key.h"
#include "common/pg_tde_utils.h"
#include "encryption/tde_keys.h"

typedef enum
{
@@ -84,9 +85,9 @@ pg_tde_set_db_file_path(Oid dbOid, char *path)
join_path_components(path, pg_tde_get_data_dir(), psprintf(PG_TDE_MAP_FILENAME, dbOid));
}

extern void pg_tde_save_smgr_key(RelFileLocator rel, const InternalKey *key);
extern void pg_tde_save_smgr_key(RelFileLocator rel, const EncryptedTdeKey *key);
extern bool pg_tde_has_smgr_key(RelFileLocator rel);
extern InternalKey *pg_tde_get_smgr_key(RelFileLocator rel);
extern EncryptedTdeKey *pg_tde_get_smgr_key(RelFileLocator rel);
extern void pg_tde_free_key_map_entry(RelFileLocator rel);

extern int pg_tde_count_relations(Oid dbOid);
39 changes: 39 additions & 0 deletions contrib/pg_tde/src/include/encryption/tde_keys.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef TDE_KEYS_H
#define TDE_KEYS_H

#include "postgres.h"

#include "utils/resowner.h"

#include "catalog/tde_principal_key.h"

#define TDE_KEY_SIZE 16
#define TDE_KEY_IV_SIZE 16
#define TDE_KEY_ENCRYPTION_IV_SIZE 16
#define TDE_KEY_ENCRYPTION_AEAD_TAG_SIZE 16

typedef struct EncryptedTdeKey
{
uint8 key_data[TDE_KEY_SIZE];
uint8 key_iv[TDE_KEY_IV_SIZE];

/* IV and tag used when encrypting the key itself */
uint8 iv[TDE_KEY_ENCRYPTION_IV_SIZE];
uint8 aead_tag[TDE_KEY_ENCRYPTION_AEAD_TAG_SIZE];
} EncryptedTdeKey;

typedef struct DecryptedTdeKey
{
uint8 data[TDE_KEY_SIZE];
uint8 iv[TDE_KEY_IV_SIZE];

ResourceOwner owner;
} DecryptedTdeKey;

extern EncryptedTdeKey *tde_keys_encrypt_key(const DecryptedTdeKey *decrypted_key, const uint8 *encryption_key, const uint8 *additional_authentication_data, int additional_authentication_data_size);
extern DecryptedTdeKey *tde_keys_decrypt_key(EncryptedTdeKey *encrypted_key, const uint8 *decryption_key, const uint8 *additional_authentication_data, int additional_authentication_data_size);
extern void tde_keys_free_decrypted_key(DecryptedTdeKey *decrypted_key);
extern DecryptedTdeKey *tde_keys_generate_decrypted_key(void);
extern EncryptedTdeKey *tde_keys_new_encrypted_key(const uint8 *encryption_key, const uint8 *additional_authentication_data, int additional_authentication_data_size);

#endif
150 changes: 100 additions & 50 deletions contrib/pg_tde/src/smgr/pg_tde_smgr.c
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
#include "access/pg_tde_xlog.h"
#include "encryption/enc_aes.h"
#include "encryption/enc_tde.h"
#include "encryption/tde_keys.h"
#include "pg_tde_event_capture.h"
#include "smgr/pg_tde_smgr.h"

@@ -46,13 +47,13 @@ typedef struct TDESMgrRelation
struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1];

TDEMgrRelationEncryptionStatus encryption_status;
InternalKey relKey;
EncryptedTdeKey relKey;
} TDESMgrRelation;

typedef struct
{
RelFileLocator rel;
InternalKey key;
EncryptedTdeKey key;
} TempRelKeyEntry;

#define INIT_TEMP_RELS 16
@@ -64,25 +65,39 @@ static HTAB *TempRelKeys = NULL;

static SMgrId OurSMgrId = MaxSMgrId;

static void tde_smgr_save_temp_key(const RelFileLocator *newrlocator, const InternalKey *key);
static InternalKey *tde_smgr_get_temp_key(const RelFileLocator *rel);
static void tde_smgr_save_temp_key(const RelFileLocator *newrlocator, const EncryptedTdeKey *key);
static EncryptedTdeKey *tde_smgr_get_temp_key(const RelFileLocator *rel);
static bool tde_smgr_has_temp_key(const RelFileLocator *rel);
static void tde_smgr_remove_temp_key(const RelFileLocator *rel);
static void CalcBlockIv(ForkNumber forknum, BlockNumber bn, const unsigned char *base_iv, unsigned char *iv);

static InternalKey *
static EncryptedTdeKey *
tde_smgr_create_key(const RelFileLocatorBackend *smgr_rlocator)
{
InternalKey *key = palloc_object(InternalKey);
EncryptedTdeKey *encrypted_key;
TDEPrincipalKey *principal_key;

pg_tde_generate_internal_key(key, TDE_KEY_TYPE_SMGR);
LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED);

principal_key = GetPrincipalKey(smgr_rlocator->locator.dbOid, LW_SHARED);
if (principal_key == NULL)
ereport(ERROR,
errmsg("principal key not configured"),
errhint("create one using pg_tde_set_key before using encrypted tables"));

encrypted_key = tde_keys_new_encrypted_key(principal_key->keyData,
(uint8 *) &smgr_rlocator->locator,
sizeof(RelFileLocator));


LWLockRelease(tde_lwlock_enc_keys());

if (RelFileLocatorBackendIsTemp(*smgr_rlocator))
tde_smgr_save_temp_key(&smgr_rlocator->locator, key);
tde_smgr_save_temp_key(&smgr_rlocator->locator, encrypted_key);
else
pg_tde_save_smgr_key(smgr_rlocator->locator, key);
pg_tde_save_smgr_key(smgr_rlocator->locator, encrypted_key);

return key;
return encrypted_key;
}

static void
@@ -100,14 +115,17 @@ tde_smgr_log_create_key(const RelFileLocatorBackend *smgr_rlocator)
void
tde_smgr_create_key_redo(const RelFileLocator *rlocator)
{
InternalKey key;
EncryptedTdeKey *encrypted_key;
RelFileLocatorBackend smgr_rlocator = {
.locator = *rlocator,
.backend = INVALID_PROC_NUMBER,
};

if (pg_tde_has_smgr_key(*rlocator))
return;

pg_tde_generate_internal_key(&key, TDE_KEY_TYPE_SMGR);

pg_tde_save_smgr_key(*rlocator, &key);
encrypted_key = tde_smgr_create_key(&smgr_rlocator);
pfree(encrypted_key);
}

static void
@@ -139,7 +157,7 @@ tde_smgr_is_encrypted(const RelFileLocatorBackend *smgr_rlocator)
return pg_tde_has_smgr_key(smgr_rlocator->locator);
}

static InternalKey *
static EncryptedTdeKey *
tde_smgr_get_key(const RelFileLocatorBackend *smgr_rlocator)
{
if (RelFileLocatorBackendIsTemp(*smgr_rlocator))
@@ -148,6 +166,55 @@ tde_smgr_get_key(const RelFileLocatorBackend *smgr_rlocator)
return pg_tde_get_smgr_key(smgr_rlocator->locator);
}

static DecryptedTdeKey *
tde_smgr_get_decrypted_key(TDESMgrRelation *tdereln)
{
DecryptedTdeKey *decrypted_key;
TDEPrincipalKey *principal_key;

for (int i = 0; i < 2; i++)
{
if (tdereln->encryption_status == RELATION_KEY_NOT_AVAILABLE)
{
EncryptedTdeKey *encrypted_key = tde_smgr_get_key(&tdereln->reln.smgr_rlocator);

tdereln->relKey = *encrypted_key;
tdereln->encryption_status = RELATION_KEY_AVAILABLE;
pfree(encrypted_key);
}

LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED);

principal_key = GetPrincipalKey(tdereln->reln.smgr_rlocator.locator.dbOid, LW_SHARED);
if (principal_key == NULL)
ereport(ERROR,
errmsg("principal key not configured"),
errhint("create one using pg_tde_set_key before using encrypted tables"));

decrypted_key = tde_keys_decrypt_key(&tdereln->relKey,
principal_key->keyData,
(uint8 *) &tdereln->reln.smgr_rlocator.locator,
sizeof(RelFileLocator));

LWLockRelease(tde_lwlock_enc_keys());

/*
* If the principal key has been rotated we need to load the encrypted
* key from file again.
*/
if (decrypted_key)
return decrypted_key;
else
tdereln->encryption_status = RELATION_KEY_NOT_AVAILABLE;

}

/* The problem was not a rotated principal key apparently. */
ereport(ERROR,
errmsg("Failed to decrypt key, incorrect principal key or corrupted key file"));

}

static void
tde_smgr_remove_key(const RelFileLocatorBackend *smgr_rlocator)
{
@@ -211,15 +278,7 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
{
unsigned char *local_blocks = palloc_aligned(BLCKSZ * nblocks, PG_IO_ALIGN_SIZE, 0);
void **local_buffers = palloc_array(void *, nblocks);

if (tdereln->encryption_status == RELATION_KEY_NOT_AVAILABLE)
{
InternalKey *int_key = tde_smgr_get_key(&reln->smgr_rlocator);

tdereln->relKey = *int_key;
tdereln->encryption_status = RELATION_KEY_AVAILABLE;
pfree(int_key);
}
DecryptedTdeKey *key = tde_smgr_get_decrypted_key(tdereln);

for (int i = 0; i < nblocks; ++i)
{
@@ -228,16 +287,17 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,

local_buffers[i] = &local_blocks[i * BLCKSZ];

CalcBlockIv(forknum, bn, tdereln->relKey.base_iv, iv);
CalcBlockIv(forknum, bn, key->iv, iv);

AesEncrypt(tdereln->relKey.key, iv, ((unsigned char **) buffers)[i], BLCKSZ, local_buffers[i]);
AesEncrypt(key->data, iv, ((unsigned char **) buffers)[i], BLCKSZ, local_buffers[i]);
}

mdwritev(reln, forknum, blocknum,
(const void **) local_buffers, nblocks, skipFsync);

pfree(local_blocks);
pfree(local_buffers);
tde_keys_free_decrypted_key(key);
}
}

@@ -282,23 +342,16 @@ tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
{
unsigned char *local_blocks = palloc_aligned(BLCKSZ, PG_IO_ALIGN_SIZE, 0);
unsigned char iv[16];
DecryptedTdeKey *key = tde_smgr_get_decrypted_key(tdereln);

if (tdereln->encryption_status == RELATION_KEY_NOT_AVAILABLE)
{
InternalKey *int_key = tde_smgr_get_key(&reln->smgr_rlocator);

tdereln->relKey = *int_key;
tdereln->encryption_status = RELATION_KEY_AVAILABLE;
pfree(int_key);
}

CalcBlockIv(forknum, blocknum, tdereln->relKey.base_iv, iv);
CalcBlockIv(forknum, blocknum, key->iv, iv);

AesEncrypt(tdereln->relKey.key, iv, ((unsigned char *) buffer), BLCKSZ, local_blocks);
AesEncrypt(key->data, iv, ((unsigned char *) buffer), BLCKSZ, local_blocks);

mdextend(reln, forknum, blocknum, local_blocks, skipFsync);

pfree(local_blocks);
tde_keys_free_decrypted_key(key);
}
}

@@ -307,19 +360,14 @@ tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
void **buffers, BlockNumber nblocks)
{
TDESMgrRelation *tdereln = (TDESMgrRelation *) reln;
DecryptedTdeKey *key;

mdreadv(reln, forknum, blocknum, buffers, nblocks);

if (tdereln->encryption_status == RELATION_NOT_ENCRYPTED)
return;
else if (tdereln->encryption_status == RELATION_KEY_NOT_AVAILABLE)
{
InternalKey *int_key = tde_smgr_get_key(&reln->smgr_rlocator);

tdereln->relKey = *int_key;
tdereln->encryption_status = RELATION_KEY_AVAILABLE;
pfree(int_key);
}
key = tde_smgr_get_decrypted_key(tdereln);

for (int i = 0; i < nblocks; ++i)
{
@@ -347,17 +395,19 @@ tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
if (allZero)
continue;

CalcBlockIv(forknum, bn, tdereln->relKey.base_iv, iv);
CalcBlockIv(forknum, bn, key->iv, iv);

AesDecrypt(tdereln->relKey.key, iv, ((unsigned char **) buffers)[i], BLCKSZ, ((unsigned char **) buffers)[i]);
AesDecrypt(key->data, iv, ((unsigned char **) buffers)[i], BLCKSZ, ((unsigned char **) buffers)[i]);
}

tde_keys_free_decrypted_key(key);
}

static void
tde_mdcreate(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool isRedo)
{
TDESMgrRelation *tdereln = (TDESMgrRelation *) reln;
InternalKey *key;
EncryptedTdeKey *key;

/* Copied from mdcreate() in md.c */
if (isRedo && tdereln->md_num_open_segs[forknum] > 0)
@@ -481,7 +531,7 @@ RegisterStorageMgr(void)
}

static void
tde_smgr_save_temp_key(const RelFileLocator *newrlocator, const InternalKey *key)
tde_smgr_save_temp_key(const RelFileLocator *newrlocator, const EncryptedTdeKey *key)
{
TempRelKeyEntry *entry;
bool found;
@@ -506,7 +556,7 @@ tde_smgr_save_temp_key(const RelFileLocator *newrlocator, const InternalKey *key
entry->key = *key;
}

static InternalKey *
static EncryptedTdeKey *
tde_smgr_get_temp_key(const RelFileLocator *rel)
{
TempRelKeyEntry *entry;
@@ -518,7 +568,7 @@ tde_smgr_get_temp_key(const RelFileLocator *rel)

if (entry)
{
InternalKey *key = palloc_object(InternalKey);
EncryptedTdeKey *key = palloc_object(EncryptedTdeKey);

*key = entry->key;
return key;