Merge pull request #27 from Happy0/slice_bug
Fix bug with scuttlebutt boxstream segments not being formed properly
diff --git a/scuttlebutt-handshake/src/main/java/org/apache/tuweni/scuttlebutt/handshake/SecureScuttlebuttStream.java b/scuttlebutt-handshake/src/main/java/org/apache/tuweni/scuttlebutt/handshake/SecureScuttlebuttStream.java
index e9ebbb3..923dd96 100644
--- a/scuttlebutt-handshake/src/main/java/org/apache/tuweni/scuttlebutt/handshake/SecureScuttlebuttStream.java
+++ b/scuttlebutt-handshake/src/main/java/org/apache/tuweni/scuttlebutt/handshake/SecureScuttlebuttStream.java
@@ -18,7 +18,9 @@
import org.apache.tuweni.crypto.sodium.SecretBox;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
final class SecureScuttlebuttStream implements SecureScuttlebuttStreamClient, SecureScuttlebuttStreamServer {
@@ -135,18 +137,36 @@
private Bytes encrypt(Bytes message, SecretBox.Key clientToServerKey, MutableBytes clientToServerNonce) {
int messages = (int) Math.ceil((double) message.size() / 4096d);
- Bytes[] encryptedMessages = new Bytes[messages];
- for (int i = 0; i < messages; i++) {
- Bytes encryptedMessage = encryptMessage(
- message.slice(i * 4096, Math.min((i + 1) * 4096, message.size() - i * 4096)),
- clientToServerKey,
- clientToServerNonce);
- encryptedMessages[i] = encryptedMessage;
- }
- return Bytes.concatenate(encryptedMessages);
+
+ ArrayList<Bytes> bytes = breakIntoParts(message);
+
+ List<Bytes> segments =
+ bytes.stream().map(slice -> encryptMessage(slice, clientToServerKey, clientToServerNonce)).collect(
+ Collectors.toList());
+
+ return Bytes.concatenate(segments.toArray(new Bytes[] {}));
}
+ private ArrayList<Bytes> breakIntoParts(Bytes message) {
+
+ byte[] original = message.toArray();
+
+ int chunk = 4096;
+
+ ArrayList<Bytes> result = new ArrayList<>();
+ for (int i = 0; i < original.length; i += chunk) {
+ byte[] bytes = Arrays.copyOfRange(original, i, Math.min(original.length, i + chunk));
+
+ Bytes wrap = Bytes.wrap(bytes);
+ result.add(wrap);
+ }
+
+ return result;
+ }
+
+
private Bytes encryptMessage(Bytes message, SecretBox.Key key, MutableBytes nonce) {
+
SecretBox.Nonce headerNonce = null;
SecretBox.Nonce bodyNonce = null;
try {
diff --git a/scuttlebutt-rpc/src/test/java/org/apache/tuweni/scuttlebutt/rpc/mux/PatchworkIntegrationTest.java b/scuttlebutt-rpc/src/test/java/org/apache/tuweni/scuttlebutt/rpc/mux/PatchworkIntegrationTest.java
index df9a620..7f2cce1 100644
--- a/scuttlebutt-rpc/src/test/java/org/apache/tuweni/scuttlebutt/rpc/mux/PatchworkIntegrationTest.java
+++ b/scuttlebutt-rpc/src/test/java/org/apache/tuweni/scuttlebutt/rpc/mux/PatchworkIntegrationTest.java
@@ -11,7 +11,6 @@
* specific language governing permissions and limitations under the License.
*/
package org.apache.tuweni.scuttlebutt.rpc.mux;
-
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -159,6 +158,38 @@
rpcMessages.forEach(msg -> System.out.println(msg.asString()));
}
+ @Test
+ @Disabled
+ /**
+ * We expect this to complete the AsyncResult with an exception.
+ */
+ public void postMessageThatIsTooLong(@VertxInstance Vertx vertx) throws Exception {
+
+ RPCHandler rpcHandler = makeRPCHandler(vertx);
+
+ List<AsyncResult<RPCResponse>> results = new ArrayList<>();
+
+ String longString = new String(new char[40000]).replace("\0", "a");
+
+ for (int i = 0; i < 20; i++) {
+ // Note: in a real use case, this would more likely be a Java class with these fields
+ HashMap<String, String> params = new HashMap<>();
+ params.put("type", "post");
+ params.put("text", longString);
+
+ RPCAsyncRequest asyncRequest = new RPCAsyncRequest(new RPCFunction("publish"), Arrays.asList(params));
+
+ AsyncResult<RPCResponse> rpcMessageAsyncResult = rpcHandler.makeAsyncRequest(asyncRequest);
+
+ results.add(rpcMessageAsyncResult);
+
+ }
+
+ List<RPCResponse> rpcMessages = AsyncResult.combine(results).get();
+
+ rpcMessages.forEach(msg -> System.out.println(msg.asString()));
+ }
+
private RPCHandler makeRPCHandler(Vertx vertx) throws Exception {
Signature.KeyPair keyPair = getLocalKeys();
String networkKeyBase64 = "1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=";