「Transparent Data Encryption for PostgreSQL Free Edition」を試してみた。

<h3>暗号化鍵の登録</h3>

昨日と同様に環境変数を定義します。
面倒なので ~/.bash_profileに追記。
<pre># for TDE
export PGSRC=~/rpmbuild/BUILD/postgresql-9.3.9
export PGHOME=/usr/pgsql-9.3
export TDEHOME=/usr/local/src/tdeforpg
export PATH=/usr/pgsql-9.3/bin/:$PATH</pre><pre>
 # cd ${TDEHOME}/SOURCES/bin/
 # sh cipher_key_regist.sh ${PGHOME}
</pre>
<ul><li>ユーザ名：postgres</li><li>DB名：postgres</li><li>暗号化キー：dummykey</li><li>暗号化アルゴリズム：aes</li>
</ul>
で登録します。
<pre>=== Database connection information ===
Please enter database server port to connect : 5432
Please enter database user name to connect : postgres
Please enter password for authentication :
Please enter database name to connect : postgres
=== Regist new cipher key ===
Please enter the new cipher key :                     ←'dummykey'を入力
Please retype the new cipher key :                    ←'dummykey'を入力
Please enter the algorithm for new cipher key : aes

Are you sure to register new cipher key(y/n) : y
 cipher_key_enable_log
\-----------------------
 t
(1 行)
</pre>
実際の暗号化キーは以下のように格納されています。
<pre>postgres=# select * from cipher_key_table;
                                                                         key                                                                          | algorithm
------------------------------------------------------------------------------------------------------------------------------------------------------+-----------
 \xc30c04090102405a645c9a4ed1d2d23901309e537d956944ef70ec15a77d9cc8a337075ede88c24dae1368996cf6bdfa877fbea6d01753f21d6aae1b5c9434fa79cf83651317167652 | aes
(1 行)
</pre>
<h3>テーブル作成～データ取得</h3>
暗号化に対応しているデータ型はENCRYPT_TEXT/ENCRYPT_BYTEAの２種類。
以下の順で操作します。
<pre>-- テーブル作成
CREATE TABLE Employee(
 id varchar(7) PRIMARY KEY,
 Name TEXT,
 mail ENCRYPT_TEXT,
 remark ENCRYPT_BYTEA
);

-- 暗号化鍵の設定
select pgtde_begin_session('dummykey');

insert into Employee values('1','ryouma','ryouma@dummy.com',E'\\000'::bytea);

-- 正常に検索できる
select * from Employee;

-- Btreeインデックスは作成できない
CREATE INDEX Employee_mail_idx ON Employee(mail);
CREATE INDEX Employee_remark_idx ON Employee(remark);

-- ハッシュインデックスはOK。
CREATE INDEX Employee_mail_idx ON Employee USING hash (mail);

-- 間違った暗号化鍵の設定
select pgtde_begin_session('wrongkey');

-- エラーになる
select * from Employee;
</pre>
結果
<pre>postgres=# -- テーブル作成
postgres=# CREATE TABLE Employee(
postgres(#  id varchar(7) PRIMARY KEY,
postgres(#  Name TEXT,
postgres(#  mail ENCRYPT_TEXT,
postgres(#  remark ENCRYPT_BYTEA
postgres(# );
CREATE TABLE

postgres=# -- 暗号化鍵の設定
postgres=# select pgtde_begin_session('dummykey');
 pgtde_begin_session
\---------------------
 t
(1 行)

postgres=# insert into Employee values('1','ryouma','ryouma@dummy.com',E'\\000'::bytea);
INSERT 0 1
postgres=# -- 正常に検索できる
postgres=# select * from Employee;
 id |  name  |       mail       | remark
----+--------+------------------+--------
 1  | ryouma | ryouma@dummy.com | \x00
(1 行)

postgres=# -- Btreeインデックスは作成できない
postgres=# CREATE INDEX Employee_mail_idx ON Employee(mail);
ERROR:  アクセスメソッド"btree"にはデータ型encrypt_text用のデフォルトの演算子クラスがありません
HINT:  このインデックス用の演算子クラスを指定する、あるいはこのデータ型のデフォルト演算子クラスを定義しなければなりません
postgres=# CREATE INDEX Employee_remark_idx ON Employee(remark);
ERROR:  アクセスメソッド"btree"にはデータ型encrypt_bytea用のデフォルトの演算子クラスがありません
HINT:  このインデックス用の演算子クラスを指定する、あるいはこのデータ型のデフォルト演算子クラスを定義しなければなりません

postgres=# -- ハッシュインデックスはOK。
postgres=# CREATE INDEX Employee_mail_idx ON Employee USING hash (mail);
CREATE INDEX
postgres=# -- 間違った暗号化鍵の設定
postgres=# select pgtde_begin_session('wrongkey');
ERROR:  TDE-E0012 cipher key is not correct(01)
postgres=# -- エラーになる
postgres=# select * from Employee;
ERROR:  TDE-E0017 could not decrypt data, because key was not set(01)
</pre>
期待通りの結果です。
<h3>暗号化キーの変更</h3>
<span style="color: #ff0000;">すべてのセッションを切断</span>後、暗号化キーを変更してみます。
<pre>
 # cd ${TDEHOME}/SOURCES/bin/
 # sh cipher_key_regist.sh ${PGHOME}
</pre>
<ul><li>変更前キー：dummykey</li><li>変更後キー：newkey</li><li>暗号化アルゴリズム：blowfish</li></ul>で登録します。
<pre>=== Database connection information ===
Please enter database server port to connect : 5432
Please enter database user name to connect : postgres
Please enter password for authentication :
Please enter database name to connect : postgres
=== Regist new cipher key ===
Please enter the current cipher key :             ←'dummykey'を入力
Please enter the new cipher key :                 ←'dummykey'を入力
Please retype the new cipher key :                ←'newkey'を入力
Please enter the algorithm for new cipher key : bf

Are you sure to register new cipher key(y/n) : y
INFO:  TDE-I0001 re-encryption of table "public"."employee" was started(01)
CONTEXT:  SQL文 "SELECT cipher_key_reencrypt_data(current_cipher_key, current_cipher_algorithm, cipher_key)"
PL/pgSQL関数cipher_key_regist(text,text,text)の65行目の型PERFORM
INFO:  TDE-I0002 re-encryption of table "public"."employee" was completed(01)
CONTEXT:  SQL文 "SELECT cipher_key_reencrypt_data(current_cipher_key, current_cipher_algorithm, cipher_key)"
PL/pgSQL関数cipher_key_regist(text,text,text)の65行目の型PERFORM
 cipher_key_enable_log
\-----------------------
 t
(1 行)</pre>
再暗号化の状況が表示されています。

再接続してSELECTしてみます。
<pre>-- 暗号化鍵の設定
select pgtde_begin_session('newkey');

-- 正常に検索できる
select * from Employee;</pre>
結果
<pre>postgres=# -- 暗号化鍵の設定
postgres=# select pgtde_begin_session('newkey');
 pgtde_begin_session
\---------------------
 t
(1 行)

postgres=#
postgres=# -- 正常に検索できる
postgres=# select * from Employee;
 id |  name  |       mail       | remark
----+--------+------------------+--------
 1  | ryouma | ryouma@dummy.com | \x00
(1 行)
</pre>
新しい暗号化キーでSELECTできました。

透過暗号化なので、DMLに暗号化関数を書かなくて済むのは非常に楽です。
これからの開発状況をWatchし続けたいと思います。