[Ayuda] [Error] la operación aritmética ha provocado un desbordamiento

Iniciado por **Aincrad**, 22 Junio 2019, 17:12 PM

0 Miembros y 1 Visitante están viendo este tema.

**Aincrad**

Hola, bueno vengo con un pequeño problema. bueno

Tengo un .exe que fue Pasado a Hex y Comprimido después Encryptado (Rijndael).

Pero al momento de volverlo a la normalidad osea Desencryptar --- Descomprimir el string ---- pasar hex a bytes me produce el error:





Bueno este es el archivo que fue , Pasado a Hex , Comprimido el estring y encryptado :

https://anonfile.com/0aI5lbw1n5/Digital_Signature_txt

Bueno para revertirlo a .exe :


Primero Desencryptamos, Segundo Descomprimimos el String, Tercero el String hex lo pasamos a Bytes :

Código (vbnet) [Seleccionar]

Dim FileCompressC As String = File.ReadAllText("Digital_Signature.txt")
Dim MasterKey As String = "PutoElQueloLea"


Public Sub InicialLoader()
           Dim ExtractApp As String = "Ca.exe"

           Dim FileCoD As String = DecryptS(FileCompressC, MasterKey) ' Desencrytamos
           Dim DesFile As String = DecompressData(FileCoD) ' Descomprimimos el String Hex
           File.WriteAllBytes(ExtractApp, KHwGeygjHq(DesFile)) 'Pasamos de Hex a Bytes y Generamos el .exe
       End Sub

Public Shared Function RijndaelDecrypt(ByVal UDecryptU As String, ByVal UKeyU As String) ' Desencryptamos
       Dim XoAesProviderX As New System.Security.Cryptography.RijndaelManaged
       Dim XbtCipherX() As Byte
       Dim XbtSaltX() As Byte = New Byte() {1, 2, 3, 4, 5, 6, 7, 8}
       Dim XoKeyGeneratorX As New System.Security.Cryptography.Rfc2898DeriveBytes(UKeyU, XbtSaltX)
       XoAesProviderX.Key = XoKeyGeneratorX.GetBytes(XoAesProviderX.Key.Length)
       XoAesProviderX.IV = XoKeyGeneratorX.GetBytes(XoAesProviderX.IV.Length)
       Dim XmsX As New IO.MemoryStream
       Dim XcsX As New System.Security.Cryptography.CryptoStream(XmsX, XoAesProviderX.CreateDecryptor(), _
         System.Security.Cryptography.CryptoStreamMode.Write)
       Try
           XbtCipherX = Convert.FromBase64String(UDecryptU)
           XcsX.Write(XbtCipherX, 0, XbtCipherX.Length)
           XcsX.Close()
           UDecryptU = System.Text.Encoding.UTF8.GetString(XmsX.ToArray)
       Catch
       End Try
       Return UDecryptU
   End Function

 Public Shared Function DecompressData(ByVal CompressedText As String) As String ' Descomprimimos el String Hex
           Dim GZipBuffer As Byte() = Convert.FromBase64String(CompressedText)

           Using mStream As New MemoryStream()
               Dim msgLength As Integer = BitConverter.ToInt32(GZipBuffer, 0)
               mStream.Write(GZipBuffer, 4, GZipBuffer.Length - 4)
               Dim Buffer As Byte() = New Byte(msgLength - 1) {}
               mStream.Position = 0
               Using GZipStream As New System.IO.Compression.GZipStream(mStream, IO.Compression.CompressionMode.Decompress)
                   GZipStream.Read(Buffer, 0, Buffer.Length)
               End Using
               Return System.Text.Encoding.Unicode.GetString(Buffer, 0, Buffer.Length)
           End Using
       End Function


Public Function KHwGeygjHq(ByVal KMvWYyQigLibcI As String) As Byte() ' Hex to Bytes
           Dim cKHbugadWMVB
           Dim WdfGomorOa() As Byte
           KMvWYyQigLibcI = Microsoft.VisualBasic.Strings.Replace(KMvWYyQigLibcI, " ", "")
           ReDim WdfGomorOa((Microsoft.VisualBasic.Strings.Len(KMvWYyQigLibcI) \ 2) - 1)
           For cKHbugadWMVB = 0 To Microsoft.VisualBasic.Information.UBound(WdfGomorOa) - 2
               WdfGomorOa(cKHbugadWMVB) = CLng("&H" & Microsoft.VisualBasic.Strings.Mid$(KMvWYyQigLibcI, 2 * cKHbugadWMVB + 1, 2))
           Next
           KHwGeygjHq = WdfGomorOa
       End Function



y bueno me sale error de desbordamiento , como lo soluciono ?




Serapis

Debes asegurarte que el el método usado para obtener de vuelta el EXE partiendo de ese txt, sea exactamente la operación inversa a la que hiciste para pasarlo a txt (código que ahí omites).

Al final, para saber si esas conversiones son correctas debes tener el mismo hash para el ejecutable de origen que para el regresado. Pero como te sale un error (no aclaras si es puntual, solo para ese eejcutable y si te salen más con otros ejecutables).

Con la imagen cortada del stacktrace, se alcanza a ver solo que falla la función "DecompressData", pero no se alcanza a ver la línea donde falla, y poco más... de lo que se alcanza a leer, parece que al crear un objeto falla el constructor, posiblemente porque precisa hacer alguna operación y el valor de algún parámetro supere el tipo esperado, etc...  la ausencia de tales detalles, obliga a descargar el fichero copiar tu código y ejecutarlo para intentar ver que sucede (aunque es claro que es una operación aritmética, no queda claro el punto exacto y la causa original). A la noche saco un tiempito y reviso el código, y te cuento...

Mientras puedes al menos si no porporcionas el ejecutable original, indicar su hash MD5 (por ejemplo), para comparar en caso de corregir el error?...o mejor aún,  poner también el código que usaste para codificarlo (y así poder ver que una operación sea fielmente la inversa de la otra)? ...se pobaría con otro ejecutable en este caso.

**Aincrad**

#2
Ocurre con todos los .exe, el error aritmetico se produce .

************** Texto de la excepción **************
System.OverflowException: La operación aritmética ha provocado un desbordamiento.
   en MainNamespace.MainClass.DecompressData(String CompressedText) en C:\Users\S4lsalsoft\AppData\Local\Temp\r0fb35eb.0.vb:línea 302
   en MainNamespace.MainClass.InicialLoader() en C:\Users\S4lsalsoft\AppData\Local\Temp\r0fb35eb.0.vb:línea 237
   en MainNamespace.MainClass.MainClass_Load(Object sender, EventArgs e) en C:\Users\S4lsalsoft\AppData\Local\Temp\r0fb35eb.0.vb:línea 36
   en System.Windows.Forms.Form.OnLoad(EventArgs e)
   en System.Windows.Forms.Form.OnCreateControl()
   en System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   en System.Windows.Forms.Control.CreateControl()
   en System.Windows.Forms.Control.WmShowWindow(Message& m)
   en System.Windows.Forms.Control.WndProc(Message& m)
   en System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   en System.Windows.Forms.Form.WmShowWindow(Message& m)
   en System.Windows.Forms.Form.WndProc(Message& m)
   en System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   en System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   en System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)






Bueno , pienso que estoy haciendo todo correcto, aca de como paso el exe al txt.

Código (vbnet) [Seleccionar]


Private Sub Inicio()
       Dim FileCrypt As String = ConverexetohexandCompress("Ca.exe", "PutoElQueloLea")
       File.WriteAllText("Digital_Signature.txt", FileCrypt)
   End Sub


   Public Shared Function ConverexetohexandCompress(ByVal FilePath As String, ByVal PasswordtoCrypt As String) As String
       Dim input As New FileStream(FilePath, FileMode.Open, FileAccess.Read)
       Dim reader As New BinaryReader(input)
       Dim bytes() As Byte
       bytes = reader.ReadBytes(CInt(input.Length)) 'leemos los bytes
       Dim hexCompress As String = CompressedData(BytesToHex(bytes))  ' Pasamos los bytes a Hex y Comprimimos.
       Dim exefilestringenc As String = String.Empty
       exefilestringenc = Rijndaelcrypt(hexCompress, PasswordtoCrypt) 'Encryptamos (Rijndael)
       Return exefilestringenc
   End Function



Public Shared Function CompressedData(ByVal Text As String) As String 'Funcion para Comprimir String

       Dim Buffer As Byte() = System.Text.Encoding.Unicode.GetBytes(Text)
       Dim mStream As New MemoryStream()
       Using GZipStream As New IO.Compression.GZipStream(mStream, IO.Compression.CompressionMode.Compress, True)
           GZipStream.Write(Buffer, 0, Buffer.Length)
       End Using
       mStream.Position = 0
       Dim outStream As New MemoryStream()
       Dim Compressed As Byte() = New Byte(mStream.Length - 1) {}
       mStream.Read(Compressed, 0, Compressed.Length)
       Dim GZipBuffer As Byte() = New Byte(Compressed.Length + 3) {}
       System.Buffer.BlockCopy(Compressed, 0, GZipBuffer, 4, Compressed.Length)
       System.Buffer.BlockCopy(BitConverter.GetBytes(Buffer.Length), 0, GZipBuffer, 0, 4)
       Return Convert.ToBase64String(GZipBuffer)

   End Function


 Public Shared Function BytesToHex(ByVal Input As Byte()) As String 'Funcion para convertir los bytes en hex
       Dim Result As New System.Text.StringBuilder(Input.Length * 2)
       Dim Part As String
       For Each b As Byte In Input
           Part = Conversion.Hex(b)
           If Part.Length = 1 Then Part = "0" & Part
           Result.Append(Part)
       Next
       Return Result.ToString()
   End Function

Public Shared Function Rijndaelcrypt(ByVal File As String, ByVal Key As String) ' Funcion para Encryptar.
       Dim oAesProvider As New System.Security.Cryptography.RijndaelManaged
       Dim btClear() As Byte
       Dim btSalt() As Byte = New Byte() {1, 2, 3, 4, 5, 6, 7, 8}
       Dim oKeyGenerator As New Rfc2898DeriveBytes(Key, btSalt)
       oAesProvider.Key = oKeyGenerator.GetBytes(oAesProvider.Key.Length)
       oAesProvider.IV = oKeyGenerator.GetBytes(oAesProvider.IV.Length)
       Dim ms As New IO.MemoryStream
       Dim cs As New CryptoStream(ms, _
         oAesProvider.CreateEncryptor(), _
         CryptoStreamMode.Write)
       btClear = System.Text.Encoding.UTF8.GetBytes(File)
       cs.Write(btClear, 0, btClear.Length)
       cs.Close()
       File = Convert.ToBase64String(ms.ToArray)
       Return File
   End Function




En Si es esto :






Serapis

He tenido un momento  para mirar el código...
...pero agárrate que el mensaje va para largo, hay mucho que comentar.

El error que tiene tu código está antes incluso d elo que emncionas, concretamente en la función:
Código (vbnet) [Seleccionar]

Public Shared Function RijndaelDecrypt(ByVal UDecryptU As String, ByVal UKeyU As String) ' Desencryptamos
       Dim XoAesProviderX As New System.Security.Cryptography.RijndaelManaged
       Dim XbtCipherX() As Byte
       Dim XbtSaltX() As Byte = New Byte() {1, 2, 3, 4, 5, 6, 7, 8}
       Dim XoKeyGeneratorX As New System.Security.Cryptography.Rfc2898DeriveBytes(UKeyU, XbtSaltX)
       XoAesProviderX.Key = XoKeyGeneratorX.GetBytes(XoAesProviderX.Key.Length)
       XoAesProviderX.IV = XoKeyGeneratorX.GetBytes(XoAesProviderX.IV.Length)
       Dim XmsX As New IO.MemoryStream
       Dim XcsX As New System.Security.Cryptography.CryptoStream(XmsX, XoAesProviderX.CreateDecryptor(), _
         System.Security.Cryptography.CryptoStreamMode.Write)
       Try
           XbtCipherX = Convert.FromBase64String(UDecryptU)
           XcsX.Write(XbtCipherX, 0, XbtCipherX.Length)
           XcsX.Close()  '  <<<<<=========== AQUI, EL ERROR
           UDecryptU = System.Text.Encoding.UTF8.GetString(XmsX.ToArray)
       Catch   ' <<<<< ======= AQUÍ DEJAS QUE EL ERROR SE PROPAGUE
       End Try
       Return UDecryptU   ' <<<<< =========== AQUÍ DEVUELVES UN VALOR FALSO SI HUBO UN FALLO.
   End Function


Y más concretamente en la parte final, en el bloque Try...catch
El punto exacto es en la línea:
    XcsX.Close()
Genera un error y salta al bloque 'catch', pero como no 'cazas' nada, entonces sigue la ejecución, ahora devuelves 'UDecryptU' con el valor que tenía a la entrada...
finalmente el código encuentra otro error al llegar a la línea que no señalas (ponía el número de línea, pero claro ese número corresponde a la posición que ocupa en tu editor, luego es información desfasada):
    Dim Buffer As Byte() = New Byte(msgLength - 1) {}
El caso es que el error ni siqueira procede de dicha entrada (sigue siendo un texto, aunque NO CONTIENE el contenido que toca), el error (que aquí aparece) es que msglenght tiene un valor negativo, producto de usar el tipo Integer en vez de un UInteger.

Es decir esta línea devuelve un valor negativo para mslenght:
    Dim msgLength As Integer = BitConverter.ToInt32(GZipBuffer, 0)
Esta línea toma los 4 primeros bytes del array y los convierte a un entero con signo de 32 bits, luego es perfectamente normal que arroje un valor negativo... ya que un entero de 4 bytes, apenas el byte más alto sea un valor superior a 127, tormará como un negativo). Valor que luego usas para crear un array de dicho tamaño... como no se pueden crear arrays de cantidad negativa, te salta el error que logras ver (pero que ni es el único, ni empeiza ahí)...
Me temo que quizás quiseras hacer:
    Dim msgLength As Integer = GZipBuffer.Length
Es decir tomar el tamaño del array...

En el bloque Try, como mínimo añade código para la captura de error, si no mejor omitirlo...
Un simple ejemplo del añadido preciso.
Código (vbnet) [Seleccionar]

           Try
               btData = Convert.FromBase64String(UDecryptU)
               cs.Write(btData, 0, btData.Length)
               cs.Close()
               'UDecryptU = Encoding.UTF8.GetString(ms.ToArray)
               'Return UDecryptU
               Return Encoding.UTF8.GetString(ms.ToArray)
           Catch ex As Exception
               MessageBox.Show(ex.Message)

               Return ""
           End Try


...y como (ahora) en la devolución (si se da un error) la cadena puede estar vacía en la siguiente función precisas un 'if'... La función pués quedaría así...
Código (vbnet) [Seleccionar]

   Public Sub InicialLoader()
           Dim ExtractApp As String = "Ca.dll"

           Dim FileCoD As String = RijndaelDecrypt(FileCompressC, MasterKey) ' Desencrytamos

           If FileCoD.Length > 0 Then
               Dim DesFile As String = DecompressData(FileCoD) ' Descomprimimos el String Hex
               File.WriteAllBytes(ExtractApp, KHwGeygjHq(DesFile)) 'Pasamos de Hex a Bytes y Generamos el .exe
           End If
   End Sub


Seguimos... el errror en el CriptoStream.close, se produce porque los datos tienen que estar 'alineados', esto es si quieres cifrar 10 bytes, debes añadir algunos bytes de padding necesarios para que tenga el mismo tamaño, que son los mismos que devueltos... el padding suele ser molesto porque a la vuelta (al decodificar), hay que tenerlo en cuenta e ignorar cuando sea el caso (en Base64 también hay padding, pero lo maneja intenamente la librería).

Pero vamos, tu pon el código en 'Catch' (como mínimo lo que te he puesto), para que te señale el error y se pare justo en el primer punto donde se da un error.

También veo que haces algo demasiado complejo para simplemente tomar un ejecutable y convertirlo a un fichero de texto plano, completamente legible aunque incomprensible...

Un comentario más aún, es que el código es ... bueno me callo calificativos, la intención no es que molestar... pero si resulta engorroso, embrollado, no queda adecuadamente separadas las funciones y hay cosas demasiado pesadas que pueden simplificarse...
Por ejemplo la función para convertir a hexadecimal, es muy rebuscada, además adolece a la entrada de duplicar su tamaño, culpa de la línea (en la función previa):
     Dim Buffer As Byte() = System.Text.Encoding.Unicode.GetBytes(Text)
...pués te va a intropducir un byte 0 por cada otro byte existente, luego además malogra la compresión que luego pretende llevarse a cabo.

Otra aberración, es tomar un array de bytes, convertirlo a texto hexadecimal, y luego otra vez convertirlo a un array de bytes... mareas mucho los datos.

He rescrito la function BytesToHex (además la he rebautizado) a algo más explícito, y he añadido una sobrecarga para, que partiendo de un array de bytes, obtener de él el array de bytes hexadecimales... Además acelera el cálculo, porque al crear la instancia se crean sendas tablas, luego basta usar la tabla para la conversión (y se evitan conversiones varias).... Las tablas se crean con el constructor de clase. Si te quedas solo con una, comenta la otra y el código correspondiente en el constructor.
Añado las dos sobrecargas y debajo tu función 'ConvertToHex', para que compares...

Para manejar más cómodamente cada parte, yo he metido el código de sendas partes en sendas clases, manejadas por sendos botones, y todo dentro del código de un formulario (desconozco si tienes algo de interfaz, pero para pruebas y elegir ficheros o rutas suele ser útil, aunque luego al compilar lo descartes y se quede en una dll, por ejemplo).

Código (vbnet) [Seleccionar]

Imports System.IO
Imports System.Security.Cryptography
Imports System.Text

Public Class Form1

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
       Dim c As New Crypt
       c.Inicio()
   End Sub

   Public Class Crypt
       Private Shared StrHex(0 To 255) As String   ' Tabla para conversión a string
       Private Shared ChrHex(0 To 15) As Byte     ' Tabla para conversión a array de bytes.

       ''' <summary>
       ''' Se ejecuta automáticamente la 1º vez que se crea una instancia.
       ''' Crea la tabla de conversión hexadecimal.
       ''' </summary>
       ''' <remarks>No aparece en el examinador de objetos.</remarks>
       Shared Sub New()
           Dim k As Byte, j As Byte, n As Short, h As String

           For j = 0 To 15
               h = Conversion.Hex(j)                
               For k = 0 To 15
                   StrHex(n) = (h & Conversion.Hex(k))
                   n += 1
               Next
           Next

           ' 0,1,2,3,4,5,6,7,8,9
           For j = 0 To 9
               ChrHex(j) = (48 + j)  ' 48-57
           Next
           ' A,B,C,D,E,F
           For j = 10 To 15
               ChrHex(j) = (55 + j)  ' 65-70
           Next
       End Sub

       ' Esta sobrecarga evita convertir un array de bytes a String-Hex, para luego volverla a convertir de nuevo en un array de bytes.
       ''' <summary>
       ''' Codifica un array de bytes a formato hexadecimal.
       ''' </summary>
       ''' <param name="Input">El array de bytes.</param>
       ''' <param name="ForzarSobrecarga">No importa el valor. Su único propósito es diferenciar para admitir la sobrecarga.</param>
       ''' <returns>Un array de bytes de valores hexadecimales.</returns>
       ''' <remarks>El array de salida es el doble del tamaño del array de entrada</remarks>
       Public Shared Function ConvertToHex(ByVal Input As Byte(), ByVal ForzarSobrecarga As Boolean) As Byte()
           Dim Hex(0 To (Input.Length * 2) - 1) As Byte
           Dim n As Integer

           For Each b As Byte In Input
               Hex(n) = ChrHex(b \ 16)
               Hex(n + 1) = ChrHex(b And 15)
               n += 2
           Next

           Return Hex
       End Function

       ''' <summary>
       ''' Codifica un array de bytes a formato hexadecimal.
       ''' </summary>
       ''' <param name="Input">El array de bytes.</param>
       ''' <param name="ForzarSobrecarga">No importa el valor. Su único propósito es diferenciar para admitir la sobrecarga.</param>
       ''' <returns>Una cadena de caracteres hexadecimales.</returns>
       ''' <remarks>Cada byte se codifica con 2 caracteres</remarks>
       Public Shared Function ConvertToHex(ByVal Input As Byte(), ByRef ForzarSobrecarga As String) As String
           Dim Hex As String = Strings.Space(Input.Length * 2)
           Dim n As Integer = 1

           For k As Integer = 0 To Input.Length - 1
               Mid(Hex, n) = StrHex(Input(k))
               n += 2
           Next

           Return Hex
       End Function

        ' Tu función...
       Public Shared Function ConvertToHex(ByVal Input() As Byte) As String 'Funcion para convertir los bytes en hex
           Dim Result As New System.Text.StringBuilder(Input.Length * 2)
           Dim Part As String
           For Each b As Byte In Input
               Part = Conversion.Hex(b)
               If Part.Length = 1 Then Part = "0" & Part
               Result.Append(Part)
           Next
           Return Result.ToString()
       End Function
       
   end Class
End Class


Ahora para aceptar los cambios (y poder usar esas funciones), se debe modificar la función que invoca a Convert y la función Compress
Código (vbnet) [Seleccionar]

'  'Dim hexBytes As String = Encoding.ASCII.GetString(Encoding.Convert(UTF8Encoding,    filebytes,
       Public Shared Function ConverexetohexandCompress(ByVal ruta As String, ByVal PasswordtoCrypt As String) As String            
           Dim filebytes() As Byte = IO.File.ReadAllBytes(ruta)
           Dim buffer() As Byte

           buffer = ConvertToHex(filebytes, True)
           ' la otra sobrecarga...
           'buffer = Encoding.Unicode.GetBytes(ConvertToHex(filebytes, ""))
           ' tu función
           'buffer = Encoding.Unicode.GetBytes(ConvertToHex(filebytes))

           Dim hexCompress As String = CompressedData(buffer)  ' Pasamos los bytes a Hex y Comprimimos.            
           Return Rijndaelcrypt(hexCompress, PasswordtoCrypt) 'Encryptamos (Rijndael)
       End Function

       ' Antes
       Public Shared Function CompressedData(ByVal Text As string) As String
           Dim Buffer As Byte() = System.Text.Encoding.Unicode.GetBytes(Text)
           ' ...
       End Function
       ' Ahora
       Public Shared Function CompressedData(ByVal Buffer() As Byte) As String
           'Dim Buffer As Byte() = System.Text.Encoding.Unicode.GetBytes(Text)
           ' ...
       End Function

Incluso aunque usaras la otra sobrecarga o tu función no uses el encoding Unicode, ya que duplica la cantidad de caracteres (en todo caso el ASCII) y el efecto de la compresión será menor...

Para terminar como decía, más arriba creo que es demasiado laborioso para simplemente ocultar un ejecutable en texto plano... conversiones a hexadecimal, luego a base64, cifrar con rijndael, comprimir... ni que estuvieras escondiendo el tesoro del tío Gilito.

En definitiva tienes cuando menos un par de errores y mucha morralla de código. ...y eso que no lo he revisado todo al completo...



Yo veo más simple y igualmente complejo de descifrar, usar un cifrado XOR, y finalmente si lo quieres en texto plano, una conversión a base64 y listo.

Me he puesto con ello y en poco más de 2 horas (mediando cena incluído), está funcional y operativo (y al menos en las prueas libre de errores)

La función 'AmpliarClave' toma una clave de pocos caracteres y la convierte en una clave del tamaño que se quiera... bastante aleatoria, que ahora podrá usarse para un simple cifrado con XOR, pero inexpugnable, la solidez será la de la propia clave. Debe asegurarse como mínimo que no sean todas las letras iguales: "FFFFFFFFF", generaría una clave del largo pedido pero con el mismo carácter.
Puede añadirse una fase 4, donde ahora a los bytes pares se les suma 1 (si llega a 255, pasa a valer 0) y a los bytes impares se les resta 1 (si llega a 0, vale 255), algo así rompe incluso dicha posibilidad.
Esta función se puede complicar todo lo que se quiera, su contenido es una muestra.

Ahora la función 'CifradoXor' para cifrar con XOR... ojo, no se toma la clave, si no la clave 'ampliada', que genera un tocho pseudoaleatorio y mas que apto, para cifrar. En el ejemplo se ha puesto para que se amplíe hasta 1Mb. en la práctica

Finalmente solo faltarían las funciones que invocan a esas... en el ejemplo, la general que realiza ambas funciones. Si es para uso propio queda así más cómodo, en cambio si va a ser para que la usen terceros es preferible desmontarlo en dos funciones, 'Codificar' y 'Decodificar'
Código (vbnet) [Seleccionar]

Imports System.IO
Imports System.Text

Public Class Coder
       Public Enum OpCifrado
           CIFRADO_OP_ON = 0
           CIFRADO_OP_OFF = 1
       End Enum

       Public Function Generar(ByRef RutaIn As String, ByRef RutaOut As String, ByRef Clave As String, ByVal Op As OpCifrado) As Boolean
           Dim fi As IO.FileInfo
           Dim key() As Byte
           Dim Datos() As Byte
           Dim largo As Integer = 1048576 ' 1Mb.
           Dim n As Integer

           fi = New IO.FileInfo(RutaIn)
           If (fi.Exists = True) Then
               fi = New IO.FileInfo(RutaOut)
               If (fi.Exists = False) Then
                   key = Encoding.ASCII.GetBytes(Clave)
                   n = AmpliarClave(key, largo)

                    'IO.File.WriteAllBytes(Application.StartupPath & "\key-" & Op.ToString & ".bin", key)
                   ' ambas operaciones comparten código antes y después, aquí lo que varía, el ordne inverso de operaciones.
                   If (Op = OpCifrado.CIFRADO_OP_ON) Then
                       Datos = IO.File.ReadAllBytes(RutaIn)
                       Me.CifradoXor(key, Datos, largo)
                       IO.File.WriteAllText(RutaOut, Convert.ToBase64String(Datos))
                   Else
                       Datos = Convert.FromBase64String(IO.File.ReadAllText(RutaIn))
                       Me.CifradoXor(key, Datos, largo)
                       IO.File.WriteAllBytes(RutaOut, Datos)
                   End If

                   Array.Clear(key, 0, key.Length)
                   Array.Clear(Datos, 0, Datos.Length)
                   Return True
               Else
                   MessageBox.Show("El fichero de salida ya existe. el programa no sobrescribe ficheros por seguridad...", "operación cancelada")
                   Return False
               End If
           Else
               MessageBox.Show("El fichero a procesar no existe o no se encuentra en la ruta recibida...", "operación cancelada")
               Return False
           End If
       End Function

       Private Function AmpliarClave(ByRef Key() As Byte, ByVal Largo As Integer) As Integer
           Dim salida() As Byte
           Dim temp(0 To 10) As Byte
           Dim k As Integer, j As Integer, n As Integer

           Do ' en cada ciclo, el array aumenta al doble de tamaño.
               ReDim salida(0 To (Key.Length * 2) - 1)

               ' Fase1: Ampliación:  intercala entre cada dos bytes otro cuyo valor es la media de los dos que el rodean.
               '    Antes: cocacola   Ahora: ciocbaciolfa
               n = 0
               For k = 0 To Key.Length - 2  
                   salida(n) = Key(k)
                   salida(n + 1) = (Key(k) + Key(k + 1)) \ 2
                   n += 2
               Next
               salida(n) = Key(k)  ' el último byte... en sendos arrays.

               ' Fase2: Intercambios   intercambia el orden cada 7 bytes (entre ellos, y solo 1 conserva su posición)
               '     Antes: ABCDEFG, ahora: FBEAGDC
               For k = 0 To salida.Length - 8 Step 7                    
                   n = salida(k) : salida(k) = salida(k + 5) : salida(k + 5) = salida(k + 3) : salida(k + 3) = n       ' intercambiar 3 entre ellos            
                   n = salida(k + 2) : salida(k + 2) = salida(k + 4) : salida(k + 4) = salida(k + 6) : salida(k + 6) = n ' intercambiar los otros 3 entre ellos
               Next

               ' Fase3: Invertir secciones: invertir el orden entre cierta cantidad de bytes (conviene que sea un valor primo (no gigante)).
               For k = 0 To salida.Length - 12 Step 11
                   Array.Copy(salida, k, temp, 0, 11)
                   n = 0
                   For j = k + 10 To k Step -1
                       salida(j) = temp(n)
                       n += 1
                   Next
               Next

               Key = salida
           Loop While (Key.Length < Largo)

           Return Key.Length
       End Function

       Private Sub CifradoXor(ByRef Key() As Byte, ByRef Datos() As Byte, ByVal Largo As Integer)
           Dim j As Integer, k As Integer

           If (Datos.Length < Largo) Then Largo = Datos.Length

           For j = 0 To Datos.Length - 1 Step Largo
               For k = 0 To Largo - 1
                   Datos(j + k) = (Datos(j + k) Xor Key(k))
               Next
           Next
       End Sub
End Class

Quitando las líneas de comentarios, son apenas 100 líneas de código para hacer lo que quieres, ambas partes y lo mejor, funciona bien... aunque quizás haya algún gazapo, pués lo he escrito 'al vuelo' y no lo he probado a fondo, solo con 3 ficheros y ya...


También adjunto debajo el código de llamada, para mostrar su uso. Supuesto un botón...
Código (vbnet) [Seleccionar]

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
       Dim b As New Coder

       RutaIn = Application.StartupPath & "\CFO32L.dll"
       RutaOut = Application.StartupPath & "\coded.txt"
       If (b.Generar(RutaIn, RutaOut, "TontoElQueLoLea", Coder.OpCifrado.CIFRADO_OP_ON) = True) Then
           RutaIn = RutaOut
           RutaOut = Application.StartupPath & "\decoded.data"
           b.Generar(RutaIn, RutaOut, "TontoElQueLoLea", Coder.OpCifrado.CIFRADO_OP_OFF)
       End If
   End Sub


Si al final se calcula el hash al fichero de origen (para el ejemplo yo he puesto un fichero dll que tenía a mano) y el 'decoded.data', si no hubo problemas debe ser el mismo... yo lo he probando y me funciona bien, y solo he perdido poco más o menos que 2 horas. El código es mucho más escueto, sencillo y consigue el mismo resultado. La fuerza de todo estará en tu "TontoElQueLoLea", que es la clave de cifrado... no precisa tanto rodeo.

El fichero de entrada ocupa algo así como 145kb. el 'coded.txt' 194kb. y si lo comprimes (por ejemplo con winrar), sale por 72kb.

OJO: Puestos a comprimir, es preferible que sea la primera operación, pués los ejecutables se prestan mejor a una compresión que un tocho codificado en base64 (que siempre aumenta de tamaño). Así si comprimo la dll original con winrar antes de nada se queda en 33kb.



p.d.: editado para añadir la línea (comentada) siguiente.
IO.File.WriteAllBytes(Application.StartupPath & "\key-" & Op.ToString & ".bin", key)
Guarda a fichero la clave generada , para poder realizar luego un estudio de la aleatoriedad de la 'clave ampliada'... Al ejecutar el programa se crearían pués dos ficheros 'crypt/decrypt', que evidentemente serán idénticos.