将VB6调用advapi32.dll的RC4解密逻辑迁移至.NET的求助
问题描述
需要从遗留系统向第三方新系统迁移数据,部分加密数据需解密后供采用现代加密方案的新系统使用。遗留解密代码由VB6编写,调用advapi32.dll的Crypt系列API,采用PROV_RSA_FULL、SHA1及RC4算法。转换为C#代码时出现System.Security.Cryptography.CryptographicException: 待解密数据长度无效错误,无法正常运行。当前环境为Windows Server 2016,需在.NET中正确实现对应RC4解密逻辑,其他加密兼容性问题后续处理。
遗留VB6解密代码
'Const ENCRYPT_BLOCK_SIZE as Integer = 8 Dim hCSP As Long Dim strContexte As String Dim Password as String Dim lngPassword as Long Dim strEncrypted as String Dim lngEncrypted as Long Dim strBuffer as String Dim lngBuffer as Long Dim hHash as Long Dim lngRC as Long strContexte = "Some Context" Password = "SomeString" lngPassword = Len(Password) strEncrypted = "String to decrypt" lngEncrypted = Len(strEncrypted) lngBuffer = lngEncrypted + ENCRYPT_BLOCK_SIZE LSet strBuffer = strEncrypted lngRC = CryptAcquireContext(hCSP, strContext, "Microsoft Base Cryptographic Provider v1.0", PROV_RSA_FULL, CRYPT_MACHINE_KEYSET) If Not CBool(lngRC) Then If Err.LastDllError = NTE_BAD_KEYSET Then lngRC = CryptAcquireContext(hCSP, strContext, "Microsoft Base Cryptographic Provider v1.0", PROV_RSA_FULL, CRYPT_NEWKEYSET + CRYPT_MACHINE_KEYSET) End If lngRC = CryptCreateHash(hCSP, CALG_SHA1, 0, 0, hHash) lngRC = CryptHashData(hHash, Password, lngPassword, 0) lngRC = CryptDeriveKey(hCSP, CALG_RC4, hHash, 0, hHash) lngRC = CryptDecrypt(hHash, 0, 1, 0, strBuffer, lngBuffer)
当前错误的C#实现代码
string Password = "SomeString"; string info = "String to decrypt"; byte[] value = Convert.ToByte(info, 16); // 语法错误,且未匹配VB6字符串编码 long lngInfo = info.Length; long lngBuffer = lngInfo + 8; byte[] Buffer = new byte[lngBuffer]; value.CopyTo(Buffer, 0); byte[] key; using (PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, null)) { key = pdb.CryptDeriveKey("TripleDES", "SHA1", 0, new byte[8]); } byte[] decrypted; using (var prov = new TripleDESCryptoServiceProvider()) { using (var decryptor = prov.CreateDecryptor(key, new byte[8])) { decrypted = decryptor.TransformFinalBlock(Buffer, 0, lngBuffer); } }
问题分析与正确实现
核心错误点
- 原VB6使用RC4算法,但C#代码误用了TripleDES,完全偏离目标算法。
- 未匹配VB6字符串的UTF-16LE编码逻辑,加密数据的字节转换方式错误。
CryptDeriveKey的调用参数不匹配,RC4不需要IV,且密钥派生逻辑需对应SHA1+RC4的组合。
正确的C#实现
using System; using System.Security.Cryptography; using System.Text; public class Vb6Rc4Decryptor { public static string Decrypt(string encryptedData, string password, string context = "Some Context") { // 1. 将VB6加密字符串转换为字节数组(VB6默认UTF-16LE编码) byte[] encryptedBytes = Encoding.Unicode.GetBytes(encryptedData); // 2. 匹配CryptDeriveKey的密钥派生逻辑:用上下文作为盐,SHA1哈希派生RC4密钥 byte[] key; using (var pdb = new PasswordDeriveBytes(password, Encoding.Unicode.GetBytes(context))) { // RC4默认128位密钥,对应CryptDeriveKey的默认参数 key = pdb.CryptDeriveKey("RC4", "SHA1", 128, new byte[0]); } // 3. RC4解密(RC4无需IV) byte[] decryptedBytes; using (var rc4 = new RC4CryptoServiceProvider()) { using (var decryptor = rc4.CreateDecryptor(key, null)) { decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); } } // 4. 转换回字符串并移除VB6 LSet填充的空字符 return Encoding.Unicode.GetString(decryptedBytes).TrimEnd('\0'); } // 测试示例 public static void Main() { string testPassword = "SomeString"; string testEncrypted = "String to decrypt"; // 替换为实际加密数据 string result = Decrypt(testEncrypted, testPassword); Console.WriteLine("解密结果: " + result); } }
关键细节说明
- VB6的
CryptAcquireContext指定的strContext需作为盐值传入PasswordDeriveBytes,确保密钥派生逻辑与原代码完全一致。 - RC4算法不需要初始化向量(IV),因此
CreateDecryptor时IV参数传null。 - VB6字符串默认采用UTF-16LE编码,所有字符串与字节数组的转换必须使用
Encoding.Unicode。 - 解密后需调用
TrimEnd('\0')移除VB6中LSet语句填充的空字符。
内容的提问来源于stack exchange,提问作者JS Petit
相关产品推荐
相关产品推荐

