必须用DBMS_CRYPTO.HASH替代DBMS_OBFUSCATION_TOOLKIT.MD5,因其支持UTF-8、正确处理NULL、输出固定16字节RAW并可通过RAWTOHEX转为32位小写十六进制字符串,与Java的MessageDigest一致。
直接用 dbms_crypto 替代 dbms_obfuscation_toolkit,是 oracle 10g 及以后版本的推荐做法;老包已废弃,且不支持 utf-8 字符集下的中文一致性加密。
为什么不能继续用 DBMS_OBFUSCATION_TOOLKIT.MD5
这个包在 Oracle 12c 后被标记为 deprecated,官方文档明确建议迁移到 DBMS_CRYPTO。它有三个硬伤:
- 只接受
RAW类型输入,对VARCHAR2中文字符串不做编码预处理,结果依赖数据库字符集(如ZHS16GBK),跨系统校验必失败 - 无法指定哈希算法的字节序或填充方式,和标准 MD5 实现不完全对齐
- 不支持盐值(salt)注入、无加盐能力,不适合密码存储场景
DBMS_CRYPTO.HASH 的正确调用方式
必须显式将字符串转为 RAW,且编码需与外部系统一致(通常为 UTF-8)。关键不是“能不能调”,而是“按什么字节流去算”:
- 用
UTL_I18N.STRING_TO_RAW(str, 'AL32UTF8')而不是UTL_RAW.CAST_TO_RAW—— 后者直接按数据库字符集编码,不可控 -
DBMS_CRYPTO.HASH第一个参数是RAW,第二个是算法常量:DBMS_CRYPTO.HASH_MD5(值为 1) - 返回仍是
RAW,必须用RAWTOHEX转成小写十六进制字符串
CREATE OR REPLACE FUNCTION md5_utf8(p_input IN VARCHAR2) RETURN VARCHAR2 IS
v_raw RAW(2000);
BEGIN
IF p_input IS NULL THEN
RETURN NULL;
END IF;
v_raw := DBMS_CRYPTO.HASH(
src => UTL_I18N.STRING_TO_RAW(p_input, 'AL32UTF8'),
typ => DBMS_CRYPTO.HASH_MD5
);
RETURN LOWER(RAWTOHEX(v_raw));
END;中文加密结果不一致?检查这三点
这是最常踩的坑,本质是字节流不统一:
加密货币综合分析工具,集成OKX、Binance数据,提供行情、技术分析、交易信号、资金流向、仓位管理、DCA计划、风险计算。触发词:分析BTC、行情查询、交易信号、仓位计算、DCA计划、巨鲸追踪、风险评估。
- 确认数据库字符集是
AL32UTF8(查SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET'),如果不是,UTL_I18N.STRING_TO_RAW(..., 'AL32UTF8')仍能强制转,但需确保传入字符串本身未被客户端截断或乱码 - Java/Python 端必须用 UTF-8 编码后取字节再算 MD5,不能直接对 Unicode 字符串调用 hash 函数
- 避免在函数里拼接 salt:若需加盐,应把 salt 也转成 UTF-8
RAW后与主字符串UTL_RAW.CONCAT,而不是字符串拼接后再转 —— 否则多一层隐式字符集转换
MD5 已不安全,但你可能还得用——那至少别裸用
Oracle 官方早已弃用 MD5,DBMS_CRYPTO 支持更安全的 HASH_SH256(值为 3)、HASH_SH512。如果只是做数据比对或兼容旧协议,MD5 还能用;但涉及密码,必须加盐+迭代(DBMS_CRYPTO.HASH 不支持 PBKDF2,得用 DBMS_CRYPTO.ENCRYPT 配合自定义逻辑,或直接上 ORACLE wallet)。
真正容易被忽略的是:哪怕只用一次 DBMS_CRYPTO.HASH,也要确认调用用户有 EXECUTE 权限 on DBMS_CRYPTO —— 很多生产库默认不开放,报错是 PLS-00201: identifier 'DBMS_CRYPTO' must be declared,而非权限不足提示。

















