nodejs and vb.net - zlib deflate compression non-compatibility between nodejs and vb - vb.net

I'm trying to communicate between a client and a server, with the client being on VB.NET and the server on nodejs.
It works, but I'm now trying to use the deflate compression method which seems to not work exactly the same in vb.net and nodejs.
Here's the code. I will explain the problem next in order to be understandable.
deflate compression on (VB.NET)
Shared Function Compression(buffer As Byte()) As Byte()
Try
Dim ms As New MemoryStream()
Using zipStream As New Compression.DeflateStream(ms, IO.Compression.CompressionMode.Compress, True)
zipStream.Write(buffer, 0, buffer.Length)
End Using
ms.Position = 0
Dim outStream As New MemoryStream()
Dim compressed As Byte() = New Byte(ms.Length - 1) {}
ms.Read(compressed, 0, compressed.Length)
Dim gzBuffer As Byte() = New Byte(compressed.Length + 3) {}
System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length)
System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4)
Return gzBuffer
Catch
Return buffer
End Try
End Function`
I use it like this:
Compression(stringtobyte("testTESTtestTESTtestTESTtestTEST"))
It returns this byte() data: [32,0,0,0,43,73,45,46,9,113,13,14,41,193,65,3,0].
deflate compression in (nodejs) (using zlib)
zlib.deflateSync(Buffer.from("testTESTtestTESTtestTESTtestTEST"))
That returns: [120, 156, 43, 73, 45, 46, 9, 113, 13, 14, 41, 193, 65, 3, 0, 201, 232, 12, 1]
As you can see, the "inside" compression bytes are the same in nodejs and VB (they are bolded). In VB there are four leading bytes [32,0,0,0]. I understand that that shows the length of uncompressed original data. That's true since the length of "testTESTtestTESTtestTESTtestTEST" is 32 chars.
However in NodeJS there is always [120,156] at the start, and some bytes at the end (always 4?). Here [201, 232, 12, 1]. They are never the same if I change the string that I want to compress.
So what i tried:
In nodejs, using zlib.inflate(Buffer.from([120, 156, 43, 73, 45, 46, 9, 113, 13, 14, 41, 193, 65, 3, 0, 201, 232, 12, 1])).toString() actually returns my input string: "testTESTtestTESTtestTESTtestTEST".
However I must compress a string in VB (without the 2 firsts chars that you get in the nodejs compression [120,156], and without also the 4 chars at the end : [201, 232, 12, 1]) , and then decompress/uncompress it in Node.js.
I tried to add the [120,156] characters in the VB compressed string, while removing the first four chars in the VB compressed string that indicate the length of uncompressed data, but I don't have any clue as to what the four last chars are in the Node.js compression function. So the inflate(uncompress function) in Node.js doesn't work with my modified VB compressed string:
vb compressed data: [32,0,0,0,43,73,45,46,9,113,13,14,41,193,65,3,0] that I must turn into: [120, 156, 43,73,45,46,9,113,13,14,41,193,65,3,0,201,232,12,1]
//but I can't get those 4 last chars in vb
zlib.inflateSync(Buffer.from([120, 156, 43,73,45,46,9,113,13,14,41,193,65,3,0]))
//i remove the first 4 chars and add 120,156 "header" that i always got in nodejs, but i can't add the last 4 chars as I don't know what there are about, i only get them in nodejs zlib.deflateSync but not in my VB.net compression function.
The inflateSync function returns an error: "unexpected end of file" (the end that precisely I don't know how to get).
How can I find out what the four last chars from the Node.js deflate function are? (I imagine the two first chars 120,156 are about specifying that it's the deflate compression mode) I would like to add them in my VB.NET return string to make it compatible with Node.js.

Actually I found a solution, it's using GZIP compression mode instead of DEFLATE, it seems more stable and cross-platform compatible.
here are my VB.Net compression and decompression
Shared Function compression(buf As Byte()) As Byte()
Using ms As New MemoryStream()
Using gzipstream As New GZipStream(ms, CompressionMode.Compress) 'si m arche pas, ajouter dernière param
gzipstream.Write(buf, 0, buf.Length)
End Using
Return ms.ToArray()
End Using
End Function
Shared Function decompression(buf As Byte()) As Byte()
Using ms As New MemoryStream(buf)
Using outputstream As New MemoryStream
Using decstream As New GZipStream(ms, CompressionMode.Decompress)
decstream.CopyTo(outputstream)
End Using
Return outputstream.ToArray()
End Using
End Using
End Function
and in node instead of deflateSync and inflateSync, i simply use gzipSync and gunzipSync... it works perfectly
bye

You are using two different formats on the two platforms, plus the extra twist of the leading uncompressed size on the VB side. On the VB side you are using raw deflate format. On the Node.js side you are using the zlib format. The zlib format is a deflate stream with a two-byte zlib header and a four-byte Adler-32 integrity check value, which is a function of the uncompressed data.
On the VB side can use ZLibStream instead of DeflateStream, and you can get rid of the leading four bytes by simply removing that from your VB code: just have one BlockCopy line: System.Buffer.BlockCopy(compressed, 0, gzBuffer, 0, compressed.Length). That will then be compatible with the use of inflate on the Node.js side.

Related

Does this seem like a solid encryption method?

I found this code on a forum:
Public Shared Sub Encryptor(wme As String, password As String)
            Try
                Dim key As Byte() = New Byte(31) {}
                Encoding.Default.GetBytes(password).CopyTo(key, 0)
                Dim aes As New RijndaelManaged() With
            {
                .Mode = CipherMode.CBC,
                .KeySize = 256,
                .BlockSize = 256,
                .Padding = PaddingMode.Zeros
            }
                Dim buffer As Byte() = File.ReadAllBytes(wme)
                Using matrizStream As New MemoryStream
                    Using cStream As New CryptoStream(matrizStream, aes.CreateEncryptor(key, key), CryptoStreamMode.Write)
                        cStream.Write(buffer, 0, buffer.Length)
                        Dim appendBuffer As Byte() = matrizStream.ToArray()
                        Dim finalBuffer As Byte() = New Byte(appendBuffer.Length - 1) {}
                        appendBuffer.CopyTo(finalBuffer, 0)
                        File.WriteAllBytes(wme, finalBuffer)
                    End Using
                End Using
                File.Move(wme, wme)
            Catch
            End Try
        End Sub
wme is the file path. Password is the password for the encryption. I was woundering if this was a strong encryption method or its some bad encryption method.
Rijndael with a BlockSize of 256-bits is not AES, AES only supports a block size if 128-bits. Not 31 bytes, there would be some unknown padding applied.
For AES use: .BlockSize = 128.
You need to supply an Initialization Vector (IV). The IV will also be the same as the block size, 128-bits (16-bytes), make it exactly that size. Use a random IV and prefix the encrypted data with it so it will be available for decryption.
Also AES supports three key sizes, 128, 192 and 256 bits, make the keys exactly the correct size.
Further, null padding is a bad idea and does not support binary data, instead the usual padding is PKCS#7 (sometimes specified as PKCS#5).

Editing ZipArchiveEntries (images) in memory

I'm not sure what I'm doing wrong with the code sample below.
I'm not getting any errors and the image looks like this after the compression is applied:
Using _stm = _ZipArchiveEntry.Open
Dim _ims = New MemoryStream
Image.FromStream(_stm, True, True).Save(_ims, _codec, params)
_stm.Seek(0, SeekOrigin.Begin)
_stm.SetLength(_ims.Length)
_ims.CopyTo(_stm)
End Using
NOTE: If I write the image to disk it works though. I would like to avoid deleting and re-inserting zip archive entries though.
Using _stm = _ZipArchiveEntry.Open
Image.FromStream(_stm, True, True).Save("C:\test.jpeg", _codec, params)
End Using
I forgot to reset the "_ims" stream position back to 0. The sad part is, I assumed .CopyTo() would do this for me. So that was the last thing I actually checked...
This worked:
Using _stm = p_ZipArchiveEntry.Open
Using _ims As New MemoryStream
Image.FromStream(_stm, True, True).Save(_ims, _codec, params)
_stm.SetLength(_ims.Length)
_stm.Seek(0, SeekOrigin.Begin)
_ims.Seek(0, SeekOrigin.Begin)
_ims.CopyTo(_stm)
End Using
End Using

HMACSHA1 gives different output between JS and VB.Net

I'm trying to translate a JavaScript application of TOTP to VB.Net: http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/
I have encountered a problem during translation of the HMAC-part:
//Javascript:
var hmacObj = new jsSHA("Hello World!", 'HEX');
var hmac = hmacObj.getHMAC("secret", 'HEX', 'SHA-1', "HEX");
This is a codesnippet of my translation in VB.Net
'VB.Net:
Dim hmacObjTest As New HMACSHA1(System.Text.Encoding.UTF8.GetBytes("secret"))
Dim hmacTest As Byte() = hmacObjTest.ComputeHash(System.Text.Encoding.UTF8.GetBytes("Hello World!"))
Dim hmacHexTest As New StringBuilder()
For i As Integer = 0 To hmacTest.Length - 1
hmacHexTest.Append(hmacTest(i).ToString("x2"))
Next i
Dim strTest As String = "HMAC = " & hmacHexTest.ToString()
The problem is that i get different output from the two languages:
Output JS: 5efed98b0787c83f9cb0135ba283c390ca49320e //Tested from jsSha demo: http://caligatio.github.io/jsSHA/
Output VB.Net: 87b0154b8420c0b58869ca103f481e824d8876ea
The outputs are not at all the same like they are in this question: hmacsha1 output hex strings different between vb.net and python
Does anyone know where I might be doing something wrong?
Hashes don't work on strings - they work on the binary representation of the string. Now you use UTF-8 as encoding for the dotnet version, while the JavaScript version is very likely not to use UTF-8 - so you get different binary representations, resulting in different hashes.
Use either webttolkit or the hackish var utfstring = unescape(encodeURIComponent(rawstring)); to convert to UTF-8 before calcualting the hash.

Append binary data to serialized xml header

I need to append binary data to file but before this data is an xml header. Whole file wont be proper xml file but it must proper xml header like following:
<EncryptedFileHeader>
<Algorithm>name</Algorithm>
<KeySize>256</KeySize>
<SubblockLength>64</SubblockLength>
<CipherMode>ECB</CipherMode>
<sessionKey>sessionKey</sessionKey>
</EncryptedFileHeader>
*binary data*
The xml header I do with JAXB marshalling easily, and even easier would be to add this binary data in base64 and store in note inside xml. But this is a clue. I have to store it as binary to save this overhead 33% space used by base64.
So the question is how to add this data and of course later read this back (serialize/deserialize) ?
Another question is how to remove from the first line of document?
I tried to use:
marshaller.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.FALSE);
but it throws an exception:
javax.xml.bind.PropertyException: name: com.sun.xml.bind.xmlDeclaration value: false
at javax.xml.bind.helpers.AbstractMarshallerImpl.setProperty(AbstractMarshallerImpl.java:358)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.setProperty(MarshallerImpl.java:527)
Thanks
Actualy I solved this by serializing xml header with JAXB, then appending binary data (bytearray) to existing file.
Reading from file with buffered reader as follows:
BufferedReader reader = new BufferedReader(new FileReader("filepath"));
String line, results = "";
while ((line = reader.readLine()) != null) {
results += line;
}
reader.close();
String[] splited = results.split("</EncryptedFileHeader>");
splited[0] += "</EncryptedFileHeader>";
String s0 = splited[0];
String s1 = new String(splited[1]);
ByteArrayInputStream bais = new ByteArrayInputStream(s0.getBytes());
Now i got a problem with second splited string s1, which consist data from "byteArrayOutputStream.toByteArray();". Now I have to transfer data from this string to byte array. From:
'��A����g�X���
to something like:
[39, -63, -116, 65, -123, -114, 27, -115, -2, 103, -64, 88, -99, -96, -26, -12]
I tried (on the same machine):
byte[] bytes = s1.getBytes();
but bytes array is different and returns 34 bytes instead 16. I read a lot about encodings but still have no idea.
EDIT:
The problem with different number of bytes was due to the different representation of new line by character and byte streams.

c++ Convert string to bytes to send over tcp

I'm trying to send a 28 character string to a remote ip address and port. I've done this successfully in vb.net using the following code snippets:
Dim swon As String = "A55A6B0550000000FFFBDE0030C8"
Dim sendBytes As [Byte]()
sendBytes = Encoding.ASCII.GetBytes(swon)
netStream.Write(sendBytes, 0, sendBytes.Length)
I now have to convert this across to c++ and have the following so far:
char *swon = "A55A6B0550000000FFFBDE0030C8";
array<Byte>^ sendBuffer = gcnew array<Byte>(bufferSize);
sendBuffer = BitConverter::GetBytes( swon );
tcpStream->Write(sendBuffer, 0, sendBuffer->Length);
but am getting stuck at this point. I'm sure I'm missing a simple syntax error but I can't figure it out!
To clarify, I'm not getting an error, but I don't think the string is being converted to bytes correctly as when I convert back, I just get a '01'
Cheers,
Chris
I don't understand why you are not just using the exact same .Net framework classes in your ++/CLI code. eg. System::String for swon, Encoding::ASCII to produce the array of bytes.
Anything you did in VB you can map directly over to C++/CLI without using different classes - that's the easest port for you. When you are in MSDN online, just select the C++ view to get examples of stuff you want to do. Try that on this page, for example: http://msdn.microsoft.com/en-us/library/system.text.encoding.ascii.aspx
Steve is correct that the same logic can be duplicated in C++. But the C++ char* already is ASCII, no conversion is necessary. Just a copy is all that's needed.
const char swon[] = { "A55A6B0550000000FFFBDE0030C8" };
array<Byte>^ sendBuffer = gcnew array<Byte>((sizeof swon) - 1);
pin_ptr<Byte> startBuffer = &sendBuffer[0];
memcpy(startBuffer, swon, sendBuffer->Length);
tcpStream->Write(sendBuffer, 0, sendBuffer->Length);