blob: 87c222ba042f70eaff7be6ed03aa95c5cc219184 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
* file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
* to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.tuweni.rlpx;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.concurrent.AsyncResult;
import org.apache.tuweni.crypto.SECP256K1;
import org.apache.tuweni.crypto.SECP256K1.KeyPair;
import org.apache.tuweni.crypto.SECP256K1.SecretKey;
import org.apache.tuweni.junit.BouncyCastleExtension;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(BouncyCastleExtension.class)
class RLPxConnectionFactoryTest {
@Test
void roundtripPayload() {
KeyPair exampleKeyPair = SECP256K1.KeyPair
.fromSecretKey(
SecretKey
.fromBytes(
Bytes32.fromHexString("0xEE647A774DF811AB577BA5F397D56BE6567DA58AF7A65368F01DD7A8313812D8")));
Bytes payload = Bytes
.fromHexString(
"0xF8A7B84135A22239600070940908090D5F051B2C597981B090E386360B87163A8AF1EDF0434A84AA31A582DF93A0396D4CC2E3574C919B0E8D47DCEA095647446C88B36D01B840B8497006E23B1F35BD6E988EC53EE759BC852162049972F777B92B5E029B840BE8BE93F513DA55B81AEE463254930EE30667825B0B6FE30938FFFA7024A03C5AA02B310D67A36F599EAB6B8D03FECB9D782CC7A0EB12FECBFF454A4094557A2EB704");
InitiatorHandshakeMessage initial = InitiatorHandshakeMessage.decode(payload, exampleKeyPair.secretKey());
Bytes encoded = initial.encode();
assertEquals(payload, encoded);
}
@Test
void roundtripInitiatorHandshakeBytes() {
KeyPair keyPair = KeyPair.random();
KeyPair peerKeyPair = KeyPair.random();
byte[] nonce = new byte[32];
new SecureRandom().nextBytes(nonce);
Bytes payload = RLPxConnectionFactory.init(keyPair, peerKeyPair.publicKey(), KeyPair.random(), Bytes32.wrap(nonce));
InitiatorHandshakeMessage init = RLPxConnectionFactory.read(payload, peerKeyPair.secretKey());
assertEquals(keyPair.publicKey(), init.publicKey());
assertEquals(Bytes.wrap(nonce), init.nonce());
}
@Test
void roundtripResponseHandshakeBytes() {
KeyPair keyPair = KeyPair.random();
KeyPair peerKeyPair = KeyPair.random();
byte[] nonce = new byte[32];
new SecureRandom().nextBytes(nonce);
Bytes payload = RLPxConnectionFactory.init(keyPair, peerKeyPair.publicKey(), KeyPair.random(), Bytes32.wrap(nonce));
AtomicReference<Bytes> ref = new AtomicReference<>();
RLPxConnectionFactory.respondToHandshake(payload, peerKeyPair, ref::set);
HandshakeMessage responder = RLPxConnectionFactory.readResponse(ref.get(), keyPair.secretKey());
assertNotNull(responder);
}
@Test
void createHandshake() {
KeyPair keyPair = KeyPair.random();
KeyPair peerKeyPair = KeyPair.random();
byte[] nonce = new byte[32];
new SecureRandom().nextBytes(nonce);
KeyPair ephemeralKeyPair = KeyPair.random();
Bytes payload = RLPxConnectionFactory.init(keyPair, peerKeyPair.publicKey(), ephemeralKeyPair, Bytes32.wrap(nonce));
AtomicReference<Bytes> ref = new AtomicReference<>();
RLPxConnection conn = RLPxConnectionFactory.respondToHandshake(payload, peerKeyPair, ref::set);
HandshakeMessage responder = RLPxConnectionFactory.readResponse(ref.get(), keyPair.secretKey());
assertNotNull(conn);
assertNotNull(responder);
}
@Test
void createHandshakeAsync() throws TimeoutException, InterruptedException {
KeyPair keyPair = KeyPair.random();
KeyPair peerKeyPair = KeyPair.random();
AtomicReference<RLPxConnection> peerConnectionReference = new AtomicReference<>();
Function<Bytes, AsyncResult<Bytes>> wireBytes = (bytes) -> {
AtomicReference<Bytes> responseReference = new AtomicReference<>();
peerConnectionReference.set(RLPxConnectionFactory.respondToHandshake(bytes, peerKeyPair, responseReference::set));
return AsyncResult.completed(responseReference.get());
};
AsyncResult<RLPxConnection> futureConn =
RLPxConnectionFactory.createHandshake(keyPair, peerKeyPair.publicKey(), wireBytes);
RLPxConnection conn = futureConn.get(1, TimeUnit.SECONDS);
assertNotNull(conn);
assertTrue(RLPxConnection.isComplementedBy(conn, peerConnectionReference.get()));
}
@Test
void createHandshakeAndExchangeMessages() throws TimeoutException, InterruptedException {
KeyPair keyPair = KeyPair.random();
KeyPair peerKeyPair = KeyPair.random();
AtomicReference<RLPxConnection> peerConnectionReference = new AtomicReference<>();
Function<Bytes, AsyncResult<Bytes>> wireBytes = (bytes) -> {
AtomicReference<Bytes> responseReference = new AtomicReference<>();
peerConnectionReference.set(RLPxConnectionFactory.respondToHandshake(bytes, peerKeyPair, responseReference::set));
return AsyncResult.completed(responseReference.get());
};
AsyncResult<RLPxConnection> futureConn =
RLPxConnectionFactory.createHandshake(keyPair, peerKeyPair.publicKey(), wireBytes);
RLPxConnection conn = futureConn.get(1, TimeUnit.SECONDS);
RLPxConnection conn2 = peerConnectionReference.get();
{
Bytes message = conn.write(new RLPxMessage(1, Bytes.fromHexString("deadbeef")));
RLPxMessage readMessage = conn2.readFrame(message);
assertEquals(Bytes.fromHexString("deadbeef"), readMessage.content());
assertEquals(1, readMessage.messageId());
}
{
Bytes message = conn.write(new RLPxMessage(1, Bytes.fromHexString("deadbeef")));
RLPxMessage readMessage = conn2.readFrame(message);
assertEquals(Bytes.fromHexString("deadbeef"), readMessage.content());
assertEquals(1, readMessage.messageId());
}
{
Bytes message = conn2.write(new RLPxMessage(1, Bytes.fromHexString("deadbeef")));
RLPxMessage readMessage = conn.readFrame(message);
assertEquals(Bytes.fromHexString("deadbeef"), readMessage.content());
assertEquals(1, readMessage.messageId());
}
}
private static final SECP256K1.PublicKey publicKey = SECP256K1.KeyPair.random().publicKey();
private static final SECP256K1.PublicKey peerPublicKey = SECP256K1.KeyPair.random().publicKey();
@Test
void fixedMessage() {
RLPxConnection conn = new RLPxConnection(
Bytes32.fromHexString("0x401EED08125776F3A23201D09847EEBEC539FD18E9CB793A53B21F7A23CEFED4"),
Bytes32.fromHexString("0x82808970451A460E89DBA968ADAA99B56BC4C6270C4285DA1CB0D40116BB02B7"),
Bytes32.fromHexString("0xEDC55BCCD06BAA6A2D593D3836D7580407FB0C01A96544C63EAA05D863E05744"),
Bytes
.fromHexString(
"0x2B72DAFCF28E915725B511BC0A73C760C785B5704EB303E961D1954D21BCC9B801F90474C2A4769AC420A0C26387A2C963264B2596CE626C679588EA733600EC4091BC7B06157E24E0CC741DDBA1E5C6645D83E1149B2CB95AF3915DC52B9485E0122EE6B4AD0B1A80D53D2CBD50BF67E22C4FCB80059CBC3EA672681350765F360F58FB934F0165B50AE928A4D8CB37F68A9B5FC845960E1D37E0869AA593E6C63ABFEB384E6512E511075F7C5D8EB16067A0C59F4882CC4F7EB415F231CDC6A0D78FC38629E38FA0A5741535378680D7E5426ED397304B83AEAEBC43F812C8172E48497DA5E52CE087267A1FEAD8221BA34398B68C3A54E9F0D18B4CECA4472C177E5BE45D631C9D5DC525E0B8D31BD926AB15465922DFD01EE9AE50D67BF78B0CCCB415D034FD89A8A1F3C4E58F1F0DC2FA87AA4E4A956CDB459102571DBB67637CE05927806D09E218EC66ADB2B6A1702C6CBC40CF33DD5FCA373E9C63570C4F4CEC523881199579447B4B557674D9428BEB035FD9807D36AF304CB05C680F8BD9752E9F347C5B9EB02DCB9E09177B5ECE2CA65E7693932B932A98798DE4B428A7D5420173BC2F5BB5AEC985D565A4BD1B7F987906D7F2D4BF51726D279850C46CF65FAF1D1EF81565630618705FF673FB8BC714991796382A07294E1100D51E5321123DB87B248CED97EEB65C3274685CF9C791114756C9B8F0B1824C4A3CFA4EB172A238025EC20973992945ACC886D593DD91555C"),
Bytes
.fromHexString(
"0xE23AC9D32A1BAD577821EB0858615BFED01C5030A5A39342DC992802679C3C1F0189049E5A5FD009FF4BE044146296CFA5AF029BF1CE5F0913D4DB477D89360E484363C8DFC8E96C6398B20440639323591C8F6337DF2A1DFE7B56DB9B2447401771FEF89700CCB6DDDCF7BA0AC80AE57374449E34F82F65FD0280306E9F62C808690390946CDFF9E9C8A5243ED7BA88E29AA7AC128DD9AE4E79497237B75B4F6D5511FDDD2E1916057ED7CC95B512299C20E90EC2134E2DDA87B7F73F3BFBFD4D68417976AA0F7C74E39BFECF677982E9EE3ED15BDEEC31D7867FA80A18A331AD0BC1C1687F9DB5AD3AB9C81B948E1EE11C1F5CFFE86B5A931CEFD2266D112458B80AA1AD6E9C7814B76CEA4B4C57B360132BFF81ACA35B9620D065F24E0000B4EB27D7B3B126DE353C6C265B391084E3CF27086FCBDF11DA364A480DD61F0899E41539F0D8DD958C95D3D09F0EB4C11136686B5EBB9D89ADFB81FAC83C5895874860F0F75CBDA479EF461CA4B75C2EE0F30FF7E0BD259E31DFE4579E334688303AB29EEAC11DBB963A34F2C09D18242F00BCF5CB5340FB7E03DE02ADEE1F3042246B0E21EF4BAF"),
publicKey,
peerPublicKey);
conn
.readFrame(
Bytes
.fromHexString(
"0x5B5B56F71CE97B8DEA5F469808441FD10675F244B062222245F5831747924934841D86A431AD89EB3C825C867F0A9820E8E4134C8438A529BE15445073C2C2C33729E6ED374BF2EEC1CA5F3D60972892"));
}
@Test
void invalidHeaderMAC() {
RLPxConnection conn = new RLPxConnection(
Bytes32.fromHexString("0x401EED08125776F3A23201D09847EEBEC539FD18E9CB793A53B21F7A23CEFED4"),
Bytes32.fromHexString("0x82808970451A460E89DBA968ADAA99B56BC4C6270C4285DA1CB0D40116BB02B7"),
Bytes32.fromHexString("0xEDC55BCCD06BAA6A2D593D3836D7580407FB0C01A96544C63EAA05D863E05744"),
Bytes
.fromHexString(
"0x2B72DAFCF28E915725B511BC0A73C760C785B5704EB303E961D1954D21BCC9B801F90474C2A4769AC420A0C26387A2C963264B2596CE626C679588EA733600EC4091BC7B06157E24E0CC741DDBA1E5C6645D83E1149B2CB95AF3915DC52B9485E0122EE6B4AD0B1A80D53D2CBD50BF67E22C4FCB80059CBC3EA672681350765F360F58FB934F0165B50AE928A4D8CB37F68A9B5FC845960E1D37E0869AA593E6C63ABFEB384E6512E511075F7C5D8EB16067A0C59F4882CC4F7EB415F231CDC6A0D78FC38629E38FA0A5741535378680D7E5426ED397304B83AEAEBC43F812C8172E48497DA5E52CE087267A1FEAD8221BA34398B68C3A54E9F0D18B4CECA4472C177E5BE45D631C9D5DC525E0B8D31BD926AB15465922DFD01EE9AE50D67BF78B0CCCB415D034FD89A8A1F3C4E58F1F0DC2FA87AA4E4A956CDB459102571DBB67637CE05927806D09E218EC66ADB2B6A1702C6CBC40CF33DD5FCA373E9C63570C4F4CEC523881199579447B4B557674D9428BEB035FD9807D36AF304CB05C680F8BD9752E9F347C5B9EB02DCB9E09177B5ECE2CA65E7693932B932A98798DE4B428A7D5420173BC2F5BB5AEC985D565A4BD1B7F987906D7F2D4BF51726D279850C46CF65FAF1D1EF81565630618705FF673FB8BC714991796382A07294E1100D51E5321123DB87B248CED97EEB65C3274685CF9C791114756C9B8F0B1824C4A3CFA4EB172A238025EC20973992945ACC886D593DD91555C"),
Bytes
.fromHexString(
"0xE23AC9D32A1BAD577821EB0858615BFED01C5030A5A39342DC992802679C3C1F0189049E5A5FD009FF4BE044146296CFA5AF029BF1CE5F0913D4DB477D89360E484363C8DFC8E96C6398B20440639323591C8F6337DF2A1DFE7B56DB9B2447401771FEF89700CCB6DDDCF7BA0AC80AE57374449E34F82F65FD0280306E9F62C808690390946CDFF9E9C8A5243ED7BA88E29AA7AC128DD9AE4E79497237B75B4F6D5511FDDD2E1916057ED7CC95B512299C20E90EC2134E2DDA87B7F73F3BFBFD4D68417976AA0F7C74E39BFECF677982E9EE3ED15BDEEC31D7867FA80A18A331AD0BC1C1687F9DB5AD3AB9C81B948E1EE11C1F5CFFE86B5A931CEFD2266D112458B80AA1AD6E9C7814B76CEA4B4C57B360132BFF81ACA35B9620D065F24E0000B4EB27D7B3B126DE353C6C265B391084E3CF27086FCBDF11DA364A480DD61F0899E41539F0D8DD958C95D3D09F0EB4C11136686B5EBB9D89ADFB81FAC83C5895874860F0F75CBDA479EF461CA4B75C2EE0F30FF7E0BD259E31DFE4579E334688303AB29EEAC11DBB963A34F2C09D18242F00BCF5CB5340FB7E03DE02ADEE1F3042246B0E21EF4BAF"),
publicKey,
peerPublicKey);
assertThrows(
InvalidMACException.class,
() -> conn
.readFrame(
Bytes
.fromHexString(
"0x5B5B56E71CE97B8DEA5F469808441FD10675F244B062222245F5831747924934841D86A431AD89EB3C825C867F0A9820E8E4134C8438A529BE15445073C2C2C33729E6ED374BF2EEC1CA5F3D60972892")));
}
@Test
void invalidFrameMAC() {
RLPxConnection conn = new RLPxConnection(
Bytes32.fromHexString("0x401EED08125776F3A23201D09847EEBEC539FD18E9CB793A53B21F7A23CEFED4"),
Bytes32.fromHexString("0x82808970451A460E89DBA968ADAA99B56BC4C6270C4285DA1CB0D40116BB02B7"),
Bytes32.fromHexString("0xEDC55BCCD06BAA6A2D593D3836D7580407FB0C01A96544C63EAA05D863E05744"),
Bytes
.fromHexString(
"0x2B72DAFCF28E915725B511BC0A73C760C785B5704EB303E961D1954D21BCC9B801F90474C2A4769AC420A0C26387A2C963264B2596CE626C679588EA733600EC4091BC7B06157E24E0CC741DDBA1E5C6645D83E1149B2CB95AF3915DC52B9485E0122EE6B4AD0B1A80D53D2CBD50BF67E22C4FCB80059CBC3EA672681350765F360F58FB934F0165B50AE928A4D8CB37F68A9B5FC845960E1D37E0869AA593E6C63ABFEB384E6512E511075F7C5D8EB16067A0C59F4882CC4F7EB415F231CDC6A0D78FC38629E38FA0A5741535378680D7E5426ED397304B83AEAEBC43F812C8172E48497DA5E52CE087267A1FEAD8221BA34398B68C3A54E9F0D18B4CECA4472C177E5BE45D631C9D5DC525E0B8D31BD926AB15465922DFD01EE9AE50D67BF78B0CCCB415D034FD89A8A1F3C4E58F1F0DC2FA87AA4E4A956CDB459102571DBB67637CE05927806D09E218EC66ADB2B6A1702C6CBC40CF33DD5FCA373E9C63570C4F4CEC523881199579447B4B557674D9428BEB035FD9807D36AF304CB05C680F8BD9752E9F347C5B9EB02DCB9E09177B5ECE2CA65E7693932B932A98798DE4B428A7D5420173BC2F5BB5AEC985D565A4BD1B7F987906D7F2D4BF51726D279850C46CF65FAF1D1EF81565630618705FF673FB8BC714991796382A07294E1100D51E5321123DB87B248CED97EEB65C3274685CF9C791114756C9B8F0B1824C4A3CFA4EB172A238025EC20973992945ACC886D593DD91555C"),
Bytes
.fromHexString(
"0xE23AC9D32A1BAD577821EB0858615BFED01C5030A5A39342DC992802679C3C1F0189049E5A5FD009FF4BE044146296CFA5AF029BF1CE5F0913D4DB477D89360E484363C8DFC8E96C6398B20440639323591C8F6337DF2A1DFE7B56DB9B2447401771FEF89700CCB6DDDCF7BA0AC80AE57374449E34F82F65FD0280306E9F62C808690390946CDFF9E9C8A5243ED7BA88E29AA7AC128DD9AE4E79497237B75B4F6D5511FDDD2E1916057ED7CC95B512299C20E90EC2134E2DDA87B7F73F3BFBFD4D68417976AA0F7C74E39BFECF677982E9EE3ED15BDEEC31D7867FA80A18A331AD0BC1C1687F9DB5AD3AB9C81B948E1EE11C1F5CFFE86B5A931CEFD2266D112458B80AA1AD6E9C7814B76CEA4B4C57B360132BFF81ACA35B9620D065F24E0000B4EB27D7B3B126DE353C6C265B391084E3CF27086FCBDF11DA364A480DD61F0899E41539F0D8DD958C95D3D09F0EB4C11136686B5EBB9D89ADFB81FAC83C5895874860F0F75CBDA479EF461CA4B75C2EE0F30FF7E0BD259E31DFE4579E334688303AB29EEAC11DBB963A34F2C09D18242F00BCF5CB5340FB7E03DE02ADEE1F3042246B0E21EF4BAF"),
publicKey,
peerPublicKey);
assertThrows(
InvalidMACException.class,
() -> conn
.readFrame(
Bytes
.fromHexString(
"0x5B5B56F71CE97B8DEA5F469808441FD10675F244B062222245F5831747924934841D86A431AD89EB3C825C867F0A9820E8E4134C8438A529BE15445073C2C2C33729E6ED374BF2EEC1CA5F3D60972893")));
}
@Test
void partialMessages() {
RLPxConnection conn = new RLPxConnection(
Bytes32.fromHexString("0x401EED08125776F3A23201D09847EEBEC539FD18E9CB793A53B21F7A23CEFED4"),
Bytes32.fromHexString("0x82808970451A460E89DBA968ADAA99B56BC4C6270C4285DA1CB0D40116BB02B7"),
Bytes32.fromHexString("0xEDC55BCCD06BAA6A2D593D3836D7580407FB0C01A96544C63EAA05D863E05744"),
Bytes
.fromHexString(
"0x2B72DAFCF28E915725B511BC0A73C760C785B5704EB303E961D1954D21BCC9B801F90474C2A4769AC420A0C26387A2C963264B2596CE626C679588EA733600EC4091BC7B06157E24E0CC741DDBA1E5C6645D83E1149B2CB95AF3915DC52B9485E0122EE6B4AD0B1A80D53D2CBD50BF67E22C4FCB80059CBC3EA672681350765F360F58FB934F0165B50AE928A4D8CB37F68A9B5FC845960E1D37E0869AA593E6C63ABFEB384E6512E511075F7C5D8EB16067A0C59F4882CC4F7EB415F231CDC6A0D78FC38629E38FA0A5741535378680D7E5426ED397304B83AEAEBC43F812C8172E48497DA5E52CE087267A1FEAD8221BA34398B68C3A54E9F0D18B4CECA4472C177E5BE45D631C9D5DC525E0B8D31BD926AB15465922DFD01EE9AE50D67BF78B0CCCB415D034FD89A8A1F3C4E58F1F0DC2FA87AA4E4A956CDB459102571DBB67637CE05927806D09E218EC66ADB2B6A1702C6CBC40CF33DD5FCA373E9C63570C4F4CEC523881199579447B4B557674D9428BEB035FD9807D36AF304CB05C680F8BD9752E9F347C5B9EB02DCB9E09177B5ECE2CA65E7693932B932A98798DE4B428A7D5420173BC2F5BB5AEC985D565A4BD1B7F987906D7F2D4BF51726D279850C46CF65FAF1D1EF81565630618705FF673FB8BC714991796382A07294E1100D51E5321123DB87B248CED97EEB65C3274685CF9C791114756C9B8F0B1824C4A3CFA4EB172A238025EC20973992945ACC886D593DD91555C"),
Bytes
.fromHexString(
"0xE23AC9D32A1BAD577821EB0858615BFED01C5030A5A39342DC992802679C3C1F0189049E5A5FD009FF4BE044146296CFA5AF029BF1CE5F0913D4DB477D89360E484363C8DFC8E96C6398B20440639323591C8F6337DF2A1DFE7B56DB9B2447401771FEF89700CCB6DDDCF7BA0AC80AE57374449E34F82F65FD0280306E9F62C808690390946CDFF9E9C8A5243ED7BA88E29AA7AC128DD9AE4E79497237B75B4F6D5511FDDD2E1916057ED7CC95B512299C20E90EC2134E2DDA87B7F73F3BFBFD4D68417976AA0F7C74E39BFECF677982E9EE3ED15BDEEC31D7867FA80A18A331AD0BC1C1687F9DB5AD3AB9C81B948E1EE11C1F5CFFE86B5A931CEFD2266D112458B80AA1AD6E9C7814B76CEA4B4C57B360132BFF81ACA35B9620D065F24E0000B4EB27D7B3B126DE353C6C265B391084E3CF27086FCBDF11DA364A480DD61F0899E41539F0D8DD958C95D3D09F0EB4C11136686B5EBB9D89ADFB81FAC83C5895874860F0F75CBDA479EF461CA4B75C2EE0F30FF7E0BD259E31DFE4579E334688303AB29EEAC11DBB963A34F2C09D18242F00BCF5CB5340FB7E03DE02ADEE1F3042246B0E21EF4BAF"),
publicKey,
peerPublicKey);
Bytes fullMessage = Bytes
.fromHexString(
"0x5B5B56F71CE97B8DEA5F469808441FD10675F244B062222245F5831747924934841D86A431AD89EB3C825C867F0A9820E8E4134C8438A529BE15445073C2C2C33729E6ED374BF2EEC1CA5F3D60972892");
AtomicReference<RLPxMessage> messageRef = new AtomicReference<>();
Bytes message1 = fullMessage.slice(0, 16);
Bytes message2 = fullMessage.slice(16, 32);
Bytes message3 = fullMessage.slice(16 + 32);
assertEquals(fullMessage, Bytes.concatenate(message1, message2, message3));
conn.stream(message1, messageRef::set);
assertNull(messageRef.get());
conn.stream(message2, messageRef::set);
assertNull(messageRef.get());
conn.stream(message3, messageRef::set);
assertNotNull(messageRef.get());
}
@Test
void twoMessagesCollated() throws TimeoutException, InterruptedException {
KeyPair keyPair = KeyPair.random();
KeyPair peerKeyPair = KeyPair.random();
AtomicReference<RLPxConnection> peerConnectionReference = new AtomicReference<>();
Function<Bytes, AsyncResult<Bytes>> wireBytes = (bytes) -> {
AtomicReference<Bytes> responseReference = new AtomicReference<>();
peerConnectionReference.set(RLPxConnectionFactory.respondToHandshake(bytes, peerKeyPair, responseReference::set));
return AsyncResult.completed(responseReference.get());
};
AsyncResult<RLPxConnection> futureConn =
RLPxConnectionFactory.createHandshake(keyPair, peerKeyPair.publicKey(), wireBytes);
RLPxConnection conn = futureConn.get(1, TimeUnit.SECONDS);
RLPxConnection conn2 = peerConnectionReference.get();
List<RLPxMessage> messages = new ArrayList<>();
Bytes message = conn.write(new RLPxMessage(1, Bytes.fromHexString("deadbeef")));
Bytes message2 = conn.write(new RLPxMessage(1, Bytes.fromHexString("deadbeef")));
conn2.stream(Bytes.concatenate(message, message2), messages::add);
assertEquals(2, messages.size());
}
@Test
void roundtripBytesEncryption() {
KeyPair peerKeyPair = KeyPair.random();
Bytes encrypted = RLPxConnectionFactory.encryptMessage(Bytes.fromHexString("deadbeef"), peerKeyPair.publicKey());
Bytes decrypted = RLPxConnectionFactory.decryptMessage(encrypted, peerKeyPair.secretKey());
assertEquals(Bytes.fromHexString("deadbeef"), decrypted.slice(0, 4));
}
@Test
void roundtripBytesEncryptionWithGarbageAppended() {
KeyPair peerKeyPair = KeyPair.random();
Bytes encrypted = RLPxConnectionFactory.encryptMessage(Bytes.fromHexString("deadbeef"), peerKeyPair.publicKey());
Bytes decrypted = RLPxConnectionFactory
.decryptMessage(Bytes.concatenate(encrypted, Bytes.of(12, 2, 2, 2, 3)), peerKeyPair.secretKey());
assertEquals(Bytes.fromHexString("deadbeef"), decrypted.slice(0, 4));
}
}