概要
Oracle Databaseで暗号化を行う場合、様々な方法があります。
その中でも無料で利用可能なものとして、DBMS_CRYPTO というパッケージがあります。
これを利用してみたところ、なかなかに使い方が面倒くさいことが分かったので、この記事ではDBMS_CRYPTOを使いやすくするファンクションのコードを紹介します。
暗号化/復号化の利用イメージ
DBMS_CRYPTOは暗号化や復号化が出来るということなので、以下のようにできるのかなぁ?と思ったけど、どうやら違うようだ。
※ 以下は動作しません
insert into employee_card(id,cardnumber) values (100001, DBMS_CRYPTO.ENCRYPT('123456789012'));
select id from employee_card where cardnumber = DBMS_CRYPTO.ENCRYPT('123456789012');
select DBMS_CRYPTO.DECRYPT(cardnumber) from employee_card where id = 100001;
実際は結構面倒なことをしないといけないらしい。
ただ、暗号化するアプリごとにそれを実装するのは超めんどい。。
なので、上記のように動作するようなファンクションを作ってしまえば良いのでは?と思い、DBUP_CRYPTOを作成しました。
前提条件
Oracle Database 19.15.0で検証しています。
また、暗号化のアルゴリズムなどは以下を選択しています。
設定項目 | 設定内容 | コマンド |
---|---|---|
暗号化アルゴリズム | AES 128bit | ENCRYPT_AES128 |
ブロック暗号連鎖 | 暗号ブロック連鎖 | CHAIN_CBC |
ブロック暗号パディング | PKCS#5 | PAD_PKCS5 |
初期化ベクター | null | null |
この辺りの詳細情報は以下公式マニュアルをご参照ください。
PL/SQLパッケージおよびタイプ・リファレンス - 42 DBMS_CRYPTO
なお、暗号化鍵情報はDBの中に格納しておいた方が安心な気がしたので、encユーザーを作り、そこにenctabというテーブルを作ってその中に格納することにしています。
事前準備
鍵とかを事前に作る必要があるので、以下を行う
- 管理者権限のユーザーでencユーザーを作成し、鍵の値を入れるテーブルを作成して鍵の値を入力する
SQL> create user enc identified by ***** quota unlimited on users;
SQL> create table enc.enctab (enckey char(16));
SQL> insert into enc.enctab values ('1234567890123456');
SQL> commit;
- encユーザーにDBMS_CRYPTOの実行権限を付与する
SQL> grant execute on dbms_crypto to enc;
- パッケージを管理者権限のユーザーでインストールする
(この手順でencユーザーにdbup_cryptoが作成される)
SQL> @dbup_crypto.sql
- 暗号化パッケージを利用するユーザーにインストールしたファンクションの権限を付与する
SQL> grant execute on enc.dbup_crypto to パッケージユーザー;
dbup_crypto.sqlのコード
create or replace package ENC.DBUP_CRYPTO
as
function encrypt (char_for_encryption in varchar2) return raw;
function decrypt (char_for_decryption in raw) return varchar2;
function readenqval return varchar2;
end;
/
create or replace package body ENC.DBUP_CRYPTO
is
function readenqval return varchar2
is
v_data varchar2(100);
begin
select enckey into v_data from ENC.ENCTAB where rownum < 2;
return v_data;
end readenqval;
function encrypt (char_for_encryption in varchar2) return raw
is
v_myKey varchar2(16);
v_enctype number := DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
v_keyval raw(16);
v_encval raw(2000);
begin
v_myKey := dbup_crypto.readenqval;
v_keyval := UTL_I18N.STRING_TO_RAW(v_myKey, 'AL32UTF8');
v_encval := UTL_I18N.STRING_TO_RAW(char_for_encryption, 'AL32UTF8');
return dbms_crypto.encrypt(src => v_encval, typ => v_enctype, key => v_keyval, iv => null);
end encrypt;
function decrypt (char_for_decryption in raw) return varchar2
is
v_myKey varchar2(16);
v_enctype number := DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
v_keyval raw(16);
begin
v_myKey := dbup_crypto.readenqval;
v_keyval := UTL_I18N.STRING_TO_RAW(v_myKey, 'AL32UTF8');
return UTL_I18N.RAW_TO_CHAR(dbms_crypto.decrypt(src => char_for_decryption, typ => v_enctype, key => v_keyval, iv => null), 'AL32UTF8');
end decrypt;
end;
/
DBUP_CRYPTOの利用サンプル
まずは暗号化データを格納するテーブルを作る
SQL> create table employee_card (id number, cardnumber raw(100));
Table created.
続いて、123456789012というデータを暗号化してテーブルに入れてみる
SQL> insert into employee_card values (100001, enc.DBUP_CRYPTO.ENCRYPT('123456789012'));
1 row created.
SQL> select * from employee_card;
ID CARDNUMBER
---------- -----------------------------------
100001 7E9634826EE8B79227B43C8B6A29AE17 ★暗号化されている
暗号化された状態でテーブルに格納された!
暗号化したデータをキーにして検索が出来るかも確認する。
SQL> select id from employee_card where cardnumber = enc.DBUP_CRYPTO.ENCRYPT('123456789012');
ID
----------
100001
検索できた!
復号したデータがselect出来るか確認する
SQL> select enc.DBUP_CRYPTO.DECRYPT(cardnumber) from employee_card where id = 100001;
ENC.DBUP_CRYPTO.DECRYPT(CARDNUMBER)
-------------------------------------
123456789012 ★暗号化する前の情報が確認できる
正しく復号出来ることが確認できた!
#結果
dbms_cryptoは使い勝手が悪いと思っていたが、使い勝手を良くするファンクションを使って開発を捗らせることができた