How to write byte[] to an IoSession - java

As shown below I can read the byte[] sent from an IoSession without having a protocol decoder.
IoBuffer in = (IoBuffer) message;
byte[] inBytes = in.array();
int length = inBytes[0];
inBytes = Arrays.copyOfRange(inBytes, 1, length + 1);
ByteString incomingMessage = ByteString.copyFrom(inBytes);
But when I try to do:
someIoSession.write(incomingMessage.toByteArray());
I get the following error.
Don't know how to handle message of type XXXX. Are you missing a protocol encoder?
How can I just write the bytes into an IoSession?

someIoSession.write(IoBuffer.wrap(incomingMessage.toByteArray()));

Related

Convert String to byte[] array

I want to convert a String to a byte array but the array must have 256 positions, I mean, like this:
public byte[] temporal1 = new byte[256];
public byte[] temporal2 = new byte[256];
So, when I do:
String send = "SEND_MESSAGE";
String sendAck = "SEND_MESSAGE_ACK";
temporal1 = send.getBytes();
temporal2 = sendAck.getBytes();
I get this error: "./th.java:24: error: <identifier> expected". I know that if I do public byte[] temporal1 = send.getBytes();it works, but I need the array with that size to compare it with other byte array byte to byte.
can you please show the exact Exception or Error which is occurring in the console. because it works completely fine with me.
byte b1[] = new byte[256];
String s = "hello there";
b1 = s.getBytes();
System.out.println(b1);
To have the byte array temporal1 padded upto 256 bytes, you might do:
public byte[] temporal1 = new byte[256];
String send = "SEND_MESSAGE";
byte[] sendB = send.getBytes(send, StandardCharsets.UTF_8);
System.arraycopy(sendB, 0, temporal1, 0, Math.max(256, sendB.length));
If you want a C like terminating 0 byte, sendB may only provide 255 bytes: Math.max(255, sendB.length).
Better:
String send = "SEND_MESSAGE";
byte[] sendB = send.getBytes(send, StandardCharsets.UTF_8);
byte[] temporal1 = Arrays.copyOf(sendB, 256); // Pads or truncates.
temportal1[255] = (byte) 0; // Maybe
To get a byte[] from String with defined size:
public static byte[] toBytes(String data, int length) {
byte[] result = new byte[length];
System.arraycopy(data.getBytes(), 0, result, length - data.length(), data.length());
return result;
}
Ex:
byte[] sample = toBytes("SEND_MESSAGE", 256);
sample will be of size 256.

Cannot open "SecretBox" generated by TweetNacl (Java) with "Libsodium-net" (C#)

I'm having problems opening a Nacl SecretBox (generated in java using the TweetNaclFast library) in C# using the libsodium-net library.
I also can't do it the other way around (open a libsodium-net generated box using TweetNaclFast).
In the following example i'll create a SecretBox using TweetNaclFast (Java) and try to open it with libsodium-net (C#)
Creating the SecretBox (Java)
String secretMessage = "Hello Stack overflow!";
byte[] messageBytes = secretMessage.getBytes("UTF-8");
byte[] keyBytes = secureRandomGenerator(); //returns 32 random bytes (256 bits)
byte[] nonceBytes = TweetNaclFast.makeSecretBoxNonce();
byte[] boxBytes = new TweetNaclFast.SecretBox(keyBytes).box(messageBytes,nonceBytes);
System.out.println("Base64 box -> "+Base64.encodeBase64String(boxBytes));
System.out.println("Base64 key -> "+Base64.encodeBase64String(keyBytes));
System.out.println("Base64 nonce -> "+Base64.encodeBase64String(nonceBytes));
Creation Output
Base64 box -> iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==
Base64 key -> FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=
Base64 nonce -> 2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV
Opening the SecretBox (C#)
string box = "iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==";
string key = "FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=";
string nonce = "2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV";
try
{
byte[] message = Sodium.SecretBox.Open(
Convert.FromBase64String(box),
Convert.FromBase64String(nonce),
Convert.FromBase64String(key));
Console.WriteLine(Encoding.UTF8.GetString(message));
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
Open Output
Failed to open SecretBox
at Sodium.SecretBox.Open(Byte[] cipherText, Byte[] nonce, Byte[] key)
Any idea about what i might be doing wrong?
EDIT
I guess the problem is with one of the libraries (libsodium-net most likely).
If i create a SecretBox with the same variables i get a different box...
Creating a Secret Box with TweetNaclFast
String message = "Hello Stack overflow!";
String key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
String nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";
SecretBox box = new SecretBox(Base64.decodeBase64(key));
byte[] cipherText = box.box(message.getBytes("UTF-8"), Base64.decodeBase64(nonce));
RETURNS: yDCt/kOLFUWPZpV3deVNUZaH0ZHLVmj9Nvm8QlbVKPe1a/INDw==
Creating a Secret Box with libsodium-net
string message = "Hello Stack overflow!";
string key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
string nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";
byte[] box = Sodium.SecretBox.Create(Encoding.UTF8.GetBytes(message),
Convert.FromBase64String(nonce),
Convert.FromBase64String(key));
Console.WriteLine(Convert.ToBase64String(box));
RETURNS: AAAAAAAAAAAAAAAAAAAAAMgwrf5DixVFj2aVd3XlTVGWh9GRy1Zo/Tb5vEJW1Sj3tWvyDQ8=
Sodium.SecretBox.Create uses the original NaCl crypto_box() API, which requires extra padding before the message and the ciphertext.
This API is a bit confusing and is rarely useful except in C. Even in C, people using it end up writing wrappers to prepend or get rid of the padding.
The box and secretbox constructions, as exposed by most APIs, do not require extra padding. The ciphertext is directly returned without 16 extra bytes before. The message can be directly given without prepending 16 nul bytes.
TweetNaclFast does not require any padding, but libsodium-net apparently does.
The extra 16 bytes before the ciphertext you are observing with libsodium-net do not contain any useful information. It's just a bunch of zeros. You can safely strip them, and add them later when calling Sodium.SecretBox.Open.
Note that unlike Sodium.SecretBox, Sodium.PublicKeyBox doesn't require padding.
I should have read the documentation (RTFM)...
Apparently libsodium-net adds a 16byte authentication tag on the start of the ciphertext (https://bitbeans.gitbooks.io/libsodium-net/content/secret-key_cryptography/authenticated_encryption.html). If i remove the first 16 bytes i get the same output as the TweetNaclFast SecretBox.
string message = "Hello Stack overflow!";
string key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
string nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";
byte[] box = Sodium.SecretBox.Create(Encoding.UTF8.GetBytes(message),
Convert.FromBase64String(nonce),
Convert.FromBase64String(key));
byte[] boxWithoutAuthenticationTag = new byte[box.Length - 16];
Array.Copy(box, 16, boxWithoutAuthenticationTag, 0, box.Length - 16);
Console.WriteLine(Convert.ToBase64String(boxWithoutAuthenticationTag));
now returns: yDCt/kOLFUWPZpV3deVNUZaH0ZHLVmj9Nvm8QlbVKPe1a/INDw==
To open (decrypt) the first example's secret box use the following code:
string box = "iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==";
string key = "FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=";
string nonce = "2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV";
try
{
//Libsodium-net SecretBox.Open() requires a 16 byte authentication tag at the start of the ciphertext
//TweetNaclFast boxing method does not append a 16 byte authentication tag anywhere
//Thus, we need to add a 16 byte authentication tag at the start of ciphertext encripted by TweetNaclFast
byte[] authenticationTag = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //Zeroed 16 Bytes Authentication Tag
byte[] tweetNaclFastCiphertextBytes = Convert.FromBase64String(box);
byte[] libsodiumNetLikeCiphertext = new byte[tweetNaclFastCiphertextBytes.Length + authenticationTag.Length];
Array.Copy(authenticationTag, libsodiumNetLikeCiphertext, authenticationTag.Length);
Array.Copy(tweetNaclFastCiphertextBytes, 0, libsodiumNetLikeCiphertext, authenticationTag.Length, tweetNaclFastCiphertextBytes.Length);
byte[] nonceBytes = Convert.FromBase64String(nonce);
byte[] keyBytes = Convert.FromBase64String(key);
Console.WriteLine(Encoding.UTF8.GetString(Sodium.SecretBox.Open(libsodiumNetLikeCiphertext, nonceBytes, keyBytes)));
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
It should now return Hello Stack overflow!

Bouncycastle in Java odd encryption and decryption results

So I have been working with the Bouncycastle libraries in an attempt to connect with a remote server. This process has been problematic from the get go and now I'm close to getting everything working but some odd things are happening.
When I first started building out the encryption process I was told to use AES 256 with PKCS7Padding. After some nagging I was provided with a c++ example of the server code. It turned out that the IV is 256 bit so I had to use the RijndaelEngine instead. Also in order for this to work correctly I have to use ZeroBytePadding.
Here is my code:
socket = new Socket(remoteIP, port);
outputStream = new PrintWriter(socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
byte[] base_64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes("UTF-8");
Security.addProvider(new BouncyCastleProvider());
public String AESEncrypt(String out) throws IOException, DataLengthException, IllegalStateException, InvalidCipherTextException {
byte[] EncKey = key;
byte randKey;
Random randNumber = new Random();
randKey = base_64[randNumber.nextInt(base_64.length)];
EncKey[randKey&0x1f] = randKey;
RijndaelEngine rijndaelEngine = new RijndaelEngine(256);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rijndaelEngine), new ZeroBytePadding());
ParametersWithIV keyParameter = new ParametersWithIV(new KeyParameter(EncKey), iv);
cipher.init(true, keyParameter);
byte[] txt = out.getBytes();
byte[] encoded = new byte[cipher.getOutputSize(txt.length)];
int len = cipher.processBytes(txt, 0, txt.length, encoded, 0);
cipher.doFinal(encoded, len);
char keyChar = (char) randKey;
String encString = new String(Base64.encode(encoded));
encString = encString.substring(0, encString.length()-1) + randKey;
return encString;
}
public void AESDecrypt(String in) throws DataLengthException, IllegalStateException, IOException, InvalidCipherTextException {
byte[] decKey = key;
byte[] msg = in.getBytes();
byte randKey = msg[msg.length-1];
decKey[randKey&0x1f] = randKey;
byte[] trimMsg = new byte[msg.length-1];
System.arraycopy(msg, 0, trimMsg, 0, trimMsg.length);
in = new String(trimMsg);
RijndaelEngine rijndaelEngine = new RijndaelEngine(256);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rijndaelEngine), new ZeroBytePadding());
ParametersWithIV keyParameter = new ParametersWithIV(new KeyParameter(decKey), iv);
cipher.init(false, keyParameter);
byte[] encoded = Base64.decode(in.trim());
byte[] decoded = new byte[cipher.getOutputSize(encoded.length)];
int len = cipher.processBytes(encoded, 0, encoded.length, decoded, 0);
cipher.doFinal(decoded, len);
String decString = new String(decoded);
}
Here is a test function I am using to send and receive messages:
public void serverTest() throws DataLengthException, IllegalStateException, InvalidCipherTextException, IOException {
//out = AESEncrypt(out);
outputStream.write(out + "\n");
outputStream.flush();
String msg = "";
while ((msg = inputStream.readLine()) != null) {
AESDecrypt(msg);
}
}
The key and iv don't change with the exception of the last byte in the key. If I am encrypting I get a random base64 char and change the last byte to that. If its decryption I get the last byte from the message and set the last value of the key to it for decryption.
In the c++ example there was an unencrypted message and two encrypted messages. I could deal with those fine.
Here is the problem, when I send my message to the remote server "encrypted" the app waits for a response until the connection times out but never gets one. If I send the message unencrypted I get either 7 responses which I can successfully decrypt and finally
org.bouncycastle.util.encoders.DecoderException: unable to decode base64 string:
String index out of range: -4 at org.bouncycastle.util.encoders.Base64.decode(Unknown Source)
or my last line before the error will look like this:
?"??n?i???el????s???!_S=??ah????CR??l6??]?{?l??Y?????Gn???+?????9!'??gU&4>??{X????G?.$c=??0?5??GP???_Q5????8??Z\?~???<Kr?????[2\ ???a$?C??z%?W???{?.?????eR?j????~?B"$??"z??W;???<?Yu??Y*???Z?K?e!?????f?;O(?Zw0B??g<???????????,)?L>???A"?????<?????W??#\???f%??j ?EhY/?? ?5R?34r???#?1??I??????M
If I set the encryption/decryption to use PKCS7Padding I get no response when my message is encrypted still but with decryption from the server I get between 2 to 6 responses and then
org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
I am at a loss with this. I don't know what I might be doing wrong so I have come here. I'm hoping the so community can point out my errors and guide me in the right direction.
I have a bit of an update I found my error in the encryption. I wasn't placing the random base64 value at the end of the encrypted string correctly so now I am doing like this.
encString += (char)randKey;
I can get response from the server now. Now the problem is I will some times get one or two readable lines but the rest are all garbage. I asked the individuals who run the server about it and they said in some c# code that they reference the have
return UTF8Encoding.UTF8.GetString(resultArray);
and thats all I have to go off of. I have tried UTF-8 encoding any place where I do getBytes or new String, and I have tried making the BurrferReader stream UTF-8 but it's still garbage.
Have you seedn the BCgit? this has bouncycastle code and examples. I am using the Csharp version in this repository. https://github.com/bcgit/bc-java
All crypto primitive examples are stored here: https://github.com/bcgit/bc-java/tree/master/core/src/test/java/org/bouncycastle/crypto/test
Try this code for testing Aes-CBC
private void testNullCBC()
throws InvalidCipherTextException
{
BufferedBlockCipher b = new BufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917"));
b.init(true, new ParametersWithIV(kp, new byte[16]));
byte[] out = new byte[b.getOutputSize(tData.length)];
int len = b.processBytes(tData, 0, tData.length, out, 0);
len += b.doFinal(out, len);
if (!areEqual(outCBC1, out))
{
fail("no match on first nullCBC check");
}
b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f")));
len = b.processBytes(tData, 0, tData.length, out, 0);
len += b.doFinal(out, len);
if (!areEqual(outCBC2, out))
{
fail("no match on second nullCBC check");
}
}

Java client server chat pads strings with squares when converting to byte[]

I'm building a chat client and server as part of a class project and running into one problem I can't seem to fix. Text has to be passed in the form of fixed size byte[] (either 32 or 64 bytes) depending on the particular case.
When I change the strings to byte[] with the .getBytes() method it pads out the length of the string with empty squares. This is fine during transit and receipt but at some point I need to change the string to it's original format (currently done with new String(byte[]) and delete the empty squares.
I can't seem to find a good way to do this. Any suggestions?
Relevant code bits client side:
byte[] bigDataByte = new byte[64];
sendData[2] = (bigDataByte = message.getBytes())
for (int i = 0; i < sendData.length; i++){
if (sendData[i] != null){
DatagramPacket sendPacket = new DatagramPacket(sendData[i], sendData[i].length, IPAddress, clientPort);
clientSocket.send(sendPacket);
}
}
Relevant code bits server side:
String name = new String(getBytes(32));
private static byte[] getBytes(int size) throws IOException {
byte[] dataByte = new byte[size];
DatagramPacket dataPacket = new DatagramPacket(dataByte, dataByte.length);
servSocket.receive(dataPacket);
return dataPacket.getData();
}
Not sure, but the issue might be that you are not specifying the charset.
Try using the
constructor: String(byte[] bytes, String charsetName)
and the method: getBytes(String charsetName).
e.g.
byte[] bytes = str.getBytes("UTF-8");
and
String str = new String(bytes, "UTF-8");
The default ones use the platform's default charset, which could lead to a mismatch.

Read byte[] from server

I am trying to read byte[] that is being send from a client to a server.
This is my client code...
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
Cipher cipher = Cipher.getInstance("RSA");
// encrypt the aeskey using the public key
cipher.init(Cipher.ENCRYPT_MODE, pk);
byte[] cipherText = cipher.doFinal(aesKey.getEncoded());
dout.write(cipherText);
And this is my server code...
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
String chiper = dis.readUTF();
System.out.println(chiper);
However, the dis.readUTF(); line fails with an exception...
java.io.EOFException at java.io.DataInputStream.readFully(DataInputStream.java:197)
at java.io.DataInputStream.readUTF(DataInputStream.java:609)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
at gameserver.ClientHandler.run(GameServer.java:65)
Could someone please help me understand why this doesn't work.
For starters, if you write a sequence of (encrypted!) bytes at one end, and trying to read a UTF-formatted string at the other end...you're going to have a bad time.
I'd suggest that on the client side you should do something like
dout.writeInt(cipherText.length);
dout.write(cipherText);
and then on the server side you should do something like
int byteLength = dis.readInt(); // now I know how many bytes to read
byte[] theBytes = new byte[byteLength];
dis.readFully(theBytes);
DataIputStream.readUTF() is for data that you have written with DataOutputStream.writeUTF()`. You haven't written UTF so you can't read it.
This is binary data so you shouldn't be thinking about UTF or strings at all. Write the length of the array with writeInt(), then the array with write(). At the other end, read the length with readInt(), allocate a byte[] buffer that big and then read the ciphertext into it with readFully().
Yo have to get the message with the read method and get the number of characters of the real messages and then convert this to a string
int bytesRead = 0;
byte[] messageByte = new byte[1000];
bytesRead = dis.read(messageByte);
String chiper = new String(messageByte, 0, bytesRead);
System.out.println(chiper);
on client side, you should convert the byte[] array to String and use
dout.writeUTF() to send the converted String.

Categories