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集成思路:
- 创建Wallet并存储密钥:
BEGIN DBMS_WALLET.create_wallet('file:/opt/oracle/wallet', 'wallet_password'); DBMS_WALLET.add_secret('ENCRYPT_KEY', '1220248819', 'file:/opt/oracle/wallet'); END; / - 加密包中动态获取密钥:
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; / - 用
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
相关产品推荐
相关产品推荐

