VB .NET - Length of the data to decrypt is invalid - vb.net

I'm trying to do an exercise about encryption and decryption. I already have the following working code to encrypt (I know that ECB is bad, I won't use it in real life, I promise):
Dim hashmd5 As MD5CryptoServiceProvider
Dim des As TripleDESCryptoServiceProvider
Dim keyhash As Byte()
Dim buff As Byte()
Try
hashmd5 = New MD5CryptoServiceProvider
keyhash = hashmd5.ComputeHash(ASCIIEncoding.ASCII.GetBytes("exe67rci89"))
des = New TripleDESCryptoServiceProvider
des.Mode = CipherMode.ECB
des.Key = keyhash
buff = ASCIIEncoding.ASCII.GetBytes(Me.txtPwd.Text)
Me.txtPwd.Text = Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buff, 0, buff.Length))
Catch ex As System.Exception
Throw ex
End Try
Now I'm trying to decrypt the output of this function. I tried to use the same code, just substituting the encryption line with:
Me.txtPwd.Text = Convert.ToBase64String(des.CreateDecryptor().TransformFinalBlock(buff, 0, buff.Length))
But it doesn't work, because I receive the error "Length of the data to decrypt is invalid". I already tried many solutions found here on stack overflow, but no one works. Can someone help me to solve this problem? Thanks in advance!

You're not reversing enough of the transformation. What's now in txtPwd is a base-64 string, not a plain string to be converted using the ASCII encoding. And conversely, what you're going to produce in decryption are bytes that should be interpreted as ASCII characters.
So what you want is:
buff = Convert.FromBase64String(Me.txtPwd.Text)
Me.txtPwd.Text = ASCIIEncoding.ASCII.GetString(des.CreateDecryptor().TransformFinalBlock(buff, 0, buff.Length))

What you're trying to decrypted isn't exactly the same as what came out of the actual encrypt:
In your encrypt you convert the encrypted bytes to a base 64 string using Convert.ToBase64String
You need to convert the string in the txtPwd field back into the byte array that was the result of the original encryption. See the matching Convert.FromBase64String method.
You might be able to view what I mean better if you split the original encrypt line up:
dim encBytes = des.CreateEncryptor().TransformFinalBlock(buff, 0, buff.Length)
Me.txtPwd.Text = Convert.ToBase64String(encBytes)
This way you can see the actual encrypt results, and validate that what you pass in is the same.

Related

What am I supposed to do in .NET with a UTF8 Encoded string?

I am using the Google Chrome Native Messaging which says that it supplies UTF8 encoded JSON. Found here.
I am pretty sure my code is fairly standard and pretty much a copy from answers here in C#. For example see this SO question.
Private Function OpenStandardStreamIn() As String
Dim MsgLength As Integer = 0
Dim InputData As String = ""
Dim LenBytes As Byte() = New Byte(3) {} 'first 4 bytes are length
Dim StdIn As System.IO.Stream = Console.OpenStandardInput() 'open the stream
StdIn.Read(LenBytes, 0, 4) 'length
MsgLength = System.BitConverter.ToInt32(LenBytes, 0) 'convert length to Int
Dim Buffer As Char() = New Char(MsgLength - 1) {} 'create Char array for remaining bytes
Using Reader As System.IO.StreamReader = New System.IO.StreamReader(StdIn) 'Using to auto dispose of stream reader
While Reader.Peek() >= 0 'while the next byte is not Null
Reader.Read(Buffer, 0, Buffer.Length) 'add to the buffer
End While
End Using
InputData = New String(Buffer) 'convert buffer to string
Return InputData
End Function
The problem I have is that when the JSON includes characters such as ß Ü Ö Ä then the whole string seems to be diffent and I cannot deserialize it. It is readable and my log shows the string is fine, but there is something different. As long as the string does NOT include these characters then deserialization works fine. I am not supplying the JavascriptSerializer code as this is not the problem.
I have tried creating the StreamReader with different Encodings such as
New System.IO.StreamReader(StdIn, Encoding.GetEncoding("iso-8859-1"), True)
however the ß Ä etc are then not correct.
What I don't understand is if the string is UTF8 and .NET uses UTF16 how am I supposed to make sure the conversion is done properly?
UPDATE
Been doing some testing. What I have found is if I receive a string with fuß then the message length (provided by native messaging) is 4 but number of Char in the buffer is 3, if the string is fus then the message length is 3 and number of characters is 3. Why is that?
With the above code the Buffer object is 1 too big and thus is why there is a problem. If I simple use the Read method on the stream then it works fine. It appears that Google Messaging is sending a message length that is different when the ß is in the string.
If I want to use the above code then how can I know that the message length is not right?
"Each message is serialized using JSON, UTF-8 encoded and is preceded with 32-bit message length in native byte order. The maximum size of a single message from the native messaging host is 1 MB." This implies that the message length is in bytes, also, that the length is not part of the message (and so its length is not included in length).
Your confusion seems to stem from one of two things:
UTF-8 encodes a Unicode codepoint in 1 to 4 code units. (A UTF-8 code unit is 8 bits, one byte.)
Char is a UTF-16 code unit. (A UTF-16 code unit is 16 bits, two bytes. UTF-16 encodes a Unicode codepoint in 1 to 2 code units.)
There is no way to tell how many codepoints or UTF-16 code units are in the message until after it is converted (or scanned, but then you might as well just convert it).
Then, presumably, stream will either be found to be closed or the next thing to read would be another length and message.
So,
Private Iterator Function Messages(stream As Stream) As IEnumerable(Of String)
Using reader = New BinaryReader(stream)
Try
While True
Dim length = reader.ReadInt32
Dim bytes = reader.ReadBytes(length)
Dim message = Encoding.UTF8.GetString(bytes)
Yield message
End While
Catch e As EndOfStreamException
' Expected when the sender is done
Return
End Try
End Using
End Function
Usage
Messages(stream).ToList()
or
For Each message In Messages(stream)
Debug.WriteLine(message)
Next message
if you're displaying the output of this code in a console, this would diffidently happen. because windows console doesn't display Unicode characters. if this wasn't the case, then try to use a string builder to convert the data inside your StdIn stream to a string

encrypt a string using SHA512

Here 's my code and I have no idea why it produces a weird code in the console
(output is "b5?2???p?????'5???.?H???Kun???a??\??d??+\??%??A)?_???j?" without the quotes)
Private Sub TestSHA512()
Dim key As String = "635357773463315343"
Dim pass As String = "somepasswd"
Dim enc As System.Text.Encoding = New System.Text.ASCIIEncoding
Dim keyBytes() As Byte = enc.GetBytes(key)
Dim passBytes() As Byte = enc.GetBytes(pass)
Dim SHA As New HMACSHA512(keyBytes)
Dim resultBytes() As Byte = SHA.ComputeHash(passBytes)
Console.WriteLine(enc.GetString(resultBytes))
Console.WriteLine(enc.GetString(SHA.Hash)) 'same...
End Sub
First, SHA512 is a hash algorithm, not an encryption scheme, so if you're trying to encrypt then SHA512 isn't the way to do it. You'd need to look at an encryption class, such as AesManaged.
ComputeHash gives you the computed hash as a byte array. You're using ASCIIEncoding.GetString to convert that into a string, but not every byte is a printable ASCII character. That's why you're seeing the ??? characters in your console output.
If you're asking how to display the hash output as a printable string, use Convert.ToBase64String, which will convert the byte array into a string using base64 encoding. If you were expecting it in hexadecimal, you can loop through the byte array and print the Hex() value of each byte.

Read Data From The Byte Array Returned From Web Service

I have a web service,which return data in byte array.Now i want to read that data in my console project.How can i do that,i already add the desire references to access that web service.I am using vb.net VS2012.Thanks.My web service method is as follow.
Public Function GetFile() As Byte()
Dim response As Byte()
Dim filePath As String = "D:\file.txt"
response = File.ReadAllBytes(filePath)
Return response
End Function
Something like,
Dim result As String
Using (Dim data As New MemoryStream(response))
Using (Dim reader As New StreamReader(data))
result = reader.ReadToEnd()
End Using
End Using
if you knew the encoding, lets say it was UTF-8 you could do,
Dim result = System.Text.UTF8Encoding.GetString(response)
Following on from your comments, I think you are asserting this.
Dim response As Byte() 'Is the bytes of a Base64 encoded string.
So, we know all the bytes will be valid ASCII (because its Base64,) so the string encoding is interchangable.
Dim base64Encoded As String = System.Text.UTF8Encoding.GetString(response)
Now, base64Encoded is the string Base64 representation of some binary.
Dim decodedBinary As Byte() = Convert.FromBase64String(base64Encoded)
So, we've changed the encoded base64 into the binary it represents. Now, because I can see that in your example, you are reading a file called "D:/file.txt" I'm going to make the assumption that the contents of the file is a character encoded string, but I don't know the encoding of the string. The StreamReader class has some logic in the constructor that can make an educated guess at character encoding.
Dim result As String
Using (Dim data As New MemoryStream(decodedBinary))
Using (Dim reader As New StreamReader(data))
result = reader.ReadToEnd()
End Using
End Using
Hopefully, now result contains the context of the text file.

How can I read Greek characters from my database in my web app?

I've got Greek text stored in my access database. For some reason it doesn't appear in Greek- it uses other symbols instead.
e.g. Ãëþóóá instead of Γλώσσα
I can convert it in my windows app like this:
Dim encoder As Encoding = Encoding.GetEncoding(1253)
Dim valueInBytes As Byte() = encoder.System.IO.File.ReadAllBytes(lanuageFilePath)
languageValue = encoder.GetString(valueInBytes)
However, I now need to use the values in my web app. But the ReadAllBytes method is not available to me. I've tried using GetBytes instead, but this doesn't seem to produce the same results.
Dim encoder As Encoding = Encoding.GetEncoding(1253)
Dim valueInBytes As Byte() = encoder.GetBytes(languageValue)
languageValue = encoder.GetString(valueInBytes)
What am I doing wrong?
The first one seems to have nothing to do with text in a variable, your reading from a file.
Dim encoder As Encoding = Encoding.GetEncoding(1253)
Dim valueInBytes As Byte() = System.IO.File.ReadAllBytes(languageValue)
languageValue = encoder.GetString(valueInBytes)
ReadAllBytes should be supported in most frameworks so there should not be a problem with this on the server.
The other code seems to be doing soething compleatly different. You are converting the string to bytes and back again in the same encoding, to get this to work you need to find out which encoding access thought it was and encode with that. However it may still not have survived the roundtrip as access may be doing some normalistion of the unicode.
Dim encoder As Encoding = Encoding.GetEncoding(1253)
Dim accessencoder As Encoding = Encoding.GetEncoding({{accesses encoding numer here}})
Dim valueInBytes As Byte() = accessencoder.GetBytes(languageValue)
languageValue = encoder.GetString(valueInBytes)

SSRS Decrypting database column throws error "Value cannot be null. Parameter name: inputBuffer"

We have a database field that is encrypted in a C# MVC app using Entity Framework. That part works fine for encrypting and decrypting. We need to show this data decrypted in an SSRS report.
I've taken the Decrypt method and converted it to VB.Net and placed in the code behind of the report. The error occurs when calling the StreamReader's ReadToEnd method. We've found some references online about there being an issue trying to close a stream that's already closed. This stream is only being read from one time and we're reading the entire stream so it should not be closed at that point.
I tried reading Length - 1 bytes from the cryptoStream and that did not throw an error. If I try to read Length bytes, I get the same error. If I read all but one byte and then read only the last byte I get the same error. Stack trace and code are below. Any help would be greatly appreciated.
Stacktrace:
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Stream.Dispose()
at ReportExprHostImpl.CustomCodeProxy.Decrypt(String ciphertext)
Code:
public function Decrypt(byval ciphertext as string) as string
dim message as string
dim key as string
dim saltSize as integer
saltsize = 32
key = "KEYGOESHERE"
dim allTheBytes as byte()
allTheBytes = Convert.FromBase64String(ciphertext)
dim saltBytes as byte()
saltBytes = new byte(saltsize) {}
dim ciphertextBytes as byte()
ciphertextBytes = new byte(allTheBytes.Length - saltSize) {}
dim i as integer
for i = 0 to saltsize - 1
saltBytes(i) = allTheBytes(i)
next i
for i = saltSize to (allTheBytes.Length - 1)
ciphertextBytes(i - saltSize) = allTheBytes(i)
next i
try
using keyDerivationFunction as System.Security.Cryptography.Rfc2898DeriveBytes = new System.Security.Cryptography.Rfc2898DeriveBytes(key, saltBytes)
dim keyBytes as byte()
keyBytes = keyDerivationFunction.GetBytes(32)
dim ivBytes as byte()
ivBytes = keyDerivationFunction.GetBytes(16)
using aesManaged as System.Security.Cryptography.AesManaged = new System.Security.Cryptography.AesManaged()
aesManaged.Padding = System.Security.Cryptography.PaddingMode.PKCS7
aesManaged.Mode = System.Security.Cryptography.CipherMode.CBC
using decryptor as System.Security.Cryptography.ICryptoTransform = aesManaged.CreateDecryptor(keyBytes, ivBytes)
using memoryStream as System.IO.MemoryStream = new System.IO.MemoryStream(ciphertextBytes)
using cryptoStream as System.Security.Cryptography.CryptoStream = new System.Security.Cryptography.CryptoStream(memoryStream, decryptor, System.Security.Cryptography.CryptoStreamMode.Read)
using streamReader as System.IO.StreamReader = new System.IO.StreamReader(cryptoStream)
message = streamReader.ReadToEnd()
return message
end using
end using
end using
end using
end using
end using
catch e as Exception
return e.StackTrace
end try
end function
This sounds like a padding error. First of all, AES in CBC mode requires an exact message size for decryption, N times the blocksize (of 16 bytes). If the message has this size then AES CBC ciphertext will always decrypt. Any other problem can only be related to padding really. So what happens is that the last deciphered plain text does not have the correct padding, and an exception occurs.
Now comes the fun part; this error occurs when:
the binary AES key is not identical;
if the algorithm or mode is incorrect or if the wrong padding algorithm is used;
if one of the last two blocks is mangled;
if the last part of the encryption is missing in action.
In other words, if something is wrong, it is likely that it will turn up during the removal of the padding bytes. If you are unlucky, the last incorrect block still ends with a byte value of 01 hexadecimal, and padding succeeds, showing that padding is no substitution for integrity protection.