You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle中CLOB加密解密实现、SHA512哈希校验、密钥安全优化及加密方案选型技术咨询

Oracle CLOB加密解密、密钥安全及通用加密方案问题

我来帮你一步步解决这些Oracle加密相关的问题,结合你的LiveSQL测试场景,给你具体的方案和代码示例:


一、先搞定CLOB加密对应的解密函数

你现有的clob_encrypt函数把CLOB加密成BLOB,对应的解密函数需要接收BLOB类型的密文,还原为CLOB明文。这里要注意和加密函数使用完全一致的算法类型、密钥,否则解密会失败:

create or replace function clob_decrypt(ab_input IN BLOB) return CLOB is
lc_variable CLOB;
inverse_type PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
inverse_key RAW(32) := UTL_RAW.cast_to_raw( '1220248819');
begin
dbms_lob.createtemporary(lc_variable, true);
DBMS_CRYPTO.DECRYPT( dst => lc_variable,
                     src => ab_input,
                     typ => inverse_type,
                     key => inverse_key );
return lc_variable;
end clob_decrypt;

测试验证:

-- 加密测试
select clob_encrypt('test clob content') encrypted_blob from dual;
-- 解密测试
select clob_decrypt(clob_encrypt('test clob content')) decrypted_clob from dual;

二、密钥安全:加密包是可行方案,但可以更完善

把代码封装成包并加密(用Oracle的wrap工具)确实能隐藏密钥和逻辑,但wrap只是代码混淆,不是真正的加密,有经验的DBA还是有可能破解。更安全的方案是:

  • 不要把密钥硬编码在代码里,而是存在Oracle Wallet中
  • 加密包通过DBMS_WALLET.get_secret动态获取密钥,这样代码里完全看不到密钥

举个简单的Wallet集成思路:

  1. 创建Wallet并存储密钥:
    BEGIN
      DBMS_WALLET.create_wallet('file:/opt/oracle/wallet', 'wallet_password');
      DBMS_WALLET.add_secret('ENCRYPT_KEY', '1220248819', 'file:/opt/oracle/wallet');
    END;
    /
    
  2. 加密包中动态获取密钥:
    CREATE OR REPLACE PACKAGE secure_crypto AS
      FUNCTION clob_encrypt(ac_input IN CLOB) RETURN BLOB;
      FUNCTION clob_decrypt(ab_input IN BLOB) RETURN CLOB;
      -- 后续可添加VARCHAR2、BLOB的加密解密函数
    END secure_crypto;
    /
    CREATE OR REPLACE PACKAGE BODY secure_crypto AS
      -- 内部函数:获取Wallet中的密钥
      FUNCTION get_encrypt_key RETURN RAW IS
        l_key VARCHAR2(100);
      BEGIN
        l_key := DBMS_WALLET.get_secret('ENCRYPT_KEY');
        RETURN UTL_RAW.cast_to_raw(l_key);
      END get_encrypt_key;
    
      FUNCTION clob_encrypt(ac_input IN CLOB) RETURN BLOB IS
        lb_variable BLOB;
        inverse_type PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
      BEGIN
        dbms_lob.createtemporary(lb_variable, true);
        DBMS_CRYPTO.ENCRYPT( dst => lb_variable,
                             src => ac_input,
                             typ => inverse_type,
                             key => get_encrypt_key() );
        RETURN lb_variable;
      END clob_encrypt;
    
      FUNCTION clob_decrypt(ab_input IN BLOB) RETURN CLOB IS
        lc_variable CLOB;
        inverse_type PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
      BEGIN
        dbms_lob.createtemporary(lc_variable, true);
        DBMS_CRYPTO.DECRYPT( dst => lc_variable,
                             src => ab_input,
                             typ => inverse_type,
                             key => get_encrypt_key() );
        RETURN lc_variable;
      END clob_decrypt;
    END secure_crypto;
    /
    
  3. 用wrap工具加密包(避免逻辑被直接查看):
    wrap iname=secure_crypto.pkg oname=secure_crypto.pkb
    

这样即使包被反编译,也看不到密钥,安全性大幅提升。


三、通用加密方案:打造支持多类型的工具包

为了避免重复开发,你可以在加密包中添加对VARCHAR2、BLOB的加密解密函数,统一算法和密钥管理。比如扩展上面的secure_crypto包:

CREATE OR REPLACE PACKAGE secure_crypto AS
  -- CLOB加密解密
  FUNCTION clob_encrypt(ac_input IN CLOB) RETURN BLOB;
  FUNCTION clob_decrypt(ab_input IN BLOB) RETURN CLOB;
  -- VARCHAR2加密解密(返回RAW类型密文)
  FUNCTION varchar_encrypt(av_input IN VARCHAR2) RETURN RAW;
  FUNCTION varchar_decrypt(ar_input IN RAW) RETURN VARCHAR2;
  -- BLOB加密解密
  FUNCTION blob_encrypt(ab_input IN BLOB) RETURN BLOB;
  FUNCTION blob_decrypt(ab_input IN BLOB) RETURN BLOB;
END secure_crypto;
/
CREATE OR REPLACE PACKAGE BODY secure_crypto AS
  -- 内部函数:获取Wallet中的密钥
  FUNCTION get_encrypt_key RETURN RAW IS
    l_key VARCHAR2(100);
  BEGIN
    l_key := DBMS_WALLET.get_secret('ENCRYPT_KEY');
    RETURN UTL_RAW.cast_to_raw(l_key);
  END get_encrypt_key;

  -- 内部函数:统一算法类型,后续修改只需改这里
  FUNCTION get_crypto_type RETURN PLS_INTEGER IS
  BEGIN
    -- 使用更安全的AES-256算法
    RETURN DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
  END get_crypto_type;

  -- CLOB加密
  FUNCTION clob_encrypt(ac_input IN CLOB) RETURN BLOB IS
    lb_variable BLOB;
  BEGIN
    dbms_lob.createtemporary(lb_variable, true);
    DBMS_CRYPTO.ENCRYPT( dst => lb_variable,
                         src => ac_input,
                         typ => get_crypto_type(),
                         key => get_encrypt_key() );
    RETURN lb_variable;
  END clob_encrypt;

  -- CLOB解密
  FUNCTION clob_decrypt(ab_input IN BLOB) RETURN CLOB IS
    lc_variable CLOB;
  BEGIN
    dbms_lob.createtemporary(lc_variable, true);
    DBMS_CRYPTO.DECRYPT( dst => lc_variable,
                         src => ab_input,
                         typ => get_crypto_type(),
                         key => get_encrypt_key() );
    RETURN lc_variable;
  END clob_decrypt;

  -- VARCHAR2加密
  FUNCTION varchar_encrypt(av_input IN VARCHAR2) RETURN RAW IS
  BEGIN
    RETURN DBMS_CRYPTO.ENCRYPT( src => UTL_RAW.cast_to_raw(av_input),
                                typ => get_crypto_type(),
                                key => get_encrypt_key() );
  END varchar_encrypt;

  -- VARCHAR2解密
  FUNCTION varchar_decrypt(ar_input IN RAW) RETURN VARCHAR2 IS
    l_raw RAW(2000);
  BEGIN
    l_raw := DBMS_CRYPTO.DECRYPT( src => ar_input,
                                  typ => get_crypto_type(),
                                  key => get_encrypt_key() );
    RETURN UTL_RAW.cast_to_varchar2(l_raw);
  END varchar_decrypt;

  -- BLOB加密
  FUNCTION blob_encrypt(ab_input IN BLOB) RETURN BLOB IS
    lb_variable BLOB;
  BEGIN
    dbms_lob.createtemporary(lb_variable, true);
    DBMS_CRYPTO.ENCRYPT( dst => lb_variable,
                         src => ab_input,
                         typ => get_crypto_type(),
                         key => get_encrypt_key() );
    RETURN lb_variable;
  END blob_encrypt;

  -- BLOB解密
  FUNCTION blob_decrypt(ab_input IN BLOB) RETURN BLOB IS
    lb_variable BLOB;
  BEGIN
    dbms_lob.createtemporary(lb_variable, true);
    DBMS_CRYPTO.DECRYPT( dst => lb_variable,
                         src => ab_input,
                         typ => get_crypto_type(),
                         key => get_encrypt_key() );
    RETURN lb_variable;
  END blob_decrypt;
END secure_crypto;
/

这样后续不管是加密字符串还是BLOB,直接调用包里的函数即可,修改算法或密钥只需要调整get_crypto_type和Wallet里的密钥,非常灵活。


四、更优的加密算法:替换DES为AES-256

你当前使用的DES算法安全性很低(密钥长度只有56位),早就被破解了。Oracle的DBMS_CRYPTO支持更安全的AES算法,推荐使用AES-256(密钥长度256位,对应32字节的RAW)。

上面的通用包已经默认用了AES-256,你只需要确保Wallet中存储的密钥是32字节长度即可(比如UTL_RAW.cast_to_raw('a_32_byte_key_1234567890abcdef'),刚好32字符)。


权限控制建议

为了实现“仅允许具备权限的用户解密”,可以:

  • 把解密函数的执行权限仅授予特定用户/角色:
    GRANT EXECUTE ON secure_crypto TO authorized_user;
    
  • 或者在包的解密函数中添加权限校验逻辑:
    FUNCTION clob_decrypt(ab_input IN BLOB) RETURN CLOB IS
      lc_variable CLOB;
      l_user VARCHAR2(30) := USER;
    BEGIN
      -- 校验用户权限
      IF l_user NOT IN ('AUTHORIZED_USER1', 'AUTHORIZED_USER2') THEN
        RAISE_APPLICATION_ERROR(-20001, 'You are not authorized to decrypt data');
      END IF;
      -- 解密逻辑
      dbms_lob.createtemporary(lc_variable, true);
      DBMS_CRYPTO.DECRYPT( dst => lc_variable,
                           src => ab_input,
                           typ => get_crypto_type(),
                           key => get_encrypt_key() );
      RETURN lc_variable;
    END clob_decrypt;
    

内容的提问来源于stack exchange,提问作者Pugzly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 09:52:31