How to pass Java signed byte into VB6 unsigned program
Hello everyone
I need to build a client in Java to talk to a VB6 server. I am the point to pass the encrypt username and password into the server. The VB6 code for the encryption is
Crypt = Crypt & Chr(Asc(Mid$(Text, Len(Text) - X + 1, 1)) Xor &HA3)
My Java code is
cryptOutput = cryptOutput + ((char)(((int) input.charAt(i)) ^ ((byte)0xa3)));
The server doesn't seem to understand my username and password. I highly suspect the reason being that Java byte is signed and VB6 is unsigned.
How could I overcome this problem? I did some research and things like &0xFF didnt help...
Thank you in advance!
[664 byte] By [
BuggyVBa] at [2007-11-27 6:17:40]

> Hello everyone
>
> I need to build a client in Java to talk to a VB6
> server. I am the point to pass the encrypt username
> and password into the server. The VB6 code for the
> encryption is
>
> Crypt = Crypt & Chr(Asc(Mid$(Text, Len(Text) - X + 1,
> 1)) Xor &HA3)
> My Java code is
> cryptOutput = cryptOutput + ((char)(((int)
> input.charAt(i)) ^ ((byte)0xa3)));
It was a long time ago since I wrote something in VB, but the VB code and the Java code doesn't do the same thing(?).
kajbja at 2007-7-12 17:30:52 >

Did u mean it is something more like thiscryptOutput = cryptOutput + ((char)(((byte)input.charAt(len-i-1)) ^ ((byte)a5)));Still the problem remains... :(
Is cryptOutput a string?
kajbja at 2007-7-12 17:30:52 >

Sorry, yes it is a string... This string will be sent to VB6 server program
> The server doesn't seem to understand my username and
> password. I highly suspect the reason being that Java
> byte is signed and VB6 is unsigned.
>
Whether a byte is signed or unsigned makes no difference UNLESS it is being used in an arithmetic operation such as multiply, divide or remainder. Operations such as add, subtract, OR, AND, XOR give exactly the same bit patterns regardless of the signed or unsigned nature of the arguments.
> Sorry, yes it is a string... This string will be sent> to VB6 server programHow do you send the String?
kajbja at 2007-7-12 17:30:52 >

> Whether a byte is signed or unsigned makes no
> difference UNLESS it is being used in an arithmetic
> operation such as multiply, divide or remainder.
> Operations such as add, subtract, OR, AND, XOR give
> exactly the same bit patterns regardless of the
> signed or unsigned nature of the arguments.
You are right! But I dont know when the byte then converted to a character, would it make a different?
Because the server keeps rejecting the password I send it... And of course, the password is correct.
A bit more information about my problem
The server uses Crypt function to encode or decode all the strings sent or received
Public Function Crypt(ByVal Text As String) As String
Dim X As Integer
For X = 1 To Len(Text)
Crypt = Crypt & Chr(Asc(Mid$(Text, Len(Text) - X + 1, 1)) Xor &HA2)
Next X
End Function
[code]
If you run Crypt(Crypt("0123")), you should get "0123" in return
What I need to to make the same encode/decode function on my client side to be exactly the same as the server side. My java code for it is
[code]
public static String crypt(String input)
{
int i = 0;
int len = input.length();
int a2 = 0xa2; // variable used in original VB code for encoding
String cryptOutput = new String("");
for (i = 0; i < input.length(); i++)
{
cryptOutput = cryptOutput + ((char)(((byte)input.charAt(len-i-1)) ^ ((byte)a5)));
}
return cryptOutput;
}
My java crypt(crypt("0123")) can also return "0123", but the result between crypt("0123") and Crypt("0123") is different. Maybe thats why the server can't authenticate the password I send it. (I use Java Socket class, while the server uses Winsock).
I can already pass un-encrypt data (i.e string like "hello") successfully between the client and the server. But with encrypt data, I have no success :(
I really think it's because of the byte differences between Java and VB6. Please point out my error :)
Thank you for your time!
I send it using
PrintWriter out = new PrintWriter(soc.getOutputStream(), true);
out.println(msg);
with soc being a Socket class instance
As I said in the post above, I can send normal string like "hello" and the server understands it. But with the encrypt string then it cant :(
> I send it using
>
> > PrintWriter out = new
> PrintWriter(soc.getOutputStream(), true);
> out.println(msg);
>
>
> with soc being a Socket class instance
>
> As I said in the post above, I can send normal string
> like "hello" and the server understands it. But with
> the encrypt string then it cant :(
How do you send that string? I thought that VB strings always had the length of the string at the first index.
kajbja at 2007-7-12 17:30:52 >

This is how I send it> PrintWriter out = new> PrintWriter(soc.getOutputStream(), true);> out.println(msg);With msg being the result of output of crypt("0123"), soc is an instance of Socket class. Hope I have answered your question :)
> Whether a byte is signed or unsigned makes no
> difference UNLESS it is being used in an arithmetic
> operation such as multiply, divide or remainder.
Actually there's no problem with multiplying either.
A mathematically inclined person might say that "unsigned" and "signed" bytes both form a ring isomorphic to the ring of integers modulo 256, and therefore their ring operations (addition, subtraction and multiplication) are compatible.
BuggyVB: Didn't you see my reply in your previous thread on the same subject? http://forum.java.sun.com/thread.jspa?threadID=5178897&messageID=9693731#9693731
Sorry jsalonen , I was trying to find the old post but I couldn't see it anywhere...
Anyway, it didnt help either...
At this point, I dont think it's the crypt function anymore... Even more debug work to do...
Anyway, thanks a lot for everyone's help. You are all very helpful!!
When you click on your screen name you get a page that has information about your account and a list of your most recent posts.
> At this point, I dont think it's the crypt function
> anymore... Even more debug work to do...
>
If your crypt function still looks like what it is above then yes, it is an issue. You can verify this by passing it some simple data you can check by hand.
My project is to convert a VB client program into the same thing in Java.
Using Ethereal, I got the following byte sent by the VB program (for password authentication)
fd fd 02 00 00 1d 3f 3f dc c2 c2 d0 e7 7c
31 30 2e 31 2e 31 2e 32 31 38 7c cb cc
c4 c2 c4 3f 3f 3f 3f 3f fe fe fe fe 0d 0a
For debuging purposes, I want to send the exact bytes above to the server...
My way of doing it is creating a string using
((char)Integer.parseInt("fd",16))
+ ((char)Integer.parseInt("fd",16))
+ ((char)Integer.parseInt("02",16))
+ ((char)Integer.parseInt("00",16))
+ .... and so on
then send this string to the server for authentication. Yet the server still refuses my connection. Please point out what I'm doing wrong or is it because of the byte signed and unsigned different in VB and Java?
PS: The server understand me if I send simple string like "0123" (I know this because the server has 2 step authentication, first step is matching a simple string, 2nd step is receiving and decoding the user name and password... I passed the first step).
> My way of doing it is creating a string using
But in Java strings contain characters, not bytes?
Have you tried passing the bytes using an array instead of a string? That's pretty much the only way to guarantee that the bytes are sent as you see them there.
By the way, in Java there are hexadecimal integer constants, for example you can write FD as 0xfd. There's no reason to use Integer.parseInt for this.
> then send this string to the server for
> authentication. Yet the server still refuses my
> connection.
You are saying you get "connection refused?" That is a networking problem. It means you are not allowed to connect at all, most likely because no service is running on the port you are trying to connect to or because there's a firewall or proxy that refuses the connection.
> PS: The server understand me if I send simple string
> like "0123" (I know this because the server has 2
> step authentication, first step is matching a simple
> string, 2nd step is receiving and decoding the user
> name and password... I passed the first step).
OK, so it works with the String "0123." With which string does it not work? The secuence of bytes that you quote?
It is not a connection problem :) The server can receive my string, it just replies me that it is not the correct password.
I can send string like "0123" and the server can understand it properly (so I can pass the 1st authentication step). But with string like crypt("0123") then the server can't get it properly.
As I said earlier, crypt(crypt("0123")) will give u back "0123". So at my client side, I encode password using crypt("0123") then send the output string to the server. The server (which I dont have access to) use Crypt(my string) to get back the original password. But it seems like either my crypt function doesnt work properly, or the bytes are treated different at the server side.
My crypt function can do crypt(crypt("0123")) == "0123". But my crypt("0123") gives different result then Crypt("0123") at the server side. (The code for the server side Crypt and my crypt are given in my original post)
Many thanks to jaslonen and others for the input given. I'm still reading the forum and debug my code to get through this project. Thanks again!
> But my crypt("0123") gives different result then Crypt("0123") at the server side.
Do you know what the server's version returns?
Are you sure what the constant you XOR against is supposed to be? I have seen you use A2, A3 and A5.
Have you tried the different implementations of crypt we have shown? In your most recent post there's a problem with bytes in the range 80-FF. They have a negative sign, and when you convert one such byte to a larger type, its sign bit is extended to the higher bytes. This way the byte -42 will come out as -42 and not some positive number. This will cause problems when you cast a negative byte to char: the byte A5 for istance will be converted to the character U+FFA5, which is "HALFWIDTH HANGUL LETTER NIEUN-CIEUC" in the unicode spec. Most likely this is not what the server does!
Because of this issue it's better to not cast anything to byte or use the byte datatype in your implementation of the "crypt" method. Or alternatively it's better not to use the char datatype. It sounds like your protocol involves passing arbitrary binary data, not text, so you should rather use arrays of byte instead of strings.
> Do you know what the server's version returns?
Yes I do, and the results are different :(
> Are you sure what the constant you XOR against is
> supposed to be? I have seen you use A2, A3 and A5.
Yeah, I'm sure about that too... I give different examples in the forum, but it is a constant in my code
> Have you tried the different implementations of crypt
> we have shown?
It is pretty silly to ask the question here and don't try the help given :P So yeah, I tried everything, but the encoded password is still not accepted by the server. Your solution jsalonen, seems to make most sense, but still didn't solve it :(
Thanks lot for your help so far jsalonen... Please let me know if you think of something else... I'm not sure what to look at now :(
> > Do you know what the server's version returns?> Yes I do, and the results are different :(> Then what does it return for the input "0123" ?
Here is an image which includes
-My java code for crypt
-My output for crypt("0123") (the first line) and crypt("Hello") (2nd line)
-The VB code for Crypt
-The output for Crypt("0123") (1st line) and Crypt("Hello") (2nd line)
The java output is displayed in a JTextArea.
Notice that the output between the 2 functions are the same for words (i.e "Hello") and different for numbers ("0123")
http://img236.imageshack.us/img236/1514/crypthk0.gif
That's why I suspect some byte differences in Java and VB that causes the problem...?
> That's why I suspect some byte differences in Java
> and VB that causes the problem...?
No, the difference is between character encodings as I tried to hint in the other thread. The Chr and Asc funtions in VB use what ever code page happens to be configured in Windows, while Java uses the international Unicode standard. It appears to be that your VB code is currently using Windows-1252. On a different computer it might use some other encoding and have different output.
The character '0' corresponds to the code point 48 in both Windows-1252 and in Unicode. When you pass this character to your crypt function, it's code point gets XORed with 0xA5, producing the decimal number 149.
Now, Java converts the number 149 to a character by looking it up in the Unicode standard. From Unicode's table we see that it corresponds to the unprintable control character U+0095, also known as "Message Waiting" as you can verify in http://www.unicode.org/charts/PDF/U0080.pdf This character is unprintable so it can't be seen in your output window.
VB converts the number 149 to a character by looking it up in the Windows-1252 character set. From Microsoft's code table http://www.microsoft.com/globaldev/reference/sbcs/1252.mspx we see that this number corresponds to the bullet character U+2022.
Now the question is do you really need to work with characters at all? Clearly you are dealing with binary data and not text. You should use arrays of bytes.
> Now the question is do you really need to work with
> characters at all? Clearly you are dealing with
> binary data and not text. You should use arrays of
> bytes.
You are right! Create the string from byte arrays solved my problem! Thanks so much jsalonen!! You have been more then helpful!!
Just so everyone who ever has similar problem to me, this is how I do my new crypt function
public static String crypt(String input)
{
int i = 0;
int len = input.length();
int a5 = 0xa3;
byte[] temp = new byte[input.length()];
for (i = 0; i < input.length(); i++)
{
// Original VB code: Crypt = Crypt & Chr(Asc(Mid$(Text, Len(Text) - X + 1, 1)) Xor &HA3)
temp[i] = ((byte)(input.charAt(len - i - 1) ^ a3));
//cryptOutput = cryptOutput + ((char)(((byte)input.charAt(len-i-1)) ^ ((byte)a5)));
//cryptOutput = cryptOutput + ((char)intToPseudoUnsignedByte(((byte)input.charAt(len-i-1)) ^ ((byte)a5)));
}
return (new String(temp));
}
Again, many thanks to jsalonen and martin@work!