C#AES CFB与第三方C实现的兼容性

C#AES CFB与第三方C实现的兼容性,c#,cryptography,aes,dllimport,rijndaelmanaged,C#,Cryptography,Aes,Dllimport,Rijndaelmanaged,我有一个C的第三方AES库(来自Lantronix)。我从C#的托管代码中包装了他们的API,如下所示,它可以工作: [DllImport("cbx_enc.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] static extern unsafe void VC_blockEncrypt(char* iv, char* key, int length, char* text,

我有一个C的第三方AES库(来自Lantronix)。我从C#的托管代码中包装了他们的API,如下所示,它可以工作:

    [DllImport("cbx_enc.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    static extern unsafe void VC_blockEncrypt(char* iv, char* key, int length, char* text, int RDkeyLen);

    /// <summary>
    /// Managed Encrypt Wrapper     
    /// </summary>
    /// <param name="buffer">provides the plain text and receives the same length cipher text</param>
    static readonly string key = "abcdef0123456789";
    static readonly string iv = "0123456789ABCDEF";
    public static void Encrypt(ref byte[] buffer)
    {
        var keyPtr = Marshal.StringToHGlobalAnsi(key);
        var ivPtr = Marshal.StringToHGlobalAnsi(iv);

        byte[] temp = new byte[16];
        Marshal.Copy(ivPtr, temp, 0, 16);
        int index = 0; 
        for (int i = 0; i < buffer.Length; i++)
        {
            if (index == 0)
            {
                Marshal.Copy(temp, 0, ivPtr, 16);
                unsafe
                {
                    VC_blockEncrypt((char*) ivPtr, (char*) keyPtr, 0, (char*) ivPtr, 128);
                }
                Marshal.Copy(ivPtr, temp, 0, 16);
                index = 16;
            }

            temp[16 - index] ^= buffer[i];
            buffer[i] = temp[16 - index];
            index--;
        }

        Marshal.FreeHGlobal(ivPtr);
        Marshal.FreeHGlobal(keyPtr);
    }
或者,我从Lantronix体系结构中阐明的算法看起来非常简单——API进行加密,在调用方法中使用纯文本对输出进行XORing。然而,对于.NET库,我无法访问中间加密输出(或者是否有?),因此我可以在加密后手动执行XOR操作,就像Lantronix那样

最终目标是停止使用非托管代码,但应该能够使用完全托管的.NET代码生成相同的密文

提前谢谢你的帮助

p、 如果您需要,我可以提供第三方C库cbx_enc.dll

编辑:@Topaco,以下是一些所需的样本数据。没有收到供应商关于分发DLL的消息;正在做这件事

CFB的通用输入:

byte[]buffer=Encoding.ASCII.GetBytes(“aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbd”)//纯文本
string key=“abcdef0123456789”;
字符串iv=“0123456789ABCDEF”

从包装器到非托管DLL的I/O:

纯文本十六进制:
414142424244
密文十六进制:
C9094F820428E07AE035B6749E18546C62F9D5FD4A78480215DA3625D376A271

来自
FeedbackSize=128的托管代码的I/O//CFB128

纯文本十六进制:
414142424244
密文十六进制:
6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83

来自管理代码的I/O,反馈大小为8//CFB8

纯文本十六进制:
414142424244
密文十六进制:
6ACA3B159D38568504248CDFF159C87BB2D3850EDAEAD89493BD91087ED7507

我还使用ECB进行了附加测试,以查看其API的行为是否与ECB类似(因此需要外部XORing)。因此,我将IV以明文形式传递给我的ECB代码,如下所示,并将其与第一个XOR之前的输出进行比较——它们都不匹配

将IV作为明文传递给欧洲央行:
303132333435363733839414243444546
密文十六进制:
2B5B11C9ED9B111A065861D29C478FDA

非托管DLL中第一个异或之前的密文十六进制:
88480EC34569A13BA174F735DF59162E

最后,以下是我对上述测试的ECB实施:

   static readonly string key = "abcdef0123456789";
    static readonly string iv = "0123456789ABCDEF";
    public static void Encrypt(ref byte[] buffer)
    {
        buffer = Encoding.ASCII.GetBytes(iv);
        Console.WriteLine($"PlainText:  {HexHelper.ToHexString(buffer)}");

        var aes = new AesManaged
        {
            KeySize = 128,
            Key = Encoding.ASCII.GetBytes(key),
            BlockSize = 128,
            Mode = CipherMode.ECB,
            Padding = PaddingMode.None,
            IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
        };

        ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
        buffer = encryptor.TransformFinalBlock(buffer, 0, buffer.Length);

        Console.WriteLine($"CipherText: {HexHelper.ToHexString(buffer)}");
    } 

谢谢。

感谢大家的帮助,特别是@Topaco非常感谢–您根据帮助文档以十六进制编码纯文本的见解! 这是修改后的包装代码;如您所见,其密码现在与托管代码的密码匹配!太好了

    static readonly string key = "61626364656630313233343536373839"; //"abcdef0123456789";
    static readonly string iv = "0123456789ABCDEF";
    public static void Encrypt(ref byte[] buffer)
    {
        Console.WriteLine($"PlainText: {HexHelper.ToHexString(buffer)}");

        var keyPtr = Marshal.StringToHGlobalAnsi(key);
        var ivPtr = Marshal.StringToHGlobalAnsi(iv);
        byte[] temp = new byte[16];
        Marshal.Copy(ivPtr, temp, 0, 16);
        int index = 0; 
        for (int i = 0; i < buffer.Length; i++)
        {
            if (index == 0)
            {
                Marshal.Copy(temp, 0, ivPtr, 16);
                unsafe
                {
                    VC_blockEncrypt((char*) ivPtr, (char*) keyPtr, 0, (char*) ivPtr, 128);
                }
                Marshal.Copy(ivPtr, temp, 0, 16);
                index = 16;
                Console.WriteLine($"CipherText BeforeXOR: {HexHelper.ToHexString(temp)}");
            }

            temp[16 - index] ^= buffer[i];
            buffer[i] = temp[16 - index];
            index--;
        }

        Marshal.FreeHGlobal(ivPtr);
        Marshal.FreeHGlobal(keyPtr);

        Console.WriteLine($"CipherText: {HexHelper.ToHexString(buffer)}");

    }
static readonly string key=“616263646566303132333435363733839”//“abcdef0123456789”;
静态只读字符串iv=“0123456789ABCDEF”;
公共静态无效加密(参考字节[]缓冲区)
{
WriteLine($“明文:{HexHelper.ToHexString(缓冲区)}”);
var keyPtr=Marshal.StringToHGlobalAnsi(键);
var ivPtr=Marshal.StringToHGlobalAnsi(iv);
字节[]临时=新字节[16];
封送员副本(ivPtr,临时,0,16);
int指数=0;
for(int i=0;i
来自修订包装器代码的I/O: 纯文本:
4141414242424244
密文:
6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83

来自托管代码的I/O: 纯文本:
4141414242424244
密文:
6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83


干杯

我不知道你的情况到底发生了什么,但有一点需要注意的是,CFB模式有一个额外的参数以及key和iv。我想这可能是
FeedbackSize
所指的。尝试将其设置为8或1,然后查看结果是否与库匹配。这里的示例将非常有用,因为缺少.dll,无法执行上面的代码。因此,您应该为两个代码中的每一个加密明文,并发布明文、两个密文(十六进制或Base64编码)以及使用的密钥和IV(以及与已发布数据不同的所有参数,例如反馈大小、填充等)。事实上,提供.dll是最有意义的,但前提是允许您这样做。我根据您的示例数据进行了一些猜测,但没有得出任何实质性的结论。可以在web上找到对的描述。第22页描述了VC_BlockEncrypt,第11页有一个与您的实现相对应的示例。我同意这种逻辑是正确的。参数见第10页。值得注意的是,密钥应作为十六进制字符串传递,即16字节字符串由32个字符表示,因此您使用的字符串
abcdef0123456789
不应简单地进行ASCII编码,而应替换为十六进制字符串
616263646566
    static readonly string key = "61626364656630313233343536373839"; //"abcdef0123456789";
    static readonly string iv = "0123456789ABCDEF";
    public static void Encrypt(ref byte[] buffer)
    {
        Console.WriteLine($"PlainText: {HexHelper.ToHexString(buffer)}");

        var keyPtr = Marshal.StringToHGlobalAnsi(key);
        var ivPtr = Marshal.StringToHGlobalAnsi(iv);
        byte[] temp = new byte[16];
        Marshal.Copy(ivPtr, temp, 0, 16);
        int index = 0; 
        for (int i = 0; i < buffer.Length; i++)
        {
            if (index == 0)
            {
                Marshal.Copy(temp, 0, ivPtr, 16);
                unsafe
                {
                    VC_blockEncrypt((char*) ivPtr, (char*) keyPtr, 0, (char*) ivPtr, 128);
                }
                Marshal.Copy(ivPtr, temp, 0, 16);
                index = 16;
                Console.WriteLine($"CipherText BeforeXOR: {HexHelper.ToHexString(temp)}");
            }

            temp[16 - index] ^= buffer[i];
            buffer[i] = temp[16 - index];
            index--;
        }

        Marshal.FreeHGlobal(ivPtr);
        Marshal.FreeHGlobal(keyPtr);

        Console.WriteLine($"CipherText: {HexHelper.ToHexString(buffer)}");

    }