VB.NET显示文件解密的进度?

时间:2016-01-01 06:43:55

标签: vb.net encryption

我正在使用此代码加密/解密文件:

Public Shared Sub encryptordecryptfile(ByVal strinputfile As String, _
                                         ByVal stroutputfile As String, _
                                         ByVal bytkey() As Byte, _
                                         ByVal bytiv() As Byte, _
                                         ByVal direction As CryptoAction)
            Try
                fsInput = New System.IO.FileStream(strinputfile, FileMode.Open, FileAccess.Read)
                fsOutput = New System.IO.FileStream(stroutputfile, FileMode.OpenOrCreate, FileAccess.Write)
                fsOutput.SetLength(0)
                Dim bytbuffer(4096) As Byte
                Dim lngbytesprocessed As Long = 0
                Dim lngfilelength As Long = fsInput.Length
                Dim intbytesincurrentblock As Integer
                Dim cscryptostream As CryptoStream
                Dim csprijndael As New System.Security.Cryptography.RijndaelManaged
                Select Case direction
                    Case CryptoAction.ActionEncrypt
                        cscryptostream = New CryptoStream(fsOutput, _
                        csprijndael.CreateEncryptor(bytkey, bytiv), _
                        CryptoStreamMode.Write)
                    Case CryptoAction.ActionDecrypt
                        cscryptostream = New CryptoStream(fsOutput, _
                        csprijndael.CreateDecryptor(bytkey, bytiv), _
                        CryptoStreamMode.Write)
                End Select
                While lngbytesprocessed < lngfilelength
                    intbytesincurrentblock = fsInput.Read(bytbuffer, 0, 4096)
                    cscryptostream.Write(bytbuffer, 0, intbytesincurrentblock)
                    lngbytesprocessed = lngbytesprocessed + CLng(intbytesincurrentblock)
                End While
                cscryptostream.Close()
                fsInput.Close()
                fsOutput.Close()
            Catch ex As Exception

            End Try
        End Sub

我是否需要将此过程的百分比作为整数来完成。我将使用后台工作程序,因此我需要从后台工作程序调用此子程序,并能够继续刷新后台工作程序报告的进度条。这可能吗? 提前谢谢。

1 个答案:

答案 0 :(得分:1)

您可以采取一些措施来提高您的加密效率和其他问题:

  • encryptordecryptfile这样的方法,然后需要&#34;模式&#34;知道采取哪种行动的论点意味着它可能会更好地作为2种方法
  • 你前进的方式,你将引发ProgressChangedProgressBar事件的暴风雪,While无法跟上动画。一个700K的文件将产生170个左右的微量进度报告
  • 可以合并一些加密步骤
  • 你有很多事情没有被处理掉;如果你通过循环运行一些文件,你可能会耗尽资源。

值得注意的是,您可以使用fsInput.CopyTo(cscryptostream)替换整个BackgroundWorker块,以便一次性处理该文件。但这不允许进度报告。它也没有更快。

您可能希望将其实现为Task,而不是DoWork(可以正常工作)。这样做的原因是所有这些变量都需要从点击按钮到实际调用方法的EncryptFile事件。任务不是使用全局变量或类来保存它们,而是更直接地工作(但在报告进度时确实需要一个额外的步骤)。首先,修改后的Private Sub EncryptFile(inFile As String, outFile As String, pass As String, Optional reporter As ProgressReportDelegate = Nothing) Const BLOCKSIZE = 4096 Dim percentDone As Integer = 0 Dim totalBytes As Int64 = 0 Dim buffSize As Int32 ' Note A Dim key = GetHashedBytes(pass) Dim iv = GetRandomBytes(16) Dim cryptor As ICryptoTransform ' Note B Using fsIn As New FileStream(inFile, FileMode.Open, FileAccess.Read), fsOut As New FileStream(outFile, FileMode.OpenOrCreate, FileAccess.Write) fsOut.SetLength(0) ' Note C 'ToDo: work out optimal block size for Lg vs Sm files If fsIn.Length > (2 * BLOCKSIZE) Then ' use buffer size to limit to 20 progress reports buffSize = CInt(fsIn.Length \ 20) ' to multiple of 4096 buffSize = CInt(((buffSize + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE) ' optional, limit to some max size like 256k? 'buffSize = Math.Min(buffSize, BLOCK256K) Else buffSize = BLOCKSIZE End If Dim buffer(buffSize-1) As Byte ' Note D ' write the IV to "naked" fs fsOut.Write(iv, 0, iv.Length) Using rij = Rijndael.Create() rij.Padding = PaddingMode.ISO10126 Try cryptor = rij.CreateEncryptor(key, iv) Using cs As New CryptoStream(fsOut, cryptor, CryptoStreamMode.Write) Dim bytesRead As Int32 Do Until fsIn.Position = fsIn.Length bytesRead = fsIn.Read(buffer, 0, buffSize) cs.Write(buffer, 0, bytesRead) If reporter IsNot Nothing Then totalBytes += bytesRead percentDone = CInt(Math.Floor((totalBytes / fsIn.Length) * 100)) reporter(percentDone) End If Loop End Using Catch crEx As CryptographicException ' ToDo: Set breakpoint and inspect message Catch ex As Exception ' ToDo: Set breakpoint and inspect message End Try End Using End Using End Sub 方法:

Public Shared Function GetHashedBytes(data As String) As Byte()
    Dim hBytes As Byte()

    ' or SHA512Managed
    Using hash As HashAlgorithm = New SHA256Managed()
        ' convert data to bytes:
        Dim dBytes = Encoding.UTF8.GetBytes(data)
        ' hash the result:
        hBytes = hash.ComputeHash(dBytes)

    End Using

    Return hBytes
End Function

Public Shared Function GetRandomBytes(size As Integer) As Byte()
    Dim data(size - 1) As Byte

    Using rng As New RNGCryptoServiceProvider
        ' fill the array 
        rng.GetBytes(data)
    End Using
    Return data

End Function

注意A
它可以处理的标准加密任务之一是为您创建Key和IV阵列。这些非常简单,可以是共享/静态成员。

Using

稍后将会看到,您可以将IV存储在加密文件中,而不是在代码中保存和管理它。

注B
Dispose阻止关闭并为您处置资源。基本上,如果某个东西有Using方法,那么你应该将它包装在Dim t As Task t = Task.Run(Sub() EncryptFile(inFile, oFile, "MyWeakPassword", AddressOf ReportProgress)) ... 块中。

注意C
您不希望报告每个块读取的进度,这只会压倒ProgressBar。而不是另一个变量来跟踪进度何时改变了一些量,此代码首先创建一个缓冲区大小,该大小为输入文件大小的5%,因此将有大约20个报告(每5%)。

如注释所示,您可能需要添加一些代码来设置最小/最大缓冲区大小。这样做会改变进度报告的频率。

注意D
在将它包装在CryptoStream中之前,您可以将IV()写入文件流(当然,在解密时首先将其读回)。这可以防止您必须存储IV。

最后一部分是将其作为一项任务:

Task

BGW所做的是在一个线程上执行工作,但是在UI线程上报告了进度。作为Invoke,我们需要做的就是使用Delegate Sub ProgressReportDelegate(value As Int32) Private Sub ReportProgress(v As Int32) If progBar.InvokeRequired Then progBar.Invoke(Sub() progBar.Value = v) Else progBar.Value = v progBar.Invalidate() End If End Sub

' small file, no progress report:
EncryptFile(ifile, oFile, "MyWeakPassword")

' report progress, but run on UI thread
EncryptFile(ifile, oFile, "MyWeakPassword", 
            AddressOf ReportProgress)

' run as task
Dim t As Task
t = Task.Run(Sub() EncryptFile(ifile, oFile, "MyWeakPassword", 
                AddressOf ReportProgress))

加密器可以直接使用,也可以作为任务使用。对于小文件,您可以完全省略进度报告:

SELECT * FROM items ORDER BY tags ASC;

...如果你有一个要做的文件列表,你可以一次性运行它们,也许可以报告总进度。