Расшифровка текстового файла с помощью Rjindael

Я использовал это руководство для шифрования значения txtCode.Text в текстовый файл, который затем скрывается - значение зашифрованных данных будет использоваться в качестве пароля для базы данных, поэтому мне нужно прочитать это значение, расшифровать его, а затем передать его в строку подключения.

Однако в этом руководстве расшифровка выполняется путем ввода значения, создавая bytKey а также bytIV а затем сравнивает результат шифрования введенной строки newl со значением в текстовом файле. Очевидно, я не могу просить пользователя вводить пароль каждый раз, когда требуется открыть базу данных, так как я могу добиться расшифровки с помощью этого кода?

Код, который расшифровывает и шифрует данные

Public 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
        errorLog(ex)

    End Try
End Sub

Мне нужно использовать эту или другую подпрограмму, чтобы прочитать файл, расшифровать данные и затем сохранить их в переменной для передачи в строку подключения. Можно ли это сделать? Если так, то как?

1 ответ

Решение

После многочисленных попыток с вашим кодом я решил отказаться от него - он просто старый, неэффективный и небезопасный (как отметил Plutonix).

Вот гораздо более эффективный фрагмент кода, в котором я изменил и улучшил мой старый класс - под названием Aes256Stream, Это получено из CryptoStream и будет обрабатывать IV автоматически для вас.

'+---------------------------------------------------------------------------------+'
'|                               === Aes256Stream ===                              |'
'|                                                                                 |'
'|                  Created by Vincent "Visual Vincent" Bengtsson                  |'
'|                      Website: https://www.mydoomsite.com/                       |'
'|                                                                                 |'
'|                                                                                 |'
'|                            === COPYRIGHT LICENSE ===                            |'
'|                                                                                 |'
'| Copyright (c) 2016-2017, Vincent Bengtsson                                      |'
'| All rights reserved.                                                            |'
'|                                                                                 |'
'| Redistribution and use in source and binary forms, with or without              |'
'| modification, are permitted provided that the following conditions are met:     |'
'|                                                                                 |'
'| 1. Redistributions of source code must retain the above copyright notice, this  |'
'|    list of conditions and the following disclaimer.                             |'
'| 2. Redistributions in binary form must reproduce the above copyright notice,    |'
'|    this list of conditions and the following disclaimer in the documentation    |'
'|    and/or other materials provided with the distribution.                       |'
'|                                                                                 |'
'| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |'
'| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED   |'
'| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE          |'
'| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |'
'| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES  |'
'| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;    |'
'| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND     |'
'| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT      |'
'| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS   |'
'| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                    |'
'+---------------------------------------------------------------------------------+'

Imports System.IO
Imports System.Security.Cryptography
Imports System.Runtime.InteropServices

Public Class Aes256Stream
    Inherits CryptoStream

#Region "Fields"
    Private _underlyingStream As Stream
    Private AES As RijndaelManaged
    Private Transform As ICryptoTransform
#End Region

#Region "Properties"
    ''' <summary>
    ''' Gets the block size, in bits, used by the stream's AES algorithm.
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property BlockSize As Integer
        Get
            Return AES.BlockSize
        End Get
    End Property

    ''' <summary>
    ''' Gets the key size, in bits, used by the stream's AES algorithm.
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property KeySize As Integer
        Get
            Return AES.KeySize
        End Get
    End Property

    ''' <summary>
    ''' Gets the length in bytes of the underlying stream.
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides ReadOnly Property Length As Long
        Get
            Return _underlyingStream.Length
        End Get
    End Property

    ''' <summary>
    ''' Gets or sets the position within the underlying stream.
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides Property Position As Long
        Get
            If _underlyingStream.CanSeek = False Then Throw New NotSupportedException("The underlying stream doesn't support seeking!")
            Return _underlyingStream.Position
        End Get
        Set(value As Long)
            If _underlyingStream.CanSeek = False Then Throw New NotSupportedException("The underlying stream doesn't support seeking!")
            _underlyingStream.Position = value
        End Set
    End Property

    ''' <summary>
    ''' Gets the underlying stream.
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property UnderlyingStream As Stream
        Get
            Return _underlyingStream
        End Get
    End Property
#End Region

#Region "Constructors"
    Private Sub New(ByVal UnderlyingStream As Stream, _
                    ByVal AES As RijndaelManaged, _
                    ByVal CryptoTransform As ICryptoTransform, _
                    ByVal Mode As CryptoStreamMode)
        MyBase.New(UnderlyingStream, CryptoTransform, Mode)
        Me._underlyingStream = UnderlyingStream
        Me.AES = AES
        Me.Transform = CryptoTransform
    End Sub
#End Region

#Region "Methods"

#Region "Instance"
    ''' <summary>
    ''' Sets the length of the underlying stream.
    ''' </summary>
    ''' <param name="value">The desired length of  underlying stream in bytes.</param>
    ''' <remarks></remarks>the
    Public Overrides Sub SetLength(value As Long)
        _underlyingStream.SetLength(value)
    End Sub
#End Region

#Region "Shared"
    ''' <summary>
    ''' Creates an AES-256 encryption stream.
    ''' </summary>
    ''' <param name="UnderlyingStream">The underlying stream to write the encrypted data to.</param>
    ''' <param name="Key">The encryption key to use when encrypting the data (automatically padded or truncated to KeySize/8 bytes).</param>
    ''' <remarks></remarks>
    Public Shared Function CreateEncryptionStream(ByVal UnderlyingStream As Stream, ByVal Key As Byte()) As Aes256Stream
        Dim AES As New RijndaelManaged
        AES.KeySize = 256
        AES.BlockSize = 128

        AES.Key = Aes256Stream.PadOrTruncate(Key, AES.KeySize / 8)
        AES.GenerateIV()

        AES.Mode = CipherMode.CBC
        AES.Padding = PaddingMode.PKCS7

        'Write the IV to the underlying stream.
        If UnderlyingStream.CanWrite = True Then
            Dim LengthIV As Byte() = BitConverter.GetBytes(AES.IV.Length) 'Convert the IV.Length Integer to a byte array.
            UnderlyingStream.Write(LengthIV, 0, LengthIV.Length) 'Write the length of the IV.
            UnderlyingStream.Write(AES.IV, 0, AES.IV.Length) 'Write the IV.
        Else
            Throw New IOException("Underlying stream is not writable!")
        End If

        Return New Aes256Stream(UnderlyingStream, AES, AES.CreateEncryptor(), CryptoStreamMode.Write)
    End Function

    ''' <summary>
    ''' Creates an AES-256 decryption stream.
    ''' </summary>
    ''' <param name="UnderlyingStream">The underlying stream to decrypt the data from.</param>
    ''' <param name="Key">The encryption key to use when encrypting the data (automatically padded or truncated to KeySize/8 bytes).</param>
    ''' <remarks></remarks>
    Public Shared Function CreateDecryptionStream(ByVal UnderlyingStream As Stream, ByVal Key As Byte()) As Aes256Stream
        Dim AES As New RijndaelManaged
        AES.KeySize = 256
        AES.BlockSize = 128

        AES.Key = Aes256Stream.PadOrTruncate(Key, AES.KeySize / 8)

        'Read the IV from the underlying stream.
        If UnderlyingStream.CanRead = True Then
            Dim BytesReadIV As Integer = 0
            Dim BufferIV As Byte() = New Byte(Marshal.SizeOf(GetType(Integer)) - 1) {}
            Dim LengthIV As Integer

            'Read the IV's length.
            While BytesReadIV < BufferIV.Length
                Dim BytesRead As Integer = UnderlyingStream.Read(BufferIV, BytesReadIV, BufferIV.Length - BytesReadIV)
                BytesReadIV += BytesRead

                If BytesRead = 0 AndAlso BytesReadIV < BufferIV.Length Then _
                    Throw New IOException("End of stream reached before IV could be parsed!")
            End While

            'Convert the bytes to an Integer.
            LengthIV = BitConverter.ToInt32(BufferIV, 0)

            'Reset the variables.
            BytesReadIV = 0
            BufferIV = New Byte(LengthIV - 1) {}

            'Read the IV.
            While BytesReadIV < BufferIV.Length
                Dim BytesRead As Integer = UnderlyingStream.Read(BufferIV, BytesReadIV, BufferIV.Length - BytesReadIV)
                BytesReadIV += BytesRead

                If BytesRead = 0 AndAlso BytesReadIV < BufferIV.Length Then _
                    Throw New IOException("End of stream reached before IV could be parsed!")
            End While

            'Set the IV.
            AES.IV = BufferIV
        Else
            Throw New IOException("Underlying stream is not readable!")
        End If

        AES.Mode = CipherMode.CBC
        AES.Padding = PaddingMode.PKCS7

        Return New Aes256Stream(UnderlyingStream, AES, AES.CreateDecryptor(), CryptoStreamMode.Read)
    End Function

    Private Shared Function PadOrTruncate(ByVal Input As Byte(), ByVal PreferredLength As Integer) As Byte()
        If Input.Length < PreferredLength Then 'Pad with zeros.
            Dim PreviousLength As Integer = Input.Length

            Array.Resize(Input, Input.Length + (PreferredLength - Input.Length))
            For i = PreviousLength To Input.Length - 1
                Input(i) = 0
            Next

            Return Input

        ElseIf Input.Length > PreferredLength Then 'Truncate.
            Array.Resize(Input, PreferredLength)
            Return Input

        End If

        Return Input 'Do nothing.
    End Function
#End Region

#End Region

#Region "Dispose()"
    Protected Overrides Sub Dispose(disposing As Boolean)
        MyBase.Dispose(disposing)
        If disposing Then
            Try
                If Transform IsNot Nothing Then
                    Transform.Dispose()
                    Transform = Nothing
                End If
            Catch
            End Try

            Try
                If AES IsNot Nothing Then
                    AES.Dispose()
                    AES = Nothing
                End If
            Catch
            End Try
        End If
    End Sub
#End Region

End Class

Две основные вещи, которые нужно запомнить:

  • CreateEncryptionStream() создает поток только длязаписи для выполнения шифрования.

  • CreateDecryptionStream() создает потоктолько длячтения для выполнения расшифровки.


Выполнение шифрования

Простейший пример выполнения шифрования требует только создания новогоAes256Streamи напиши ему:

Using AesStream As Aes256Stream = Aes256Stream.CreateEncryptionStream(<output stream>, <encryption key>)
    AesStream.Write(<buffer>, <offset>, <length>)
End Using

Заметки:

  • <output stream>поток для шифрования данных (например,FileStream).

  • <encryption key>является ключом (в виде байтового массива), который используется при шифровании данных.

  • <buffer>, <offset>а также<length>вести себя так же, как при записи в обычный поток.


Выполнение расшифровки

Аналогично, самый простой пример выполнения дешифрования требует только создания новогоAes256Streamи читать из него:

Using AesStream As Aes256Stream = Aes256Stream.CreateDecryptionStream(<input stream>, <decryption key>)

    Dim DecryptedData As Byte() = New Byte(AesStream.Length - 1) {}
    AesStream.Read(DecryptedData, 0, DecryptedData.Length)

End Using

Заметки:

  • <input stream> поток для расшифровки данных (например, FileStream).

  • <decryption key> (такой же как <encryption key> выше).

  • AesStream.Length равно звонить <input stream>.Length (то же самое касается AesStream.Position а также <input stream>.Position).


Для вашего использования

Вот как вы можете адаптировать свой код для работы с ним...

Методы:

''' <summary>
''' Encrypts data to a file.
''' </summary>
''' <param name="File">The file to encrypt data to.</param>
''' <param name="Data">The data to encrypt.</param>
''' <param name="Key">The key to use to perform the encryption.</param>
''' <remarks></remarks>
Public Sub EncryptFile(ByVal File As String, ByVal Data As Byte(), ByVal Key As Byte())
    Using OutputStream As New FileStream(File, FileMode.Create, FileAccess.Write, FileShare.None)
        Using AesStream As Aes256Stream = Aes256Stream.CreateEncryptionStream(OutputStream, Key)
            AesStream.Write(Data, 0, Data.Length)
        End Using
    End Using
End Sub

''' <summary>
''' Decrypts a file and returns the decrypted data.
''' </summary>
''' <param name="File">The file to decrypt.</param>
''' <param name="Key">The key to use to perform the decryption.</param>
''' <remarks></remarks>
Public Function DecryptFile(ByVal File As String, ByVal Key As Byte()) As Byte()
    Using InputStream As New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.Read)
        Using DecryptedStream As New MemoryStream
            Using AesStream As Aes256Stream = Aes256Stream.CreateDecryptionStream(InputStream, Key)

                Dim Buffer As Byte() = New Byte(4096 - 1) {}
                While AesStream.Position < AesStream.Length
                    Dim BytesRead As Integer = AesStream.Read(Buffer, 0, Buffer.Length)
                    DecryptedStream.Write(Buffer, 0, BytesRead)
                End While

                Return DecryptedStream.ToArray()

            End Using
        End Using
    End Using
End Function

Пример использования:

Dim Key As Byte() = System.Text.Encoding.UTF8.GetBytes("verysecretpassword") 'If you actually use a password here do hash it first!

Dim TextToEncrypt As String = "Hello World! How are you?"
Dim DataToEncrypt As Byte() = System.Text.Encoding.UTF8.GetBytes(TextToEncrypt)

EncryptFile("encrypted.txt", DataToEncrypt, Key)

Dim DecryptedData As Byte() = DecryptFile("encrypted.txt", Key)
Dim DecryptedText As String = System.Text.Encoding.UTF8.GetString(DecryptedData)


Онлайн тест

Онлайн-версию этого кода можно проверить здесь: https://dotnetfiddle.net/PXaJF8

Другие вопросы по тегам