我被赋予了一个任务,放弃我们的产品的DLL之一,并用一个纯粹的C#replace它。 旧的DLL是.NET 2.0托pipeC ++(C ++ CLI),它将对Win32本地Crypto API的调用进行封装。 新的DLL应该公开一个具有相同名称和方法的新对象,但应该用C#(.NET 4.0)编写。 当然,新的DLL应该像旧的一样encryption(和解密),否则,所有保存在一个持久性存储器,如数据库或文件中的encryption密码将不会被解决!
这是本机(Win32)API调用的(伪)代码(注意input总是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,PROV_DH_SCHANNEL,CRYPT_MACHINE_KEYSET | CRYPT_VERIFYCONTEXT); CryptCreateHash( m_provider,CALG_SHA1,&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(),TRUE,buffer_to_encrypt,&dwFilled,(DWORD)total ); return buffer_to_encrypt;
现在,我正在尝试使用C#(System.Security.Cryptography命名空间)和.NET API公开的新Crypto对象编写相同的过程:
class Encryptor { private static byte[] password = { 0xF1,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,streamToEncrypt.Length); } return resultArray; } }
在这里,我正面临一个烦人的问题 – encryption数组(结果encryption的缓冲区)是不一样的使用两种方法! 每个arrays的前8个字节(64位)是相同的,但接下来的字节不是。 这会导致使用两种方法对短string(最多3个字符)进行相同的encryption,但更长的string会导致不同的encryption数据。
如何获得服务器上打开的HTTP连接的总数?
错误“目录不是空的。”当目录是empy时
在Windowslogin屏幕中在后台C#WinForms应用程序中进行networking连接期间出现DNS错误
如何使用Windows应用程序在第三方网站上填写和提交Web表单?
有没有办法来检查用户是否有特定的权利?
我怎样才能强制这两种方法是等价的? 那就是 – 以相同的方式encryption和解密,以便输出相同? 我在这里错过了什么? .NET和Native(Win32)API之间的默认值行为是否有变化? (我认为Win32 Crypto API中的默认3DES密码模式是EBC,而使用C#的默认密码是CBC – 如果我错了,请纠正我的错误)。
谢谢!
奥马里
设置Form.KeyPreview = true的缺点?
ItemDataBound为Windows窗体DataGridView?
无法连接到ABB Freelance OPC服务器
Process.GetCurrentProcess()。MainWindowHandle返回零
根据CryptDeriveKey的MSDN页面,似乎3DES的默认密码模式不是EBC,而是CBC – “当为对称分组密码生成密钥时,默认密钥在密码块链接(CBC)模式下设置,初始化向量为零,这种加密模式为批量加密数据提供了一个很好的默认方法,要改变这些参数,使用CryptSetKeyParam函数。 .Net TripleDES提供程序的默认模式也是CBC。 尝试删除您设置到EBC的行,看看是否有帮助。
这里的重要注意事项,您将需要知道初始化向量能够成功解密。 CryptDeriveKey函数将默认使用零IV,这意味着为了在纯粹的C#代码中有一个匹配,您需要确保您也使用零IV。
只需发布正确的C#代码以备将来参考,请注意设置IV&CBC模式的更改:
class Encryptor{ private static byte[] password = { 0xF1,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.CBC; prov3des.Padding = PaddingMode.PKCS7; prov3des.IV = new byte[]{0,0}; //8 bytes,zero-ed using (PasswordDeriveBytes pdb = new PasswordDeriveBytes(password,prov3des.IV); } ICryptoTransform cTransform = prov3des.CreateEncryptor(); resultArray = cTransform.TransformFinalBlock(streamToEncrypt,streamToEncrypt.Length); } return resultArray; }
}
非常感谢“pstrjds”! 加密解密结果现在是相同的=>方法是相同的:-)
奥马里
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。