wip
This commit is contained in:
parent
b4a3793d5d
commit
0f92f5bcbe
12 changed files with 378 additions and 46 deletions
36
pom.xml
36
pom.xml
|
@ -20,5 +20,41 @@
|
||||||
<artifactId>Java-WebSocket</artifactId>
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
<version>1.5.7</version>
|
<version>1.5.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.seancfoley</groupId>
|
||||||
|
<artifactId>ipaddress</artifactId>
|
||||||
|
<version>5.5.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.6.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
<minimizeJar>true</minimizeJar>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>**</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>module-info.class</exclude>
|
||||||
|
<exclude>META-INF/</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
|
@ -1,7 +1,10 @@
|
||||||
package eu.m724.autopeerer.client;
|
package eu.m724.autopeerer.client;
|
||||||
|
|
||||||
import eu.m724.autopeerer.packet.Packets;
|
import eu.m724.autopeerer.packet.Packets;
|
||||||
import eu.m724.autopeerer.packet.PingRequestPacket;
|
import eu.m724.autopeerer.packet.client.PingRequestPacket;
|
||||||
|
import eu.m724.autopeerer.packet.client.VpnRequestPacket;
|
||||||
|
import inet.ipaddr.IPAddressString;
|
||||||
|
import inet.ipaddr.ipv6.IPv6Address;
|
||||||
import org.java_websocket.client.WebSocketClient;
|
import org.java_websocket.client.WebSocketClient;
|
||||||
import org.java_websocket.handshake.ServerHandshake;
|
import org.java_websocket.handshake.ServerHandshake;
|
||||||
|
|
||||||
|
@ -32,9 +35,10 @@ public class MyWebsocketClient extends WebSocketClient {
|
||||||
System.out.printf("Connected in %.3f ms\n", connectTime);
|
System.out.printf("Connected in %.3f ms\n", connectTime);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (int i=0; i<10; i++) {
|
send(Packets.compose(new PingRequestPacket((short)1, InetAddress.getByName("1.1.1.3"))));
|
||||||
send(Packets.compose(new PingRequestPacket((short)i, InetAddress.getByName("1.1.1." + i))));
|
send(Packets.compose(new PingRequestPacket((short)2, InetAddress.getByName("1.1.1.1"))));
|
||||||
}
|
|
||||||
|
send(Packets.compose(new VpnRequestPacket((short)1, (IPv6Address) new IPAddressString("fefe::fefe").getAddress(), "sAt8JSXW4leihcAAdsghsfgFWkO5stBZJm87PGLZFXY=", "example.com", 6823)));
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package eu.m724.autopeerer.client;
|
package eu.m724.autopeerer.client;
|
||||||
|
|
||||||
import eu.m724.autopeerer.packet.Packet;
|
import eu.m724.autopeerer.client.wireguard.WireGuardSession;
|
||||||
import eu.m724.autopeerer.packet.Packets;
|
import eu.m724.autopeerer.packet.*;
|
||||||
import eu.m724.autopeerer.packet.PingRequestPacket;
|
import eu.m724.autopeerer.packet.client.PingRequestPacket;
|
||||||
import eu.m724.autopeerer.packet.PingResponsePacket;
|
import eu.m724.autopeerer.packet.client.VpnRequestPacket;
|
||||||
|
import eu.m724.autopeerer.packet.server.PingResponsePacket;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -34,41 +35,52 @@ public class PacketHandler {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p instanceof PingRequestPacket packet) {System.out.printf("Ping request #%d to %s\n", packet.requestId, packet.target.getHostAddress());
|
if (p instanceof PingRequestPacket packet) {
|
||||||
|
handlePingRequest(packet);
|
||||||
CompletableFuture.runAsync(() -> {
|
} else if (p instanceof VpnRequestPacket packet) {
|
||||||
float average = -1, meanDeviation = -1;
|
handleVpnRequest(packet);
|
||||||
var status = PingResponsePacket.PingResponseStatus.ERROR;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Process process = Runtime.getRuntime().exec(new String[] { "ping", "-3Ac", "10", packet.target.getHostAddress() });
|
|
||||||
|
|
||||||
try (BufferedReader reader = process.inputReader()) {
|
|
||||||
for (String l : reader.lines().toList()) {
|
|
||||||
boolean error = l.startsWith("From"); // indicates an error
|
|
||||||
boolean end = l.startsWith("rtt");
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
status = PingResponsePacket.PingResponseStatus.UNREACHABLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end) {
|
|
||||||
String[] results = l.split(" ")[3].split("/");
|
|
||||||
average = Float.parseFloat(results[1]);
|
|
||||||
meanDeviation = Float.parseFloat(results[3]);
|
|
||||||
status = PingResponsePacket.PingResponseStatus.OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Error pinging");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.printf("Ping request #%d to %s - %s avg %.3f / mdev %.3f ms\n", packet.requestId, packet.target.getHostAddress(), status, average, meanDeviation);
|
|
||||||
sender.accept(new PingResponsePacket(packet.requestId, status, average, meanDeviation).serialize());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handlePingRequest(PingRequestPacket packet) {
|
||||||
|
System.out.printf("Ping request #%d to %s\n", packet.requestId, packet.target.getHostAddress());
|
||||||
|
CompletableFuture.runAsync(() -> {
|
||||||
|
float average = -1, meanDeviation = -1;
|
||||||
|
var status = PingResponsePacket.PingResponseStatus.ERROR;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Process process = Runtime.getRuntime().exec(new String[] { "ping", "-3Ac", "10", packet.target.getHostAddress() });
|
||||||
|
|
||||||
|
try (BufferedReader reader = process.inputReader()) {
|
||||||
|
for (String l : reader.lines().toList()) {
|
||||||
|
boolean error = l.startsWith("From"); // indicates an error
|
||||||
|
boolean end = l.startsWith("rtt");
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
status = PingResponsePacket.PingResponseStatus.UNREACHABLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end) {
|
||||||
|
String[] results = l.split(" ")[3].split("/");
|
||||||
|
average = Float.parseFloat(results[1]);
|
||||||
|
meanDeviation = Float.parseFloat(results[3]);
|
||||||
|
status = PingResponsePacket.PingResponseStatus.OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error pinging");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf("Ping request #%d to %s - %s avg %.3f / mdev %.3f ms\n", packet.requestId, packet.target.getHostAddress(), status, average, meanDeviation);
|
||||||
|
sender.accept(new PingResponsePacket(packet.requestId, status, average, meanDeviation).serialize());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleVpnRequest(VpnRequestPacket packet) {
|
||||||
|
var session = new WireGuardSession(12345, "serverpoecjteta", "fefe:fefe::fefe", packet.linkLocal.toCompressedString(), packet.endpointHost + ":" + packet.endpointPort, packet.publicKey);
|
||||||
|
System.err.println(session.config());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package eu.m724.autopeerer.client.wireguard;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class WireGuardKeys {
|
||||||
|
public static String generatePrivateKey() {
|
||||||
|
try {
|
||||||
|
Process process = Runtime.getRuntime().exec("wg genkey");
|
||||||
|
process.waitFor();
|
||||||
|
return process.inputReader().readLine();
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive a WireGuard public key from a private key
|
||||||
|
* @param privateKey base64 encoded private key
|
||||||
|
* @return base64 encoded public key or null if invalid private key
|
||||||
|
*/
|
||||||
|
public static String derivePublicKey(String privateKey) {
|
||||||
|
try {
|
||||||
|
Process process = Runtime.getRuntime().exec("wg genkey");
|
||||||
|
process.outputWriter().write(privateKey);
|
||||||
|
|
||||||
|
int code = process.waitFor();
|
||||||
|
if (code != 0) return null;
|
||||||
|
|
||||||
|
return process.inputReader().readLine();
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package eu.m724.autopeerer.client.wireguard;
|
||||||
|
|
||||||
|
public record WireGuardSession(
|
||||||
|
int listenPort,
|
||||||
|
String serverPrivateKey,
|
||||||
|
String localLinkLocal,
|
||||||
|
String clientLinkLocal,
|
||||||
|
String endpoint,
|
||||||
|
String clientPublicKey
|
||||||
|
) {
|
||||||
|
public String config() {
|
||||||
|
return """
|
||||||
|
[Interface]
|
||||||
|
ListenPort = %d
|
||||||
|
PrivateKey = %s
|
||||||
|
PostUp = /sbin/ip addr add dev %%i %s peer %s
|
||||||
|
Table = off
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
Endpoint = %s
|
||||||
|
PublicKey = %s
|
||||||
|
AllowedIPs = ::/0"""
|
||||||
|
.formatted(listenPort, serverPrivateKey, localLinkLocal, clientLinkLocal, endpoint, clientPublicKey);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,10 @@
|
||||||
package eu.m724.autopeerer.packet;
|
package eu.m724.autopeerer.packet;
|
||||||
|
|
||||||
|
import eu.m724.autopeerer.packet.client.PingRequestPacket;
|
||||||
|
import eu.m724.autopeerer.packet.client.VpnRequestPacket;
|
||||||
|
import eu.m724.autopeerer.packet.server.PingResponsePacket;
|
||||||
|
import eu.m724.autopeerer.packet.server.VpnResponsePacket;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class Packets {
|
public class Packets {
|
||||||
|
@ -10,6 +15,8 @@ public class Packets {
|
||||||
|
|
||||||
if (id == 1) {
|
if (id == 1) {
|
||||||
packet = PingRequestPacket.deserialize(buffer);
|
packet = PingRequestPacket.deserialize(buffer);
|
||||||
|
} else if (id == 2) {
|
||||||
|
packet = VpnRequestPacket.deserialize(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
|
@ -21,7 +28,9 @@ public class Packets {
|
||||||
Packet<?> packet = null;
|
Packet<?> packet = null;
|
||||||
|
|
||||||
if (id == 1) {
|
if (id == 1) {
|
||||||
PingResponsePacket.deserialize(buffer);
|
packet = PingResponsePacket.deserialize(buffer);
|
||||||
|
} else if (id == 2) {
|
||||||
|
packet = VpnResponsePacket.deserialize(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package eu.m724.autopeerer.packet.client;
|
||||||
|
|
||||||
|
import eu.m724.autopeerer.packet.Packet;
|
||||||
|
import inet.ipaddr.ipv6.IPv6Address;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class BgpRequestPacket implements Packet<BgpRequestPacket> {
|
||||||
|
public final short id;
|
||||||
|
public final long asn;
|
||||||
|
public final IPv6Address linkLocal;
|
||||||
|
|
||||||
|
public BgpRequestPacket(short id, long asn, IPv6Address linkLocal) {
|
||||||
|
this.id = id;
|
||||||
|
this.asn = asn;
|
||||||
|
this.linkLocal = linkLocal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getId() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer serialize() {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(22);
|
||||||
|
buffer.putShort(id);
|
||||||
|
buffer.putInt((int) (asn & 0xFFFFFFFFL));
|
||||||
|
buffer.put(linkLocal.getBytes());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BgpRequestPacket deserialize(ByteBuffer buffer) {
|
||||||
|
var id = buffer.getShort();
|
||||||
|
var asn = Integer.toUnsignedLong(buffer.getInt());
|
||||||
|
|
||||||
|
var ip = new byte[16];
|
||||||
|
buffer.get(ip);
|
||||||
|
var linkLocal = new IPv6Address(ip);
|
||||||
|
|
||||||
|
return new BgpRequestPacket(id, asn, linkLocal);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
package eu.m724.autopeerer.packet;
|
package eu.m724.autopeerer.packet.client;
|
||||||
|
|
||||||
|
import eu.m724.autopeerer.packet.Packet;
|
||||||
|
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
|
@ -0,0 +1,80 @@
|
||||||
|
package eu.m724.autopeerer.packet.client;
|
||||||
|
|
||||||
|
import eu.m724.autopeerer.packet.Packet;
|
||||||
|
import inet.ipaddr.HostName;
|
||||||
|
import inet.ipaddr.HostNameException;
|
||||||
|
import inet.ipaddr.IPAddressString;
|
||||||
|
import inet.ipaddr.ipv6.IPv6Address;
|
||||||
|
|
||||||
|
import java.net.IDN;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class VpnRequestPacket implements Packet<VpnRequestPacket> {
|
||||||
|
public final short connectionId;
|
||||||
|
public final IPv6Address linkLocal;
|
||||||
|
public final String publicKey;
|
||||||
|
public final String endpointHost;
|
||||||
|
public final int endpointPort;
|
||||||
|
|
||||||
|
public VpnRequestPacket(short connectionId, IPv6Address linkLocal, String publicKey, String endpointHost, int endpointPort) {
|
||||||
|
this.connectionId = connectionId;
|
||||||
|
|
||||||
|
this.linkLocal = linkLocal;
|
||||||
|
assert new IPAddressString("fe80::/10").getAddress().contains(linkLocal);
|
||||||
|
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
assert Base64.getDecoder().decode(publicKey).length == 32;
|
||||||
|
|
||||||
|
this.endpointHost = IDN.toASCII(endpointHost, IDN.ALLOW_UNASSIGNED);
|
||||||
|
try {
|
||||||
|
new HostName(endpointHost).validate();
|
||||||
|
} catch (HostNameException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.endpointPort = endpointPort;
|
||||||
|
assert endpointPort > 0 && endpointPort < 65536;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getId() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VpnRequestPacket deserialize(ByteBuffer buffer) throws Exception {
|
||||||
|
var id = buffer.getShort();
|
||||||
|
|
||||||
|
var ll = new byte[16];
|
||||||
|
buffer.get(ll);
|
||||||
|
var linkLocal = new IPv6Address(ll);
|
||||||
|
|
||||||
|
var pk = new byte[32];
|
||||||
|
buffer.get(pk);
|
||||||
|
var publicKey = Base64.getEncoder().encodeToString(pk);
|
||||||
|
|
||||||
|
var endpointPort = buffer.getShort();
|
||||||
|
|
||||||
|
var epl = buffer.get() & 0xFF;
|
||||||
|
var ep = new byte[epl];
|
||||||
|
buffer.get(ep);
|
||||||
|
var endpointHost = new String(ep, StandardCharsets.US_ASCII);
|
||||||
|
|
||||||
|
return new VpnRequestPacket(id, linkLocal, publicKey, endpointHost, endpointPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer serialize() {
|
||||||
|
var buffer = ByteBuffer.allocate(53 + endpointHost.length());
|
||||||
|
|
||||||
|
buffer.putShort(connectionId); // 2b
|
||||||
|
buffer.put(linkLocal.getBytes()); // 16b
|
||||||
|
buffer.put(Base64.getDecoder().decode(publicKey)); // 32b
|
||||||
|
buffer.putShort((short)endpointPort); // 2b
|
||||||
|
buffer.put((byte) endpointHost.length()); // 1b
|
||||||
|
buffer.put(endpointHost.getBytes(StandardCharsets.US_ASCII));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package eu.m724.autopeerer.packet.server;
|
||||||
|
|
||||||
|
import eu.m724.autopeerer.packet.Packet;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class BgpResponsePacket implements Packet<BgpResponsePacket> {
|
||||||
|
public final short id;
|
||||||
|
public final boolean success;
|
||||||
|
|
||||||
|
public BgpResponsePacket(short id, boolean success) {
|
||||||
|
this.id = id;
|
||||||
|
this.success = success;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getId() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer serialize() {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(3);
|
||||||
|
|
||||||
|
buffer.putShort(id);
|
||||||
|
buffer.put((byte) (success ? 1 : 0));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BgpResponsePacket deserialize(ByteBuffer buffer) {
|
||||||
|
var id = buffer.getShort();
|
||||||
|
var success = buffer.get() == 1;
|
||||||
|
|
||||||
|
return new BgpResponsePacket(id, success);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
package eu.m724.autopeerer.packet;
|
package eu.m724.autopeerer.packet.server;
|
||||||
|
|
||||||
|
import eu.m724.autopeerer.packet.Packet;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package eu.m724.autopeerer.packet.server;
|
||||||
|
|
||||||
|
import eu.m724.autopeerer.packet.Packet;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class VpnResponsePacket implements Packet<VpnResponsePacket> {
|
||||||
|
public final short connectionId;
|
||||||
|
public final boolean success;
|
||||||
|
public final int port;
|
||||||
|
public final String publicKey;
|
||||||
|
|
||||||
|
public VpnResponsePacket(short connectionId, boolean success, int port, String publicKey) {
|
||||||
|
this.connectionId = connectionId;
|
||||||
|
this.success = success;
|
||||||
|
this.port = port;
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getId() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VpnResponsePacket deserialize(ByteBuffer buffer) throws Exception {
|
||||||
|
var id = buffer.getShort();
|
||||||
|
var port = buffer.getShort() & 0xFFFF;
|
||||||
|
var success = port != 0;
|
||||||
|
|
||||||
|
var pkb = new byte[32];
|
||||||
|
buffer.get(pkb);
|
||||||
|
var publicKey = Base64.getEncoder().encodeToString(pkb);
|
||||||
|
|
||||||
|
return new VpnResponsePacket(id, success, port, publicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer serialize() {
|
||||||
|
var buffer = ByteBuffer.allocate(35);
|
||||||
|
|
||||||
|
buffer.putShort(connectionId); // 2b
|
||||||
|
buffer.put((byte) (success ? 1 : 0));
|
||||||
|
buffer.put(Base64.getDecoder().decode(publicKey));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue