From 86ee2c613776d0d75e2f734a582681f5c96423b8 Mon Sep 17 00:00:00 2001 From: Satoshi Nagayasu Date: Sat, 11 Jul 2015 08:06:51 +0000 Subject: [PATCH 1/2] Fix to make the module a PostgreSQL extension. Making the module an extension allows users to install just only with 'CREATE EXTENSION data_encryption' instead of using the install script (cipher_setup.sh). And also it allows users to build with 'make USE_PGXS=1' instead of using the dedicated build script. --- SOURCES/bin/cipher_setup.sh | 338 -------- SOURCES/data_encryption/93/Makefile | 49 -- SOURCES/data_encryption/Makefile | 20 + .../data_encryption/data_encryption--0.1.sql | 719 ++++++++++++++++++ .../{93 => }/data_encryption.c | 31 +- .../data_encryption/data_encryption.control | 5 + .../{93 => }/data_encryption.h | 0 SOURCES/data_encryption/makedencryption.sh | 37 - SOURCES/lib/init/cipher_definition.sql | 316 -------- SOURCES/lib/init/cipher_key_function.sql | 310 -------- SOURCES/lib/init/common_session_create.sql | 83 -- 11 files changed, 758 insertions(+), 1150 deletions(-) delete mode 100644 SOURCES/bin/cipher_setup.sh delete mode 100644 SOURCES/data_encryption/93/Makefile create mode 100644 SOURCES/data_encryption/Makefile create mode 100644 SOURCES/data_encryption/data_encryption--0.1.sql rename SOURCES/data_encryption/{93 => }/data_encryption.c (98%) create mode 100644 SOURCES/data_encryption/data_encryption.control rename SOURCES/data_encryption/{93 => }/data_encryption.h (100%) delete mode 100644 SOURCES/data_encryption/makedencryption.sh delete mode 100644 SOURCES/lib/init/cipher_definition.sql delete mode 100644 SOURCES/lib/init/cipher_key_function.sql delete mode 100644 SOURCES/lib/init/common_session_create.sql diff --git a/SOURCES/bin/cipher_setup.sh b/SOURCES/bin/cipher_setup.sh deleted file mode 100644 index 5b4fe27..0000000 --- a/SOURCES/bin/cipher_setup.sh +++ /dev/null @@ -1,338 +0,0 @@ -#! /bin/bash - -################################################### -# Setting Necessary Path. # -################################################### -export PROGRAMNAME=`basename $0` -#get program root path -export CURRENTPATH=`echo $0|sed "s/${PROGRAMNAME}$//g"` - -#change directory to program root -if [ -n "$CURRENTPATH" ]; then - cd $CURRENTPATH -fi - -#set external program(psql) execution path -export PGPATH=$1 -export LD_PRELOAD=${PGPATH}/lib/libpq.so.5 - -#set the psql path -export PSQLPATH=${PGPATH}/bin/ -#set initscript path -export SCRPATH=../lib/init -#activate db file directory path -export INSTPATH=../sys - -export PATH=${PSQLPATH}:${PATH} - - -################################################### -# Setting PSQL Environment # -################################################### -export PGOPTIONS="-c client_min_messages=ERROR" - - -################################################### -# Setting Common Variable # -################################################### -export KEYTBL="cipher_key_table" -export NOKEYTBL="cipher_key_table_uninst" - -export ERRFILE="error_`date +%Y%m%d-%H%M%S`.log" - -################################################### -# Input PSQL Parameter Function # -################################################### -input_psql_param(){ - - #set the delimiter to newline - OLDIFS="${IFS}" - IFS=$'\n' - echo -n 'Please enter database server port to connect : ' - read PORT; - - echo -n 'Please enter database user name to connect : ' - read USER; - - echo -n 'Please enter password for authentication : ' - stty -echo - read PASS; - stty echo - echo - - echo -n 'Please enter database name to connect : ' - read DB; - if [ "${DB}" = "template1" ];then echo "ERROR: Can not use template1 database";exit 1;fi - if [ "${DB}" = "" ];then echo "ERROR: The length of database name must not be zero";exit 1;fi - IFS="${OLDIFS}" - - export PGHOST=localhost - export PGDATABASE="${DB}" - export PGPORT="${PORT}" - export PGPASSWORD="${PASS}" - export PGUSER="${USER}" - - return 0; -} - -##################################################### -# Connection Test Function # -##################################################### -connection_test(){ - psql -w -c "select 1" 1>/dev/null ; - return $? -} - -##################################################### -# File Exist Test Function # -##################################################### -file_exist_check(){ - if [ ! -f "$1" ]; - then - echo "ERROR: There is not exist a definition-script : $1" - rm -rf "${INSTALLFILE}" - exit 1; - fi -} - -##################################################### -# Decide Function # -##################################################### -decide(){ - prompt="Please input [Yes/No] > " - status=0 - - while : ; do - line="" - read -p "${prompt}" line - case "$line" in - Y|y|[Yy]es|YES) - status=0 - break - ;; - N|n|[Nn]o|NO) - status=1 - break - ;; - esac - - echo "ERROR: Invalid input." - done - - return $status -} - -################################################### -# Output Parameter Function # -################################################### -printErr(){ - echo "error occured at `date +%Y-%m-%d-%H:%M:%S`" - echo "parameters:" - echo " user:${PGUSER}" - echo " db:${PGDATABASE}" - echo " port:${PGPORT}" - echo " menu:$select" - echo -} - -################################################### -# Validate Function # -################################################### -validate(){ - - ######## - # initial activate … true - # reactivate … false - ######## - VALIDATE_NEW=false - - #input connection parameter for psql - input_psql_param - - #connection test - connection_test - if [ $? -ne 0 ]; - then - echo "ERROR: Could not connect to the database"; - exit 1; - fi - - #check existing of cipher_key_table - CIPHER_EXIST=`psql -t -c "SELECT COUNT(*) FROM PG_TABLES WHERE TABLENAME='${KEYTBL}';"` - if [ $CIPHER_EXIST -eq 1 ]; - then - echo "ERROR: Transparent data encryption function has already been activated" - exit 1; - fi - - - #store all activation query to file for execution - INSTALLFILE="${INSTPATH}"/"${DB}".cipher.inst - if [ -f "${INSTALLFILE}" ]; - then - echo "ERROR: Lock file already exists. File name: ${INSTALLFILE}" - echo "HINT: Remove the Lock file, and Try again" - exit 1; - fi - - #check existing of cipher_key_table_uninst - CIPHER_NOEXIST=`psql -t -c "SELECT COUNT(*) FROM PG_TABLES WHERE TABLENAME='${NOKEYTBL}';"` - if [ $CIPHER_NOEXIST -ne 0 ]; - then - #exits -- reactivate - VALIDATE_NEW=false - echo "WARN: Are you sure you want to reactivate the transparent data encryption feature? " - decide - if [ $? -eq 1 ]; - then - echo "INFO: terminated" - exit 0; - fi - - - #init activation file - echo "" > "${INSTALLFILE}" - #remove installation file, if installation is terminated abnormally - trap 'rm -rf "${INSTALLFILE}"; exit 1;' 1 2 3 15 - #rename cipher_key_table_uninst to cipher_key_table - QUERY="ALTER TABLE \"${NOKEYTBL}\" RENAME TO \"${KEYTBL}\";"; - echo "${QUERY}" >> "${INSTALLFILE}" - else - #not exists -- initial activate - VALIDATE_NEW=true - #execute CREATE LANGUAGE - psql -c "CREATE OR REPLACE LANGUAGE plpgsql;" 2> /dev/null - - file_exist_check "${SCRPATH}/cipher_definition.sql" - file_exist_check "${SCRPATH}/cipher_key_function.sql" - - #init activation file - echo "" > "${INSTALLFILE}" - #remove installation file, if installation is terminated abnormally - trap 'rm -rf "${INSTALLFILE}"; exit 1;' 1 2 3 15 - cat "${SCRPATH}/cipher_definition.sql" >> "${INSTALLFILE}" - cat "${SCRPATH}/cipher_key_function.sql" >> "${INSTALLFILE}" - echo "GRANT SELECT ON cipher_key_table TO PUBLIC;" >> "${INSTALLFILE}" - fi - - file_exist_check "${SCRPATH}/common_session_create.sql" - #define session function A - cat "${SCRPATH}/common_session_create.sql" >> "${INSTALLFILE}" - - #run all query in installation file using transaction - psql --set ON_ERROR_STOP=ON -1 -f "${INSTALLFILE}" 1>/dev/null 2>"${ERRFILE}" - if [ `wc -c < ${ERRFILE}` -gt 0 ]; - then - printErr >> "${ERRFILE}" - echo "ERROR: Could not activate transparent data encryption feature" - echo "HINT : Please see ${ERRFILE} for detail" - rm -rf "${INSTALLFILE}" - exit 1; - fi - #remove empty error log - rm -rf "${ERRFILE}" - - echo "INFO: Transparent data encryption feature has been activated" - - return 0; -} - -################################################### -# Invalidate Function # -################################################### -invalidate(){ - - - #input connection parameters for psql - input_psql_param - - #connection test - connection_test - if [ $? -ne 0 ];then echo "ERROR: Could not connect to the database";exit 1;fi - - #check existence of cipher_key_table - CIPHER_EXIST=`psql -t -c "SELECT COUNT(*) FROM PG_TABLES WHERE TABLENAME='${KEYTBL}';"` - if [ $CIPHER_EXIST -eq 0 ]; - then #cipher_key_table is not exists - echo "ERROR: Transparent data encryption feature has not been activated yet" - exit 1 - fi - - #store all query for inactivate to file - INSTALLFILE="${INSTPATH}"/"${DB}".cipher.inst - if [ ! -f "${INSTALLFILE}" ]; - then - echo "ERROR: Lock file does not exist. File name : ${INSTALLFILE}" - exit 1; - fi - #init inactivate file - echo "" > "${INSTALLFILE}" - - #drop session function C - echo "DROP FUNCTION PGTDE_BEGIN_SESSION(TEXT);" >> "${INSTALLFILE}" - #drop end session function - echo "DROP FUNCTION PGTDE_END_SESSION();" >> "${INSTALLFILE}" - - - - #rename cipher_key_table - QUERY="ALTER TABLE \"${KEYTBL}\" RENAME TO \"${NOKEYTBL}\";"; - echo "${QUERY}" >> "${INSTALLFILE}" - - - #run all query in inactivation file using transaction - psql --set ON_ERROR_STOP=ON -1 -f "${INSTALLFILE}" 1>/dev/null 2>"${ERRFILE}" - if [ `wc -c < ${ERRFILE}` -gt 0 ]; - then - printErr >> "${ERRFILE}" - echo "ERROR: Could not inactivate the transparent data encryption feature" - echo "HINT : Please see ${ERRFILE} for detail" - exit 1; - fi - #remove empty error log - rm -rf "${ERRFILE}" - - #remove dbname.cipher.inst - rm -f "${INSTALLFILE}" - - echo "INFO: The transparent data encryption feature has been inactivated" - - return 0; -} - - -################################################### -# Main Process # -################################################### - -if [ $# -ne 1 ]; then - echo "usage: sh bin/cipher_setup.sh POSTGRESQL_DIR" - echo "Please specify PostgreSQL installed directory" - exit 1 -fi - -echo "Transparent data encryption feature setup script" -echo "Please select from the setup menu below" - - -while [ 1 ] -do - echo 'Transparent data encryption feature setup menu' - echo '1: activate the transparent data encryption feature' - echo '2: inactivate the transparent data encryption feature' - prompt="select menu [1 - 2] > " - read -p "${prompt}" select - - case $select in - 1) - validate;break - ;; - 2) - invalidate;break - ;; - *) - echo "ERROR: Invalid menu number : $select" - continue; - ;; - esac -done diff --git a/SOURCES/data_encryption/93/Makefile b/SOURCES/data_encryption/93/Makefile deleted file mode 100644 index f7ab2ab..0000000 --- a/SOURCES/data_encryption/93/Makefile +++ /dev/null @@ -1,49 +0,0 @@ - -INSTDIR = /usr/local/pgsql/lib - -PGSQL_SRC_PATH ?= /usr/local/src/postgresql-9.3.6 -PGSQL_INCLUDE_PATH ?= $(PGSQL_SRC_PATH)/src/include -PGSQL_LIBRARY_PATH ?= $(PGSQL_SRC_PATH)/contrib/pgcrypto -export PGSQL_SRC_PATH -export PGSQL_INCLUDE_PATH -export PGSQL_LIBRARY_PATH - -BINARY = data_encryption.so -OBJS = data_encryption.o - -CC = /usr/bin/gcc -ifeq ($(debug),yes) - CFLAGS = -c -Wall -O0 -ggdb $(DEBUG) -fPIC -else - CFLAGS = -c -Wall -O3 -fPIC -endif - -LFLAGS = -L$(PGSQL_LIBRARY_PATH) -LINKER = -lpgcrypto -Wl,-rpath,'$(PGSQL_LIBRARY_PATH)' -IFLAGS = -I$(PGSQL_INCLUDE_PATH) -I$(PGSQL_LIBRARY_PATH) - -all: $(BINARY) - -$(BINARY): $(OBJS) - $(CC) -shared -o $(BINARY) $(OBJS) $(LFLAGS) $(LINKER) - -%.o: %.c - $(CC) $(CFLAGS) $(IFLAGS) $< - -install: $(BINARY) - @if [ -d $(INSTDIR) ]; \ - then \ - cp $(BINARY) $(INSTDIR)/ && \ - chmod a+x $(INSTDIR)/$(BIN) && \ - echo ""; \ - echo "[SUCCESS] $(BINARY) Installed Complete in '$(INSTDIR)'."; \ - echo ""; \ - else \ - echo "[ERROR] $(BINARY) Installed Failure.($(INSTDIR) does't exist)"; \ - fi - -uninstall: - rm -f $(INSTDIR)/$(BIN) - -clean: - rm -f $(BINARY) $(OBJS) diff --git a/SOURCES/data_encryption/Makefile b/SOURCES/data_encryption/Makefile new file mode 100644 index 0000000..cc66021 --- /dev/null +++ b/SOURCES/data_encryption/Makefile @@ -0,0 +1,20 @@ +# contrib/data_encryption/Makefile + +MODULE_big = data_encryption +OBJS = data_encryption.o + +EXTENSION = data_encryption +DATA = data_encryption--0.1.sql + +SHLIB_LINK = $(shell $(PG_CONFIG) --libdir)/pgcrypto.so + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/data_encryption +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/SOURCES/data_encryption/data_encryption--0.1.sql b/SOURCES/data_encryption/data_encryption--0.1.sql new file mode 100644 index 0000000..12785e5 --- /dev/null +++ b/SOURCES/data_encryption/data_encryption--0.1.sql @@ -0,0 +1,719 @@ +/* contrib/data_encryption/data_encryption--0.1.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION data_encryption" to load this file. \quit + +-- +-- FILE: cipher_definition.sql +-- +/*------------------------------------------------------------* + * cipher_key_definition + * + * define type, function, index end etc for TDE. + *------------------------------------------------------------*/ + +/* define a new procedural language */ +/* CREATE TRUSTED LANGUAGE 'plpgsql' HANDLER language_handler_in;*/ + + /* drop if encrypted data types are already exist */ + DROP TYPE IF EXISTS encrypt_text CASCADE; + DROP TYPE IF EXISTS encrypt_bytea CASCADE; + + /* create encrypted data types */ + CREATE TYPE encrypt_text; + CREATE TYPE encrypt_bytea; + + /* define input function of encrypted text type */ + CREATE FUNCTION + enctext_in(cstring) + RETURNS + encrypt_text + AS + '$libdir/data_encryption.so','enctext_in' + LANGUAGE C STRICT; + + /* define output function of encrypted text type */ + CREATE FUNCTION + enctext_out(encrypt_text) + RETURNS + cstring + AS + '$libdir/data_encryption.so','enctext_out' + LANGUAGE C IMMUTABLE STRICT; + + /* define recv function of encrypted text type */ + CREATE FUNCTION + enctext_recv(internal) + RETURNS + encrypt_text + AS + '$libdir/data_encryption.so','encrecv' + LANGUAGE C STRICT; + + /* define send function of encrypted text type */ + CREATE FUNCTION + enctext_send(encrypt_text) + RETURNS + bytea + AS + '$libdir/data_encryption.so','encsend' + LANGUAGE C STRICT; + + /* define input function of encrypted binary type */ + CREATE FUNCTION + encbytea_in(cstring) + RETURNS + encrypt_bytea + AS + '$libdir/data_encryption.so','encbytea_in' + LANGUAGE C STRICT; + + /* define output function of encrypted binary type */ + CREATE FUNCTION + encbytea_out(encrypt_bytea) + RETURNS + cstring + AS + '$libdir/data_encryption.so','encbytea_out' + LANGUAGE C IMMUTABLE STRICT; + + /* define recv function of encrypted binary type */ + CREATE FUNCTION + encbytea_recv(internal) + RETURNS + encrypt_bytea + AS + '$libdir/data_encryption.so','encrecv' + LANGUAGE C STRICT; + + /* define send function of encrypted binary type */ + CREATE FUNCTION + encbytea_send(encrypt_bytea) + RETURNS + bytea + AS + '$libdir/data_encryption.so','encsend' + LANGUAGE C STRICT; + + /* define encrypted text types */ + CREATE TYPE ENCRYPT_TEXT ( + INPUT = enctext_in + , OUTPUT = enctext_out + , RECEIVE = enctext_recv + , SEND = enctext_send + , INTERNALLENGTH = VARIABLE + , ALIGNMENT = int4 + , STORAGE = extended); + + /* define encrypted binary types */ + CREATE TYPE ENCRYPT_BYTEA ( + INPUT = encbytea_in + , OUTPUT = encbytea_out + , RECEIVE = encbytea_recv + , SEND = encbytea_send + , INTERNALLENGTH = VARIABLE + , ALIGNMENT = int4 + , STORAGE = extended); + + /* index operator of encrypted text types */ + CREATE OR REPLACE FUNCTION + enc_compeq_enctext(encrypt_text,encrypt_text) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_compeq_enctext' + LANGUAGE C STRICT; + + /* compare function of encrypted text type and text */ + CREATE OR REPLACE FUNCTION + enc_compeq_text_enctext(text,encrypt_text) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_compeq_text_enctext' + LANGUAGE C STRICT; + CREATE OR REPLACE FUNCTION + enc_compeq_enctext_text(encrypt_text,text) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_compeq_enctext_text' + LANGUAGE C STRICT; + + /* index operator of encrypted binary types */ + CREATE OR REPLACE FUNCTION + enc_compeq_encbytea(encrypt_bytea,encrypt_bytea) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_compeq_encbytea' + LANGUAGE C STRICT; + + /* compare encrypted binary type and binary */ + CREATE OR REPLACE FUNCTION + enc_compeq_bytea_encbytea(bytea,encrypt_bytea) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_compeq_bytea_encbytea' + LANGUAGE C STRICT; + CREATE OR REPLACE FUNCTION + enc_compeq_encbytea_bytea(encrypt_bytea,bytea) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_compeq_encbytea_bytea' + LANGUAGE C STRICT; + + /* hash function for encrypted text */ + CREATE OR REPLACE FUNCTION + enc_hash_enctext(encrypt_text) + RETURNS + integer + AS + '$libdir/data_encryption.so','enc_hash_encdata' + LANGUAGE C STRICT IMMUTABLE; + + /* hash function for encrypted binary */ + CREATE OR REPLACE FUNCTION + enc_hash_encbytea(encrypt_bytea) + RETURNS + integer + AS + '$libdir/data_encryption.so','enc_hash_encdata' + LANGUAGE C STRICT IMMUTABLE; + + /* load current encryption key */ + CREATE OR REPLACE FUNCTION + enc_store_key_info(text, text) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_store_key_info' + LANGUAGE C STRICT; + + /* load old key to memory for re-encryption */ + CREATE OR REPLACE FUNCTION + enc_store_old_key_info(text, text) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_store_old_key_info' + LANGUAGE C STRICT; + + /* drops key informaiton from memory */ + CREATE OR REPLACE FUNCTION + enc_drop_key_info() + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_drop_key_info' + LANGUAGE C STRICT; + + /* drops old key information from memory */ + CREATE OR REPLACE FUNCTION + enc_drop_old_key_info() + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_drop_old_key_info' + LANGUAGE C STRICT; + + /* rename bakcup file, if it is exists */ + CREATE OR REPLACE FUNCTION + enc_rename_backupfile(text,text) + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_rename_backupfile' + LANGUAGE C STRICT; + + /* backup current parameters of loglevel */ + CREATE OR REPLACE FUNCTION + enc_save_logsetting() + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_save_logsetting' + LANGUAGE C STRICT; + + /* restore log parameters from backup */ + CREATE OR REPLACE FUNCTION + enc_restore_logsetting() + RETURNS + bool + AS + '$libdir/data_encryption.so','enc_restore_logsetting' + LANGUAGE C STRICT; + +/* define index operator */ + /* for encrypted text */ + CREATE OPERATOR = ( + leftarg = encrypt_text, rightarg = encrypt_text, procedure = enc_compeq_enctext, restrict = eqsel, join = eqjoinsel ); + /* for encrypted binary */ + CREATE OPERATOR = ( + leftarg = encrypt_bytea, rightarg = encrypt_bytea, procedure = enc_compeq_encbytea, restrict = eqsel, join = eqjoinsel ); + +/* define index operator for encrypted type and plain type */ + /* text → encrypted text */ + CREATE OPERATOR = ( + leftarg = text, rightarg = encrypt_text, procedure = enc_compeq_text_enctext, commutator = =, restrict = eqsel, join = eqjoinsel ); + /* encrypted text → text */ + CREATE OPERATOR = ( + leftarg = encrypt_text, rightarg = text, procedure = enc_compeq_enctext_text, commutator = =, restrict = eqsel, join = eqjoinsel ); + /* binary → encrypted binary */ + CREATE OPERATOR = ( + leftarg = bytea, rightarg = encrypt_bytea, procedure = enc_compeq_bytea_encbytea, commutator = =, restrict = eqsel, join = eqjoinsel ); + /* encrypted binary → binary */ + CREATE OPERATOR = ( + leftarg = encrypt_bytea, rightarg = bytea, procedure = enc_compeq_encbytea_bytea, commutator = =, restrict = eqsel, join = eqjoinsel ); + +/* define index for encrypted type column */ + /* define hash index for encrypted text */ + CREATE OPERATOR CLASS + hashtext_enc_ops + DEFAULT FOR TYPE + encrypt_text + USING + hash + AS + OPERATOR 1 = (encrypt_text,encrypt_text), + FUNCTION 1 enc_hash_enctext(encrypt_text); + + /* define hash index for encrypted binary */ + CREATE OPERATOR CLASS + hashbytea_enc_ops + DEFAULT FOR TYPE + encrypt_bytea + USING + hash + AS + OPERATOR 1 = (encrypt_bytea,encrypt_bytea), + FUNCTION 1 enc_hash_encbytea(encrypt_bytea); + +/* define cast function for encrypted type column */ + /* encrypted test → text */ + CREATE CAST + (encrypt_text AS text) + WITH INOUT + AS IMPLICIT; + /* text → encrypted text */ + CREATE CAST + (text AS encrypt_text) + WITH INOUT + AS IMPLICIT; + + /* binary → encrypted binary */ + CREATE CAST + (encrypt_bytea AS bytea) + WITH INOUT + AS IMPLICIT; + /* encrypted binary → binary */ + CREATE CAST + (bytea AS encrypt_bytea) + WITH INOUT + AS IMPLICIT; + +/* define table for managing encryption key */ + DROP TABLE IF EXISTS cipher_key_table; + CREATE TABLE cipher_key_table (key BYTEA + , algorithm TEXT); + +-- +-- FILE: cipher_key_function.sql +-- + +/*------------------------------------------------------------* + * Function : cipher_key_regist + * + * add new key to the encryption key table + * + * @param TEXT $1 current encryption key + * @param TEXT $2 new encryption key + * @param TEXT $3 encryption algorithm + *------------------------------------------------------------*/ +CREATE OR REPLACE FUNCTION cipher_key_regist (TEXT, TEXT, TEXT) RETURNS INTEGER AS $$ + +DECLARE + current_cipher_key ALIAS FOR $1; + cipher_key ALIAS FOR $2; + cipher_algorithm ALIAS FOR $3; + + current_cipher_algorithm TEXT; + + f_key_num SMALLINT; /* number of encryption key*/ + +BEGIN + /* if flag of checking log_statement is 'on', checking parameters */ + IF (SELECT setting FROM pg_settings WHERE name = 'encrypt.checklogparam') = 'on' THEN + /* of log_statement is 'all' stop process and loggin error */ + IF (SELECT setting FROM pg_settings WHERE name = 'log_statement') = 'all' THEN + RAISE EXCEPTION 'TDE-E0001 log_statement must not be ''all''(02)'; + END IF; + END IF; + + IF cipher_key IS NULL OR cipher_key = '' THEN + RAISE EXCEPTION 'TDE-E0002 new cipher key is invalid(01)'; + END IF; + + /* validate encryption algorithm */ + IF cipher_algorithm != 'aes' AND cipher_algorithm != 'bf' THEN + RAISE EXCEPTION 'TDE-E0003 invalid cipher algorithm "%"(01)', cipher_algorithm; + END IF; + + SET LOCAL search_path TO public; + SET LOCAL enable_seqscan TO off; + + /* obtain lock of enryption key table */ + LOCK TABLE cipher_key_table IN EXCLUSIVE MODE; + + /* getting the number of encryption key */ + SELECT count(*) INTO f_key_num FROM cipher_key_table; + /* if encryption key is already exist */ + IF f_key_num = 1 THEN + IF current_cipher_key IS NULL THEN + RAISE EXCEPTION 'TDE-E0008 current cipher key is not correct(01)'; + END IF; + /* if current key is valid and save current encryption algorithm*/ + BEGIN + SELECT algorithm INTO current_cipher_algorithm FROM cipher_key_table WHERE pgp_sym_decrypt(key, current_cipher_key)=current_cipher_key; + EXCEPTION + WHEN SQLSTATE '39000' THEN + RAISE EXCEPTION 'TDE-E0008 current cipher key is not correct(01)'; + END; + /* delete current key */ + DELETE FROM cipher_key_table; + + /* too many key is exists */ + ELSEIF f_key_num > 1 THEN + RAISE EXCEPTION 'TDE-E0009 too many encryption keys are exists in cipher_key_table(01)'; + END IF; + + /* encrypt and register new key */ + INSERT INTO cipher_key_table VALUES(pgp_sym_encrypt(cipher_key, cipher_key, 'cipher-algo=aes256, s2k-mode=1'), cipher_algorithm); + + /* backup encryption key table */ + PERFORM cipher_key_backup(); + /* reencrypt all data */ + IF f_key_num = 1 THEN + PERFORM cipher_key_reencrypt_data(current_cipher_key, current_cipher_algorithm, cipher_key); + END IF; + + /* return 1 */ + RETURN 1; +END; +$$ LANGUAGE plpgsql; + + +/*------------------------------------------------------------* + * Function : cipher_key_reencrypt_data + * + * re-encrypt specified data periodically using encryption key + * which is specified custom parameter + * + * @return true if re-encryption is successfully done + *------------------------------------------------------------*/ +CREATE OR REPLACE FUNCTION cipher_key_reencrypt_data (TEXT, TEXT, TEXT) RETURNS BOOLEAN AS $$ + +DECLARE + + old_cipher_key ALIAS FOR $1; + old_cipher_algorithm ALIAS FOR $2; + new_cipher_key ALIAS FOR $3; + + f_rec RECORD; /* store target update column */ + f_rec2 RECORD; /* store target update row */ + f_cu REFCURSOR; /* fetch target update column */ + f_cu2 REFCURSOR; /* fetch target update row */ + + f_counter BIGINT; /* number of processed target record*/ + f_result BIGINT; + + f_query TEXT; /* store dynamic SQL string */ + + f_relid BIGINT; + f_nspname TEXT; + f_relname TEXT; + f_islast BOOLEAN; + +BEGIN + /* init */ + f_counter := 0; + f_relid := 0; + f_nspname = ''; + f_relname = ''; + f_islast = FALSE; + + SET LOCAL search_path TO public; + SET LOCAL encrypt.enable TO on; + SET LOCAL encrypt.noversionerror TO on; + + /* set new key to memory */ + PERFORM pgtde_begin_session(new_cipher_key); + /* set old key to memory */ + PERFORM enc_store_old_key_info(old_cipher_key, old_cipher_algorithm); + + /* store column of user defined table */ + OPEN + f_cu + FOR + SELECT a.attrelid, n.nspname, c.relname, a.attname, t.typname + FROM pg_attribute a, pg_class c, pg_type t, pg_namespace n + WHERE a.attrelid = c.oid + AND t.oid = a.atttypid + AND c.relnamespace = n.oid + AND c.relkind = 'r' + AND t.typname IN ('encrypt_text', 'encrypt_bytea') + AND n.nspname != 'information_schema' + AND n.nspname NOT LIKE E'pg\\_%' + ORDER BY nspname, relname, attname; + + + /* re-encryption */ + FETCH f_cu INTO f_rec; + IF NOT FOUND THEN + f_islast := TRUE; + END IF; + + /* update each encrypted column */ + LOOP + IF f_islast THEN + EXIT; + END IF; + + f_relid := f_rec.attrelid; + f_nspname := f_rec.nspname; + f_relname := f_rec.relname; + + f_query := 'UPDATE ONLY ' || quote_ident(f_rec.nspname) || '.' || quote_ident(f_rec.relname) || ' SET '; + + LOOP + IF f_rec.typname = 'encrypt_text' THEN + f_query := f_query || quote_ident(f_rec.attname) || ' = ' || quote_ident(f_rec.attname) || '::text::encrypt_text '; + ELSE + f_query := f_query || quote_ident(f_rec.attname) || ' = ' || quote_ident(f_rec.attname) || '::bytea::encrypt_bytea '; + END IF; + + FETCH f_cu INTO f_rec; + IF NOT FOUND THEN + f_islast := TRUE; + END IF; + + IF f_islast OR f_relid != f_rec.attrelid THEN + f_query := f_query || ';'; + EXIT; + ELSE + f_query := f_query || ', '; + END IF; + END LOOP; + + RAISE INFO 'TDE-I0001 re-encryption of table "%"."%" was started(01)', f_nspname, f_relname; + + EXECUTE f_query; + + RAISE INFO 'TDE-I0002 re-encryption of table "%"."%" was completed(01)', f_nspname, f_relname; + END LOOP; + + CLOSE f_cu; + + /* delete old key from memory */ + PERFORM enc_drop_old_key_info(); + /* drop key from memory */ + PERFORM pgtde_end_session(); + + RETURN TRUE; +END; +$$ LANGUAGE plpgsql; + + +/*------------------------------------------------------------* + * Function : cipher_key_backup + * + * backup encryption key table + * if backup already exists, rename backup to .sv + * and backup current key table + * + * @return true, if + *------------------------------------------------------------*/ +CREATE OR REPLACE FUNCTION cipher_key_backup () RETURNS BOOLEAN AS $$ + +DECLARE + f_filepath TEXT; /* path of backupfile */ + f_old_filepath TEXT; /* old backupfile */ + f_query TEXT; /* dynamic SQL */ + f_dbname TEXT; /* current dbname */ + result BOOLEAN; + +BEGIN + /* get path of backup file from encrypt.backup */ + SELECT setting INTO f_filepath FROM pg_settings WHERE name = 'encrypt.backup'; + + /* if encrypt.backup is not set, get value of data_directory */ + IF(f_filepath = '')THEN + SELECT setting INTO f_filepath FROM pg_settings WHERE name = 'data_directory'; + + IF f_filepath IS NULL THEN + RAISE EXCEPTION 'TDE-E0014 could not get data directory path(01)'; + END IF; + END IF; + + /* get name of current db */ + SELECT current_database() INTO f_dbname; + + /* set filename of backup */ + f_filepath := f_filepath || E'/ck_backup_' || f_dbname; + f_old_filepath := f_filepath || E'.sv'; + + /* rename if "ck_backup" is already exists */ + SELECT enc_rename_backupfile(f_filepath, f_old_filepath) INTO result; + + IF result = FALSE THEN + RAISE EXCEPTION 'TDE-E0015 could not rename old backup file of cipher key(01)'; + END IF; + + /* backup current encryption key table */ + f_query := 'COPY cipher_key_table TO ''' || f_filepath || ''''; + EXECUTE f_query; + + RETURN result; +END; +$$ LANGUAGE plpgsql +SET search_path TO public; + + +/*------------------------------------------------------------* + * Function : cipher_key_disable_log + * + * backup current log parameters and set log parameter + * to lower level + * related parameter is log_statement, log_min_error_statement + * and log_min_duration_statement + * + * @return false if backup of log parameter is already exists + *------------------------------------------------------------*/ +CREATE OR REPLACE FUNCTION cipher_key_disable_log () RETURNS BOOLEAN AS $$ + +DECLARE + save_result BOOLEAN; /* result of backup current parameter */ + +BEGIN + /* backup current parameters */ + SELECT enc_save_logsetting() INTO save_result; + + RETURN save_result; + +END; +$$ LANGUAGE plpgsql +SET search_path TO public; + + +/*------------------------------------------------------------* + * Function : cipher_key_enable_log + * + * restore log parameter from backup + * related parameter is log_statement, log_min_error_statement + * and log_min_duration_statement + * + * @return false if backup is not exists + *------------------------------------------------------------*/ +CREATE OR REPLACE FUNCTION cipher_key_enable_log () RETURNS BOOLEAN AS $$ + +DECLARE + save_result BOOLEAN; + +BEGIN + /* restore log parameter from backup */ + SELECT enc_restore_logsetting() INTO save_result; + + RETURN save_result; + +END; +$$ LANGUAGE plpgsql +SET search_path TO public; + +-- +-- FILE: common_session_create.sql +-- + +/*------------------------------------------------------------* + * Function : pgtde_begin_session + * + * load encryption key table to memory + * exception will be raised in below cases + * 1. value of log_statement is 'all' + * 2. encryption key is invalid + * + * @param TEXT $1 lastest encryption key + * @return result of load encryption key table to memory + *------------------------------------------------------------*/ +CREATE OR REPLACE FUNCTION pgtde_begin_session (TEXT) RETURNS BOOLEAN AS $$ + +DECLARE + cipher_key ALIAS FOR $1; + + f_algorithm TEXT; /* encryption algorithm of lastest key */ + f_key_num INTEGER; /* number of encryption key */ + f_result BOOLEAN; + +BEGIN + + /* checking log_statement parameter if log encrypt.checklogparam is on */ + IF cipher_key IS NOT NULL AND (SELECT setting FROM pg_settings WHERE name = 'encrypt.checklogparam') = 'on' THEN + /* function failed if log_statement is 'all' */ + IF (SELECT setting FROM pg_settings WHERE name = 'log_statement') = 'all' THEN + RAISE EXCEPTION 'TDE-E0001 log_statement must not be ''all''(01)'; + END IF; + END IF; + + /* drop encryption key information in memory */ + PERFORM enc_drop_key_info(); + /* drop old-encryption key information in memory */ + PERFORM enc_drop_old_key_info(); + + IF cipher_key IS NOT NULL THEN + /* get number of registered encryption key */ + SELECT count(*) INTO f_key_num FROM cipher_key_table; + + /* return false, if there is no or too many encryption key */ + IF f_key_num = 0 THEN + RETURN FALSE; + ELSIF f_key_num>1 THEN + RAISE EXCEPTION 'TDE-E0009 too many encryption keys are exists in cipher_key_table(02)'; + END IF; + + BEGIN + /* load encrption key table to memory */ + PERFORM enc_store_key_info(pgp_sym_decrypt(key, cipher_key), algorithm) + FROM (SELECT key, algorithm FROM cipher_key_table) AS ckt; + EXCEPTION + WHEN SQLSTATE '39000' THEN + PERFORM enc_drop_key_info(); + RAISE EXCEPTION 'TDE-E0012 cipher key is not correct(01)'; + END; + END IF; + RETURN TRUE; +END; +$$ LANGUAGE plpgsql; + + +/*------------------------------------------------------------* + * Function : pgtde_end_session + * + * drop encryption key table from memory + * return false, if there is no encryption key table in memory + * + * @return result of drop encryption key table in memory + *------------------------------------------------------------*/ +CREATE OR REPLACE FUNCTION pgtde_end_session () RETURNS BOOLEAN AS $$ + +BEGIN + /* drop encryption key table in memory */ + IF (SELECT enc_drop_key_info()) THEN + RETURN TRUE; + ELSE + RETURN FALSE; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT SELECT ON cipher_key_table TO PUBLIC; diff --git a/SOURCES/data_encryption/93/data_encryption.c b/SOURCES/data_encryption/data_encryption.c similarity index 98% rename from SOURCES/data_encryption/93/data_encryption.c rename to SOURCES/data_encryption/data_encryption.c index dd79996..079a372 100644 --- a/SOURCES/data_encryption/93/data_encryption.c +++ b/SOURCES/data_encryption/data_encryption.c @@ -31,7 +31,9 @@ #include "access/hash.h" #include "libpq/pqformat.h" -#include "pgcrypto.h" +//#include "pgcrypto.h" +Datum pg_encrypt(PG_FUNCTION_ARGS); +Datum pg_decrypt(PG_FUNCTION_ARGS); #include "data_encryption.h" @@ -39,6 +41,9 @@ PG_MODULE_MAGIC; #endif /* END PG_MODULE_MAGIC */ +void _PG_init(void); +void _PG_fini(void); + /* enable encryption/decryption function */ static bool encrypt_enable = true; @@ -700,16 +705,12 @@ enc_store_old_key_info(PG_FUNCTION_ARGS) * drop cipher key information from memory */ PG_FUNCTION_INFO_V1(enc_drop_key_info); -bool -enc_drop_key_info(void) +Datum +enc_drop_key_info(PG_FUNCTION_ARGS) { if (newest_key_info != NULL) { - if (newest_key_info->key != NULL) { - free(newest_key_info->key); - } - if (newest_key_info->algorithm != NULL) { - free(newest_key_info->algorithm); - } + free(newest_key_info->key); + free(newest_key_info->algorithm); free(newest_key_info); newest_key_info = NULL; @@ -730,15 +731,11 @@ enc_drop_key_info(void) PG_FUNCTION_INFO_V1(enc_drop_old_key_info); Datum -enc_drop_old_key_info(void) +enc_drop_old_key_info(PG_FUNCTION_ARGS) { if (old_key_info != NULL) { - if (old_key_info->key != NULL) { - free(old_key_info->key); - } - if (old_key_info->algorithm != NULL) { - free(old_key_info->algorithm); - } + free(old_key_info->key); + free(old_key_info->algorithm); free(old_key_info); old_key_info = NULL; @@ -803,7 +800,7 @@ enc_rename_backupfile(PG_FUNCTION_ARGS) PG_FUNCTION_INFO_V1(enc_save_logsetting); Datum -enc_save_logsetting(void) +enc_save_logsetting(PG_FUNCTION_ARGS) { /* if backup of current parameters are not exist */ if(save_log_statement == -1 && save_log_min_error_statement == -1 && diff --git a/SOURCES/data_encryption/data_encryption.control b/SOURCES/data_encryption/data_encryption.control new file mode 100644 index 0000000..b7437bc --- /dev/null +++ b/SOURCES/data_encryption/data_encryption.control @@ -0,0 +1,5 @@ +# data_encryption extension +comment = 'Transparent Data Encryption for PostgreSQL Free Edition' +default_version = '0.1' +module_pathname = '$libdir/data_encryption' +relocatable = true diff --git a/SOURCES/data_encryption/93/data_encryption.h b/SOURCES/data_encryption/data_encryption.h similarity index 100% rename from SOURCES/data_encryption/93/data_encryption.h rename to SOURCES/data_encryption/data_encryption.h diff --git a/SOURCES/data_encryption/makedencryption.sh b/SOURCES/data_encryption/makedencryption.sh deleted file mode 100644 index e6ea0ab..0000000 --- a/SOURCES/data_encryption/makedencryption.sh +++ /dev/null @@ -1,37 +0,0 @@ -#! /bin/bash - - -################################################################### -# data_encryption module build script # -################################################################### -# Version-1.0 # -# 1.0(20110921) # -################################################################### - -PGVERSION=$1 -SPATH=$2 - -cd $PGVERSION -CDIR=`pwd` - -#set path from Makefile if SPATH is not set -if [ -z $SPATH ]; -then - SPATH=`cat Makefile |grep ^PGSQL_SRC_PATH|cut -f3 -d" "` -fi - -#build data_encryption -make clean -make PGSQL_SRC_PATH=${SPATH} -mv data_encryption.so data_encryption${PGVERSION}.so -ldd data_encryption${PGVERSION}.so - -echo -if [ ! -f data_encryption${PGVERSION}.so ]; -then - echo "ERROR: cannot make data_encryption.so" - exit 1; -fi - -echo "INFO: data_encryption.so was made." -echo diff --git a/SOURCES/lib/init/cipher_definition.sql b/SOURCES/lib/init/cipher_definition.sql deleted file mode 100644 index 74a3849..0000000 --- a/SOURCES/lib/init/cipher_definition.sql +++ /dev/null @@ -1,316 +0,0 @@ -/*------------------------------------------------------------* - * cipher_key_definition - * - * define type, function, index end etc for TDE. - *------------------------------------------------------------*/ - -SET search_path TO public; -SET check_function_bodies TO off; - - -/* define a new procedural language */ -/* CREATE TRUSTED LANGUAGE 'plpgsql' HANDLER language_handler_in;*/ - - /* drop if encrypted data types are already exist */ - DROP TYPE IF EXISTS encrypt_text CASCADE; - DROP TYPE IF EXISTS encrypt_bytea CASCADE; - - /* create encrypted data types */ - CREATE TYPE encrypt_text; - CREATE TYPE encrypt_bytea; - - /* define input function of encrypted text type */ - CREATE FUNCTION - enctext_in(cstring) - RETURNS - encrypt_text - AS - '/usr/lib64/data_encryption.so','enctext_in' - LANGUAGE C STRICT; - - /* define output function of encrypted text type */ - CREATE FUNCTION - enctext_out(encrypt_text) - RETURNS - cstring - AS - '/usr/lib64/data_encryption.so','enctext_out' - LANGUAGE C IMMUTABLE STRICT; - - /* define recv function of encrypted text type */ - CREATE FUNCTION - enctext_recv(internal) - RETURNS - encrypt_text - AS - '/usr/lib64/data_encryption.so','encrecv' - LANGUAGE C STRICT; - - /* define send function of encrypted text type */ - CREATE FUNCTION - enctext_send(encrypt_text) - RETURNS - bytea - AS - '/usr/lib64/data_encryption.so','encsend' - LANGUAGE C STRICT; - - /* define input function of encrypted binary type */ - CREATE FUNCTION - encbytea_in(cstring) - RETURNS - encrypt_bytea - AS - '/usr/lib64/data_encryption.so','encbytea_in' - LANGUAGE C STRICT; - - /* define output function of encrypted binary type */ - CREATE FUNCTION - encbytea_out(encrypt_bytea) - RETURNS - cstring - AS - '/usr/lib64/data_encryption.so','encbytea_out' - LANGUAGE C IMMUTABLE STRICT; - - /* define recv function of encrypted binary type */ - CREATE FUNCTION - encbytea_recv(internal) - RETURNS - encrypt_bytea - AS - '/usr/lib64/data_encryption.so','encrecv' - LANGUAGE C STRICT; - - /* define send function of encrypted binary type */ - CREATE FUNCTION - encbytea_send(encrypt_bytea) - RETURNS - bytea - AS - '/usr/lib64/data_encryption.so','encsend' - LANGUAGE C STRICT; - - /* define encrypted text types */ - CREATE TYPE ENCRYPT_TEXT ( - INPUT = enctext_in - , OUTPUT = enctext_out - , RECEIVE = enctext_recv - , SEND = enctext_send - , INTERNALLENGTH = VARIABLE - , ALIGNMENT = int4 - , STORAGE = extended); - - /* define encrypted binary types */ - CREATE TYPE ENCRYPT_BYTEA ( - INPUT = encbytea_in - , OUTPUT = encbytea_out - , RECEIVE = encbytea_recv - , SEND = encbytea_send - , INTERNALLENGTH = VARIABLE - , ALIGNMENT = int4 - , STORAGE = extended); - - /* index operator of encrypted text types */ - CREATE OR REPLACE FUNCTION - enc_compeq_enctext(encrypt_text,encrypt_text) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_compeq_enctext' - LANGUAGE C STRICT; - - /* compare function of encrypted text type and text */ - CREATE OR REPLACE FUNCTION - enc_compeq_text_enctext(text,encrypt_text) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_compeq_text_enctext' - LANGUAGE C STRICT; - CREATE OR REPLACE FUNCTION - enc_compeq_enctext_text(encrypt_text,text) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_compeq_enctext_text' - LANGUAGE C STRICT; - - /* index operator of encrypted binary types */ - CREATE OR REPLACE FUNCTION - enc_compeq_encbytea(encrypt_bytea,encrypt_bytea) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_compeq_encbytea' - LANGUAGE C STRICT; - - /* compare encrypted binary type and binary */ - CREATE OR REPLACE FUNCTION - enc_compeq_bytea_encbytea(bytea,encrypt_bytea) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_compeq_bytea_encbytea' - LANGUAGE C STRICT; - CREATE OR REPLACE FUNCTION - enc_compeq_encbytea_bytea(encrypt_bytea,bytea) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_compeq_encbytea_bytea' - LANGUAGE C STRICT; - - /* hash function for encrypted text */ - CREATE OR REPLACE FUNCTION - enc_hash_enctext(encrypt_text) - RETURNS - integer - AS - '/usr/lib64/data_encryption.so','enc_hash_encdata' - LANGUAGE C STRICT IMMUTABLE; - - /* hash function for encrypted binary */ - CREATE OR REPLACE FUNCTION - enc_hash_encbytea(encrypt_bytea) - RETURNS - integer - AS - '/usr/lib64/data_encryption.so','enc_hash_encdata' - LANGUAGE C STRICT IMMUTABLE; - - /* load current encryption key */ - CREATE OR REPLACE FUNCTION - enc_store_key_info(text, text) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_store_key_info' - LANGUAGE C STRICT; - - /* load old key to memory for re-encryption */ - CREATE OR REPLACE FUNCTION - enc_store_old_key_info(text, text) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_store_old_key_info' - LANGUAGE C STRICT; - - /* drops key informaiton from memory */ - CREATE OR REPLACE FUNCTION - enc_drop_key_info() - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_drop_key_info' - LANGUAGE C STRICT; - - /* drops old key information from memory */ - CREATE OR REPLACE FUNCTION - enc_drop_old_key_info() - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_drop_old_key_info' - LANGUAGE C STRICT; - - /* rename bakcup file, if it is exists */ - CREATE OR REPLACE FUNCTION - enc_rename_backupfile(text,text) - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_rename_backupfile' - LANGUAGE C STRICT; - - /* backup current parameters of loglevel */ - CREATE OR REPLACE FUNCTION - enc_save_logsetting() - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_save_logsetting' - LANGUAGE C STRICT; - - /* restore log parameters from backup */ - CREATE OR REPLACE FUNCTION - enc_restore_logsetting() - RETURNS - bool - AS - '/usr/lib64/data_encryption.so','enc_restore_logsetting' - LANGUAGE C STRICT; - -/* define index operator */ - /* for encrypted text */ - CREATE OPERATOR = ( - leftarg = encrypt_text, rightarg = encrypt_text, procedure = enc_compeq_enctext, restrict = eqsel, join = eqjoinsel ); - /* for encrypted binary */ - CREATE OPERATOR = ( - leftarg = encrypt_bytea, rightarg = encrypt_bytea, procedure = enc_compeq_encbytea, restrict = eqsel, join = eqjoinsel ); - -/* define index operator for encrypted type and plain type */ - /* text → encrypted text */ - CREATE OPERATOR = ( - leftarg = text, rightarg = encrypt_text, procedure = enc_compeq_text_enctext, commutator = =, restrict = eqsel, join = eqjoinsel ); - /* encrypted text → text */ - CREATE OPERATOR = ( - leftarg = encrypt_text, rightarg = text, procedure = enc_compeq_enctext_text, commutator = =, restrict = eqsel, join = eqjoinsel ); - /* binary → encrypted binary */ - CREATE OPERATOR = ( - leftarg = bytea, rightarg = encrypt_bytea, procedure = enc_compeq_bytea_encbytea, commutator = =, restrict = eqsel, join = eqjoinsel ); - /* encrypted binary → binary */ - CREATE OPERATOR = ( - leftarg = encrypt_bytea, rightarg = bytea, procedure = enc_compeq_encbytea_bytea, commutator = =, restrict = eqsel, join = eqjoinsel ); - -/* define index for encrypted type column */ - /* define hash index for encrypted text */ - CREATE OPERATOR CLASS - hashtext_enc_ops - DEFAULT FOR TYPE - encrypt_text - USING - hash - AS - OPERATOR 1 = (encrypt_text,encrypt_text), - FUNCTION 1 enc_hash_enctext(encrypt_text); - - /* define hash index for encrypted binary */ - CREATE OPERATOR CLASS - hashbytea_enc_ops - DEFAULT FOR TYPE - encrypt_bytea - USING - hash - AS - OPERATOR 1 = (encrypt_bytea,encrypt_bytea), - FUNCTION 1 enc_hash_encbytea(encrypt_bytea); - -/* define cast function for encrypted type column */ - /* encrypted test → text */ - CREATE CAST - (encrypt_text AS text) - WITH INOUT - AS IMPLICIT; - /* text → encrypted text */ - CREATE CAST - (text AS encrypt_text) - WITH INOUT - AS IMPLICIT; - - /* binary → encrypted binary */ - CREATE CAST - (encrypt_bytea AS bytea) - WITH INOUT - AS IMPLICIT; - /* encrypted binary → binary */ - CREATE CAST - (bytea AS encrypt_bytea) - WITH INOUT - AS IMPLICIT; - -/* define table for managing encryption key */ - DROP TABLE IF EXISTS cipher_key_table; - CREATE TABLE cipher_key_table (key BYTEA - , algorithm TEXT); diff --git a/SOURCES/lib/init/cipher_key_function.sql b/SOURCES/lib/init/cipher_key_function.sql deleted file mode 100644 index 85245e3..0000000 --- a/SOURCES/lib/init/cipher_key_function.sql +++ /dev/null @@ -1,310 +0,0 @@ -SET search_path TO public; -SET check_function_bodies TO off; - -/*------------------------------------------------------------* - * Function : cipher_key_regist - * - * add new key to the encryption key table - * - * @param TEXT $1 current encryption key - * @param TEXT $2 new encryption key - * @param TEXT $3 encryption algorithm - *------------------------------------------------------------*/ -CREATE OR REPLACE FUNCTION cipher_key_regist (TEXT, TEXT, TEXT) RETURNS INTEGER AS $$ - -DECLARE - current_cipher_key ALIAS FOR $1; - cipher_key ALIAS FOR $2; - cipher_algorithm ALIAS FOR $3; - - current_cipher_algorithm TEXT; - - f_key_num SMALLINT; /* number of encryption key*/ - -BEGIN - /* if flag of checking log_statement is 'on', checking parameters */ - IF (SELECT setting FROM pg_settings WHERE name = 'encrypt.checklogparam') = 'on' THEN - /* of log_statement is 'all' stop process and loggin error */ - IF (SELECT setting FROM pg_settings WHERE name = 'log_statement') = 'all' THEN - RAISE EXCEPTION 'TDE-E0001 log_statement must not be ''all''(02)'; - END IF; - END IF; - - IF cipher_key IS NULL OR cipher_key = '' THEN - RAISE EXCEPTION 'TDE-E0002 new cipher key is invalid(01)'; - END IF; - - /* validate encryption algorithm */ - IF cipher_algorithm != 'aes' AND cipher_algorithm != 'bf' THEN - RAISE EXCEPTION 'TDE-E0003 invalid cipher algorithm "%"(01)', cipher_algorithm; - END IF; - - SET LOCAL search_path TO public; - SET LOCAL enable_seqscan TO off; - - /* obtain lock of enryption key table */ - LOCK TABLE cipher_key_table IN EXCLUSIVE MODE; - - /* getting the number of encryption key */ - SELECT count(*) INTO f_key_num FROM cipher_key_table; - /* if encryption key is already exist */ - IF f_key_num = 1 THEN - IF current_cipher_key IS NULL THEN - RAISE EXCEPTION 'TDE-E0008 current cipher key is not correct(01)'; - END IF; - /* if current key is valid and save current encryption algorithm*/ - BEGIN - SELECT algorithm INTO current_cipher_algorithm FROM cipher_key_table WHERE pgp_sym_decrypt(key, current_cipher_key)=current_cipher_key; - EXCEPTION - WHEN SQLSTATE '39000' THEN - RAISE EXCEPTION 'TDE-E0008 current cipher key is not correct(01)'; - END; - /* delete current key */ - DELETE FROM cipher_key_table; - - /* too many key is exists */ - ELSEIF f_key_num > 1 THEN - RAISE EXCEPTION 'TDE-E0009 too many encryption keys are exists in cipher_key_table(01)'; - END IF; - - /* encrypt and register new key */ - INSERT INTO cipher_key_table VALUES(pgp_sym_encrypt(cipher_key, cipher_key, 'cipher-algo=aes256, s2k-mode=1'), cipher_algorithm); - - /* backup encryption key table */ - PERFORM cipher_key_backup(); - /* reencrypt all data */ - IF f_key_num = 1 THEN - PERFORM cipher_key_reencrypt_data(current_cipher_key, current_cipher_algorithm, cipher_key); - END IF; - - /* return 1 */ - RETURN 1; -END; -$$ LANGUAGE plpgsql; - - -/*------------------------------------------------------------* - * Function : cipher_key_reencrypt_data - * - * re-encrypt specified data periodically using encryption key - * which is specified custom parameter - * - * @return true if re-encryption is successfully done - *------------------------------------------------------------*/ -CREATE OR REPLACE FUNCTION cipher_key_reencrypt_data (TEXT, TEXT, TEXT) RETURNS BOOLEAN AS $$ - -DECLARE - - old_cipher_key ALIAS FOR $1; - old_cipher_algorithm ALIAS FOR $2; - new_cipher_key ALIAS FOR $3; - - f_rec RECORD; /* store target update column */ - f_rec2 RECORD; /* store target update row */ - f_cu REFCURSOR; /* fetch target update column */ - f_cu2 REFCURSOR; /* fetch target update row */ - - f_counter BIGINT; /* number of processed target record*/ - f_result BIGINT; - - f_query TEXT; /* store dynamic SQL string */ - - f_relid BIGINT; - f_nspname TEXT; - f_relname TEXT; - f_islast BOOLEAN; - -BEGIN - /* init */ - f_counter := 0; - f_relid := 0; - f_nspname = ''; - f_relname = ''; - f_islast = FALSE; - - SET LOCAL search_path TO public; - SET LOCAL encrypt.enable TO on; - SET LOCAL encrypt.noversionerror TO on; - - /* set new key to memory */ - PERFORM pgtde_begin_session(new_cipher_key); - /* set old key to memory */ - PERFORM enc_store_old_key_info(old_cipher_key, old_cipher_algorithm); - - /* store column of user defined table */ - OPEN - f_cu - FOR - SELECT a.attrelid, n.nspname, c.relname, a.attname, t.typname - FROM pg_attribute a, pg_class c, pg_type t, pg_namespace n - WHERE a.attrelid = c.oid - AND t.oid = a.atttypid - AND c.relnamespace = n.oid - AND c.relkind = 'r' - AND t.typname IN ('encrypt_text', 'encrypt_bytea') - AND n.nspname != 'information_schema' - AND n.nspname NOT LIKE E'pg\\_%' - ORDER BY nspname, relname, attname; - - - /* re-encryption */ - FETCH f_cu INTO f_rec; - IF NOT FOUND THEN - f_islast := TRUE; - END IF; - - /* update each encrypted column */ - LOOP - IF f_islast THEN - EXIT; - END IF; - - f_relid := f_rec.attrelid; - f_nspname := f_rec.nspname; - f_relname := f_rec.relname; - - f_query := 'UPDATE ONLY ' || quote_ident(f_rec.nspname) || '.' || quote_ident(f_rec.relname) || ' SET '; - - LOOP - IF f_rec.typname = 'encrypt_text' THEN - f_query := f_query || quote_ident(f_rec.attname) || ' = ' || quote_ident(f_rec.attname) || '::text::encrypt_text '; - ELSE - f_query := f_query || quote_ident(f_rec.attname) || ' = ' || quote_ident(f_rec.attname) || '::bytea::encrypt_bytea '; - END IF; - - FETCH f_cu INTO f_rec; - IF NOT FOUND THEN - f_islast := TRUE; - END IF; - - IF f_islast OR f_relid != f_rec.attrelid THEN - f_query := f_query || ';'; - EXIT; - ELSE - f_query := f_query || ', '; - END IF; - END LOOP; - - RAISE INFO 'TDE-I0001 re-encryption of table "%"."%" was started(01)', f_nspname, f_relname; - - EXECUTE f_query; - - RAISE INFO 'TDE-I0002 re-encryption of table "%"."%" was completed(01)', f_nspname, f_relname; - END LOOP; - - CLOSE f_cu; - - /* delete old key from memory */ - PERFORM enc_drop_old_key_info(); - /* drop key from memory */ - PERFORM pgtde_end_session(); - - RETURN TRUE; -END; -$$ LANGUAGE plpgsql; - - -/*------------------------------------------------------------* - * Function : cipher_key_backup - * - * backup encryption key table - * if backup already exists, rename backup to .sv - * and backup current key table - * - * @return true, if - *------------------------------------------------------------*/ -CREATE OR REPLACE FUNCTION cipher_key_backup () RETURNS BOOLEAN AS $$ - -DECLARE - f_filepath TEXT; /* path of backupfile */ - f_old_filepath TEXT; /* old backupfile */ - f_query TEXT; /* dynamic SQL */ - f_dbname TEXT; /* current dbname */ - result BOOLEAN; - -BEGIN - /* get path of backup file from encrypt.backup */ - SELECT setting INTO f_filepath FROM pg_settings WHERE name = 'encrypt.backup'; - - /* if encrypt.backup is not set, get value of data_directory */ - IF(f_filepath = '')THEN - SELECT setting INTO f_filepath FROM pg_settings WHERE name = 'data_directory'; - - IF f_filepath IS NULL THEN - RAISE EXCEPTION 'TDE-E0014 could not get data directory path(01)'; - END IF; - END IF; - - /* get name of current db */ - SELECT current_database() INTO f_dbname; - - /* set filename of backup */ - f_filepath := f_filepath || E'/ck_backup_' || f_dbname; - f_old_filepath := f_filepath || E'.sv'; - - /* rename if "ck_backup" is already exists */ - SELECT enc_rename_backupfile(f_filepath, f_old_filepath) INTO result; - - IF result = FALSE THEN - RAISE EXCEPTION 'TDE-E0015 could not rename old backup file of cipher key(01)'; - END IF; - - /* backup current encryption key table */ - f_query := 'COPY cipher_key_table TO ''' || f_filepath || ''''; - EXECUTE f_query; - - RETURN result; -END; -$$ LANGUAGE plpgsql -SET search_path TO public; - - -/*------------------------------------------------------------* - * Function : cipher_key_disable_log - * - * backup current log parameters and set log parameter - * to lower level - * related parameter is log_statement, log_min_error_statement - * and log_min_duration_statement - * - * @return false if backup of log parameter is already exists - *------------------------------------------------------------*/ -CREATE OR REPLACE FUNCTION cipher_key_disable_log () RETURNS BOOLEAN AS $$ - -DECLARE - save_result BOOLEAN; /* result of backup current parameter */ - -BEGIN - /* backup current parameters */ - SELECT enc_save_logsetting() INTO save_result; - - RETURN save_result; - -END; -$$ LANGUAGE plpgsql -SET search_path TO public; - - -/*------------------------------------------------------------* - * Function : cipher_key_enable_log - * - * restore log parameter from backup - * related parameter is log_statement, log_min_error_statement - * and log_min_duration_statement - * - * @return false if backup is not exists - *------------------------------------------------------------*/ -CREATE OR REPLACE FUNCTION cipher_key_enable_log () RETURNS BOOLEAN AS $$ - -DECLARE - save_result BOOLEAN; - -BEGIN - /* restore log parameter from backup */ - SELECT enc_restore_logsetting() INTO save_result; - - RETURN save_result; - -END; -$$ LANGUAGE plpgsql -SET search_path TO public; diff --git a/SOURCES/lib/init/common_session_create.sql b/SOURCES/lib/init/common_session_create.sql deleted file mode 100644 index 4f2594d..0000000 --- a/SOURCES/lib/init/common_session_create.sql +++ /dev/null @@ -1,83 +0,0 @@ -SET search_path TO public; -SET check_function_bodies TO off; - -/*------------------------------------------------------------* - * Function : pgtde_begin_session - * - * load encryption key table to memory - * exception will be raised in below cases - * 1. value of log_statement is 'all' - * 2. encryption key is invalid - * - * @param TEXT $1 lastest encryption key - * @return result of load encryption key table to memory - *------------------------------------------------------------*/ -CREATE OR REPLACE FUNCTION pgtde_begin_session (TEXT) RETURNS BOOLEAN AS $$ - -DECLARE - cipher_key ALIAS FOR $1; - - f_algorithm TEXT; /* encryption algorithm of lastest key */ - f_key_num INTEGER; /* number of encryption key */ - f_result BOOLEAN; - -BEGIN - - /* checking log_statement parameter if log encrypt.checklogparam is on */ - IF cipher_key IS NOT NULL AND (SELECT setting FROM pg_settings WHERE name = 'encrypt.checklogparam') = 'on' THEN - /* function failed if log_statement is 'all' */ - IF (SELECT setting FROM pg_settings WHERE name = 'log_statement') = 'all' THEN - RAISE EXCEPTION 'TDE-E0001 log_statement must not be ''all''(01)'; - END IF; - END IF; - - /* drop encryption key information in memory */ - PERFORM enc_drop_key_info(); - /* drop old-encryption key information in memory */ - PERFORM enc_drop_old_key_info(); - - IF cipher_key IS NOT NULL THEN - /* get number of registered encryption key */ - SELECT count(*) INTO f_key_num FROM cipher_key_table; - - /* return false, if there is no or too many encryption key */ - IF f_key_num = 0 THEN - RETURN FALSE; - ELSIF f_key_num>1 THEN - RAISE EXCEPTION 'TDE-E0009 too many encryption keys are exists in cipher_key_table(02)'; - END IF; - - BEGIN - /* load encrption key table to memory */ - PERFORM enc_store_key_info(pgp_sym_decrypt(key, cipher_key), algorithm) - FROM (SELECT key, algorithm FROM cipher_key_table) AS ckt; - EXCEPTION - WHEN SQLSTATE '39000' THEN - PERFORM enc_drop_key_info(); - RAISE EXCEPTION 'TDE-E0012 cipher key is not correct(01)'; - END; - END IF; - RETURN TRUE; -END; -$$ LANGUAGE plpgsql; - - -/*------------------------------------------------------------* - * Function : pgtde_end_session - * - * drop encryption key table from memory - * return false, if there is no encryption key table in memory - * - * @return result of drop encryption key table in memory - *------------------------------------------------------------*/ -CREATE OR REPLACE FUNCTION pgtde_end_session () RETURNS BOOLEAN AS $$ - -BEGIN - /* drop encryption key table in memory */ - IF (SELECT enc_drop_key_info()) THEN - RETURN TRUE; - ELSE - RETURN FALSE; - END IF; -END; -$$ LANGUAGE plpgsql; From 55cd52a3b369cf39b73a5707e7fc9f0f2432d7c1 Mon Sep 17 00:00:00 2001 From: Satoshi Nagayasu Date: Sun, 19 Jul 2015 05:14:43 +0000 Subject: [PATCH 2/2] Fix the installation note. Now, tdeforpg can be installed as a PostgreSQL extension. --- SOURCES/INSTALL-NOTE.TXT | 50 +++++++++++----------------------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/SOURCES/INSTALL-NOTE.TXT b/SOURCES/INSTALL-NOTE.TXT index f1546e3..e1d33ec 100644 --- a/SOURCES/INSTALL-NOTE.TXT +++ b/SOURCES/INSTALL-NOTE.TXT @@ -4,48 +4,26 @@ Installation instructions for Transparent Data Encryption for PostgreSQL Free Ed Requirements ============ -1. PostgreSQL 9.3 Source Code -2. PostgreSQL 9.3 with psql installed +1. PostgreSQL 9.3/9.4/9.5 server, client, contrib and libraries. Installation and Configuration ============================== 1. Setting environment variables - $ export PGSRC = #path of PostgreSQL source code - $ export PGHOME = #path of PostgreSQL installed - $ export TDEHOME = #path of pgTDE downloaded + $ export PGHOME=/path/to/pgsql + $ export PATH=$PGHOME/bin:$PATH + $ export PGDATA=/path/to/your/pgdata -2. Install pgcrypto from source code - # If you have already installed pgcrypto, you can skip this section. - $ cd $PGSRC/contrib/pgcrypto - $ gmake - $ gmake install - $ pg_ctl start - $ psql << EOF - > CREATE EXTENSION pgcrypto; - > EOF +2. Install the pgcrypo extension. + $ psql -c 'CREATE EXTENSION pgcrypto' mydb 3. Building pgTDE - $ sudo ln -s $PGHOME/lib/pgcrypto.so /usr/lib64/libpgcrypto.so - $ cd $PGSRC - $ ./configure - $ cd $TDEHOME/SOURCES/data_encryption - $ sh makedencryption.sh 93 $PGSRC + $ cd /path/to/tdeforpg/SOURCES + $ make USE_PGXS=1 all 4. install pgTDE to PostgreSQL - $ sudo ln -s $TDEHOME/SOURCES/data_encryption/93/data_encryption93.so /usr/lib64/data_encryption.so - $ vim $PGDATA/postgresql.conf # add shared_preload_libraries to postgresql.conf - shared_preload_libraries='/usr/lib64/data_encryption.so' - $ pg_ctl restart - $ cd $TDEHOME/SOURCES - $ sh bin/cipher_setup.sh $PGHOME - Transparent data encryption feature setup script - Please select from the setup menu below - Transparent data encryption feature setup menu - 1: activate the transparent data encryption feature - 2: inactivate the transparent data encryption feature - select menu [1 - 2] > 1 - Please enter database server port to connect : - Please enter database user name to connect : - Please enter password for authentication : - Please enter database name to connect : - + $ cd /path/to/tdeforpg/SOURCES + $ sudo make USE_PGXS=1 install + $ vim $PGDATA/postgresql.conf # enable data_encryption.so in shared_preload_libraries. + shared_preload_libraries = 'data_encryption.so' + $ pg_ctl -D $PGDATA restart + $ psql -c 'CREATE EXTENSION data_encryption' mydb