导读:本期聚焦于印尼程序员创作的《Oracle dbms_crypto加密解密函数怎么用?详细用法与示例解析》,敬请观看详情。数据库里的敏感数据如果直接明文存储,一旦被拖库后果不堪设想。Oracle自带的dbms_crypto包提供了一套完整的加密解密方案,支持DES、AES、3DES等多种算法,还能配合MD5、SHA1做哈希摘要。本文详细讲解dbms_crypto的授权开启方法、加密解密函数的调用方式、各加密类型的区别,以及如何处理中文乱码、密钥管理等常见问题,并给出可直接运行的PL/SQL代码示例,帮助你快速落地数据加密方案。

dbms_crypto是Oracle 10g开始内置的加密包,位于SYS用户下,封装了对称加密、哈希计算、随机数生成等常用密码学功能。对于存储身份证号、手机号、银行卡这类敏感字段的系统来说,用它在数据库层面做加密是一种成本很低的方案,不需要改动应用架构,写几个PL/SQL函数就能覆盖增删改查的加密解密需求。本文从包的授权开始,逐步演示加密、解密、哈希的完整用法。

Oracle dbms_crypto加密解密函数怎么用?详细用法与示例解析

一、开启dbms_crypto的使用权限

dbms_crypto默认只有SYS用户可以使用,普通业务用户第一次调用时会报PLS-00201错误,提示标识符DBMS_CRYPTO必须声明。解决办法是用SYSDBA登录后给业务用户授权:

-- 以SYSDBA身份执行
SQL> conn / as sysdba
SQL> GRANT EXECUTE ON dbms_crypto TO your_user;

授权完成后建议先跑一个简单的验证,确认包可以正常访问。需要注意的是,dbms_crypto只在Oracle 10g及以后版本提供,9i以前的版本对应的是dbms_obfuscation_toolkit,那个包只支持DES且密钥长度受限,如果还在用老版本建议评估升级。

验证方式很简单,直接查询加密算法常量是否可见:

SELECT dbms_crypto.ENCRYPT_AES256 FROM dual;
-- 返回数字即说明包可用

二、加密与解密函数的编写

dbms_crypto的核心入口是dbms_crypto.encryptdbms_crypto.decrypt两个函数,两者参数一致:src是RAW类型的原文,typ指定加密算法和填充模式的组合,key是密钥,iv是初始向量。typ参数并不是随便填的,它等于算法常量加链接模式常量加填充常量之和,例如AES256加密、CBC模式、PKCS5填充就写成dbms_crypto.ENCRYPT_AES256 + dbms_crypto.CHAIN_CBC + dbms_crypto.PAD_PKCS5

下面是一套完整的加密解密函数,可以直接在业务用户下创建:

CREATE OR REPLACE PACKAGE pkg_crypto AS
  FUNCTION encrypt_data(p_plain  IN VARCHAR2,
                        p_key    IN VARCHAR2) RETURN RAW;
  FUNCTION decrypt_data(p_cipher IN RAW,
                        p_key    IN VARCHAR2) RETURN VARCHAR2;
END pkg_crypto;
/

CREATE OR REPLACE PACKAGE BODY pkg_crypto AS
  -- 加密:AES256 + CBC + PKCS5
  FUNCTION encrypt_data(p_plain  IN VARCHAR2,
                        p_key    IN VARCHAR2) RETURN RAW IS
    v_key    RAW(32);
    v_typ    PLS_INTEGER;
    v_enc    RAW(2048);
  BEGIN
    v_key := utl_raw.cast_to_raw(p_key);
    -- 密钥长度必须是32字节,不足补齐
    v_key := rpad(v_key, 64, '0');
    v_typ := dbms_crypto.ENCRYPT_AES256
           + dbms_crypto.CHAIN_CBC
           + dbms_crypto.PAD_PKCS5;
    v_enc := dbms_crypto.encrypt(src => utl_raw.cast_to_raw(p_plain),
                                 typ => v_typ,
                                 key => v_key,
                                 iv  => NULL);
    RETURN v_enc;
  END;

  FUNCTION decrypt_data(p_cipher IN RAW,
                        p_key    IN VARCHAR2) RETURN VARCHAR2 IS
    v_key  RAW(32);
    v_typ  PLS_INTEGER;
    v_dec  RAW(2048);
  BEGIN
    v_key := rpad(utl_raw.cast_to_raw(p_key), 64, '0');
    v_typ := dbms_crypto.ENCRYPT_AES256
           + dbms_crypto.CHAIN_CBC
           + dbms_crypto.PAD_PKCS5;
    v_dec := dbms_crypto.decrypt(src => p_cipher,
                                 typ => v_typ,
                                 key => v_key,
                                 iv  => NULL);
    RETURN utl_raw.cast_to_varchar2(v_dec);
  END;
END pkg_crypto;
/

调用测试:先加密再解密,如果返回原文说明整条链路通了。

DECLARE
  v_raw RAW(2048);
  v_txt VARCHAR2(200);
BEGIN
  v_raw := pkg_crypto.encrypt_data('测试数据13800138000', 'mySecretKey');
  dbms_output.put_line('密文:' || rawtohex(v_raw));
  v_txt := pkg_crypto.decrypt_data(v_raw, 'mySecretKey');
  dbms_output.put_line('明文:' || v_txt);
END;
/

这里有个细节要说明:iv参数传NULL时,Oracle会使用默认的全零初始向量。生产环境更严谨的做法是用dbms_crypto.randombytes生成随机iv,并把iv与密文拼接存库,解密时再拆出来,这样同样的明文每次加密出来的密文都不同,能防止模式分析攻击。

三、算法选择与常见坑

dbms_crypto支持的算法常量包括ENCRYPT_DES、ENCRYPT_3DES_2KEY、ENCRYPT_AES128、ENCRYPT_AES192、ENCRYPT_AES256等。DES因为密钥只有56位,已经不安全,新系统一律不要用;3DES安全性尚可但性能只有AES的一半左右;没有特殊兼容要求时首选AES,密钥长度选128或256均可。链接模式推荐CBC,填充模式用PKCS5,这是最稳妥的组合。

密钥长度必须严格匹配:AES256要求32字节,AES128要求16字节。utl_raw.cast_to_raw是按字符ASCII码逐个转字节的,一个字符对应两个十六进制位,所以32字节的密钥需要64位长度的十六进制串。上面例子中用rpad补齐是一种偷懒做法,更规范的方式是对密钥先做SHA256哈希,天然得到32字节的定长结果:

v_key := dbms_crypto.hash(src => utl_raw.cast_to_raw(p_key),
                          typ => dbms_crypto.HASH_SH256);

中文乱码是最常见的坑。因为函数内部以RAW字节流处理数据,utl_raw.cast_to_varchar2返回的结果取决于数据库字符集。如果数据库是GBK而客户端是UTF8,直接存储解密结果可能乱码。稳妥的处理是用utl_i18n.string_to_raw显式指定字符集:

-- 加密前:指定UTF8编码转RAW
v_src := utl_i18n.string_to_raw(p_plain, 'AL32UTF8');
-- 解密后:RAW转回UTF8字符串
v_txt := utl_i18n.raw_to_char(v_dec, 'AL32UTF8');

最后提醒两点:一是密文必须用RAW类型或转成十六进制字符串存储,字段长度要留足,AES加密后长度大约是明文字节数向上取整到16的倍数再加16;二是密钥不要硬编码在包体里,建议配合Oracle Wallet或者独立密钥表加权限控制,否则拿到代码的人等于拿到密钥,加密形同虚设。

四、哈希与随机数的补充用法

除了对称加密,dbms_crypto还提供哈希和MAC计算,常用于密码存储和数据完整性校验。密码存储推荐SHA256起步,且不要只对明文做一次哈希,应加盐处理:

DECLARE
  v_salt  RAW(16);
  v_hash  RAW(32);
BEGIN
  v_salt := dbms_crypto.randombytes(16);  -- 生成16字节随机盐
  v_hash := dbms_crypto.hash(
              src => utl_raw.concat(v_salt, utl_raw.cast_to_raw('用户密码')),
              typ => dbms_crypto.HASH_SH256);
  dbms_output.put_line('盐:' || rawtohex(v_salt));
  dbms_output.put_line('加盐哈希:' || rawtohex(v_hash));
END;
/

dbms_crypto.mac则是在哈希基础上引入密钥的HMAC实现,适合接口签名场景,即使盐值泄露,没有密钥也难以伪造。另外dbms_crypto.randombytesdbms_crypto.randominteger可以用来生成随机数据,比SQL里的dbms_random质量更高,生成验证码、临时令牌时优先用它。

整体来说,dbms_crypto的API设计比较底层,直接调用容易在字符集和密钥长度上踩坑,但只要把这些细节封装成规范的包,再配合触发器或视图做透明加解密,就能以很小的改造成本满足绝大多数合规审计要求。

Oracle dbms_crypto加密解密PL/SQL加密函数修改时间:2026-09-15 15:03:40

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。