You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Oracle PL/SQL实现带PKCS7填充的Rijndael/SHA1加密求助

Oracle PL/SQL实现符合Rijndael/SHA1、256位密钥/块大小、PKCS7填充的加密方案

首先,咱们得明确几个关键点:Oracle的DBMS_CRYPTO包是实现这个需求的核心,不过需要注意参数和C#代码的严格对齐,不然很容易出现加密结果不一致的情况。下面是一步步的实现方案:

前提准备

确保你的数据库用户拥有DBMS_CRYPTO的执行权限,执行以下授权语句(需要DBA权限):

GRANT EXECUTE ON DBMS_CRYPTO TO your_username;

核心加密函数实现

下面的函数完全匹配你提到的参数要求:256位密钥、256位块大小、PKCS7填充,并且兼容C#的Rijndael实现逻辑(默认CBC模式、UTF8编码、Base64输出):

CREATE OR REPLACE FUNCTION encrypt_for_vendor(
    p_plaintext IN VARCHAR2,  -- 要加密的明文
    p_key IN VARCHAR2,        -- 32字节(256位)的密钥字符串
    p_iv IN VARCHAR2          -- 32字节(256位)的初始化向量字符串
) RETURN VARCHAR2 IS
    l_plaintext_raw RAW(2000);
    l_key_raw RAW(32);
    l_iv_raw RAW(32);
    l_encrypted_raw RAW(2000);
BEGIN
    -- 将字符串转换为UTF8编码的RAW(和C#的Encoding.UTF8对齐)
    l_plaintext_raw := UTL_I18N.STRING_TO_RAW(p_plaintext, 'AL32UTF8');
    l_key_raw := UTL_I18N.STRING_TO_RAW(p_key, 'AL32UTF8');
    l_iv_raw := UTL_I18N.STRING_TO_RAW(p_iv, 'AL32UTF8');

    -- 校验密钥和IV的长度必须为32字节(256位)
    IF DBMS_UTILITY.GET_LENGTH(l_key_raw) != 32 THEN
        RAISE_APPLICATION_ERROR(-20001, '密钥必须是32字节(256位)长度,请检查输入');
    END IF;
    IF DBMS_UTILITY.GET_LENGTH(l_iv_raw) != 32 THEN
        RAISE_APPLICATION_ERROR(-20002, '初始化向量(IV)必须是32字节(256位)长度,请检查输入');
    END IF;

    -- 执行加密:AES-256、CBC模式、PKCS7兼容填充、256位块大小
    l_encrypted_raw := DBMS_CRYPTO.ENCRYPT(
        src => l_plaintext_raw,
        typ => DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5,
        key => l_key_raw,
        iv => l_iv_raw,
        block_size => 32  -- 明确指定256位块大小(32字节)
    );

    -- 将加密后的RAW转换为Base64字符串(和C#的Convert.ToBase64String对齐)
    RETURN UTL_ENCODE.BASE64_ENCODE(l_encrypted_raw);
END;
/

关键细节说明

  1. PKCS7填充的兼容:Oracle的PAD_PKCS5常量实际上完全兼容PKCS7填充逻辑——PKCS5是PKCS7针对8字节块的特例,当块大小为32字节时,它会自动填充到32字节的倍数,符合PKCS7的要求。
  2. 块大小指定:默认AES的块大小是128位,但通过block_size => 32参数明确指定为256位,和你的需求匹配。
  3. 编码对齐:必须使用AL32UTF8编码转换字符串为RAW,确保和C#的Encoding.UTF8生成的字节完全一致。
  4. 密钥/IV校验:函数里添加了长度校验,避免因输入长度错误导致加密失败或结果不一致。

关于SHA1的补充说明

你提到的HashAlgorithm = Rijndael/SHA1,大概率是指密钥通过SHA1派生(比如用用户密码生成SHA1哈希,再扩展为256位密钥)。如果你的C#代码是这样实现的,可以修改函数里的密钥处理逻辑,比如:

-- 示例:将输入的密码通过SHA1哈希后,补0扩展为32字节密钥
l_key_raw := DBMS_CRYPTO.HASH(UTL_I18N.STRING_TO_RAW(p_password, 'AL32UTF8'), DBMS_CRYPTO.HASH_SH1) 
             || UTL_RAW.CAST_TO_RAW('000000000000'); -- 补12字节0,凑够32字节

注意:这里的扩展逻辑必须和C#代码完全一致,否则加密结果会不同。

测试验证

建议用相同的明文、密钥、IV分别在C#和PL/SQL中执行加密,对比Base64输出是否一致,以此验证实现的正确性。

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

火山引擎 最新活动