You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用System.Security.Cryptography加密速度过慢的优化咨询

加密操作导致性能瓶颈的优化方案

问题背景

实际业务应用运行缓慢,排查后确认是加密操作耗时过长。为复现问题,制作了一个仅含按钮的简单表单,加密Northwind数据库Orders表中的数据:

  • 本地环境下加密830条记录耗时约20秒,移除加密后耗时不足1秒
  • 尝试将加密函数嵌入表单而非调用外部类,速度无改善
  • 实际场景虽无需加密830次,但性能差异明显,且必须完成加密操作

原表单代码

Dim cTools As New cTools

Dim objConn As New SqlConnection(ConfigurationManager.ConnectionStrings("conNorth").ToString)
objConn.Open()

Dim s As String = ""
Dim sSQL As String = "SELECT  OrderID FROM Orders ORDER BY OrderID"
Dim objCmd As New SqlCommand(sSQL, objConn)
objCmd.CommandType = CommandType.Text

Dim objRdr As SqlDataReader
objRdr = objCmd.ExecuteReader
Dim dtStart As Date = System.DateTime.Now

Response.Write("<br>Before With Encrypt " & System.DateTime.Now & "<br>")

Do While objRdr.Read()
    s = cTools.Encrypt(objRdr("OrderID"))
Loop

Dim dtEnd As Date = System.DateTime.Now

Response.Write("After With Encrypt " & System.DateTime.Now & "<br>")
Response.Write("Duration With Encrypt " & DateDiff(DateInterval.Second, dtStart, dtEnd) & "<br>")

objRdr.Close()

objConn.Close()
objConn.Dispose()

原加密类代码

Imports System.IO
Imports System.Security.Cryptography

Public Class cTools
    Public Function Encrypt(clearText As String) As String
        Dim EncryptionKey As String = "MAKV2SPBNI99212"
        Dim clearBytes As Byte() = Encoding.Unicode.GetBytes(clearText)
        Using encryptor As Aes = Aes.Create()
            Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D,
         &H65, &H64, &H76, &H65, &H64, &H65,
         &H76})
            encryptor.Key = pdb.GetBytes(32)
            encryptor.IV = pdb.GetBytes(16)
            Using ms As New MemoryStream()
                Using cs As New CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)
                    cs.Write(clearBytes, 0, clearBytes.Length)
                    cs.Close()
                End Using
                clearText = Convert.ToBase64String(ms.ToArray())
            End Using
        End Using
        Return clearText
    End Function
    Public Function Decrypt(cipherText As String) As String
        Dim EncryptionKey As String = "MAKV2SPBNI99212"
        cipherText = cipherText.Replace(" ", "+")
        Dim cipherBytes As Byte() = Convert.FromBase64String(cipherText)
        Using encryptor As Aes = Aes.Create()
            Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D,
             &H65, &H64, &H76, &H65, &H64, &H65,
             &H76})
            encryptor.Key = pdb.GetBytes(32)
            encryptor.IV = pdb.GetBytes(16)
            Using ms As New MemoryStream()
                Using cs As New CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)
                    cs.Write(cipherBytes, 0, cipherBytes.Length)
                    cs.Close()
                End Using
                cipherText = Encoding.Unicode.GetString(ms.ToArray())
            End Using
        End Using
        Return cipherText
    End Function
End Class

优化方案

1. 预计算密钥和IV,避免重复推导

Rfc2898DeriveBytes(PBKDF2)是计算密集型操作,每次加密都重新推导密钥和IV是核心性能浪费点。可以在类初始化时一次性计算完成,后续加密直接复用:

修改后的cTools类:

Imports System.IO
Imports System.Security.Cryptography

Public Class cTools
    Private ReadOnly _aesKey As Byte()
    Private ReadOnly _aesIV As Byte()
    Private Const EncryptionKey As String = "MAKV2SPBNI99212"
    Private ReadOnly _salt As Byte() = New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D, &H65, &H64, &H76, &H65, &H64, &H65, &H76}

    Public Sub New()
        ' 初始化时一次性推导密钥和IV
        Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, _salt)
        _aesKey = pdb.GetBytes(32)
        _aesIV = pdb.GetBytes(16)
    End Sub

    Public Function Encrypt(clearText As String) As String
        Dim clearBytes As Byte() = Encoding.Unicode.GetBytes(clearText)
        Using encryptor As Aes = Aes.Create()
            encryptor.Key = _aesKey
            encryptor.IV = _aesIV
            Using ms As New MemoryStream()
                Using cs As New CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)
                    cs.Write(clearBytes, 0, clearBytes.Length)
                    cs.FlushFinalBlock() ' 替代Close,更安全且性能更优
                End Using
                clearText = Convert.ToBase64String(ms.ToArray())
            End Using
        End Using
        Return clearText
    End Function

    Public Function Decrypt(cipherText As String) As String
        cipherText = cipherText.Replace(" ", "+")
        Dim cipherBytes As Byte() = Convert.FromBase64String(cipherText)
        Using encryptor As Aes = Aes.Create()
            encryptor.Key = _aesKey
            encryptor.IV = _aesIV
            Using ms As New MemoryStream()
                Using cs As New CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)
                    cs.Write(cipherBytes, 0, cipherBytes.Length)
                    cs.FlushFinalBlock()
                End Using
                cipherText = Encoding.Unicode.GetString(ms.ToArray())
            End Using
        End Using
        Return cipherText
    End Function
End Class

2. 复用AES实例(单线程场景可选)

单线程环境下,可以复用AES实例减少对象创建开销,进一步提升性能:

' 在cTools类中添加
Private ReadOnly _aes As Aes

Public Sub New()
    Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, _salt)
    _aesKey = pdb.GetBytes(32)
    _aesIV = pdb.GetBytes(16)
    _aes = Aes.Create()
    _aes.Key = _aesKey
    _aes.IV = _aesIV
End Sub

' 修改Encrypt方法,直接复用_aes实例
Public Function Encrypt(clearText As String) As String
    Dim clearBytes As Byte() = Encoding.Unicode.GetBytes(clearText)
    Using ms As New MemoryStream()
        Using cs As New CryptoStream(ms, _aes.CreateEncryptor(), CryptoStreamMode.Write)
            cs.Write(clearBytes, 0, clearBytes.Length)
            cs.FlushFinalBlock()
        End Using
        clearText = Convert.ToBase64String(ms.ToArray())
    End Using
    Return clearText
End Function

注意:Aes实例不是线程安全的,多线程场景下不要复用,保持每个方法创建实例+预计算密钥的方案即可。

3. 批量读取数据优化流程

原代码逐条读取数据库记录,可一次性将所有数据加载到内存后再加密,减少数据库连接持有时间:

修改后的表单代码:

Dim cTools As New cTools

Dim objConn As New SqlConnection(ConfigurationManager.ConnectionStrings("conNorth").ToString)
objConn.Open()

Dim sSQL As String = "SELECT  OrderID FROM Orders ORDER BY OrderID"
Dim objCmd As New SqlCommand(sSQL, objConn)
objCmd.CommandType = CommandType.Text

' 一次性读取所有数据到DataTable
Dim dt As New DataTable()
dt.Load(objCmd.ExecuteReader())

Dim dtStart As Date = System.DateTime.Now
Response.Write("<br>Before With Encrypt " & System.DateTime.Now & "<br>")

' 批量加密
For Each row As DataRow In dt.Rows
    Dim s = cTools.Encrypt(row("OrderID").ToString())
Next

Dim dtEnd As Date = System.DateTime.Now
Response.Write("After With Encrypt " & System.DateTime.Now & "<br>")
Response.Write("Duration With Encrypt " & DateDiff(DateInterval.Second, dtStart, dtEnd) & "<br>")

objConn.Close()
objConn.Dispose()

4. 异步并行加密(Web场景适用)

Web应用中可使用异步+并行加密,避免阻塞主线程,提升用户体验:

' 按钮点击事件改为异步处理
Async Sub YourButton_Click(sender As Object, e As EventArgs) Handles YourButton.Click
    Dim cTools As New cTools
    Dim objConn As New SqlConnection(ConfigurationManager.ConnectionStrings("conNorth").ToString)
    Await objConn.OpenAsync()

    Dim sSQL As String = "SELECT  OrderID FROM Orders ORDER BY OrderID"
    Dim objCmd As New SqlCommand(sSQL, objConn)
    objCmd.CommandType = CommandType.Text

    Dim dt As New DataTable()
    dt.Load(Await objCmd.ExecuteReaderAsync())

    Dim dtStart As Date = System.DateTime.Now
    Response.Write("<br>Before With Encrypt " & System.DateTime.Now & "<br>")

    ' 并行加密(预计算密钥的方案线程安全,可放心使用)
    Await Task.WhenAll(dt.AsEnumerable().Select(Async row => 
        Dim s = cTools.Encrypt(row("OrderID").ToString())
        ' 此处可处理加密后的数据(如写入数据库)
    ))

    Dim dtEnd As Date = System.DateTime.Now
    Response.Write("After With Encrypt " & System.DateTime.Now & "<br>")
    Response.Write("Duration With Encrypt " & DateDiff(DateInterval.Second, dtStart, dtEnd) & "<br>")

    objConn.Close()
    objConn.Dispose()
End Sub

内容的提问来源于stack exchange,提问作者Corobori

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 11:17:58