I have a encryption/decryption method that works just fine with one exception. When I attempt to read in encrypted text from a text file and then decrypt it I get the following error.
Invalid character in a Base-64 string
The strange thing is if I just read the encrypted text into a textbox and then copy and pate it into another text box that decrypts used the same decryption method it works just fine. No errors and the decryption proceeds. I am listing the decryption method and method used to read in the text file below.
Decryption Method
Public Shared Function DecryptUserString(ByRef cipheredText As String, ByRef password As String) As String
Dim RijndaelManagedObj As New RijndaelManaged
Dim RijndaelEncObj As ICryptoTransform, MD5Obj As New MD5CryptoServiceProvider
Dim DecryptedBytes As Byte(), EncryptedData As Byte()
Dim PasswordBytes As Byte() = New ASCIIEncoding().GetBytes(password)
Dim UTF8Encoding As System.Text.Encoding = System.Text.Encoding.UTF8
'A modified Base64 is sent with ~ and - so it can be sent as a form post
EncryptedData = Convert.FromBase64String(Replace(Replace(cipheredText, "~", "+"), "-", "="))
RijndaelManagedObj.BlockSize = 128
RijndaelManagedObj.KeySize = 128
RijndaelManagedObj.Mode = CipherMode.ECB
RijndaelManagedObj.Padding = PaddingMode.None
RijndaelManagedObj.Key = MD5Obj.ComputeHash(PasswordBytes)
RijndaelEncObj = RijndaelManagedObj.CreateDecryptor()
DecryptedBytes = RijndaelEncObj.TransformFinalBlock(EncryptedData, 0, EncryptedData.Length)
If DecryptedBytes.Length > 0 Then
DecryptUserString = UTF8Encoding.GetString(DecryptedBytes, 0, DecryptedBytes.Length)
If DecryptedBytes.Length = 0 Then DecryptUserString = New ASCIIEncoding().GetString(DecryptedBytes)
Else
DecryptUserString = ""
End If
End Function
Method to read text from file
Private Function ReadText(ByVal TextFilePath As String) As String
Using ReadStream As FileStream = File.OpenRead(TextFilePath)
Dim FileTextBuilder As New StringBuilder()
Dim DataTransit As Byte() = New Byte(ReadStream.Length) {}
Dim DataEncoding As New UTF8Encoding(True)
While ReadStream.Read(DataTransit, 0, DataTransit.Length) > 0
FileTextBuilder.Append(DataEncoding.GetString(DataTransit))
End While
Return FileTextBuilder.ToString()
End Using
End Function
Can't you use File.ReadAllText() method to read the whole file and then decrypt the same way you do with textboxes?
I know, if file is huge that's not a good idea, but you can give it a try to see if file is well saved or if you're reading it bad.
Related
I am creating a project where a zip file is base 64 encoded and then the file is decoded and saved, but when I unzip the file it gives a corrupted file error.
Dim zip As New Xs_UnZipFilesCompat
''Encode()
Dim base64encoded As String
Using r As StreamReader = New StreamReader(File.OpenRead("E:\zip_test.zip"))
Dim data As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(r.ReadToEnd())
base64encoded = System.Convert.ToBase64String(data)
r.Dispose()
End Using
'decode --> write back
Using w As StreamWriter = New StreamWriter(File.Create("e:\stcRepositorio\Entrena_To_Art\Enviar\testDEco.zip"))
Dim data As Byte() = System.Convert.FromBase64String(base64encoded)
w.Write(System.Text.ASCIIEncoding.ASCII.GetString(data))
w.Dispose()
End Using
I can't find the solution
The encode is not correct. Specifically, this line:
Dim data As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(r.ReadToEnd())
You definitely don't want to read a file with a *.zip extension as if it were made of ASCII characters. Replace it with this:
Dim data As Byte() = System.IO.File.ReadAllBytes(fileName)
Which means you also no longer need the StreamReader, so we end up with this:
Public Function Encode(fileName As String) As String
Return Convert.ToBase64String(IO.File.ReadAllBytes(fileName))
End Function
Then the Decode would look like this:
Public Sub Decode(fileName As String, base64Data As String)
IO.File.WriteAllBytes(fileName, Convert.FromBase64String(base64Data))
End Sub
And you could call them like this:
Dim base64encoded As String = Encode("E:\zip_test.zip")
Decode("e:\stcRepositorio\Entrena_To_Art\Enviar\testDEco.zip", base64encoded)
Or we can write it without the methods like this:
Dim base64encoded As String = Convert.ToBase64String(IO.File.ReadAllBytes("E:\zip_test.zip"))
IO.File.WriteAllBytes("e:\stcRepositorio\Entrena_To_Art\Enviar\testDEco.zip", Convert.FromBase64String(base64encoded))
But it seems like that all reduces down to this:
IO.File.Copy("E:\zip_test.zip", "e:\stcRepositorio\Entrena_To_Art\Enviar\testDEco.zip")
I'm trying to copy the encrypted contents of a text file into a memory stream and then decrypt and copy those contents into a new memory stream. When I reach the code where the copy occurs I get a Invalid Data error on debug.
This is the block of code I got:
Function DecryptFile(ByVal sInputFilename As String, ByVal sKey As String) As Byte()
Dim DES As New DESCryptoServiceProvider()
DES.Key() = ASCIIEncoding.ASCII.GetBytes(sKey)
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey)
Dim desdecrypt As ICryptoTransform = DES.CreateDecryptor()
Dim encryptedByteArray() As Byte
encryptedByteArray = File.ReadAllBytes(sInputFilename)
Dim encryptedMS As MemoryStream = New MemoryStream(encryptedByteArray)
Dim cryptostreamDecr As New CryptoStream(encryptedMS, desdecrypt, CryptoStreamMode.Read)
Dim decryptedMS As MemoryStream = New MemoryStream()
cryptostreamDecr.CopyTo(decryptedMS) 'Error occurs here
cryptostreamDecr.Close()
Return decryptedMS.ToArray()
End Function
I'm following examples I've found scattered around the web and from what I've read, this code should work...
May anyone explain to me what am I doing wrong?
Here's an example to encrypt/decrypt a string and a file using a Key without explicitly providing an Initialization Vector (so yo don't need to store and retrieve it to decrypt encrypted data).
The Encryption provider I'm using here is TripleDESCryptoServiceProvider.
If you need to use a DES provider, it's exactly the same thing, you just need to change TripleDESCryptoServiceProvider to DESCryptoServiceProvider.
But, as you can read in the Docs, better move to the AesCryptoServiceProvider, if/when possible.
The Initialization Vector (IV) is calculated based on the Key specified and it's the same Hashed value if the Key to Decrypt the data is the same as the Key used to Encrypt it.
In this case, you lose some security, but you don't need to store either the Key or the IV (if the Key is provided by a User, who's responsible for protecting the Key).
The Mode is left to its default: CipherMode.CBC.
The Padding Mode to its default: PaddingMode.PKCS7.
Encrypt and decrypt a sting to and from a Base64String:
Dim enc3Des As New TripleDesEncryptor("MyFancyKey")
Dim inputString = "Some fancy string to be encoded to a Base64 string"
Dim encodedB64 = enc3Des.EncryptStringToBase64(inputString)
Dim decoded64 = enc3Des.DecryptBase64String(encoded64)
To encrypt a file, provide the path to the Source file, then save the bytes returned by the Encryption method to a destination file:
Dim enc3Des As New TripleDesEncryptor("MyFancyKey")
Dim plainTextFilePath = [Source file Path]
Dim encryptedFilePath = [Encrypted file Path]
Dim encodedBytes = enc3Des.EncryptFile(plainTextFilePath)
File.WriteAllBytes(encryptedFilePath, encodedBytes)
You can of course decrypt the File when required, using the same Key:
Dim encryptedFilePath = [Encrypted file Path]
Dim decryptedFilePath = [Decrypted file Path]
Dim enc3Des2 As New TripleDesEncryptor("MyFancyKey")
Dim decodedBytes = enc3Des2.DecryptFile(encryptedFilePath)
File.WriteAllBytes(decryptedFilePath, decodedBytes)
The TripleDesEncryptor helper class:
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Public NotInheritable Class TripleDesEncryptor
Private tripleDesProvider As New TripleDESCryptoServiceProvider()
Sub New(key As String)
tripleDesProvider.Key = GetKeyHash(key, tripleDesProvider.LegalKeySizes(0).MaxSize \ 8)
tripleDesProvider.IV = GetKeyHash(key, tripleDesProvider.LegalBlockSizes(0).MaxSize \ 8)
End Sub
Public Function EncryptStringToBase64(inputString As String) As String
Dim dataBytes As Byte() = Encoding.Unicode.GetBytes(inputString)
Return Convert.ToBase64String(Encrypt(dataBytes))
End Function
Public Function EncryptFile(fileName As String) As Byte()
Dim dataBytes As Byte() = File.ReadAllBytes(fileName)
Return Encrypt(dataBytes)
End Function
Private Function Encrypt(dataBytes As Byte()) As Byte()
Using ms As New MemoryStream(),
encStream As New CryptoStream(ms, tripleDesProvider.CreateEncryptor(), CryptoStreamMode.Write)
encStream.Write(dataBytes, 0, dataBytes.Length)
encStream.FlushFinalBlock()
Return ms.ToArray()
End Using
End Function
Public Function DecryptBase64String(base64String As String) As String
Dim dataBytes As Byte() = Convert.FromBase64String(base64String)
Return Encoding.Unicode.GetString(Decrypt(dataBytes))
End Function
Public Function DecryptFile(fileName As String) As Byte()
Dim dataBytes As Byte() = File.ReadAllBytes(fileName)
Return Decrypt(dataBytes)
End Function
Private Function Decrypt(encryptedData As Byte()) As Byte()
Using ms As New MemoryStream(),
decStream As New CryptoStream(ms, tripleDesProvider.CreateDecryptor(), CryptoStreamMode.Write)
decStream.Write(encryptedData, 0, encryptedData.Length)
decStream.FlushFinalBlock()
Return ms.ToArray()
End Using
End Function
Private Function GetKeyHash(key As String, length As Integer) As Byte()
Using sha1 = SHA1.Create()
Dim varHash As Byte() = New Byte(length - 1) {}
Dim keyBytes As Byte() = Encoding.Unicode.GetBytes(key)
Dim hash As Byte() = sha1.ComputeHash(keyBytes).Take(length).ToArray()
Array.Copy(hash, 0, varHash, 0, hash.Length)
hash = Nothing
keyBytes = Nothing
Return varHash
End Using
End Function
End Class
Perhaps I should have explained what I'm trying to achieve in the first place.
I have a text file that has over 1000 keywords. The vb.net application will, at some point, read these keywords from the text file to do something with them.
Now, my approach here is to not let prying eyes to edit the text file, changing the key words or even knowing which keywords are on it.
Therefor, what I did was encrypt the keywords and save the encrypted content into a new file and deleted the unencrypted file, so that this way I don't need to care about people checking the encrypted file, because it's just gibberish.
According to Jimi's explanation, posted before, I see now that in order to decrypt the file, I need the same IV I used for encrypting the previous file.
So the only way I see for this to be possible without having an unencrypted file 'lying around' is to store the IV secret key within the application's settings, correct?
I'm aware of the other thread on this issue (AES decryption error " The input data is not a complete block." Error vb.net), but I'm either not implementing the solutions offered there correctly, or something about my particular variant of this issue isn't covered by those solutions. In any event I'm getting the incomplete block error from the following code
Private GD As System.Security.Cryptography.Aes = System.Security.Cryptography.Aes.Create
Private PDB As New System.Security.Cryptography.Rfc2898DeriveBytes(EK, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D, &H65, &H64, &H76, &H65, &H64, &H65, &H76})
Public Function Decrypt(ByVal val As String) As String
Dim ret As String = Nothing
Dim TTB As New System.Text.UTF8Encoding
Try
Dim input() As Byte = TTB.GetBytes(val)
Using ms As New System.IO.MemoryStream(input)
Using cs As New System.Security.Cryptography.CryptoStream(ms, GD.CreateDecryptor(PDB.GetBytes(32), PDB.GetBytes(16)), Security.Cryptography.CryptoStreamMode.Read)
Using sr As New System.IO.StreamReader(cs)
ret = sr.ReadToEnd()
End Using
End Using
End Using
input = nothing
Catch ex As Exception
EL.AddErr("Encountered an error while decrypting the provided text for " & FName & ". Error Details: " & ex.Message, path)
End Try
Return ret
End Function
EK is my key, which I'll not be including. It's just a String though, nothing special.
I've tried several other methods to decrypt based on guidance on the MSDN site, DreamInCode, etc. None worked, but they all had different issues (typically returning a blank string). Seeing as this version of code closely mirrors my encryption code, I'd like to stick with it (or at least as close as I can while still having functional code).
Despite all comments, I still lack understanding of your intentions. Therefore, the sample code below may not provide what you exactly want, but at least should give an idea how to employ cryptographic functions. Particularly, the most notable difference from your approach is that the encryption key and initialization vector are computed once and for all messages, rather than reevaluated on each occasion, because the latter is prone to synchronization errors — such as when you reuse single crypto object to communicate with multiple parties, or when some messages get lost in transmission.
Public Shared Sub Test()
' Note: You should not actually hard-code any sensitive information in your source files, ever!
Dim sKeyPreimage As String = "MySuperPassword"
Dim oMyCrypto As New MyCrypto(sKeyPreimage)
Dim sPlaintext As String = "My super secret data"
Dim sEncrypted As String = oMyCrypto.EncryptText(sPlaintext)
Dim sDecrypted As String = oMyCrypto.DecryptText(sEncrypted)
Console.Out.WriteLine("Plaintext: {0}", sPlaintext) ' "My super secret data"
Console.Out.WriteLine("Encrypted: {0}", sEncrypted) ' "72062997872DC4B4D1BCBF48D5D30DF0D498B20630CAFA28D584CCC3030FC5F1"
Console.Out.WriteLine("Decrypted: {0}", sDecrypted) ' "My super secret data"
End Sub
Public Class MyCrypto
Private Shared TextEncoding As Text.Encoding = Text.Encoding.UTF8
Private CipherEngine As System.Security.Cryptography.SymmetricAlgorithm
' Note: Unlike in the question, same key and IV are reused for all messages.
Private CipherKey() As Byte
Private CipherIV() As Byte
Public Sub New(ByVal sKeyPreimage As String)
Dim abKeyPreimage() As Byte = TextEncoding.GetBytes(sKeyPreimage)
Dim abKeySalt() As Byte = TextEncoding.GetBytes("Ivan Medvedev")
Const KeyDerivationRounds As Integer = 1 << 12
Dim oKeyDerivationEngine As New System.Security.Cryptography.Rfc2898DeriveBytes(abKeyPreimage, abKeySalt, KeyDerivationRounds)
Me.CipherEngine = System.Security.Cryptography.Aes.Create()
Me.CipherEngine.Padding = Security.Cryptography.PaddingMode.PKCS7
Me.CipherKey = oKeyDerivationEngine.GetBytes(Me.CipherEngine.KeySize >> 3)
Me.CipherIV = oKeyDerivationEngine.GetBytes(Me.CipherEngine.BlockSize >> 3)
End Sub
Public Function Encrypt(ByVal abPlaintext() As Byte) As Byte()
Dim abCiphertext() As Byte
Using hStreamSource As New System.IO.MemoryStream(abPlaintext),
hStreamCipher As New System.Security.Cryptography.CryptoStream(
hStreamSource,
Me.CipherEngine.CreateEncryptor(Me.CipherKey, Me.CipherIV),
Security.Cryptography.CryptoStreamMode.Read),
hStreamTarget As New System.IO.MemoryStream
hStreamCipher.CopyTo(hStreamTarget)
abCiphertext = hStreamTarget.ToArray()
End Using
Return abCiphertext
End Function
Public Function Decrypt(ByVal abCiphertext() As Byte) As Byte()
Dim abPlaintext() As Byte
Using hStreamSource As New System.IO.MemoryStream(abCiphertext),
hStreamCipher As New System.Security.Cryptography.CryptoStream(
hStreamSource,
Me.CipherEngine.CreateDecryptor(Me.CipherKey, Me.CipherIV),
Security.Cryptography.CryptoStreamMode.Read),
hStreamTarget As New System.IO.MemoryStream
hStreamCipher.CopyTo(hStreamTarget)
abPlaintext = hStreamTarget.ToArray()
End Using
Return abPlaintext
End Function
Public Function EncryptText(ByVal sPlaintext As String) As String
Dim abPlaintext() As Byte = TextEncoding.GetBytes(sPlaintext)
Dim abCiphertext() As Byte = Me.Encrypt(abPlaintext)
Dim sCiphertext As String = Hex.Format(abCiphertext)
Return sCiphertext
End Function
Public Function DecryptText(ByVal sCiphertext As String) As String
Dim abCiphertext() As Byte = Hex.Parse(sCiphertext)
Dim abPlaintext() As Byte = Me.Decrypt(abCiphertext)
Dim sPlaintext As String = TextEncoding.GetChars(abPlaintext)
Return sPlaintext
End Function
End Class
Public Class Hex
Public Shared Function Format(ByVal abValue() As Byte) As String
Dim asChars(0 To abValue.Length * 2 - 1) As Char
Dim ndxChar As Integer = 0
For ndxByte As Integer = 0 To abValue.Length - 1
Dim bNibbleHi As Byte = abValue(ndxByte) >> 4, bNibbleLo As Byte = CByte(abValue(ndxByte) And &HFUS)
asChars(ndxChar) = Convert.ToChar(If(bNibbleHi <= 9, &H30US + bNibbleHi, &H37US + bNibbleHi)) : ndxChar += 1
asChars(ndxChar) = Convert.ToChar(If(bNibbleLo <= 9, &H30US + bNibbleLo, &H37US + bNibbleLo)) : ndxChar += 1
Next
Return New String(asChars)
End Function
Public Shared Function Parse(ByVal sValue As String) As Byte()
If String.IsNullOrEmpty(sValue) Then Return New Byte() {}
If (sValue.Length Mod 2) > 0 Then Return Nothing
Dim ndxText As Integer = 0
Dim ndxByteMax As Integer = (sValue.Length \ 2) - 1
Dim abValue(0 To ndxByteMax) As Byte
Try
For ndxByte As Integer = 0 To ndxByteMax
abValue(ndxByte) = Convert.ToByte(sValue.Substring(ndxText, 2), 16)
ndxText += 2
Next
Catch ex As Exception
Return Nothing
End Try
Return abValue
End Function
End Class
Again, please, note that this is just an example. I am not endorsing any kind of protection techniques shown here, especially because your task remains unknown. The code above simply illustrates the syntax and semantics — not how to do it right.
I have this method
Public Shared Function HashPassword(ByVal password As String) As String
Dim algorithm As HashAlgorithm
algorithm = SHA1.Create
Dim data As Byte() = algorithm.ComputeHash(Encoding.UTF8.GetBytes(password))
Dim HashedPassword As String = ""
Dim i As Integer = 0
Do While i < data.Length
HashedPassword &= data(i).ToString("x2").ToLowerInvariant()
i += 1
Loop
Return HashedPassword
End Function
How can I decode a string which has been encoded by this function?
A hash is a one way so you dont decrypt them. Instead, compare the new input value to the stored hash to verify. If you want to encrypt/decrypt data (not the best way to protect passwords), then you need to encrypt, not hash.
But there may be a problem with your method: the result is usually converted to base64 for storing/saving. A hex string might work (never tried) but there is a built in way for this:
Public Shared Function HashPassword(password As String) As String
Dim algorithm As HashAlgorithm
algorithm = SHA1.Create
Dim data As Byte() = algorithm.ComputeHash(Encoding.UTF8.GetBytes(password))
Return Convert.ToBase64String(data)
End Function
So, new user registration would be something like:
hashedPW = HashPassword(thePWText)
To check it later:
thisPW = HashPassword(PWInput)
If thisPW = hashedPW Then
' user knows the PW
Else
' wrong password
End If
I am trying to encrypt a zip in VB.NET to send to an android device using Air. Then once its on the device, decrypt it using the key and IV.
Here is part of my VB.NET Code:
Private Sub EncryptBytes(ByVal fileIn As String, ByVal fileOut As String, ByVal pass As String, ByVal ivString As String)
Dim crypt As New RijndaelManaged
crypt.KeySize = 256
crypt.BlockSize = 256
crypt.Padding = PaddingMode.PKCS7
crypt.Mode = CipherMode.CFB
'read byte array from file location, ie c:\temp\file.zip
Dim data As Byte() = ReadByteArray(fileIn)
Dim iv As Byte() = System.Text.Encoding.UTF8.GetBytes(ivString)
Dim key As Byte() = System.Text.Encoding.UTF8.GetBytes(pass)
Dim encryptor As ICryptoTransform = crypt.CreateEncryptor(key, iv)
Using ms As New System.IO.MemoryStream
Using cs As New CryptoStream(ms, encryptor, CryptoStreamMode.Write)
cs.Write(data, 0, data.Length)
cs.FlushFinalBlock()
End Using
'write byte array to file location, ie c:\temp\file_e.zip
WriteByteArray(fileOut, ms.ToArray)
End Using
End Sub
Two things, first I don't want to use PaddingMode.PKCS7 but when I change it to PaddingMode.None I get an error which says "Length of the data to encrypt is invalid" during decryption.
Second, I have a decryption SUB and it still works if I send it a bogus IV. Why is the IV not effecting the decryption process.
DECRYPTION
In Air I'm using the com.hurlant.crypto package I found at http://crypto.hurlant.com/docs/.
Here is my function:
public static function decryptZip(src:ByteArray, k:String, iv:String):ByteArray {
var key:ByteArray = Hex.toArray(Hex.fromString(k));
var mode:CFBMode = new CFBMode(new AESKey(key), new PKCS7(256));
mode.IV = Hex.toArray(Hex.fromString(iv));
mode.decrypt(src);
return src;
}
This is not working ... Note that I tried to write a PKCS7 class based on a Java class I found. The hurlant package I downloaded only had PKCS5. VB.NET did not provide any of the same padding classes as hurlant comes with. I wish I could using "None" but I couldn't get passed the error in VB.
I think there may also be an issue with the way I am converting a string into a byte array in VB vs Air.
Please help!
check out this sample code i am not sure if it's the solution you are looking for or not,
http://www.obviex.com/samples/Encryption.aspx