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

如何在C#的BouncyCastle中兼容非8字节块的Blowfish加密?

兼容Delphi MyDAC/LockBox3 Blowfish无填充加密的C#实现方案

问题核心分析

MyDAC和LockBox3的Blowfish无填充加密实现是非标准的:标准块密码(Blowfish块大小固定为8字节)的NoPadding要求输入长度必须是块大小的整数倍,但这两个Delphi库允许对不足块长度的数据直接加密(如单个字符转单个字节密文),而BouncyCastle的标准实现会因长度不匹配抛出异常。

1. 先确保密钥生成逻辑一致

Delphi的密钥生成逻辑需要在C#中精准复现,这是兼容的前提:

using System.Security.Cryptography;
using System.Text;

byte[] GenerateCompatibleKey(string password)
{
    // 对应Delphi WideString的UTF-16LE编码
    byte[] passBytes = Encoding.Unicode.GetBytes(password);
    
    // 计算SHA1哈希(20字节)
    byte[] sha1Hash;
    using (SHA1 sha1 = SHA1.Create())
    {
        sha1Hash = sha1.ComputeHash(passBytes);
    }
    
    // 计算MD5哈希(16字节)
    byte[] md5Hash;
    using (MD5 md5 = MD5.Create())
    {
        md5Hash = md5.ComputeHash(passBytes);
    }
    
    // 拼接成36字节数组,取前32字节作为最终密钥(对应MyDAC SetKey的32长度参数)
    byte[] keyBytes = new byte[36];
    Buffer.BlockCopy(sha1Hash, 0, keyBytes, 0, 20);
    Buffer.BlockCopy(md5Hash, 0, keyBytes, 20, 16);
    
    byte[] finalKey = new byte[32];
    Buffer.BlockCopy(keyBytes, 0, finalKey, 0, 32);
    return finalKey;
}

2. 调整BouncyCastle加密逻辑兼容短数据

模拟Delphi库的非标准无填充行为:对不足块长度的数据,先补零到块大小,加密后截断回原数据长度;块倍数长度数据直接用标准CBC无填充加密。

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

byte[] EncryptWithBouncyCastle(string data, byte[] key)
{
    byte[] plaintext = Encoding.UTF8.GetBytes(data);
    int blockSize = 8; // Blowfish块大小固定8字节
    byte[] iv = new byte[8]; // 对应Delphi的全零IV
    
    if (plaintext.Length % blockSize == 0)
    {
        // 块倍数长度,直接用标准CBC无填充加密
        ICipher cipher = CipherUtilities.GetCipher("Blowfish/CBC/NoPadding");
        cipher.Init(true, new ParametersWithIV(new KeyParameter(key), iv));
        return cipher.DoFinal(plaintext);
    }
    else
    {
        // 短数据:补零到块大小,加密后截断回原长度
        byte[] paddedPlaintext = new byte[((plaintext.Length + blockSize - 1) / blockSize) * blockSize];
        Buffer.BlockCopy(plaintext, 0, paddedPlaintext, 0, plaintext.Length);
        
        ICipher cipher = CipherUtilities.GetCipher("Blowfish/CBC/NoPadding");
        cipher.Init(true, new ParametersWithIV(new KeyParameter(key), iv));
        byte[] fullEncrypted = cipher.DoFinal(paddedPlaintext);
        
        // 截断到原明文长度
        byte[] result = new byte[plaintext.Length];
        Buffer.BlockCopy(fullEncrypted, 0, result, 0, plaintext.Length);
        return result;
    }
}

// 解密逻辑对应调整
byte[] DecryptWithBouncyCastle(byte[] encryptedData, byte[] key)
{
    int blockSize = 8;
    byte[] iv = new byte[8];
    
    if (encryptedData.Length % blockSize == 0)
    {
        ICipher cipher = CipherUtilities.GetCipher("Blowfish/CBC/NoPadding");
        cipher.Init(false, new ParametersWithIV(new KeyParameter(key), iv));
        return cipher.DoFinal(encryptedData);
    }
    else
    {
        // 补零到块大小,解密后截断回原密文长度
        byte[] paddedEncrypted = new byte[((encryptedData.Length + blockSize - 1) / blockSize) * blockSize];
        Buffer.BlockCopy(encryptedData, 0, paddedEncrypted, 0, encryptedData.Length);
        
        ICipher cipher = CipherUtilities.GetCipher("Blowfish/CBC/NoPadding");
        cipher.Init(false, new ParametersWithIV(new KeyParameter(key), iv));
        byte[] fullDecrypted = cipher.DoFinal(paddedEncrypted);
        
        byte[] result = new byte[encryptedData.Length];
        Buffer.BlockCopy(fullDecrypted, 0, result, 0, encryptedData.Length);
        return result;
    }
}

3. 可尝试的其他C#加密库

如果调整BouncyCastle逻辑后仍不兼容,可尝试以下库:

  • .NET自定义Blowfish实现:基于System.Security.Cryptography手动实现CBC模式的非标准块处理逻辑
  • Cryptography.Cipher:轻量第三方库,支持自定义填充和块处理,适配非标准加密场景
  • SharpZipLib:以压缩功能为主,但内置Blowfish实现,可调用其底层加密接口
  • DotNetCrypto:全面的加密库,支持多种算法的灵活配置,适合兼容旧系统加密逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 09:10:54