C# AES CFB 与第 3 方 C 实现的兼容性
C# AES CFB compatibility with 3rd party C implementation
我有一个用于 C 的第 3 方 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);
}
现在,当我自己写的时候,使用System.Security.Cryptography
来完全避免使用他们的非托管DLL,我的最终密文似乎与他们不同!我使用相同的模式、相同的密钥、相同的 iv 和相同的纯文本,但算法不兼容。下面显示的是 RijndaelManaged
对象和代码的 属性 设置;我错过了导致这种不兼容的东西吗?
/// <summary>
/// Managed Encrypt
/// </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)
{
using (RijndaelManaged cipher = new RijndaelManaged())
{
cipher.Mode = CipherMode.CFB;
cipher.Key = Encoding.ASCII.GetBytes(key);
cipher.IV = Encoding.ASCII.GetBytes(iv);
cipher.Padding = PaddingMode.None;
cipher.FeedbackSize = 128;
ICryptoTransform encryptor = cipher.CreateEncryptor(cipher.Key, cipher.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter swEncrypt = new BinaryWriter(csEncrypt))
{
swEncrypt.Write(buffer);
}
buffer = msEncrypt.ToArray();
}
}
}
}
或者,我从 Lantronix 架构阐明的算法看起来非常简单 - API 进行加密,并在调用方法中对输出与纯文本进行异或运算。然而,对于 .NET 库,我没有对中间加密输出的这种访问权限(或者有一个?),所以我可以像 Lantronix 在加密后手动执行的那样进行 XOR...
最终目标是停止使用非托管代码,但应该能够使用完全托管的 .NET 代码生成相同的密文。
提前感谢您的帮助。
p.s。如果您需要,我可以提供第 3 方 C 库 cbx_enc.dll。
编辑:@Topaco,这里有一些请求的示例数据。还没有从供应商那里听到有关分发他们的 DLL 的信息;正在努力……
CFB 的常见输入:
byte[] buffer = Encoding.ASCII.GetBytes("AAAAAAAAAAAAAABBBBBBBBBBBBBBBBBD"); //plain text
string key = "abcdef0123456789";
string iv = "0123456789ABCDEF";
I/O 从包装器到非托管 DLL:
纯文本十六进制:4141414141414141414141414141424242424242424242424242424242424244
密文十六进制:C9094F820428E07AE035B6749E18546C62F9D5FD4A78480215DA3625D376A271
I/O 来自带有 FeedbackSize = 128; //CFB128
:
的托管代码
纯文本十六进制:4141414141414141414141414141424242424242424242424242424242424244
密文十六进制:6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83
I/O 来自托管代码 FeedbackSize = 8 //CFB8
:
纯文本十六进制:4141414141414141414141414141424242424242424242424242424242424244
密文十六进制:6ACA3B1159D38568504248CDFF159C87BB2D3850EDAEAD89493BD91087ED7507
我还使用 ECB 进行了额外测试,以查看它们的 API 行为是否像 ECB(因此需要外部 XORing)。因此,我将 IV 作为纯文本传递给我的 ECB 代码,如下所示,并将其与第一个 XOR 之前的输出进行比较——它们都不匹配!
将 IV 作为明文传递给欧洲央行:30313233343536373839414243444546
密文十六进制:2B5B11C9ED9B111A065861D29C478FDA
来自非托管 DLL 的十六进制密文,在第一个 XOR 之前: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 非常感谢 - 你对根据文档 将纯文本编码为 HEX 的见解很有帮助!
这是修改后的包装代码;如您所见,它的密码现在与托管代码的密码相匹配!完美!!
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)}");
}
I/O 来自修改后的包装代码:
纯文本:4141414141414141414141414141424242424242424242424242424242424244
密文:6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83
I/O 来自托管代码:
纯文本:4141414141414141414141414141424242424242424242424242424242424244
密文:6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83
干杯!!
我有一个用于 C 的第 3 方 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);
}
现在,当我自己写的时候,使用System.Security.Cryptography
来完全避免使用他们的非托管DLL,我的最终密文似乎与他们不同!我使用相同的模式、相同的密钥、相同的 iv 和相同的纯文本,但算法不兼容。下面显示的是 RijndaelManaged
对象和代码的 属性 设置;我错过了导致这种不兼容的东西吗?
/// <summary>
/// Managed Encrypt
/// </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)
{
using (RijndaelManaged cipher = new RijndaelManaged())
{
cipher.Mode = CipherMode.CFB;
cipher.Key = Encoding.ASCII.GetBytes(key);
cipher.IV = Encoding.ASCII.GetBytes(iv);
cipher.Padding = PaddingMode.None;
cipher.FeedbackSize = 128;
ICryptoTransform encryptor = cipher.CreateEncryptor(cipher.Key, cipher.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter swEncrypt = new BinaryWriter(csEncrypt))
{
swEncrypt.Write(buffer);
}
buffer = msEncrypt.ToArray();
}
}
}
}
或者,我从 Lantronix 架构阐明的算法看起来非常简单 - API 进行加密,并在调用方法中对输出与纯文本进行异或运算。然而,对于 .NET 库,我没有对中间加密输出的这种访问权限(或者有一个?),所以我可以像 Lantronix 在加密后手动执行的那样进行 XOR...
最终目标是停止使用非托管代码,但应该能够使用完全托管的 .NET 代码生成相同的密文。
提前感谢您的帮助。
p.s。如果您需要,我可以提供第 3 方 C 库 cbx_enc.dll。
编辑:@Topaco,这里有一些请求的示例数据。还没有从供应商那里听到有关分发他们的 DLL 的信息;正在努力……
CFB 的常见输入:
byte[] buffer = Encoding.ASCII.GetBytes("AAAAAAAAAAAAAABBBBBBBBBBBBBBBBBD"); //plain text
string key = "abcdef0123456789";
string iv = "0123456789ABCDEF";
I/O 从包装器到非托管 DLL:
纯文本十六进制:4141414141414141414141414141424242424242424242424242424242424244
密文十六进制:C9094F820428E07AE035B6749E18546C62F9D5FD4A78480215DA3625D376A271
I/O 来自带有 FeedbackSize = 128; //CFB128
:
纯文本十六进制:4141414141414141414141414141424242424242424242424242424242424244
密文十六进制:6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83
I/O 来自托管代码 FeedbackSize = 8 //CFB8
:
纯文本十六进制:4141414141414141414141414141424242424242424242424242424242424244
密文十六进制:6ACA3B1159D38568504248CDFF159C87BB2D3850EDAEAD89493BD91087ED7507
我还使用 ECB 进行了额外测试,以查看它们的 API 行为是否像 ECB(因此需要外部 XORing)。因此,我将 IV 作为纯文本传递给我的 ECB 代码,如下所示,并将其与第一个 XOR 之前的输出进行比较——它们都不匹配!
将 IV 作为明文传递给欧洲央行:30313233343536373839414243444546
密文十六进制:2B5B11C9ED9B111A065861D29C478FDA
来自非托管 DLL 的十六进制密文,在第一个 XOR 之前: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 非常感谢 - 你对根据文档 将纯文本编码为 HEX 的见解很有帮助! 这是修改后的包装代码;如您所见,它的密码现在与托管代码的密码相匹配!完美!!
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)}");
}
I/O 来自修改后的包装代码:
纯文本:4141414141414141414141414141424242424242424242424242424242424244
密文:6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83
I/O 来自托管代码:
纯文本:4141414141414141414141414141424242424242424242424242424242424244
密文:6A1A5088ACDA505B47192093DD06CD987868BFD85278A4D7D3120CC85FCD3D83
干杯!!