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

将C语言OpenSSL实现的TripleDes加密逻辑移植到.NET的问题求助

问题排查与修复方案

你的实现存在4处核心逻辑差异,按优先级排序如下:

  • 核心差异1:未处理DES密钥的奇偶校验位
    OpenSSL的DES_set_key_checked会自动校验并校正每个DES密钥字节的奇校验位(每个字节的二进制1的个数为奇数,最低位为校验位),但.NET的TripleDESCryptoServiceProvider默认直接使用原始密钥字节,不会做校验位校正,这是加密结果不一致的核心原因。
  • 核心差异2:缺少PIN补空格逻辑
    C代码中idata的8~15位固定为8字节,PIN长度不足8位时末尾补ASCII空格(0x20),你当前的实现直接取PIN的ASCII字节,长度不足时会导致输入加密块长度错误,即使测试用的PIN是8位,短PIN场景下也会出错。
  • 核心差异3:随机数生成逻辑不对等
    你使用的System.Random是普通伪随机数生成器,不是密码学安全的随机数,和OpenSSL的RAND_bytes逻辑不符。另外因为加密输入前7字节是随机值,正常运行时每次输出都不同,你给出的固定预期输出是基于特定随机数生成的,调试时需要先固定前7字节的随机值和生成预期结果时的随机值一致,才能验证加密逻辑是否正确。
  • 次要差异:未显式指定3DES参数
    建议显式指定3DES的密钥长度为192位(24字节),避免不同系统默认配置差异导致的异常。

修复后的代码

internal static class PINEncoding
{
    internal static string EncodePIN(string unencodedPIN, string decryptedWorkingKey, byte[] debugFixedRandom = null)
    {
        var randomBytes = debugFixedRandom ?? GenerateSecureRandomBytes();
        var asciiPin = ConvertPINToASCIIBytes(unencodedPIN);
        var checksum = ComputeChecksum(asciiPin);
        var pinBlock = ObtainPinBlock(randomBytes, checksum, asciiPin);
        return EncryptPIN(pinBlock, decryptedWorkingKey);
    }

    // 替换为密码学安全的随机数生成,和OpenSSL RAND_bytes逻辑一致
    private static byte[] GenerateSecureRandomBytes()
    {
        byte[] b = new byte[7];
        using (var rng = System.Security.Cryptography.RNGCryptoServiceProvider.Create())
        {
            rng.GetBytes(b);
        }
        return b;
    }

    // 新增补空格逻辑,固定输出8字节
    private static byte[] ConvertPINToASCIIBytes(string pin)
    {
        byte[] pinBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(pin);
        byte[] result = new byte[8];
        // 填充空格(ASCII 0x20)
        for (int i = 0; i < 8; i++)
        {
            result[i] = i < pinBytes.Length ? pinBytes[i] : (byte)' ';
        }
        return result;
    }

    private static byte ComputeChecksum(byte[] data)
    {
        long longSum = data.Sum(x => (long)x);
        return unchecked((byte)longSum);
    }

    private static byte[] ObtainPinBlock(byte[] random, byte checksum, byte[] asciiPin)
    {
        var result = new byte[16];
        Buffer.BlockCopy(random, 0, result, 0, 7);
        result[7] = checksum;
        Buffer.BlockCopy(asciiPin, 0, result, 8, 8);
        return result;
    }

    private static string EncryptPIN(byte[] eanBlock, string decryptedWorkingKey)
    {
        var keyAsBytes = ConvertHexStringToByteArray(decryptedWorkingKey);
        // 校正密钥的奇校验位,和OpenSSL DES_set_key_checked逻辑对齐
        AdjustDESKeyParity(keyAsBytes);
        var byteResult = TripleDESEncryption.Encrypt(eanBlock, keyAsBytes);
        return BitConverter.ToString(byteResult).Replace("-", "");
    }

    // 新增:DES密钥奇校验位校正
    private static void AdjustDESKeyParity(byte[] key)
    {
        for (int i = 0; i < key.Length; i++)
        {
            int b = key[i];
            // 统计1的个数
            int parity = 0;
            for (int j = 0; j < 8; j++)
            {
                parity += (b >> j) & 1;
            }
            // 如果是偶数个1,翻转最低位变成奇数
            if (parity % 2 == 0)
            {
                key[i] = (byte)(b ^ 1);
            }
        }
    }

    // 新增:16进制字符串转字节数组,和OpenSSL hex2bin逻辑对齐
    private static byte[] ConvertHexStringToByteArray(string hex)
    {
        byte[] result = new byte[hex.Length / 2];
        for (int i = 0; i < hex.Length; i += 2)
        {
            result[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
        }
        return result;
    }
}

public static class TripleDESEncryption
{
    public static byte[] Encrypt(byte[] toEncrypt, byte[] key)
    {
        using (var tdes = new System.Security.Cryptography.TripleDESCryptoServiceProvider
        {
            KeySize = 192,
            Key = key,
            IV = new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
            Mode = System.Security.Cryptography.CipherMode.CBC,
            Padding = System.Security.Cryptography.PaddingMode.None
        })
        {
            var cTransform = tdes.CreateEncryptor();
            return cTransform.TransformFinalBlock(toEncrypt, 0, toEncrypt.Length);
        }
    }
}

调试验证说明

你给出的固定预期输出是基于特定随机值生成的,调试时可以调用EncodePIN方法时传入debugFixedRandom参数,填入生成预期结果时用到的7字节随机值,即可得到和预期一致的输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 14:30:01