データベース内の機密情報(個人情報・クレジットカード番号・パスワードなど)を暗号化して保護したい場面は多くあります。Oracle には DBMS_CRYPTO パッケージが組み込まれており、PL/SQL から直接 AES・3DES などの業界標準アルゴリズムによる暗号化・復号・ハッシュ生成を実行できます。
DBMS_CRYPTO はアプリケーション層での列レベル暗号化に適しています。ストレージ全体を暗号化したい場合は TDE(Transparent Data Encryption)と目的が異なります。
- DBMS_CRYPTO.ENCRYPT / DECRYPT で AES 暗号化・復号を行う方法
- 暗号化アルゴリズム・モード・パディングの定数の組み合わせ方
- DBMS_CRYPTO.HASH で MD5・SHA-1・SHA-256 ハッシュを生成する
- DBMS_CRYPTO.MAC でメッセージ認証コード(HMAC)を生成する
- テーブル列の暗号化・復号を行う実践的なパターン
- DBMS_CRYPTO と TDE の使い分け
DBMS_CRYPTO の利用に必要な権限
-- DBMS_CRYPTO の EXECUTE 権限を確認する SELECT grantee, privilege, grantor FROM DBA_TAB_PRIVS WHERE table_name = 'DBMS_CRYPTO' AND grantee = 'YOUR_USER'; -- 権限がない場合は DBA が付与する(SYS で実行) GRANT EXECUTE ON DBMS_CRYPTO TO YOUR_USER; -- 実行前に RAW 型の扱いに必要な UTL_RAW も確認 GRANT EXECUTE ON UTL_RAW TO YOUR_USER;
AES 暗号化・復号の基本
DBMS_CRYPTO はデータを RAW 型で扱います。文字列を暗号化する場合は UTL_I18N.STRING_TO_RAW で RAW に変換し、復号後は UTL_I18N.RAW_TO_CHAR で文字列に戻します。
暗号化アルゴリズムはアルゴリズム定数 + モード定数 + パディング定数を加算(+)して指定します。
| 種別 | 定数 | 値(参考) | 説明 |
|---|---|---|---|
| アルゴリズム | ENCRYPT_AES128 | 6 | AES 128ビット鍵 |
| ENCRYPT_AES192 | 7 | AES 192ビット鍵 | |
| ENCRYPT_AES256 | 8 | AES 256ビット鍵 | |
| モード | CHAIN_CBC | 256 | Cipher Block Chaining(推奨) |
| CHAIN_ECB | 768 | Electronic Codebook(同一平文→同一暗号文、非推奨) | |
| CHAIN_CFB | 512 | Cipher Feedback | |
| パディング | PAD_PKCS5 | 4096 | PKCS#5(ブロック境界に自動パディング) |
| PAD_NONE | 8192 | パディングなし(入力がブロック長の倍数である必要がある) |
DECLARE
-- 暗号化アルゴリズムの指定: AES256 + CBC モード + PKCS5 パディング
c_algo CONSTANT PLS_INTEGER :=
DBMS_CRYPTO.ENCRYPT_AES256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
-- 鍵: AES-256 は 32 バイト(256 ビット)必要
-- 実運用では安全な鍵管理機構(Oracle Wallet 等)を使うこと
v_key RAW(32) := UTL_I18N.STRING_TO_RAW('MySecretKey12345MySecretKey12345', 'AL32UTF8');
-- IV(初期化ベクトル): CBC モードでは 16 バイトの IV が必要
v_iv RAW(16) := UTL_RAW.CAST_TO_RAW('InitVector16Byte');
v_plain RAW(2000);
v_enc RAW(2000);
v_dec RAW(2000);
v_result VARCHAR2(200);
BEGIN
-- 平文を RAW に変換する
v_plain := UTL_I18N.STRING_TO_RAW('暗号化するテキスト', 'AL32UTF8');
-- 暗号化する
v_enc := DBMS_CRYPTO.ENCRYPT(
src => v_plain,
typ => c_algo,
key => v_key,
iv => v_iv
);
DBMS_OUTPUT.PUT_LINE('暗号化結果(HEX): ' || RAWTOHEX(v_enc));
-- 復号する(同じ鍵・IV・アルゴリズムが必要)
v_dec := DBMS_CRYPTO.DECRYPT(
src => v_enc,
typ => c_algo,
key => v_key,
iv => v_iv
);
-- RAW を文字列に戻す
v_result := UTL_I18N.RAW_TO_CHAR(v_dec, 'AL32UTF8');
DBMS_OUTPUT.PUT_LINE('復号結果: ' || v_result);
END;
/
CBC(Cipher Block Chaining)モードでは、同じ平文・同じ鍵でも IV(初期化ベクトル)が異なれば異なる暗号文が生成されます。同一平文→同一暗号文になる ECB モードより安全です。実運用では暗号化のたびにランダムな IV を生成し、暗号文と一緒に保管する必要があります。
ランダムな鍵・IV を生成する
DECLARE
-- AES-256 鍵(32バイト)をランダムに生成する
v_key RAW(32) := DBMS_CRYPTO.RANDOMBYTES(32);
-- CBC 用 IV(16バイト)をランダムに生成する
v_iv RAW(16) := DBMS_CRYPTO.RANDOMBYTES(16);
BEGIN
DBMS_OUTPUT.PUT_LINE('鍵(HEX): ' || RAWTOHEX(v_key));
DBMS_OUTPUT.PUT_LINE('IV(HEX): ' || RAWTOHEX(v_iv));
-- 実運用: v_key を Oracle Wallet や Key Vault で管理する
-- v_iv は暗号文と一緒に DB に保存する(秘密にする必要はない)
END;
/
DBMS_CRYPTO.HASH でハッシュを生成する
ハッシュは一方向変換です。パスワードの保存・データの改ざん検知に使います。MD5 は衝突耐性が弱いため、新規実装では SHA-256(HASH_SH256)を推奨します。
DECLARE
v_hash RAW(32); -- SHA-256 は 32 バイト(256 ビット)
BEGIN
v_hash := DBMS_CRYPTO.HASH(
src => UTL_I18N.STRING_TO_RAW('ハッシュ化するテキスト', 'AL32UTF8'),
typ => DBMS_CRYPTO.HASH_SH256
);
DBMS_OUTPUT.PUT_LINE('SHA-256: ' || RAWTOHEX(v_hash));
END;
/
| 定数 | アルゴリズム | 出力サイズ | 推奨度 |
|---|---|---|---|
| HASH_MD5 | MD5 | 16バイト(128ビット) | 非推奨(衝突耐性が低い) |
| HASH_SH1 | SHA-1 | 20バイト(160ビット) | 非推奨(廃止検討) |
| HASH_SH256 | SHA-256 | 32バイト(256ビット) | 推奨 |
| HASH_SH384 | SHA-384 | 48バイト(384ビット) | 推奨(高セキュリティ) |
| HASH_SH512 | SHA-512 | 64バイト(512ビット) | 推奨(高セキュリティ) |
- パスワードを HASH_SH256 のみで保存するとレインボーテーブル攻撃に脆弱です
- パスワード保存にはソルト(RANDOMBYTES で生成したランダム値)をパスワードに連結してからハッシュ化する
- DBMS_CRYPTO の HASH は反復処理に対応していないため、強固なパスワードハッシュが必要な場合は PBKDF2 相当の反復処理をアプリ側で実装することを検討する
DBMS_CRYPTO.MAC でメッセージ認証コードを生成する
MAC(Message Authentication Code)は鍵付きハッシュです。データの改ざん検知と送信者の認証を同時に行いたい場合に使います(HMAC)。ハッシュと異なり、検証側も同じ鍵が必要です。
DECLARE
v_mac RAW(32);
-- 秘密鍵(送受信者が共有する鍵)
v_key RAW(32) := DBMS_CRYPTO.RANDOMBYTES(32);
v_data RAW(2000);
BEGIN
v_data := UTL_I18N.STRING_TO_RAW('認証するメッセージ内容', 'AL32UTF8');
v_mac := DBMS_CRYPTO.MAC(
src => v_data,
typ => DBMS_CRYPTO.HMAC_SH256, -- HMAC-SHA-256
key => v_key
);
DBMS_OUTPUT.PUT_LINE('HMAC-SHA-256: ' || RAWTOHEX(v_mac));
-- 検証: 同じ鍵・データで同じ MAC が生成されれば改ざんなし
END;
/
テーブル列の暗号化・復号を実装する
実運用では暗号化した値と IV を別々の列に保存するパターンが一般的です。IV は毎回ランダムに生成することで同じ平文が常に異なる暗号文になります。
-- 個人情報テーブル(メールアドレスを暗号化して保存)
CREATE TABLE personal_info (
user_id NUMBER PRIMARY KEY,
name VARCHAR2(100) NOT NULL,
email_enc RAW(256), -- 暗号化されたメールアドレス
email_iv RAW(16), -- 暗号化に使用した IV
created_at DATE DEFAULT SYSDATE
);
-- 暗号化パッケージ(鍵管理を一元化する設計)
CREATE OR REPLACE PACKAGE email_crypto AS
-- 実運用では鍵を環境変数・Oracle Wallet・外部 KMS で管理すること
-- このサンプルは構造の説明を目的としている
c_key CONSTANT RAW(32) := HEXTORAW('0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF');
c_algo CONSTANT PLS_INTEGER :=
DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
PROCEDURE insert_user(
p_user_id IN NUMBER,
p_name IN VARCHAR2,
p_email IN VARCHAR2
);
FUNCTION get_email(p_user_id IN NUMBER) RETURN VARCHAR2;
END email_crypto;
/
CREATE OR REPLACE PACKAGE BODY email_crypto AS
PROCEDURE insert_user(
p_user_id IN NUMBER,
p_name IN VARCHAR2,
p_email IN VARCHAR2
) IS
v_iv RAW(16);
v_enc RAW(256);
BEGIN
-- 毎回ランダムな IV を生成する
v_iv := DBMS_CRYPTO.RANDOMBYTES(16);
v_enc := DBMS_CRYPTO.ENCRYPT(
src => UTL_I18N.STRING_TO_RAW(p_email, 'AL32UTF8'),
typ => c_algo,
key => c_key,
iv => v_iv
);
INSERT INTO personal_info(user_id, name, email_enc, email_iv)
VALUES (p_user_id, p_name, v_enc, v_iv);
END insert_user;
FUNCTION get_email(p_user_id IN NUMBER) RETURN VARCHAR2 IS
v_enc RAW(256);
v_iv RAW(16);
v_dec RAW(256);
BEGIN
SELECT email_enc, email_iv
INTO v_enc, v_iv
FROM personal_info
WHERE user_id = p_user_id;
v_dec := DBMS_CRYPTO.DECRYPT(
src => v_enc,
typ => c_algo,
key => c_key,
iv => v_iv
);
RETURN UTL_I18N.RAW_TO_CHAR(v_dec, 'AL32UTF8');
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END get_email;
END email_crypto;
/
-- 使用例
BEGIN
email_crypto.insert_user(1, '山田太郎', 'yamada@example.com');
COMMIT;
END;
/
SELECT email_crypto.get_email(1) AS email FROM DUAL;
DBMS_CRYPTO と TDE(Transparent Data Encryption)の比較
| 項目 | DBMS_CRYPTO | TDE |
|---|---|---|
| 暗号化の対象 | PL/SQL で明示的に指定した列・データ | 表領域または列(透過的) |
| アプリへの影響 | アプリが暗号化・復号を意識する必要あり | アプリを変更しなくても透過的に動作 |
| 鍵管理 | 開発者が管理(要注意) | Oracle Wallet(自動管理) |
| 暗号化粒度 | 列単位・任意のデータ | 表領域単位または列単位 |
| パフォーマンス影響 | PL/SQL 処理のオーバーヘッドあり | ストレージ層で処理するため比較的軽量 |
| 主な用途 | 特定列のアプリレベル暗号化・ハッシュ保存 | ストレージ盗難対策・コンプライアンス対応 |
・ディスク盗難・バックアップ漏洩対策が目的 → TDE(アプリ変更不要)
・特定列(個人情報・機密データ)をアプリ層でアクセス制御したい → DBMS_CRYPTO(DBA でも復号不可にできる)
・パスワードの保存 → DBMS_CRYPTO.HASH(ソルト付き SHA-256)
・データ整合性の検証 → DBMS_CRYPTO.MAC(HMAC-SHA-256)
まとめ
- DBMS_CRYPTO.ENCRYPT/DECRYPT:AES-256 + CBC + PAD_PKCS5 の組み合わせが現代的な標準。毎回ランダムな IV を生成・保存する
- DBMS_CRYPTO.HASH:新規実装は SHA-256(HASH_SH256)以上を使う。MD5・SHA-1 は非推奨
- DBMS_CRYPTO.MAC:HMAC-SHA-256 でデータ改ざん検知と送信者認証を両立できる
- 鍵管理が最重要:鍵をソースコードに埋め込まず、Oracle Wallet や外部 KMS で管理すること
- TDE との使い分け:ストレージ保護は TDE、アプリレベルの列暗号化は DBMS_CRYPTO が適切
暗号化パッケージの設計方針は パッケージ完全ガイドを参照してください。ファイルへの出力が必要な場合は UTL_FILE完全ガイドも参照してください。