Oracle到YashanDB适配:dbms_obfuscation_toolkit的平滑迁移

我们的文章会在微信公众号IT民工的龙马人生博客网站 ( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢!
由于博客中有大量代码,通过页面浏览效果更佳。

1.1 前言

在数据库国产化迁移的过程中,安全能力的对标成熟商业数据库与核心逻辑的平滑过渡到YashanDB是关键环节。Oracle 早期版本常使用 dbms_obfuscation_toolkit 进行基础加密,但是在后期Oracle dbms_obfuscation_toolkit列为过期组件。但在现代国产数据库研发(如 YashanDB)中,为了获得更强的算法支持和更标准化的接口,通常只适配了 DBMS_CRYPTO ,这就涉及到需要将 dbms_obfuscation_toolkit改写为DBMS_CRYPTO

本文将详细展示如何将一个基于 DES 算法的解密函数从旧有的 Oracle Toolkit 模式迁移至 Oracle的DBMS_CRYPTO 模式,在平滑的迁移到YashanDB 兼容的 DBMS_CRYPTO 模式,并分享验证一致性的最佳实践。


1.2 现状分析:Oracle 原始逻辑

在 Oracle 早期遗留系统中,解密逻辑通常如下所示。该方法直接处理 VARCHAR2 类型,且对 DES 块对齐的要求较为隐蔽。
原始代码如下:

-- 原始基于 dbms_obfuscation_toolkit 的代码
CREATE OR REPLACE FUNCTION "HTZ"."DECRYPT_DES" (
    p_text VARCHAR
)
RETURN VARCHAR
IS
v_text VARCHAR(2000);
BEGIN
    IF p_text IS NULL OR p_text = '' THEN  
        RETURN p_text;
    END IF ;
    dbms_obfuscation_toolkit.DESDECRYPT(
        input_string => UTL_RAW.CAST_TO_varchar2(p_text), 
        key_string => 'huangtin', 
        decrypted_string => v_text
    );
    v_text := rtrim(v_text, chr(0));
    RETURN v_text;
EXCEPTION
    WHEN others THEN RETURN p_text;
END;
/

1.3 演进与适配:改写为 DBMS_CRYPTO 模式

YashanDB 高度兼容 Oracle 的系统包,所以我们现在Oracle数据库中将代码修改为DBMS_CRYPTO。改写为 DBMS_CRYPTO 能够提供更明确的填充模式控制。以下代码展示了如何通过定义 v_typ(DES + CBC模式 + 无填充)来精准模拟原始逻辑。

CREATE OR REPLACE FUNCTION "HTZ"."DECRYPT_DES" (
    p_text IN VARCHAR2
)
RETURN VARCHAR2
IS
    v_ret          RAW(2000);
    v_key          RAW(8);
    v_input        RAW(2000);
    v_decrypted    VARCHAR2(2000);
    -- DES + CBC + No Padding (精确匹配原始逻辑,手动处理补齐)
    v_typ          PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_NONE;
BEGIN
    -- 1. 处理空值输入
    IF p_text IS NULL THEN 
        RETURN p_text;
    END IF;

    -- 2. 准备密钥与输入 (强制使用 RAW 类型确保字节级安全)
    v_key   := UTL_RAW.CAST_TO_RAW('huangtin');
    v_input := UTL_RAW.CAST_TO_RAW(p_text);

    -- 3. 调用 DBMS_CRYPTO 进行解密
    v_ret := DBMS_CRYPTO.DECRYPT(
        src => v_input,
        typ => v_typ,
        key => v_key
    );

    -- 4. 转换回字符串并去除末尾的 CHR(0) 填充
    v_decrypted := UTL_RAW.CAST_TO_VARCHAR2(v_ret);
    v_decrypted := RTRIM(v_decrypted, CHR(0));

    RETURN v_decrypted;

EXCEPTION
    WHEN OTHERS THEN
        -- 遵循原始需求,报错时返回原文本
        RETURN p_text;
END;
/


1.4 兼容性验证:确保逻辑闭环

在正式迁移到 YashanDB 之前,我们需要在 Oracle 环境中通过“新旧对比测试”验证改写后的函数是否能正确解密由旧包产生的数据。

1.4.1 场景一:模拟旧数据解密验证

由于 DES 要求输入必须是 8 的倍数,我们在测试中对不足 8 位的 huanghtz 进行了补齐处理。

SET SERVEROUTPUT ON;

DECLARE
    v_raw_text      VARCHAR2(100) := 'huanghtz'; 
    v_key           VARCHAR2(20)  := 'huangtin';
    v_padded_text   VARCHAR2(100);
    v_encrypted_str VARCHAR2(2000);
    v_decrypted_new VARCHAR2(2000);

    -- 模拟老方法加密逻辑
    PROCEDURE mock_old_encrypt(p_in IN VARCHAR2, p_out OUT VARCHAR2) IS
    BEGIN
        v_padded_text := RPAD(p_in, 8, CHR(0));
        DBMS_OBFUSCATION_TOOLKIT.DESENCRYPT(
            input_string     => v_padded_text,
            key_string       => v_key,
            encrypted_string => p_out
        );
    END;

BEGIN
    DBMS_OUTPUT.PUT_LINE('--- Testing String: ' || v_raw_text || ' ---');

    -- Step A: 旧包加密
    mock_old_encrypt(v_raw_text, v_encrypted_str);
    DBMS_OUTPUT.PUT_LINE('Step 1: Encrypted String (Hex): ' || UTL_RAW.CAST_TO_RAW(v_encrypted_str));

    -- Step B: 新函数解密
    v_decrypted_new := "HTZ"."DECRYPT_DES"(v_encrypted_str);
    
    -- Step C: 结果比对
    DBMS_OUTPUT.PUT_LINE('Step 2: Decrypted Result: ' || v_decrypted_new);

    IF v_decrypted_new = v_raw_text THEN
        DBMS_OUTPUT.PUT_LINE('SUCCESS: The new method matches the old logic.');
    ELSE
        DBMS_OUTPUT.PUT_LINE('FAILURE: Results do not match.');
    END IF;
END;
/

1.5 迁移 YashanDB 后的生产验证

将上述 DECRYPT_DES 函数迁移至 YashanDB 后,我们使用 YashanDB 原生的 DBMS_CRYPTO 能力进行最终验证。

1.5.1 场景二:YashanDB 环境内独立验证

SET SERVEROUTPUT ON;

DECLARE
    v_original_plain  VARCHAR2(100) := 'huanghtz'; 
    v_encryption_key  VARCHAR2(20)  := 'huangtin';
    v_encrypted_raw   RAW(2000);
    v_encrypted_char  VARCHAR2(2000);
    v_decrypted_final VARCHAR2(2000);
BEGIN
    -- 1. 在 YashanDB 中模拟生成标准 DES 加密数据
    v_encrypted_raw := DBMS_CRYPTO.ENCRYPT(
        src => UTL_RAW.CAST_TO_RAW(v_original_plain),
        typ => DBMS_CRYPTO.ENCRYPT_DES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_NONE,
        key => UTL_RAW.CAST_TO_RAW(v_encryption_key)
    );
    
    v_encrypted_char := UTL_RAW.CAST_TO_VARCHAR2(v_encrypted_raw);

    -- 2. 调用迁移后的解密函数
    v_decrypted_final := "HTZ"."DECRYPT_DES"(v_encrypted_char);

    -- 3. 验证输出
    DBMS_OUTPUT.PUT_LINE('--- Function Verification in YashanDB ---');
    DBMS_OUTPUT.PUT_LINE('Original Text: ' || v_original_plain);
    DBMS_OUTPUT.PUT_LINE('Function Output: ' || v_decrypted_final);

    IF v_decrypted_final = v_original_plain THEN
        DBMS_OUTPUT.PUT_LINE('RESULT: SUCCESS');
    ELSE
        DBMS_OUTPUT.PUT_LINE('RESULT: FAILED');
    END IF;
END;
/


1.6 总结与建议

  1. 权限控制:在 YashanDB 中编译该函数前,务必确保 HTZ 用户已被显式授予权限:GRANT EXECUTE ON DBMS_CRYPTO TO HTZ;
  2. RAW 类型的重要性:从 Oracle 迁移到 YashanDB 时,应尽量将加密数据存储为 RAW 。如果必须以 VARCHAR2 存储,需格外注意字符集对不可见字符的影响。
  3. 算法演进:DES 算法在安全性上已逐渐被 AES 取代。在完成平滑迁移后,建议后续考虑将业务中的解密算法升级为 AES-256

通过上述改写流程,我们不仅成功实现了 Oracle 到 YashanDB 的逻辑迁移,更将底层的安全组件升级到了更可靠的 DBMS_CRYPTO 架构。

posted @ 2026-01-26 23:45  认真就输  阅读(0)  评论(0)    收藏  举报