mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-23 19:16:14 +01:00
Add StructureModifier for extracting the signature data in chat and login packets (#1742)
This commit is contained in:
parent
c3dc00de05
commit
11a8184c3e
@ -929,6 +929,40 @@ public abstract class AbstractStructure {
|
||||
BukkitConverters.getWrappedPublicKeyDataConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return read/write structure for login encryption packets
|
||||
*/
|
||||
public StructureModifier<Either<byte[], WrappedSaltedSignature>> getLoginSignatures() {
|
||||
return getEithers(Converters.passthrough(byte[].class), BukkitConverters.getWrappedSignatureConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return read/writer structure direct access to signature data like chat messages
|
||||
*/
|
||||
public StructureModifier<WrappedSaltedSignature> getSignatures() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getSaltedSignatureClass(),
|
||||
BukkitConverters.getWrappedSignatureConverter()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leftConverter converter for left values
|
||||
* @param rightConverter converter for right values
|
||||
* @return ProtocolLib's read/write structure for Mojang either structures
|
||||
* @param <L> left data type after converting from NMS
|
||||
* @param <R> right data type after converting from NMS
|
||||
*/
|
||||
public <L, R> StructureModifier<Either<L, R>> getEithers(EquivalentConverter<L> leftConverter,
|
||||
EquivalentConverter<R> rightConverter) {
|
||||
return structureModifier.withType(
|
||||
com.mojang.datafixers.util.Either.class,
|
||||
BukkitConverters.getEitherConverter(
|
||||
leftConverter, rightConverter
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the Map class.
|
||||
* @param keyConverter Converter for map keys
|
||||
|
@ -34,10 +34,7 @@ import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.reflect.fuzzy.*;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
@ -1499,6 +1496,31 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("world.entity.player.ProfilePublicKey");
|
||||
}
|
||||
|
||||
public static Class<?> getSaltedSignatureClass() {
|
||||
try {
|
||||
return getMinecraftClass("SaltedSignature");
|
||||
} catch (RuntimeException runtimeException) {
|
||||
Class<?> messageSigClass = getMinecraftClass("network.chat.MessageSignature", "MessageSignature");
|
||||
|
||||
FuzzyClassContract signatureContract = FuzzyClassContract.newBuilder().
|
||||
constructor(FuzzyMethodContract.newBuilder().
|
||||
parameterCount(2).
|
||||
parameterSuperOf(Long.TYPE, 0).
|
||||
parameterSuperOf(byte[].class, 1).
|
||||
build()
|
||||
).build();
|
||||
|
||||
FuzzyFieldContract fuzzyFieldContract = FuzzyFieldContract.newBuilder().
|
||||
typeMatches(getMinecraftObjectMatcher().and(signatureContract)).
|
||||
build();
|
||||
|
||||
Class<?> signatureClass = FuzzyReflection.fromClass(messageSigClass, true)
|
||||
.getField(fuzzyFieldContract)
|
||||
.getType();
|
||||
return setMinecraftClass("SaltedSignature", signatureClass);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getProfilePublicKeyDataClass() {
|
||||
return getProfilePublicKeyClass().getClasses()[0];
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.wrappers.Either.Left;
|
||||
import com.comphenix.protocol.wrappers.Either.Right;
|
||||
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.*;
|
||||
@ -407,6 +409,43 @@ public class BukkitConverters {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param leftConverter convert the left value if available
|
||||
* @param rightConverter convert the right value if available
|
||||
* @return converter for Mojang either class
|
||||
* @param <A> converted left type
|
||||
* @param <B> converted right type
|
||||
*/
|
||||
public static <A, B> EquivalentConverter<Either<A, B>> getEitherConverter(EquivalentConverter<A> leftConverter,
|
||||
EquivalentConverter<B> rightConverter) {
|
||||
return ignoreNull(new EquivalentConverter<Either<A, B>>() {
|
||||
@Override
|
||||
public Object getGeneric(Either<A, B> specific) {
|
||||
return specific.map(
|
||||
left -> com.mojang.datafixers.util.Either.left(leftConverter.getGeneric(left)),
|
||||
right -> com.mojang.datafixers.util.Either.right(rightConverter.getGeneric(right))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<A, B> getSpecific(Object generic) {
|
||||
com.mojang.datafixers.util.Either<A, B> mjEither = (com.mojang.datafixers.util.Either<A, B>) generic;
|
||||
|
||||
return mjEither.map(
|
||||
left -> new Left<>(leftConverter.getSpecific(left)),
|
||||
right -> new Right<>(rightConverter.getSpecific(right))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Either<A, B>> getSpecificType() {
|
||||
Class<?> dummy = Either.class;
|
||||
return (Class<Either<A, B>>) dummy;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an equivalent converter for a set of generic items.
|
||||
* @param <T> Element type
|
||||
@ -564,6 +603,13 @@ public class BukkitConverters {
|
||||
return ignoreNull(handle(WrappedProfileKeyData::getHandle, WrappedProfileKeyData::new, WrappedProfileKeyData.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return converter for cryptographic signature data that are used in login and chat packets
|
||||
*/
|
||||
public static EquivalentConverter<WrappedSaltedSignature> getWrappedSignatureConverter() {
|
||||
return ignoreNull(handle(WrappedSaltedSignature::getHandle, WrappedSaltedSignature::new, WrappedSaltedSignature.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a converter for watchable objects and the respective wrapper.
|
||||
* @return A watchable object converter.
|
||||
|
100
src/main/java/com/comphenix/protocol/wrappers/Either.java
Normal file
100
src/main/java/com/comphenix/protocol/wrappers/Either.java
Normal file
@ -0,0 +1,100 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Represents a datatype where either left or right is present. The values are available with a xor semantic. So at
|
||||
* most and at least one value will be available.
|
||||
*
|
||||
* @param <L> left data type
|
||||
* @param <R> right data type
|
||||
*/
|
||||
public abstract class Either<L, R> {
|
||||
|
||||
public static class Left<L, R> extends Either<L, R> {
|
||||
|
||||
private final L value;
|
||||
|
||||
protected Left(L value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T map(Function<L, T> leftConsumer, Function<R, T> rightConsumer) {
|
||||
return leftConsumer.apply(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<L> left() {
|
||||
return Optional.ofNullable(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<R> right() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Right<L, R> extends Either<L, R> {
|
||||
|
||||
private final R value;
|
||||
|
||||
protected Right(R value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T map(Function<L, T> leftConsumer, Function<R, T> rightConsumer) {
|
||||
return rightConsumer.apply(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<L> left() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<R> right() {
|
||||
return Optional.ofNullable(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leftConsumer transformer if the left value is present
|
||||
* @param rightConsumer transformer if the right value is present
|
||||
* @return result of applying the given functions to the left or right side
|
||||
* @param <T> result data type of both transformers
|
||||
*/
|
||||
public abstract <T> T map(Function<L, T> leftConsumer, Function<R, T> rightConsumer);
|
||||
|
||||
/**
|
||||
* @return left value if present
|
||||
*/
|
||||
public abstract Optional<L> left();
|
||||
|
||||
/**
|
||||
* @return right value if present
|
||||
*/
|
||||
public abstract Optional<R> right();
|
||||
|
||||
/**
|
||||
* @param value containing value
|
||||
* @return either containing a left value
|
||||
* @param <L> data type of the containing value
|
||||
* @param <R> right data type
|
||||
*/
|
||||
public static <L, R> Either<L, R> left(L value) {
|
||||
return new Left<>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value containing value
|
||||
* @return either containing a right value
|
||||
* @param <L> left data type
|
||||
* @param <R> data type of the containing value
|
||||
*/
|
||||
public static <L, R> Either<L, R> right(R value) {
|
||||
return new Right<>(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
/**
|
||||
* Wrapper representing the signature data associated to signed data by the player. This includes signed chat messages
|
||||
* and login encryption acknowledgments.
|
||||
*/
|
||||
public class WrappedSaltedSignature extends AbstractWrapper {
|
||||
|
||||
private static ConstructorAccessor CONSTRUCTOR;
|
||||
|
||||
private final StructureModifier<Object> modifier;
|
||||
|
||||
/**
|
||||
* Construct a wrapper from a NMS handle
|
||||
*
|
||||
* @param handle NMS Signature object
|
||||
*/
|
||||
public WrappedSaltedSignature(Object handle) {
|
||||
super(MinecraftReflection.getSaltedSignatureClass());
|
||||
|
||||
this.setHandle(handle);
|
||||
this.modifier = new StructureModifier<>(MinecraftReflection.getSaltedSignatureClass()).withTarget(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a wrapper and NMS handle containing the given values
|
||||
* @param salt salt/nonce for this signature
|
||||
* @param signature binary cryptographic signature
|
||||
*/
|
||||
public WrappedSaltedSignature(long salt, byte[] signature) {
|
||||
super(MinecraftReflection.getSaltedSignatureClass());
|
||||
|
||||
if (CONSTRUCTOR == null) {
|
||||
CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
this.getHandleType(),
|
||||
Long.TYPE, byte[].class);
|
||||
}
|
||||
|
||||
this.setHandle(CONSTRUCTOR.invoke(salt, signature));
|
||||
this.modifier = new StructureModifier<>(MinecraftReflection.getSaltedSignatureClass()).withTarget(this.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if a cryptographic signature data is present
|
||||
*/
|
||||
public boolean isSigned() {
|
||||
return getSignature().length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return cryptographic salt/nonce
|
||||
*/
|
||||
public long getSalt() {
|
||||
return (long) modifier.withType(Long.TYPE).read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param salt cryptographic salt/nonce
|
||||
*/
|
||||
public void setSalt(long salt) {
|
||||
modifier.withType(Long.TYPE).write(0, salt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return binary signature data associated to the salt and message
|
||||
*/
|
||||
public byte[] getSignature() {
|
||||
return modifier.<byte[]>withType(byte[].class).read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param signature binary signature data associated to the salt and message
|
||||
*/
|
||||
public void setSignature(byte[] signature) {
|
||||
modifier.<byte[]>withType(byte[].class).write(0, signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the long salt represented in 8 bytes
|
||||
*/
|
||||
public byte[] getSaltBytes() {
|
||||
return Longs.toByteArray(getSalt());
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.ComponentConverter;
|
||||
import com.comphenix.protocol.wrappers.Either;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
||||
@ -52,6 +53,7 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import com.comphenix.protocol.wrappers.WrappedEnumEntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.comphenix.protocol.wrappers.WrappedSaltedSignature;
|
||||
import com.comphenix.protocol.wrappers.WrappedRegistry;
|
||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
@ -707,6 +709,46 @@ public class PacketContainerTest {
|
||||
assertArrayEquals(components, back);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginSignatureNonce() {
|
||||
PacketContainer encryptionStart = new PacketContainer(PacketType.Login.Client.ENCRYPTION_BEGIN);
|
||||
encryptionStart.getByteArrays().write(0, new byte[]{1, 2, 3});
|
||||
|
||||
byte[] nonce = {4, 5, 6};
|
||||
encryptionStart.getLoginSignatures().write(0, Either.left(nonce));
|
||||
|
||||
byte[] read = encryptionStart.getLoginSignatures().read(0).left().get();
|
||||
assertArrayEquals(nonce, read);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginSignatureSigned() {
|
||||
PacketContainer encryptionStart = new PacketContainer(PacketType.Login.Client.ENCRYPTION_BEGIN);
|
||||
encryptionStart.getByteArrays().write(0, new byte[]{1, 2, 3});
|
||||
|
||||
byte[] signature = new byte[512];
|
||||
long salt = 124L;
|
||||
encryptionStart.getLoginSignatures().write(0, Either.right(new WrappedSaltedSignature(salt, signature)));
|
||||
|
||||
WrappedSaltedSignature read = encryptionStart.getLoginSignatures().read(0).right().get();
|
||||
assertEquals(salt, read.getSalt());
|
||||
assertArrayEquals(signature, read.getSignature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignedChatMessage() {
|
||||
PacketContainer chatPacket = new PacketContainer(PacketType.Play.Client.CHAT);
|
||||
|
||||
byte[] signature = new byte[512];
|
||||
long salt = 124L;
|
||||
WrappedSaltedSignature wrappedSignature = new WrappedSaltedSignature(salt, signature);
|
||||
chatPacket.getSignatures().write(0, wrappedSignature);
|
||||
|
||||
WrappedSaltedSignature read = chatPacket.getSignatures().read(0);
|
||||
assertEquals(salt, read.getSalt());
|
||||
assertArrayEquals(signature, read.getSignature());
|
||||
}
|
||||
|
||||
private void assertPacketsEqual(PacketContainer constructed, PacketContainer cloned) {
|
||||
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
|
||||
assertEquals(firstMod.size(), secondMod.size());
|
||||
|
@ -17,6 +17,7 @@ import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.network.protocol.status.ServerPing;
|
||||
import net.minecraft.network.syncher.DataWatcher;
|
||||
import net.minecraft.server.network.PlayerConnection;
|
||||
import net.minecraft.util.MinecraftEncryption;
|
||||
import net.minecraft.world.level.ChunkCoordIntPair;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import org.bukkit.Material;
|
||||
@ -119,6 +120,11 @@ public class MinecraftReflectionTest {
|
||||
assertEquals(DataWatcher.Item.class, MinecraftReflection.getDataWatcherItemClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginSignature() {
|
||||
assertEquals(MinecraftEncryption.b.class, MinecraftReflection.getSaltedSignatureClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
ItemStack stack = new ItemStack(Material.GOLDEN_SWORD);
|
||||
|
@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.wrappers.Either.Left;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
@ -38,4 +40,19 @@ public class BukkitConvertersTest {
|
||||
assertEquals(item.hasItemMeta(), back.hasItemMeta());
|
||||
assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEither() {
|
||||
Either<String, String> test = new Left<>("bla");
|
||||
|
||||
EquivalentConverter<Either<String, String>> converter = BukkitConverters.getEitherConverter(
|
||||
Converters.passthrough(String.class), Converters.passthrough(String.class)
|
||||
);
|
||||
|
||||
com.mojang.datafixers.util.Either<String, String> nmsEither = (com.mojang.datafixers.util.Either<String, String>) converter.getGeneric(test);
|
||||
Either<String, String> wrapped = converter.getSpecific(nmsEither);
|
||||
|
||||
assertEquals(wrapped.left(), nmsEither.left());
|
||||
assertEquals(wrapped.right(), nmsEither.right());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.wrappers.Either.Left;
|
||||
import com.comphenix.protocol.wrappers.Either.Right;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class EitherTest {
|
||||
|
||||
@Test
|
||||
void testLeft() {
|
||||
Left<String, ?> left = new Left<>("left");
|
||||
|
||||
assertEquals(left.left(), Optional.of("left"));
|
||||
assertEquals(left.right(), Optional.empty());
|
||||
|
||||
String map = left.map(l -> l + "left", r -> r + "right");
|
||||
assertEquals("leftleft", map);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRight() {
|
||||
Right<?, String> right = new Right<>("right");
|
||||
|
||||
assertEquals(right.left(), Optional.empty());
|
||||
assertEquals(right.right(), Optional.of("right"));
|
||||
|
||||
String map = right.map(l -> l + "left", r -> r + "right");
|
||||
assertEquals("rightright", map);
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import net.minecraft.util.MinecraftEncryption;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class WrappedSaltedSignatureTest {
|
||||
|
||||
@BeforeAll
|
||||
static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginSignature() {
|
||||
long salt = ThreadLocalRandom.current().nextLong();
|
||||
byte[] signature = new byte[512];
|
||||
ThreadLocalRandom.current().nextBytes(signature);
|
||||
|
||||
// test key data conversion
|
||||
WrappedSaltedSignature loginSignature = new WrappedSaltedSignature(salt, signature);
|
||||
|
||||
Object handle = loginSignature.getHandle();
|
||||
MinecraftEncryption.b data = assertInstanceOf(MinecraftEncryption.b.class, handle);
|
||||
|
||||
assertTrue(data.a());
|
||||
assertArrayEquals(signature, data.d());
|
||||
assertEquals(salt, data.c());
|
||||
|
||||
// test key data unwrapping
|
||||
WrappedSaltedSignature unwrapped = BukkitConverters.getWrappedSignatureConverter().getSpecific(data);
|
||||
assertNotNull(unwrapped);
|
||||
assertTrue(unwrapped.isSigned());
|
||||
assertEquals(loginSignature.getSalt(), unwrapped.getSalt());
|
||||
assertArrayEquals(loginSignature.getSignature(), unwrapped.getSignature());
|
||||
assertArrayEquals(loginSignature.getSaltBytes(), unwrapped.getSaltBytes());
|
||||
|
||||
// test key data wrapping
|
||||
Object wrappedData = BukkitConverters.getWrappedSignatureConverter().getGeneric(loginSignature);
|
||||
MinecraftEncryption.b wrapped = assertInstanceOf(MinecraftEncryption.b.class, wrappedData);
|
||||
|
||||
assertTrue(wrapped.a());
|
||||
assertEquals(loginSignature.getSalt(), wrapped.c());
|
||||
assertArrayEquals(loginSignature.getSignature(), wrapped.d());
|
||||
assertArrayEquals(loginSignature.getSaltBytes(), wrapped.b());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSignedMessageWithoutSignature() {
|
||||
long salt = ThreadLocalRandom.current().nextLong();
|
||||
byte[] signature = {};
|
||||
|
||||
// test key data conversion
|
||||
WrappedSaltedSignature loginSignature = new WrappedSaltedSignature(salt, signature);
|
||||
|
||||
Object handle = loginSignature.getHandle();
|
||||
MinecraftEncryption.b data = assertInstanceOf(MinecraftEncryption.b.class, handle);
|
||||
|
||||
assertFalse(data.a());
|
||||
assertArrayEquals(signature, data.d());
|
||||
assertEquals(salt, data.c());
|
||||
|
||||
// test key data unwrapping
|
||||
WrappedSaltedSignature unwrapped = BukkitConverters.getWrappedSignatureConverter().getSpecific(data);
|
||||
assertNotNull(unwrapped);
|
||||
assertFalse(unwrapped.isSigned());
|
||||
assertEquals(loginSignature.getSalt(), unwrapped.getSalt());
|
||||
assertArrayEquals(loginSignature.getSignature(), unwrapped.getSignature());
|
||||
assertArrayEquals(loginSignature.getSaltBytes(), unwrapped.getSaltBytes());
|
||||
|
||||
// test key data wrapping
|
||||
Object wrappedData = BukkitConverters.getWrappedSignatureConverter().getGeneric(loginSignature);
|
||||
MinecraftEncryption.b wrapped = assertInstanceOf(MinecraftEncryption.b.class, wrappedData);
|
||||
|
||||
assertFalse(wrapped.a());
|
||||
assertEquals(loginSignature.getSalt(), wrapped.c());
|
||||
assertArrayEquals(loginSignature.getSignature(), wrapped.d());
|
||||
assertArrayEquals(loginSignature.getSaltBytes(), wrapped.b());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user