我被分配了删除我们产品的一个 dll 并将其替换为纯 C# 的任务。旧 DLL 是一个 .NET 2.0 托管 C++ (C++\CLI),它封装了对 Win32 本机 Crypto API 的调用。新的 DLL 应该公开一个具有相同名称和方法的新对象,但应该使用 C# (.NET 4.0) 编写。当然,新的 DLL 应该以与旧 DLL 相同的方式加密(和解密) - 否则,所有保存在持久存储(如数据库或文件中)中的加密密码 - 将无法解析!
这是本机 (Win32) API 调用的(伪)代码(注意输入总是 Unicode 编码):
//buffer_to_encrypt - Is the input to the following procedure and is the buffer
// to be encrypted using 3DES and the below password to generate a valid 3DES key
// The buffer is Unicode encoded!!!
HCRYPTPROV m_provider = NULL;
HCRYPTHASH m_hash = NULL;
HCRYPTKEY m_key = NULL;
static const unsigned char password[] = {
0xF1, 0x49, 0x4C, 0xD0, 0xC1,
0xE2, 0x1A, 0xEA, 0xFB, 0x34,
0x25, 0x5A, 0x63, 0xA5, 0x29,
0x09, 0x8E, 0xB6, 0x7B, 0x75
}; //20 BYTES password
CryptAcquireContextW( &m_provider, NULL, NULL, PROV_DH_SCHANNEL, CRYPT_MACHINE_KEYSET | CRYPT_VERIFYCONTEXT);
CryptCreateHash( m_provider, CALG_SHA1, NULL, 0, &m_hash );
CryptHashData( m_hash, password, (DWORD)20, 0 ); //password is a 20Bytes buffer
CryptDeriveKey(m_provider, CALG_3DES, m_hash, CRYPT_EXPORTABLE, &m_key);
CryptEncrypt( m_key.handle(), NULL, TRUE, 0, buffer_to_encrypt, &dwFilled, (DWORD)total );
return buffer_to_encrypt;
现在,我正在尝试使用 C#(System.Security.Cryptography 命名空间)和 .NET API 公开的新 Crypto 对象编写相同的过程:
class Encryptor
{
private static byte[] password = {
0xF1, 0x49, 0x4C, 0xD0, 0xC1,
0xE2, 0x1A, 0xEA, 0xFB, 0x34,
0x25, 0x5A, 0x63, 0xA5, 0x29,
0x09, 0x8E, 0xB6, 0x7B, 0x75
}; //20 BYTES password, same as the above native code
private static byte[] EncryptInternal(string source)
{
byte[] resultArray = null;
byte[] streamToEncrypt = Encoding.Unicode.GetBytes(source);
using (TripleDESCryptoServiceProvider prov3des = new TripleDESCryptoServiceProvider())
{
prov3des.Mode = CipherMode.ECB;
prov3des.Padding = PaddingMode.PKCS7;
using (PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, null)) //No slat needed here
{
prov3des.Key = pdb.CryptDeriveKey("TripleDES", "SHA1", prov3des.KeySize, ZeroIV);
}
ICryptoTransform cTransform = prov3des.CreateEncryptor();
resultArray = cTransform.TransformFinalBlock(streamToEncrypt, 0, streamToEncrypt.Length);
}
return resultArray;
}
}
在这里,我遇到了一个烦人的问题- 使用这两种方法的加密数组(结果加密缓冲区)不一样!每个数组的前 8 个字节(64 位)相同,但接下来的字节不同。这会导致使用两种方法对短字符串(最多 3 个字符)进行相同的加密,但较长的字符串会导致不同的加密数据。
如何强制这两种方法等效?那就是-以相同的方式加密和解密以使输出相同?我在这里想念什么?.NET 和本机 (Win32) API 之间的默认值\行为是否有变化?(我认为 Win32 Crypto API 中的默认 3DES 密码模式是 EBC,而使用 C# 的默认密码模式是 CBC - 如果我错了,请纠正我)。
谢谢!
暗里