VB加密解密实战:从CryptoAPI调用到核心源码剖析

发布时间:2026/7/29 8:56:25
VB加密解密实战:从CryptoAPI调用到核心源码剖析 1. 项目概述为什么今天还要聊VB加密“Visual Basic加密解密实战源码剖析”这个标题乍一看可能会让很多新入行的开发者感到困惑。Visual Basic那不是上个世纪的古董语言吗现在谁还用VB做加密啊确实在Python、Go、Java等现代语言大行其道的今天VB尤其是经典的VB6早已不是技术主流。但恰恰是这种“非主流”让这个项目具备了独特的教学和实践价值。我之所以想深入聊聊这个话题是因为加密解密本身是计算机安全领域的基石其核心思想——对称加密、非对称加密、哈希算法、密钥管理——是跨语言、跨时代的。而VB以其极致的简单性和直观的可视化界面成为了理解这些复杂概念的绝佳“教学模具”。当你用VB写一个加密程序时你不得不关注每一个字节的流动每一个API的调用这比在高级语言中调用一个现成的crypto库要深刻得多。这个过程能让你真正明白一个AES加密函数内部到底在做什么一个RSA密钥对是如何生成的而不是仅仅成为一个“调包侠”。此外仍有大量的遗留系统、工业控制软件或特定行业应用是基于VB包括VB6和VB.NET开发的。为这些系统增加或维护数据安全模块是真实存在的需求。因此掌握如何在VB环境下实现安全的加密解密不仅是一次怀旧的技术考古更是一项具有现实意义的技能。本文将从一个老程序员的角度带你手把手剖析VB实现加密解密的完整流程、核心源码与那些教科书上不会写的“坑”。2. 核心思路与方案选型在VB的“枷锁”中跳舞在VB中实现加密首先面临的就是环境与能力的限制。VB6没有内置的强加密库.NET Framework中的System.Security.Cryptography命名空间虽然强大但在VB.NET中直接使用也需要理解其背后的原理。我们的核心思路是利用Windows系统底层提供的加密APICryptoAPI/CNG或实现经典的加密算法。2.1 方案对比与选型理由面对VB的加密需求通常有以下几个路径调用Windows CryptoAPI这是最正统、兼容性最好的方式。CryptoAPI是微软提供的一套加密接口从Windows 95时代就存在VB6可以通过API声明直接调用。它支持DES、3DES、AESRijndael、RSA等主流算法并且密钥管理、证书存储等都由系统负责相对安全。使用第三方ActiveX控件或COM组件市面上有一些封装好的加密控件通过简单的属性设置和方法调用就能完成加密。优点是快速缺点是黑盒化、可能有许可费用、且存在依赖。纯VB代码实现算法自己用VB代码重写AES、DES、MD5等算法。这无疑是最有挑战性也最能学到东西的方式。但对于生产环境除非你是密码学专家否则极易因实现不当引入安全漏洞如侧信道攻击。在VB.NET中使用.NET Cryptography库如果项目是VB.NET那么这是首选。AesCryptoServiceProvider、RSACryptoServiceProvider等类功能完善是托管代码中的标准做法。为什么我们选择“调用CryptoAPI”作为主线进行剖析因为它最具代表性。它连接了古老的VB6和现代的加密理念整个过程涉及API声明、字节数组操作、内存管理、错误处理等VB编程的核心难点。理解了它你不仅能学会加密更能深刻理解VB与操作系统交互的本质。这对于维护遗留代码或深化Windows编程理解至关重要。2.2 整体架构设计一个健壮的VB加密模块无论采用哪种方案都应遵循以下架构层次用户界面层简单的文本框输入明文/密文按钮触发加密/解密操作。VB的强项正在于此用TextBox和CommandButton快速搭建。业务逻辑层协调整个流程。包括获取用户输入、选择算法和密钥、调用核心加密函数、处理返回结果如将字节数组转换为Base64字符串以便显示和传输。加密核心层这是我们剖析的重点。它封装了与CryptoAPI交互的所有细节创建加密上下文(CryptAcquireContext)、生成或导入密钥(CryptGenKey/CryptImportKey)、执行加密解密(CryptEncrypt/CryptDecrypt)、以及最后的清理工作。数据表示层负责在VB的字符串、字节数组与CryptoAPI所需的字节流之间进行转换。这里涉及到VB令人头疼的字符串编码问题ANSI vs Unicode。这个架构确保了功能的模块化即使未来想替换核心的实现方式比如改用.NET库其他层也能保持相对稳定。3. 核心细节解析与CryptoAPI的“握手”直接调用Windows API是VB进阶的必经之路也是很多新手望而生畏的地方。加密相关的API尤其如此因为它涉及大量二进制数据和复杂的数据结构。3.1 API声明与常量定义第一步是在VB模块中正确声明要使用的CryptoAPI函数、结构和常量。一个错误的声明会导致调用失败甚至程序崩溃。‘ 在模块顶部声明 Option Explicit ‘ 常量声明 Public Const PROV_RSA_FULL As Long 1 Public Const CALG_RC4 As Long H6801 ‘ 这里以RC4流加密为例实际可根据需要改为CALG_AES_128等 Public Const CRYPT_EXPORTABLE As Long H1 Public Const KP_MODE As Long 4 Public Const CRYPT_MODE_CBC As Long 1 ‘ 使用CBC模式 ‘ 关键API函数声明 Public Declare Function CryptAcquireContext Lib “advapi32.dll” Alias “CryptAcquireContextA” _ (ByRef phProv As Long, ByVal pszContainer As String, ByVal pszProvider As String, _ ByVal dwProvType As Long, ByVal dwFlags As Long) As Long Public Declare Function CryptCreateHash Lib “advapi32.dll” _ (ByVal hProv As Long, ByVal Algid As Long, ByVal hKey As Long, ByVal dwFlags As Long, _ ByRef phHash As Long) As Long Public Declare Function CryptHashData Lib “advapi32.dll” _ (ByVal hHash As Long, ByVal pbData As String, ByVal dwDataLen As Long, ByVal dwFlags As Long) As Long Public Declare Function CryptDeriveKey Lib “advapi32.dll” _ (ByVal hProv As Long, ByVal Algid As Long, ByVal hBaseData As Long, ByVal dwFlags As Long, _ ByRef phKey As Long) As Long Public Declare Function CryptEncrypt Lib “advapi32.dll” _ (ByVal hKey As Long, ByVal hHash As Long, ByVal Final As Long, ByVal dwFlags As Long, _ ByVal pbData As String, ByRef pdwDataLen As Long, ByVal dwBufLen As Long) As Long Public Declare Function CryptDecrypt Lib “advapi32.dll” _ (ByVal hKey As Long, ByVal hHash As Long, ByVal Final As Long, ByVal dwFlags As Long, _ ByVal pbData As String, ByRef pdwDataLen As Long) As Long ‘ … 其他如CryptDestroyKey, CryptReleaseContext等清理函数声明省略注意这里使用的是Declare Function和Alias “CryptAcquireContextA”这表示我们调用的是ANSI版本的API。在VB6中字符串默认是BSTR一种Unicode字符串但很多老API需要ANSI字符串。使用Alias “A”版本并传递String类型VB会自动进行Unicode到ANSI的转换。这是一个非常重要的细节处理不当会导致乱码或失败。3.2 密钥管理与派生安全的加密密钥是根本。在示例中我们通常从一个密码口令派生出一个加密密钥而不是直接使用密码本身。这需要使用哈希函数。创建哈希对象使用CryptCreateHash指定算法如CALG_MD5。哈希密码数据使用CryptHashData将用户输入的密码字符串需转换为ANSI添加到哈希对象中。派生密钥使用CryptDeriveKey从刚才生成的哈希值派生出指定算法如CALG_RC4或CALG_AES_128的密钥。这个过程确保了即使密码简单派生出的密钥也具有密码学强度并且相同的密码总是派生出相同的密钥用于解密。但请注意单纯使用MD5等哈希从口令派生密钥在现代标准下已不够安全更佳实践是使用PBKDF2等密钥派生函数但在纯VB6CryptoAPI环境下实现较复杂。3.3 加密解密的数据缓冲区管理这是整个过程中最容易出错的地方。CryptEncrypt函数有一个关键特性它可能增大数据。为什么因为块加密算法如AES、DES需要填充Padding以使数据长度符合块大小的整数倍。例如AES-128的块大小是16字节。你加密一个15字节的数据加密后会变成16字节填充了1个字节。你加密一个16字节的数据加密后会变成32字节因为需要填充一个完整的块来标识结束具体取决于填充模式。如何应对第一次调用CryptEncrypt时将pbData参数设为vbNullStringpdwDataLen参数传入一个变量如lngDataLen函数会在这个变量中返回所需的缓冲区大小。根据返回的大小重新分配一个足够大的字符串缓冲区。将你的明文数据拷贝到这个缓冲区的前部。第二次调用CryptEncrypt传入这个缓冲区并再次传入缓冲区长度此时是实际分配的大小。函数会执行加密并更新pdwDataLen为加密后的实际数据长度。解密时CryptDecrypt会处理填充的移除所以解密后的数据长度会小于或等于密文长度。你需要根据pdwDataLen返回的实际长度来截取有效数据。‘ 伪代码示意加密过程 Dim lngPlainLen As Long, lngBufLen As Long Dim strBuffer As String lngPlainLen Len(strPlainText) lngBufLen lngPlainLen ‘ 第一次调用获取所需缓冲区大小 If CryptEncrypt(hKey, 0, 1, 0, vbNullString, lngBufLen, 0) 0 Then ‘ 错误处理 End If ‘ 分配缓冲区 strBuffer String$(lngBufLen, Chr$(0)) ‘ 将明文拷贝到缓冲区 Mid$(strBuffer, 1) strPlainText lngPlainLen lngBufLen ‘ 注意此时lngPlainLen被用作输入长度参数 ‘ 第二次调用真正加密 If CryptEncrypt(hKey, 0, 1, 0, strBuffer, lngPlainLen, lngBufLen) 0 Then ‘ 错误处理 End If ‘ 此时strBuffer的前lngPlainLen字节就是密文 strCipherText Left$(strBuffer, lngPlainLen)4. 完整实战流程从零构建一个VB加密工具让我们抛开理论动手构建一个简单的、支持口令加密的文本加密器。我们将使用CryptoAPI和RC4算法因其是流加密无需处理填充简化初次理解。4.1 第一步创建项目与界面打开VB6新建一个“标准EXE”工程。在默认的Form1上添加以下控件TextBox命名为txtPassword用于输入密码。将PasswordChar属性设为*。TextBox命名为txtInputMultiLine设为True用于输入明文或密文。TextBox命名为txtOutputMultiLine设为TrueLocked设为True用于显示结果。CommandButton命名为cmdEncryptCaption设为“加密”。CommandButton命名为cmdDecryptCaption设为“解密”。添加一个模块Module1.bas将上一节中所有的API声明、常量定义和核心函数代码粘贴进去。4.2 第二步编写核心加密函数在模块中我们编写一个可重用的加密/解密函数。由于RC4是对称算法加密和解密是同一个过程。Public Function SimpleRC4Crypt(ByVal strInput As String, ByVal strPassword As String, ByVal fEncrypt As Boolean) As String Dim hProv As Long, hHash As Long, hKey As Long Dim lngResult As Long Dim strBuffer As String Dim lngDataLen As Long ‘ 1. 获取加密服务上下文 If CryptAcquireContext(hProv, vbNullString, vbNullString, PROV_RSA_FULL, 0) 0 Then ‘ 尝试创建新的密钥容器 If CryptAcquireContext(hProv, vbNullString, vbNullString, PROV_RSA_FULL, CRYPT_NEWKEYSET) 0 Then MsgBox “无法获取加密上下文” vbCritical Exit Function End If End If On Error GoTo ErrorHandler ‘ 确保发生错误时能释放资源 ‘ 2. 创建哈希对象 If CryptCreateHash(hProv, CALG_MD5, 0, 0, hHash) 0 Then GoTo ErrorHandler ‘ 3. 将密码加入哈希 ‘ 注意CryptoAPI的ANSI版本需要ANSI字符串。VB的String是Unicode直接传递会导致问题。 ‘ 一种简单转换使用StrConv(strPassword, vbFromUnicode)但更严谨的做法是操作字节数组。 ‘ 此处为简化假设密码是ASCII字符直接传递。 If CryptHashData(hHash, strPassword, Len(strPassword), 0) 0 Then GoTo ErrorHandler ‘ 4. 从哈希派生密钥 If CryptDeriveKey(hProv, CALG_RC4, hHash, CRYPT_EXPORTABLE, hKey) 0 Then GoTo ErrorHandler ‘ 5. 准备数据缓冲区 lngDataLen Len(strInput) strBuffer strInput ‘ 复制输入数据 ‘ 6. 执行加密或解密RC4加密解密是同一操作 If fEncrypt Then lngResult CryptEncrypt(hKey, 0, 1, 0, strBuffer, lngDataLen, Len(strBuffer)) Else lngResult CryptDecrypt(hKey, 0, 1, 0, strBuffer, lngDataLen) End If If lngResult 0 Then GoTo ErrorHandler ‘ 7. 返回结果 SimpleRC4Crypt Left$(strBuffer, lngDataLen) ErrorHandler: ‘ 8. 逆序清理所有句柄 If hKey 0 Then CryptDestroyKey hKey If hHash 0 Then CryptDestroyHash hHash If hProv 0 Then CryptReleaseContext hProv, 0 If Err.Number 0 Then ‘ 可以记录错误信息 Err.Number, Err.Description SimpleRC4Crypt “” End If End Function4.3 第三步连接界面与逻辑回到Form1为两个按钮编写点击事件。Private Sub cmdEncrypt_Click() Dim strPassword As String, strInput As String, strOutput As String strPassword Trim$(txtPassword.Text) strInput txtInput.Text If strPassword “” Then MsgBox “请输入密码” vbExclamation Exit Sub End If strOutput SimpleRC4Crypt(strInput, strPassword, True) If strOutput “” Then txtOutput.Text strOutput ‘ 通常我们会将二进制密文转换为Base64以便于文本显示和传输 ‘ 这里为了直观直接显示可能包含不可见字符 Else txtOutput.Text “加密失败” End If End Sub Private Sub cmdDecrypt_Click() Dim strPassword As String, strInput As String, strOutput As String strPassword Trim$(txtPassword.Text) strInput txtInput.Text ‘ 这里输入的是密文 If strPassword “” Then MsgBox “请输入密码” vbExclamation Exit Sub End If strOutput SimpleRC4Crypt(strInput, strPassword, False) If strOutput “” Then txtOutput.Text strOutput Else txtOutput.Text “解密失败密码错误或数据损坏。” End If End Sub4.4 第四步测试与验证运行程序F5。在密码框输入一个密码如“MySecret”。在上方文本框输入一段明文如“Hello, VB Crypto World!”。点击“加密”下方文本框会显示一堆乱码密文。点击“解密”下方文本框应该能正确恢复出“Hello, VB Crypto World!”。恭喜你已经完成了一个最基础的VB加密工具但这仅仅是开始它存在很多问题比如密码编码、错误处理粗糙、结果不是文本友好格式而这正是我们接下来要优化的。5. 进阶优化与关键问题剖析一个玩具级的加密模块和工业级可用的模块之间隔着无数个细节。下面我们来逐一攻克。5.1 编码问题的终极解决方案前面提到密码字符串的传递存在编码问题。CryptHashData期望的是字节序列。如果密码包含中文或特殊字符直接传递String会导致错误。正确的做法是使用字节数组Byte Array。我们需要修改SimpleRC4Crypt函数中哈希密码的部分‘ … 省略其他代码 … ‘ 3. 将密码加入哈希 (修正版) Dim abytPassword() As Byte ‘ 将Unicode密码转换为ANSI字节数组。注意这会丢失非ANSI字符信息。 ‘ 更健壮的做法是使用UTF-8转换但这需要额外的辅助函数或使用VB.NET。 abytPassword StrConv(strPassword, vbFromUnicode) If CryptHashData(hHash, abytPassword(0), UBound(abytPassword) 1, 0) 0 Then GoTo ErrorHandler ‘ … 省略其他代码 …同时输入输出数据也可能不是纯文本。为了通用性我们的函数应该处理字节数组而不是字符串。但为了接口友好可以提供字符串版本内部转换和字节数组版本。5.2 实现更安全的算法与模式以AES-CBC为例RC4已被证明是不安全的应避免用于新系统。让我们将核心算法升级到AES-256-CBC。这涉及到更多细节更改算法常量使用CALG_AES_256H6610。处理初始化向量IVCBC模式需要IV。IV应该是随机且不可预测的每次加密都应不同但需要和密文一起保存以供解密。处理填充AES是块加密必须处理填充。CryptoAPI默认使用PKCS#7填充。我们需要重写核心函数使其能够生成随机IV并将IV预置在密文之前一种常见做法。解密时先从密文头部提取IV。Public Function AES256EncryptData(abytPlain() As Byte, strPassword As String) As Byte() ‘ 返回的字节数组结构IV (16字节) 密文 Dim hProv As Long, hHash As Long, hKey As Long Dim abytIV(0 To 15) As Byte ‘ AES块大小是16字节 Dim abytCipher() As Byte Dim lngPlainLen As Long, lngBufLen As Long Dim i As Long ‘ 1. 获取上下文、创建哈希、派生密钥略同前 ‘ 2. 生成随机IV If CryptGenRandom(hProv, 16, abytIV(0)) 0 Then GoTo ErrorHandler ‘ 3. 设置密钥的CBC模式和IV If CryptSetKeyParam(hKey, KP_MODE, CRYPT_MODE_CBC, 0) 0 Then GoTo ErrorHandler If CryptSetKeyParam(hKey, KP_IV, abytIV(0), 0) 0 Then GoTo ErrorHandler ‘ 4. 计算加密后所需缓冲区大小 lngPlainLen UBound(abytPlain) 1 lngBufLen lngPlainLen If CryptEncrypt(hKey, 0, 1, 0, ByVal 0, lngBufLen, 0) 0 Then GoTo ErrorHandler ‘ 5. 准备缓冲区IV 密文 ReDim abytCipher(0 To 15 lngBufLen - 1) ‘ 前16字节放IV For i 0 To 15 abytCipher(i) abytIV(i) Next i ‘ 将明文数据拷贝到缓冲区IV之后的部分 For i 0 To lngPlainLen - 1 abytCipher(16 i) abytPlain(i) Next i ‘ 6. 执行加密 lngPlainLen lngBufLen ‘ 注意这个技巧lngPlainLen现在代表“待加密数据长度” If CryptEncrypt(hKey, 0, 1, 0, abytCipher(16), lngPlainLen, lngBufLen) 0 Then GoTo ErrorHandler ‘ 7. 调整数组大小为实际大小IV长度 密文长度 ReDim Preserve abytCipher(0 To 15 lngPlainLen - 1) AES256EncryptData abytCipher ErrorHandler: ‘ 清理代码略 End Function解密函数则需要先拆分出IV然后设置密钥模式和IV最后解密。5.3 错误处理与日志记录生产代码绝不能仅仅用MsgBox或静默失败。我们需要一个完善的错误处理机制。使用GetLastErrorAPI当CryptoAPI函数返回0失败时可以调用GetLastError获取详细的系统错误码。错误码转换编写一个函数将错误码转换为可读的描述。可以通过FormatMessageAPI实现。日志记录将错误信息、操作时间等记录到文件或事件查看器便于排查问题。Private Declare Function GetLastError Lib “kernel32” () As Long Private Declare Function FormatMessage Lib “kernel32” Alias “FormatMessageA” _ (ByVal dwFlags As Long, ByVal lpSource As Long, ByVal dwMessageId As Long, _ ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, _ ByVal Arguments As Long) As Long Public Function GetCryptoAPIErrorText(ByVal lngErrorCode As Long) As String Const FORMAT_MESSAGE_FROM_SYSTEM H1000 Dim strBuffer As String Dim lngLength As Long strBuffer String$(256, Chr$(0)) lngLength FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, lngErrorCode, 0, strBuffer, Len(strBuffer), 0) If lngLength 0 Then GetCryptoAPIErrorText Left$(strBuffer, lngLength) Else GetCryptoAPIErrorText “未知错误” CStr(lngErrorCode) End If End Function在错误处理标签ErrorHandler中可以这样使用If hKey 0 Then CryptDestroyKey hKey ‘ … 其他清理 … If Err.Number 0 Then LogError “SimpleRC4Crypt函数内部错误” Err.Description ElseIf lngResult 0 Then ‘ API调用失败 Dim lngErr As Long lngErr GetLastError() LogError “CryptoAPI调用失败” GetCryptoAPIErrorText(lngErr) End If6. 常见陷阱与实战排坑指南在VB中玩加密踩坑是家常便饭。下面是我多年总结的一些典型问题和解决方法。6.1 数据对齐与缓冲区溢出这是最隐蔽的Bug来源之一。Windows API特别是涉及内存操作的对数据对齐很敏感。在VB中如果你直接传递一个字节数组的某个元素地址如abytData(0)需要确保这个数组在内存中是连续且对齐的。使用ReDim声明的动态数组通常是安全的。但如果你操作的是结构体问题就复杂了。避坑技巧对于复杂的API调用尽量使用动态字节数组作为中间缓冲区。避免直接传递自定义Type变量的地址除非你完全了解其内存布局并使用了LenB和VarPtr等危险操作。6.2 字符串与字节数组的转换黑洞VB6的字符串是BSTR以双字节Unicode存储。而加密操作本质是面向字节的。StrConv函数是你的朋友但也是陷阱。vbFromUnicode将Unicode字符串转换为当前系统代码页的ANSI字节数组。如果字符串包含当前代码页无法表示的字符如中文在英文系统上信息会丢失。vbUnicode将字节数组解释为Unicode字符序列。如果你把一个加密后的字节数组本质是随机字节用这个转换得到的是乱码并且可能包含字符串结束符Chr$(0)导致字符串被意外截断。解决方案对于需要保持数据完整性的场景如加密后的密文、哈希值永远不要使用String类型作为内部处理类型始终使用字节数组Byte()。仅在最终需要显示或传输时将字节数组转换为Base64或Hex字符串。‘ 字节数组转Base64需要自己实现或借助第三方控件 Function BytesToBase64(abytData() As Byte) As String ‘ 实现略可使用MSXML的DOMDocument或第三方代码 End Function ‘ Base64转字节数组 Function Base64ToBytes(ByVal strBase64 As String) As Byte() ‘ 实现略 End Function6.3 密钥管理不当我们示例中从口令派生密钥的方式非常初级。在实际项目中不要硬编码密钥任何写在源码里的密钥都不是秘密。使用强密钥派生函数如果必须从口令派生应使用PBKDF2、bcrypt或scrypt并加入盐值Salt。在纯VB6中实现这些有难度可以考虑封装一个小的、经过审计的C DLL来提供这些功能。考虑使用Windows证书存储对于高安全需求可以使用CryptoAPI将非对称密钥对RSA存储在受保护的Windows证书存储区中这是更专业和安全的做法。6.4 算法与模式的选择弃用弱算法绝对不要使用DES、RC2、RC4、MD5、SHA1进行新的加密或完整性验证。使用AES128/256、SHA256/384/512。理解模式ECB模式是不安全的它会暴露明文中的重复模式。始终使用CBC需要IV、CTR或GCM认证加密模式。GCM模式在CryptoAPI中可能支持有限在.NET中更易用。认证很重要加密只能保证机密性不能保证完整性。攻击者可能篡改密文。对于重要数据应使用HMAC或选择像GCM这样的认证加密模式。6.5 资源泄露每一个通过CryptAcquireContext、CryptCreateHash、CryptGenKey等函数获得的句柄hProvhHashhKey都必须有对应的释放函数CryptReleaseContextCryptDestroyHashCryptDestroyKey来释放。VB不会自动帮你做这些。务必在错误处理路径和正常路径上都确保释放并且通常按创建顺序的逆序释放。7. 从VB6到VB.NET的迁移与升级如果你的项目有机会升级到VB.NET那么加密解密将变得简单而强大。.NET Framework提供了System.Security.Cryptography命名空间。以下是一个VB.NET中使用AES-256-CBC加密的示例其简洁性和安全性远超VB6的API调用Imports System.Security.Cryptography Imports System.Text Public Class CryptoHelper Public Shared Function EncryptStringToBytes_Aes(ByVal plainText As String, ByVal Key() As Byte, ByVal IV() As Byte) As Byte() Using aesAlg As Aes Aes.Create() aesAlg.Key Key aesAlg.IV IV Dim encryptor As ICryptoTransform aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV) Using msEncrypt As New IO.MemoryStream() Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write) Using swEncrypt As New IO.StreamWriter(csEncrypt) swEncrypt.Write(plainText) End Using Return msEncrypt.ToArray() End Using End Using End Using End Function Public Shared Function DecryptStringFromBytes_Aes(ByVal cipherText() As Byte, ByVal Key() As Byte, ByVal IV() As Byte) As String Using aesAlg As Aes Aes.Create() aesAlg.Key Key aesAlg.IV IV Dim decryptor As ICryptoTransform aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV) Using msDecrypt As New IO.MemoryStream(cipherText) Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read) Using srDecrypt As New IO.StreamReader(csDecrypt) Return srDecrypt.ReadToEnd() End Using End Using End Using End Using End Function End Class在VB.NET中密钥派生可以使用Rfc2898DeriveBytesPBKDF2内存管理和资源释放由Using语句自动处理代码的可读性和安全性都得到了质的飞跃。因此对于新项目或重大重构强烈建议迁移到.NET平台。回过头看在VB6中折腾加密就像用手工工具打造精密仪器过程繁琐但能让你对每一个齿轮和螺丝都有深刻的理解。这种理解在你日后使用更高级的工具时会转化为一种笃定和洞察力。你知道在那一行简单的Aes.Create().Encrypt()背后大概发生着什么样的数据流动和数学变换。这份底层的认知或许就是这个“过时”项目留给我们的最大财富。