I'm having a problem authenticating an API with OAuth. I can get it work fine in Python, but not in VB.Net. I realised the issue is that SHA1 algorithm is returning a different value in Python and VB.NET for the what I thought was the same message. This only seems to be the case when there is a newline character "\n" in the message (which there has to be for the API call). Using Environment.NewLine doesn't seem to help.
The code I'm using (based on this answer) is here, with the expected values I get from my Python program:
Public Sub Main()
' Expect D/5B78PD9pFhmqZQi3eenPBy6ks=
' Get D/5B78PD9pFhmqZQi3eenPBy6ks=
console.writeline(getHash("a", "msg"))
' Expect yuuq6RwtwkoJ6n3PquGFx60MLas=
' Get uv4AwQjvYeCTajhHw7EFtPlJfCE=
console.writeline(getHash("a", "msg\n"))
' Expect yuuq6RwtwkoJ6n3PquGFx60MLas=
' Get efRfAnmIN/C/YX/UPHVPFY5VjJg=
console.writeline(getHash("a", "msg" + Environment.NewLine))
End Sub
Public Function getHash(ByVal key As String, ByVal msg As String) As String
Dim myEncoder As New System.Text.UTF8Encoding
Dim keyBytes() As Byte = myEncoder.GetBytes(key)
Dim msgBytes() As Byte = myEncoder.GetBytes(msg)
Dim myHMACSHA1 As New System.Security.Cryptography.HMACSHA1(keyBytes)
Dim HashCode As Byte() = myHMACSHA1.ComputeHash(msgBytes)
Return Convert.ToBase64String(HashCode)
End Function
In case it's useful, my Python program is:
import base64
import hashlib
import hmac
key = "a"
msg = "msg\n"
key_byte = key.encode('utf-8')
msg_byte = msg.encode('utf-8')
h = hmac.new(key_byte, msg_byte, hashlib.sha1)
print base64.b64encode(h.digest()) # yuuq6RwtwkoJ6n3PquGFx60MLas=
My guess is it's something to do with how the newline character is encoded, but I can't figure out how to solve it.
To start with I'd just like to point out that \n in VB.NET does not represent a new line character. It will literally just become \n.
Environment.NewLine adapts to the current OS. Different operating systems use different line endings. The issue here is that the Python code is using a Line Feed character (\n) as a new line indicator, but since Environment.NewLine adapts to the OS it will return Windows' line ending, which is Carriage Return + Line Feed (\r\n).
Therefore if you want it to match the Python code you've got to be sure to insert a Line Feed only. For instance:
Console.WriteLine(getHash("a", "msg" & vbLf))
Related
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
I'm trying to create an MP3 ID3v1 Tag editor in Visual Basic (2010)
I have no problem reading tags, however, I can't seem to update the tags correctly.
I use FileStream to open the file, and then I use BinaryWriter. I seek to right after the "TAG" header, which is 125 bytes from the end of file.
The first field is the Title field, which is 30 characters long.
So before writing the new tag, I would clear it by writing 30 spaces.
Then I seek back to the beginning, and try to write the new data. But it ends up overwriting data in the next field.
Dim file As New System.IO.FileStream(songpath, IO.FileMode.Open)
Dim bw As New System.IO.StreamWriter(file)
file.Seek(-125, IO.SeekOrigin.End)
bw.Write(" ")
file.Seek(-125, IO.SeekOrigin.End)
bw.Write(data(0))
bw.Close()
file.Close()
Here is a screen cap of the result. I attempted to write "Test" in the title field, I write the data and then reopen the file and this is what I get.
Rather than using file.Seek, I would set the .Position property, like this:
Imports System.IO
Imports System.Text
Module Module1
Sub Main()
Dim f = "C:\temp\sample.MP3"
Dim newTitle = "This is a test."
Dim dataLen = 30
Dim titleData(dataLen - 1) As Byte
Dim newTitleBytes = Encoding.ASCII.GetBytes(newTitle)
Array.Copy(newTitleBytes, titleData, Math.Min(dataLen, newTitleBytes.Length))
Using str As New FileStream(f, FileMode.Open, FileAccess.Write, FileShare.None)
Dim titlePosition = str.Length - 125
str.Position = titlePosition
str.Write(titleData, 0, dataLen)
End Using
End Sub
End Module
The unused portion of the title should be bytes with a value of zero - when you create an array its values are set to zero* for you. Then you can fill the start of the title bytes with the bytes which represent the string in ASCII. I suspect you could get away with using ISO-8859-1 if you need accented characters, but don't rely on that.
The Using construction makes sure that the file is closed afterwards even if something goes wrong.
* If it's an array of a numeric type, like Byte or Integer and so on.
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.
I have been developing a program which communicates with a COM device (Fluke 123 Scopemeter). When I am sending over ASCII data, I have had no issues.
What I need to do is send over a combination of ASCII and HEX data. I've been looking at a number of posts on this site, but they seem to be focussed on exclusively sending HEX data. I need to find a way of sending combined ASCII and HEX - essentially, I need to find a way to effectively format the HEX data so it is understood by the COM device.
An example of how I've been building my string follows. It gives me an error "Conversion from string PS #0x" to type 'Double' is not valid" which I'm assuming is because I'm mixing two data types! I hope I'm doing something really silly and this is actually straightforward!
'Building my command line
Command = "PS"
Command += ControlChars.Cr
Command += "#0 x"
Command += &H0 + &H2 + &H0 + &H0 + &H0
Command += " y"
Command += &H0 + &H1 + &H0 + &H0
...
'Writing my command to the COM device
moRS232.Write(Command)
Any help anyone can give would be most appreciated!
The trick is to send bytes, which means that your strings need to be converted to bytes. An example:
Dim buf As New List(Of Byte)
buf.AddRange(moRS232.Encoding.GetBytes("PS" & ControlChars.Cr & "#0 x"))
buf.AddRange(New Byte() {0, 2, 0, 0, 0})
buf.AddRange(moRS232.Encoding.GetBytes(" y"))
buf.AddRange(New Byte() {0, 1, 0, 0})
moRS232.Write(buf.ToArray, 0, buf.Count)
Do you have a manual that shows the protocol? If you paste a link.
You are right - it will get very confusing for the Fluke if it gets both ascii and hex data [even if it were possible to send in one method].
So, if the Write method needs a string, then you need to convert your hex commands to a string as well see the ASC() / CHR() commands
I have an application which creates a list from items in a collection. Then for each item, I will add it to an empty string, then add a newline character to the end of it. So ideally my string will look something like:
List1\nList2\nList3\n
Once this string is generated, I send it back to be placed in a placeholder for a pdf. If I try this code in a simple console application, it prints everything on a newline. But in my real world situation, I have to print it to a pdf. The items only show up with spaces in between them and not newlines. How can can format my strings so that pdf recognizes the newline symbol rather than ignoring it?
Here is my code that generates the string with newlines.
Private Function ConcatPlacardNumbers(ByVal BusinessPlacardCollection As BusinessPlacardCollection) As String
Dim PlacardNumbersList As String = Nothing
Dim numberofBusinessPlacards As Long = BusinessPlacardCollection.LongCount()
For Each BusinessPlacard As BusinessPlacard In BusinessPlacardCollection
numberofBusinessPlacards = numberofBusinessPlacards - 1
PlacardNumbersList = String.Concat(PlacardNumbersList, BusinessPlacard.PlacardNumber)
If numberofBusinessPlacards <> 0 Then
PlacardNumbersList = String.Concat(PlacardNumbersList, Enviornment.newline)
End If
Next
Return PlacardNumbersList
End Function
Try to add \u2028 instead:
Private Function ConcatPlacardNumbers(ByVal BusinessPlacardCollection As _
BusinessPlacardCollection) As String
Dim PlacardNumbersList As New StringBuilder()
For Each BusinessPlacard As BusinessPlacard In BusinessPlacardCollection
PlacardNumbersList.Append(BusinessPlacard.PlacardNumber)
'PlacardNumbersList.Append(ChrW(8232)) '\u2028 line in decimal form
PlacardNumbersList.Append(ChrW(8233)) '\u2029 paragr. in decimal form
Next
Return PlacardNumbersList.ToString
End Function
For paragraphs use \u2029instead. Fore more details:
http://blogs.adobe.com/formfeed/2009/01/paragraph_breaks_in_plain_text.html
The answer will depend on the tool that is being used to produce the PDF. Since newline doesn't work, I would actually try \n. The other possibility is that the PDF generation code is not designed to emit multiple lines; you can only determine this by examining the generation code.
However, there is a significant performance issue that you should address in your code: you will be generating a lot of string objects using this code. You should change the design to use System.Text.StringBuilder, which will greatly improve the performance:
Private Function ConcatPlacardNumbers(ByVal BusinessPlacardCollection As BusinessPlacardCollection) As String
Dim PlacardNumbersList As New System.Text.StringBuilder(10000)
For Each BusinessPlacard As BusinessPlacard In BusinessPlacardCollection
If PlacardNumbersList.Length <> 0 Then
' This is equivalent to Environment.NewLine
'PlacardNumbersList.AppendLine()
' The attempt to use \n
PlacardNumbersList.Append("\n")
End If
PlacardNumbersList.Append(BusinessPlacard.PlacardNumber)
Next
Return PlacardNumbersList.ToString
End Function
Note that you also do not need to keep track of the placard number: you can add a newline to the end of the previous item on each pass after the first one.