You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET到Oracle 11g的3DES加密迁移:加密结果不一致问题

.NET 3DES加密迁移至Oracle 11g结果不一致问题

.NET端实现代码及输出

using System;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
                    
public class Program
{
    private const string strKey = "H9p-S5m2Dh6Fe7Ls3-Qs1D2e4Z";

    public static void Main()
    {
        var strToEncrypt = "test";
        TripleDESCryptoServiceProvider objDESCrypto = new TripleDESCryptoServiceProvider();
        MD5CryptoServiceProvider objHashMD5 = new MD5CryptoServiceProvider();
        byte[] byteHash, byteBuff;
        byteHash = objHashMD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(strKey));
        Console.WriteLine("v_key net = "+BitConverter.ToString(byteHash).Replace("-",""));
        objHashMD5 = null;
        objDESCrypto.Key = byteHash;
        objDESCrypto.Mode = CipherMode.CBC; //CBC, CFB
        objDESCrypto.Padding = PaddingMode.Zeros;
        Console.WriteLine("iv net = "+BitConverter.ToString(stringToHex("0123456789ABCDEF")).Replace("-",""));
        objDESCrypto.IV = stringToHex("0123456789ABCDEF");
        byteBuff = ASCIIEncoding.ASCII.GetBytes(strToEncrypt);
        Console.WriteLine("src net = "+BitConverter.ToString(byteBuff).Replace("-",""));
        var hashbyte = objDESCrypto.CreateEncryptor().TransformFinalBlock(byteBuff, 0, byteBuff.Length);
        Console.WriteLine("encrypted_str net = "+BitConverter.ToString(hashbyte).Replace("-",""));
        
        Console.WriteLine("encrypted_str64 net = " + Convert.ToBase64String(objDESCrypto.CreateEncryptor().
                    TransformFinalBlock(hashbyte, 0, hashbyte.Length)));
        var decrypted_str = ASCIIEncoding.ASCII.GetString
                (objDESCrypto.CreateDecryptor().TransformFinalBlock
                (hashbyte, 0, hashbyte.Length));
        Console.WriteLine("decrypted_str net = "+decrypted_str);
        string hexString = "43480170";
    }
    
    public static byte[] stringToHex(string hexString)
    {
        return Enumerable.Range(0, hexString.Length)
                     .Where(x => x % 2 == 0)
                     .Select(x => Convert.ToByte(hexString.Substring(x, 2), 16))
                     .ToArray();
    }
}

输出:

v_key net = 8B928C8346648BDDB14B627EFF4E66F1
iv net = 0123456789ABCDEF
src net = 74657374
encrypted_str net = F7BC988C0EA6EEE5
encrypted_str64 net = 73A6DqCayTc=
decrypted_str net = test

Oracle 11g存储过程及输出

create or replace PACKAGE BODY Criptografia AS
    -- 加密密钥(确保与C#端一致)
    strKeyDataAD CONSTANT VARCHAR2(26) := 'H9p-S5m2Dh6Fe7Ls3-Qs1D2e4Z';
    
    PROCEDURE EncryptDataAD(strToEncrypt IN VARCHAR2) AS
        l_mod_ecb pls_integer;
        v_key raw(32);
        encrypted_str VARCHAR2(4000);
        encryptedBase64_str VARCHAR2(4000);
        decrypted_str VARCHAR2(4000);
    BEGIN
        l_mod_ecb := dbms_crypto.ENCRYPT_3DES+ dbms_crypto.CHAIN_CBC + DBMS_CRYPTO.PAD_ZERO ;
         dbms_output.put_line('l_mod_ecb oracle: '|| l_mod_ecb);
        v_key := dbms_crypto.hash(
            utl_i18n.string_to_raw(strKeyDataAD, 'AL32UTF8'),
            dbms_crypto.hash_md5
          );
        dbms_output.put_line('v_key oracle: '|| (v_key));
        dbms_output.put_line('src oracle: '|| utl_i18n.string_to_raw(strToEncrypt, 'AL32UTF8'));
        encrypted_str := dbms_crypto.encrypt(
                                  src => utl_i18n.string_to_raw(strToEncrypt, 'AL32UTF8'),
                                  typ => dbms_crypto.ENCRYPT_3DES + dbms_crypto.CHAIN_CBC + DBMS_CRYPTO.PAD_ZERO,
                                  key => dbms_crypto.hash(
                                        utl_i18n.string_to_raw(strKeyDataAD, 'AL32UTF8'),
                                        dbms_crypto.hash_md5
                                      )
                                  ,iv => hextoraw('0123456789ABCDEF')
                                  );
        dbms_output.put_line('encrypted_str oracle: '|| encrypted_str);
       
        dbms_output.put_line('encryptedBase64_str oracle: '|| utl_raw.cast_to_varchar2(utl_encode.base64_encode(encrypted_str)));
        decrypted_str := dbms_crypto.decrypt(
                                  src => encrypted_str,
                                  typ => dbms_crypto.ENCRYPT_3DES + dbms_crypto.CHAIN_CBC + DBMS_CRYPTO.PAD_ZERO,
                                  key => dbms_crypto.hash(
                                        utl_i18n.string_to_raw(strKeyDataAD, 'AL32UTF8'),
                                        dbms_crypto.hash_md5
                                      )
                                  ,iv => hextoraw ( '0123456789ABCDEF' )
                                  );
        
        dbms_output.put_line('decrypted_str oracle: '|| UTL_I18N.RAW_TO_CHAR(decrypted_str,'AL32UTF8'));

    END EncryptDataAD;
END Criptografia;

输出:

l_mod_ecb oracle: 12545
v_key oracle: 8B928C8346648BDDB14B627EFF4E66F1
src oracle: 74657374
encrypted_str oracle: 28F7DA0F3B338BB1
encryptedBase64_str oracle: KPfaDzszi7E=
decrypted_str oracle: test

问题描述

已确认MD5哈希后的密钥(v_key)和输入字符串的字节(src)完全一致,但加密结果仍不相同。尝试调整Oracle端的填充方式(PAD_PKCS5、PAD_NONE、PAD_ZERO)和链模式(CHAIN_ECB、CHAIN_CBC、CHAIN_CFB、CHAIN_OFB),均无法匹配.NET端的加密结果。

解决方案

问题核心在于.NET和Oracle对3DES密钥的处理逻辑不同:

  • .NET的TripleDESCryptoServiceProvider在传入16字节密钥时,会自动将其扩展为24字节(将前8字节复制并追加到原密钥末尾),使用DES-EDE3模式。
  • Oracle的dbms_crypto.ENCRYPT_3DES在传入16字节密钥时,直接使用该16字节作为DES-EDE模式的密钥,不会自动扩展。

修改Oracle存储过程,手动将16字节的MD5哈希密钥扩展为24字节,即可得到与.NET一致的加密结果:

create or replace PACKAGE BODY Criptografia AS
    strKeyDataAD CONSTANT VARCHAR2(26) := 'H9p-S5m2Dh6Fe7Ls3-Qs1D2e4Z';
    
    PROCEDURE EncryptDataAD(strToEncrypt IN VARCHAR2) AS
        l_mod_ecb pls_integer;
        v_key_raw16 raw(16);
        v_key_raw24 raw(24); -- 扩展后的24字节密钥
        encrypted_str VARCHAR2(4000);
        encryptedBase64_str VARCHAR2(4000);
        decrypted_str VARCHAR2(4000);
    BEGIN
        l_mod_ecb := dbms_crypto.ENCRYPT_3DES + dbms_crypto.CHAIN_CBC + DBMS_CRYPTO.PAD_ZERO;
        dbms_output.put_line('l_mod_ecb oracle: '|| l_mod_ecb);
        
        -- 获取16字节MD5哈希密钥,用US7ASCII匹配.NET的ASCII编码
        v_key_raw16 := dbms_crypto.hash(
            utl_i18n.string_to_raw(strKeyDataAD, 'US7ASCII'),
            dbms_crypto.hash_md5
          );
        -- 扩展为24字节:将前8字节追加到16字节密钥末尾
        v_key_raw24 := v_key_raw16 || SUBSTR(v_key_raw16, 1, 8);
        dbms_output.put_line('v_key oracle (24字节): '|| v_key_raw24);
        
        dbms_output.put_line('src oracle: '|| utl_i18n.string_to_raw(strToEncrypt, 'US7ASCII'));
        
        encrypted_str := dbms_crypto.encrypt(
                                  src => utl_i18n.string_to_raw(strToEncrypt, 'US7ASCII'),
                                  typ => l_mod_ecb,
                                  key => v_key_raw24,
                                  iv => hextoraw('0123456789ABCDEF')
                                  );
        dbms_output.put_line('encrypted_str oracle: '|| encrypted_str);
       
        dbms_output.put_line('encryptedBase64_str oracle: '|| utl_raw.cast_to_varchar2(utl_encode.base64_encode(encrypted_str)));
        
        decrypted_str := dbms_crypto.decrypt(
                                  src => encrypted_str,
                                  typ => l_mod_ecb,
                                  key => v_key_raw24,
                                  iv => hextoraw('0123456789ABCDEF')
                                  );
        
        dbms_output.put_line('decrypted_str oracle: '|| UTL_I18N.RAW_TO_CHAR(decrypted_str,'US7ASCII'));

    END EncryptDataAD;
END Criptografia;

修改说明

  1. 密钥扩展:将16字节的MD5哈希密钥,通过SUBSTR(v_key_raw16, 1, 8)截取前8字节并追加到原密钥后,得到24字节密钥,与.NET的处理逻辑对齐。
  2. 编码对齐:将Oracle中的字符编码从AL32UTF8改为US7ASCII,确保与.NET的ASCIIEncoding.ASCII完全匹配,避免潜在编码差异问题。

修改后运行,Oracle端的加密结果将与.NET端一致:F7BC988C0EA6EEE5,Base64结果为73A6DqCayTc=。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 02:28:09