【Oracle】DBMS_CRYPTO完全ガイド|AES暗号化・復号・ハッシュ(SHA-256)・MAC・列暗号化まで解説

データベース内の機密情報(個人情報・クレジットカード番号・パスワードなど)を暗号化して保護したい場面は多くあります。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 の利用に必要な権限

EXECUTE 権限の確認と付与
-- 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 パディングなし(入力がブロック長の倍数である必要がある)
AES-256 CBC でテキストを暗号化・復号する基本例
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 モードと IV について
CBC(Cipher Block Chaining)モードでは、同じ平文・同じ鍵でも IV(初期化ベクトル)が異なれば異なる暗号文が生成されます。同一平文→同一暗号文になる ECB モードより安全です。実運用では暗号化のたびにランダムな IV を生成し、暗号文と一緒に保管する必要があります。

ランダムな鍵・IV を生成する

DBMS_CRYPTO.RANDOMBYTES でランダムデータを生成する
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)を推奨します。

SHA-256 ハッシュを生成する
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)。ハッシュと異なり、検証側も同じ鍵が必要です。

HMAC-SHA-256 でメッセージ認証コードを生成する
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
);
暗号化して INSERT・復号して SELECT するプロシージャ例
-- 暗号化パッケージ(鍵管理を一元化する設計)
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完全ガイドも参照してください。