diff --git a/src/main/java/net/nosial/socialclient/Client.java b/src/main/java/net/nosial/socialclient/Client.java index d4a10e3..f9647a8 100644 --- a/src/main/java/net/nosial/socialclient/Client.java +++ b/src/main/java/net/nosial/socialclient/Client.java @@ -1,4 +1,79 @@ package net.nosial.socialclient; -public class Client { +import net.nosial.socialclient.abstracts.RpcResult; +import net.nosial.socialclient.classes.Cryptography; +import net.nosial.socialclient.classes.RpcClient; +import net.nosial.socialclient.classes.Utilities; +import net.nosial.socialclient.exceptions.CryptographyException; +import net.nosial.socialclient.exceptions.ResolutionException; +import net.nosial.socialclient.exceptions.RpcException; +import net.nosial.socialclient.objects.RpcRequest; + +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.HashMap; +import java.util.Map; + +public class Client extends RpcClient +{ + protected Client(String domain) throws ResolutionException, CryptographyException + { + super(domain); + } + + public Client(String endpoint, PublicKey serverPublicKey) + { + super(endpoint, serverPublicKey); + } + + public String createSession(KeyPair keyPair) throws RpcException + { + RpcResult response = this.sendRequest(new RpcRequest("create_session", Utilities.randomCrc32(), new HashMap<>(){{ + put("public_key", Cryptography.exportPublicKey(keyPair)); + }})); + + if(response == null) + { + throw new RpcException("Response is null"); + } + + if(!response.isSuccess()) + { + throw new RpcException(response); + } + + return (String) response.getResponse().getResult(); + } + + public void setSession(String sessionUuid, PrivateKey privateKey) + { + this.sessionUuid = sessionUuid; + this.privateKey = privateKey; + } + + public String createAndSetSession(KeyPair keyPair) throws RpcException + { + String sessionUuid = this.createSession(keyPair); + this.setSession(sessionUuid, keyPair.getPrivate()); + + return sessionUuid; + } + + public boolean ping() throws RpcException + { + RpcResult response = this.sendRequest(new RpcRequest("ping", Utilities.randomCrc32())); + + if(response == null) + { + throw new RpcException("Response is null"); + } + + if(!response.isSuccess()) + { + throw new RpcException(response); + } + + return true; + } } diff --git a/src/main/java/net/nosial/socialclient/classes/Cryptography.java b/src/main/java/net/nosial/socialclient/classes/Cryptography.java index 7f874a3..35e78cc 100644 --- a/src/main/java/net/nosial/socialclient/classes/Cryptography.java +++ b/src/main/java/net/nosial/socialclient/classes/Cryptography.java @@ -7,6 +7,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; @@ -79,15 +80,15 @@ public final class Cryptography */ public static String signContent(String content, PrivateKey privateKey) throws CryptographyException { - // Convert content to sha1 hash try { - final Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); - + Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(privateKey); - signature.update(MessageDigest.getInstance("SHA-1").digest(content.getBytes())); + signature.update(sha1(content).getBytes(StandardCharsets.UTF_8)); + byte[] signatureBytes = signature.sign(); - return Base64.getEncoder().encodeToString(signature.sign()); + // Base64 encode the signature + return Base64.getEncoder().encodeToString(signatureBytes); } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { @@ -95,6 +96,22 @@ public final class Cryptography } } + private static String bytesToHex(byte[] hash) + { + StringBuilder hexString = new StringBuilder(2 * hash.length); + for (byte b : hash) + { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) + { + hexString.append('0'); + } + hexString.append(hex); + } + + return hexString.toString(); + } + /** * Verifies the content using the provided signature and public key. * @@ -123,9 +140,8 @@ public final class Cryptography try { final Signature sign = Signature.getInstance(SIGNATURE_ALGORITHM); - sign.initVerify(publicKey); - sign.update(MessageDigest.getInstance("SHA-1").digest(content.getBytes())); + sign.update(sha1(content).getBytes(StandardCharsets.UTF_8)); return sign.verify(Base64.getDecoder().decode(signature)); } @@ -372,7 +388,7 @@ public final class Cryptography X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); return getKeyFactory().generatePublic(spec); } - catch (InvalidKeySpecException | NoSuchAlgorithmException e) + catch (InvalidKeySpecException | NoSuchAlgorithmException | IllegalArgumentException e) { throw new CryptographyException("Failed to import public key", e); } @@ -399,4 +415,11 @@ public final class Cryptography } } + public static String sha1(String data) throws NoSuchAlgorithmException + { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8)); + return bytesToHex(hash); + } + } diff --git a/src/main/java/net/nosial/socialclient/classes/Resolver.java b/src/main/java/net/nosial/socialclient/classes/Resolver.java index 601e9fa..2381daa 100644 --- a/src/main/java/net/nosial/socialclient/classes/Resolver.java +++ b/src/main/java/net/nosial/socialclient/classes/Resolver.java @@ -6,89 +6,54 @@ import net.nosial.socialclient.objects.ResolvedServer; import javax.naming.NamingException; import javax.naming.directory.*; import java.util.Hashtable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -// Improved Resolver class -public class Resolver -{ - /** - * Resolves the domain to obtain endpoint and public key from its DNS TXT records. - * - * @param domain The domain to be resolved. - * @return ResolvedServer An instance of ResolvedServer containing the endpoint and public key. - * @throws ResolutionException If the DNS TXT records cannot be resolved or if required information is missing. - */ - public static ResolvedServer resolveDomain(String domain) throws ResolutionException - { - final String endpointPrefix = "socialbox="; - final String keyPrefix = "socialbox-key="; +public class Resolver { + public static ResolvedServer resolveDomain(String domain) throws ResolutionException { + final Pattern fullPattern = Pattern.compile("v=socialbox;sb-rpc=(https?://[^;]+);sb-key=([^;]+)"); - // Disable caching Hashtable env = new Hashtable<>(); env.put("com.sun.jndi.dns.timeout.retries", "1"); - env.put("com.sun.jndi.dns.cache.ttl", "0"); + env.put("com.sun.jndi.dns.cache.ttl", "1"); env.put("com.sun.jndi.dns.cache.negative.ttl", "0"); - try - { + try { DirContext dirContext = new InitialDirContext(env); Attributes attributes = dirContext.getAttributes("dns:/" + domain, new String[]{"TXT"}); Attribute attributeTXT = attributes.get("TXT"); - if (attributeTXT == null) - { + if (attributeTXT == null) { throw new ResolutionException("Failed to resolve DNS TXT records for " + domain); } - String endpoint = null; - StringBuilder publicKeyBuilder = new StringBuilder(); - boolean publicKeyFound = false; + StringBuilder fullRecordBuilder = new StringBuilder(); - for (int i = 0; i < attributeTXT.size(); i++) - { + for (int i = 0; i < attributeTXT.size(); i++) { String value = (String) attributeTXT.get(i); + fullRecordBuilder.append(value.replaceAll("^\"|\"$", "").trim()); + } - // Remove surrounding quotes if present - if (value.startsWith("\"") && value.endsWith("\"")) - { - value = value.substring(1, value.length() - 1); + String fullRecord = fullRecordBuilder.toString(); + Matcher matcher = fullPattern.matcher(fullRecord); + + if (matcher.find()) { + String endpoint = matcher.group(1); + String publicKey = matcher.group(2).replaceAll("\\s+", ""); + + if (endpoint == null || endpoint.isEmpty()) { + throw new ResolutionException("Failed to resolve RPC endpoint for " + domain); } - // Split the value into fragments to find the relevant keys - String[] fragments = value.split("\\s+"); - for (String fragment : fragments) - { - if (fragment.startsWith(endpointPrefix)) - { - endpoint = fragment.substring(endpointPrefix.length()); - } - else if (fragment.startsWith(keyPrefix)) - { - publicKeyBuilder.append(fragment.substring(keyPrefix.length())); - publicKeyFound = true; - } - else if (publicKeyFound) - { - // If the public key has already started, append the fragment - publicKeyBuilder.append(fragment); - } + if (publicKey == null || publicKey.isEmpty()) { + throw new ResolutionException("Failed to resolve public key for " + domain); } - } - if (endpoint == null) - { - throw new ResolutionException("Failed to resolve RPC endpoint for " + domain); + return new ResolvedServer(endpoint, publicKey); + } else { + throw new ResolutionException("Failed to find valid SocialBox record for " + domain); } - - if (publicKeyBuilder.isEmpty()) - { - throw new ResolutionException("Failed to resolve public key for " + domain); - } - - String publicKey = publicKeyBuilder.toString(); - return new ResolvedServer(endpoint, publicKey); - } - catch (NamingException e) - { + } catch (NamingException e) { throw new ResolutionException("Error resolving domain: " + e.getMessage(), e); } } diff --git a/src/main/java/net/nosial/socialclient/classes/RpcClient.java b/src/main/java/net/nosial/socialclient/classes/RpcClient.java index 77b1596..05870b3 100644 --- a/src/main/java/net/nosial/socialclient/classes/RpcClient.java +++ b/src/main/java/net/nosial/socialclient/classes/RpcClient.java @@ -12,6 +12,7 @@ import net.nosial.socialclient.objects.ResolvedServer; import net.nosial.socialclient.objects.RpcRequest; import java.io.IOException; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.util.ArrayList; @@ -30,8 +31,8 @@ public class RpcClient private final PublicKey serverPublicKey; private final OkHttpClient httpClient; - private String sessionUuid; - private PrivateKey privateKey; + protected String sessionUuid; + protected PrivateKey privateKey; /** * Initializes a new instance of the RpcClient class using the specified domain. @@ -118,7 +119,7 @@ public class RpcClient * @param privateKey the private key to be imported * @throws CryptographyException if an error occurs while importing the private key */ - public void setSession(String sessionUuid, String privateKey) throws CryptographyException + protected void setSession(String sessionUuid, String privateKey) throws CryptographyException { this.sessionUuid = sessionUuid; this.privateKey = Cryptography.importPrivateKey(privateKey); @@ -130,7 +131,7 @@ public class RpcClient * @param sessionUuid the UUID of the session * @param privateKey the private key associated with the session */ - public void setSession(String sessionUuid, PrivateKey privateKey) + protected void setSession(String sessionUuid, PrivateKey privateKey) { this.sessionUuid = sessionUuid; this.privateKey = privateKey; @@ -165,6 +166,7 @@ public class RpcClient if(sessionUuid != null) { + // We are seeing the session UUID correctly. this.addHeader("Session-UUID", sessionUuid); } @@ -172,9 +174,12 @@ public class RpcClient { try { + // NOTE: Signature looks okay, it's base64 encoded. + System.out.println("Hash: " + Cryptography.sha1(jsonData)); + System.out.println("Signature: " + Cryptography.signContent(jsonData, privateKey)); this.addHeader("Signature", Cryptography.signContent(jsonData, privateKey)); } - catch(CryptographyException e) + catch(CryptographyException | NoSuchAlgorithmException e) { throw new RuntimeException(e); } @@ -193,7 +198,7 @@ public class RpcClient throw new RuntimeException(responseString); } - throw new RuntimeException("Failed to send request"); + throw new RuntimeException("Failed to send request: " + response.code()); } if(response.code() == 204) @@ -242,7 +247,14 @@ public class RpcClient */ public RpcResult sendRequest(RpcRequest request) { - return sendRequest(encode(request.toMap())).getFirst(); + List results = sendRequest(encode(request.toMap())); + + if(results.isEmpty()) + { + return null; + } + + return results.getFirst(); } /** diff --git a/src/main/java/net/nosial/socialclient/classes/Utilities.java b/src/main/java/net/nosial/socialclient/classes/Utilities.java new file mode 100644 index 0000000..c296259 --- /dev/null +++ b/src/main/java/net/nosial/socialclient/classes/Utilities.java @@ -0,0 +1,44 @@ +package net.nosial.socialclient.classes; + +import java.util.concurrent.ThreadLocalRandom; + +public class Utilities +{ + private static final int[] CRC32_TABLE = new int[256]; + + static + { + for (int i = 0; i < 256; i++) + { + int crc = i; + for (int j = 8; j > 0; j--) + { + if ((crc & 1) == 1) + { + crc = (crc >>> 1) ^ 0xEDB88320; + } + else + { + crc = crc >>> 1; + } + } + + CRC32_TABLE[i] = crc; + } + } + + public static String randomCrc32() + { + long randomValue = ThreadLocalRandom.current().nextLong(Long.MAX_VALUE); + String valueString = Long.toString(randomValue); + int crc = 0xFFFFFFFF; + + for (char c : valueString.toCharArray()) + { + crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ c) & 0xFF]; + } + + crc = ~crc; + return Integer.toHexString(crc); + } +} diff --git a/src/main/java/net/nosial/socialclient/exceptions/RpcException.java b/src/main/java/net/nosial/socialclient/exceptions/RpcException.java index 65a9cf5..255fcb2 100644 --- a/src/main/java/net/nosial/socialclient/exceptions/RpcException.java +++ b/src/main/java/net/nosial/socialclient/exceptions/RpcException.java @@ -1,6 +1,21 @@ package net.nosial.socialclient.exceptions; +import net.nosial.socialclient.abstracts.RpcResult; + public class RpcException extends Exception { + public RpcException(String message) + { + super(message); + } + public RpcException(String message, Throwable cause) + { + super(message, cause); + } + + public RpcException(RpcResult result) + { + super(result.getErrorResponse().getError()); + } } diff --git a/src/main/java/net/nosial/socialclient/objects/ResolvedServer.java b/src/main/java/net/nosial/socialclient/objects/ResolvedServer.java index 9fd4cfa..bae8838 100644 --- a/src/main/java/net/nosial/socialclient/objects/ResolvedServer.java +++ b/src/main/java/net/nosial/socialclient/objects/ResolvedServer.java @@ -7,6 +7,11 @@ public class ResolvedServer public ResolvedServer(String endpoint, String publicKey) { + if(endpoint == null || publicKey == null) + { + throw new IllegalArgumentException("Endpoint and public key must not be null"); + } + this.endpoint = endpoint; this.publicKey = publicKey; } diff --git a/src/main/java/net/nosial/socialclient/objects/RpcRequest.java b/src/main/java/net/nosial/socialclient/objects/RpcRequest.java index 2a4cfab..3f476fe 100644 --- a/src/main/java/net/nosial/socialclient/objects/RpcRequest.java +++ b/src/main/java/net/nosial/socialclient/objects/RpcRequest.java @@ -7,7 +7,7 @@ public class RpcRequest { private final String method; private final String id; - private final Map params; + private final Map parameters; /** * Initializes a new RpcRequest object using the provided data map. @@ -23,7 +23,7 @@ public class RpcRequest { this.method = (String) data.get("method"); this.id = (String) data.get("id"); - this.params = (Map) data.get("params"); + this.parameters = (Map) data.get("params"); } /** @@ -31,13 +31,13 @@ public class RpcRequest * * @param method the RPC method to be called * @param id the unique identifier for this request - * @param params the parameters for the RPC method + * @param parameters the parameters for the RPC method */ - public RpcRequest(String method, String id, Map params) + public RpcRequest(String method, String id, Map parameters) { this.method = method; this.id = id; - this.params = params; + this.parameters = parameters; } /** @@ -45,13 +45,13 @@ public class RpcRequest * The request ID will be set to null. * * @param method the name of the method being called - * @param params the parameters to be sent with the method call + * @param parameters the parameters to be sent with the method call */ - public RpcRequest(String method, Map params) + public RpcRequest(String method, Map parameters) { this.id = null; this.method = method; - this.params = params; + this.parameters = parameters; } /** @@ -64,7 +64,7 @@ public class RpcRequest { this.method = method; this.id = id; - this.params = null; + this.parameters = null; } /** @@ -76,7 +76,7 @@ public class RpcRequest { this.id = null; this.method = method; - this.params = null; + this.parameters = null; } /** @@ -104,9 +104,9 @@ public class RpcRequest * * @return a Map containing the parameters of the RPC request. */ - public Map getParams() + public Map getParameters() { - return this.params; + return this.parameters; } /** @@ -124,9 +124,9 @@ public class RpcRequest map.put("id", this.id); } - if(this.params != null) + if(this.parameters != null) { - map.put("params", this.params); + map.put("parameters", this.parameters); } return map; diff --git a/src/test/java/net/nosial/socialclient/SessionTest.java b/src/test/java/net/nosial/socialclient/SessionTest.java new file mode 100644 index 0000000..34b0aca --- /dev/null +++ b/src/test/java/net/nosial/socialclient/SessionTest.java @@ -0,0 +1,89 @@ +package net.nosial.socialclient; + +import net.nosial.socialclient.classes.Cryptography; +import net.nosial.socialclient.exceptions.CryptographyException; +import net.nosial.socialclient.exceptions.ResolutionException; +import net.nosial.socialclient.exceptions.RpcException; +import org.junit.jupiter.api.Test; + +import java.security.KeyPair; + +import static org.junit.jupiter.api.Assertions.*; + +class SessionTest +{ + + @Test + void createSessionTest() + { + Client socialClient; + KeyPair keyPair; + String sessionUuid; + + try + { + socialClient = new Client("n64.cc"); + } + catch (ResolutionException | CryptographyException e) + { + fail(e.getMessage(), e); + return; + } + + try + { + keyPair = Cryptography.generateKeyPair(); + } + catch (CryptographyException e) + { + fail(e.getMessage(), e); + return; + } + + try + { + sessionUuid = socialClient.createSession(keyPair); + } + catch (RpcException e) + { + fail(e.getMessage(), e); + return; + } + + assertNotNull(sessionUuid); + System.out.println("Session UUID: " + sessionUuid); + } + + @Test + public void pingSignedTest() + { + final Client socialClient; + final KeyPair keyPair; + final String sessionUuid; + + try + { + socialClient = new Client("n64.cc"); + keyPair = Cryptography.generateKeyPair(); + sessionUuid = socialClient.createAndSetSession(keyPair); + + } + catch (ResolutionException | CryptographyException | RpcException e) + { + fail(e.getMessage(), e); + return; + } + + System.out.println("Session UUID: " + sessionUuid); + assertNotNull(sessionUuid); + + try + { + assertTrue(socialClient.ping()); + } + catch (RpcException e) + { + fail(e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/src/test/java/net/nosial/socialclient/classes/CryptographyTest.java b/src/test/java/net/nosial/socialclient/classes/CryptographyTest.java index 8c740f6..29ca509 100644 --- a/src/test/java/net/nosial/socialclient/classes/CryptographyTest.java +++ b/src/test/java/net/nosial/socialclient/classes/CryptographyTest.java @@ -4,8 +4,16 @@ import net.nosial.socialclient.exceptions.CryptographyException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; import java.util.Collections; +import java.util.Objects; import static org.junit.jupiter.api.Assertions.*; @@ -259,4 +267,78 @@ class CryptographyTest // Assert assertThrows(CryptographyException.class, () -> Cryptography.encrypt(content, invalidPublicKey), "Encrypt should throw CryptographyException when public key is invalid"); } + + + @Test + public void clientSignTest() { + ClassLoader classLoader = getClass().getClassLoader(); + + PrivateKey privateKey; + PublicKey publicKey; + String content; + + try + { + privateKey = Cryptography.importPrivateKey(Files.readString(new File(Objects.requireNonNull(classLoader.getResource("client_private.der")).getFile()).toPath())); + publicKey = Cryptography.importPublicKey(Files.readString(new File(Objects.requireNonNull(classLoader.getResource("client_public.der")).getFile()).toPath())); + content = Files.readString(new File(Objects.requireNonNull(classLoader.getResource("content.txt")).getFile()).toPath()); + } + catch(CryptographyException | IOException e) + { + fail(e.getMessage(), e); + return; + } + + assertNotNull(privateKey, "Private key should not be null"); + assertNotNull(publicKey, "Public key should not be null"); + assertNotNull(content, "Content should not be null"); + + // Hash the content to sha1 string + String sha1Content; + try + { + sha1Content = Cryptography.sha1(content); + } + catch (NoSuchAlgorithmException e) + { + fail(e.getMessage(), e); + return; + } + + assertNotNull(sha1Content, "SHA1 content should not be null"); + assertEquals(40, sha1Content.length(), "SHA1 content should be 40 characters length"); + assertEquals("fa2415f0735a8aa151195688852178e8fd6e77c5", sha1Content, "SHA1 content should be equal to expected value"); + System.out.println("SHA1 content: " + sha1Content); + + // Signature testing + String signature; + + try + { + signature = Cryptography.signContent(content, privateKey); + } + catch (CryptographyException e) + { + fail(e.getMessage(), e); + return; + } + + assertNotNull(signature, "Signature should not be null"); + assertEquals("Gcnijq7V8AYXgdk/eP9IswXN7831FevlBNDTKN60Ku7xesPDuPX8e55+38WFGCQ87DbeiIr+61XIDoN4+bTM4Wl0YSUe7oHV9BBnBqGhyZTntDPedUYUomrF3IRcpVRK0SbQSRaYucIp/ZsSHdbQgQBtDCvH5pK1+5g+VK9ZFT16Isvk0PhMjZiLkUYxUklFuzak7agWiS3wllFPqYSM6ri0RF+5I5JbnR9fUAOfhOceax//5H7d2WsdLj6DwtuY+eL5WyHxSmGA04YeQF3JgOGJ3WX2DSH8L0zA7pkGOjz5y1Nu6+0U6KRUXcezU/iM4zy5OJOnD5eJH4pYZizkiA==", signature, "Signature should be equal to expected value"); + System.out.println("Signature: " + signature); + + // Verify the signature + boolean verified; + try + { + verified = Cryptography.verifyContent(content, signature, publicKey); + } + catch (CryptographyException e) + { + fail(e.getMessage(), e); + return; + } + + assertTrue(verified, "Signature should be verified successfully"); + } } diff --git a/src/test/java/net/nosial/socialclient/classes/UtilitiesTest.java b/src/test/java/net/nosial/socialclient/classes/UtilitiesTest.java new file mode 100644 index 0000000..8aace5d --- /dev/null +++ b/src/test/java/net/nosial/socialclient/classes/UtilitiesTest.java @@ -0,0 +1,37 @@ +package net.nosial.socialclient.classes; + +import net.nosial.socialclient.classes.Utilities; +import org.junit.jupiter.api.Test; + +import java.util.regex.Pattern; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +public class UtilitiesTest { + + @Test + public void testRandomCrc32_formatValidity() { + String crcOutput = Utilities.randomCrc32(); + assertNotNull(crcOutput); + assertTrue(crcOutput.matches("[a-f0-9]+"), "Expected hexadecimal output"); + } + + @Test + public void testRandomCrc32_lengthValidity() { + String crcOutput = Utilities.randomCrc32(); + assertEquals(8, crcOutput.length(), "Expected 8 characters length"); + } + + @Test + public void testRandomCrc32_randomness() { + Set randomResults = new HashSet<>(); + + for (int i = 0; i < 10_000; i++) { + randomResults.add(Utilities.randomCrc32()); + } + + assertTrue(randomResults.size() > 1, "Expected more than one different results"); + } +} \ No newline at end of file diff --git a/src/test/resources/client_private.der b/src/test/resources/client_private.der new file mode 100644 index 0000000..249edf1 --- /dev/null +++ b/src/test/resources/client_private.der @@ -0,0 +1 @@ +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDZb4K+28kKYe1CvHPWHJALJFS396HOFmBv+anpAVWMDGBUyAWbWEqxmTAV17cBHiICjDDCNFBpOZLWzIiUpdWKA0Jo+Vu9zgWSPUyGe/Lik4GFNZ38gfolfdKGnLNFnn4nFR/fsZQ7hg4wWDarJmhJ+ZSLShOz2uIb4LaKk2qy12c6Zepufgrbk9TwWZQiXkzqBWbrZDpw0pp50CzoIwEnYJ+a7vhb98jpeS+Jjnp5zWlFjv9RgzOQUOwwOK4We2gNAVeFC5BP9trklpTh1bJlit4CECH68fCGjgoTOU92UbgucgyA4O5FVPGQYPAMuiZMGFaqXE2E7z1XwYIMAL4VAgMBAAECggEAAKiJz3CYuO+gGnL+F7qjaSXCUE8VvPfoCwuNYHNEFXo9DJBmnL7EU2WrYG+wARCP7O7qd0dEidx9u36ytjyCcKT4nYni8lM1zU7rVvbnLbsuRZS/4RO/RaYfPxig94fDfSeJ2ma0i7G56onj+MBbyTZarZ7Bf8hpcmKg9pkNEcEVcklNIwwbXKBOGq75Vka/+W56JZKJD3G9YmfrAO5RGF1prh93MRXlxlN/91k/m2pqkN9xYofepn0ePmI8Ci18jrMpJbmeu8BkypzgvC/5EfHipn7y/yJ215o/EtB575muz2zngRXe+GVO5lB5d5PuEwmXoaV5o3BqkIcb3aiz4QKBgQD7P1AE2/3oATNUF1FwlXzvdCS7M2BB28jQWjzJvHus1d1+qA2StWPgCPG2D/YTtHPI3xefBnAmeSIFCFEub0YLONbRvtQAZdTt5SAaZuUyMprqD1sCUHCizyVO0wHxo3DS0sIFmo/Lpc+jnYHn3KcuRPRJk3ncZNCQhy9a/rrnxQKBgQDdjHY82YdkWQWj/xM1EuVtkVVeCJWJ6tSDn+Uq8d+hXILFAQ47GOUbzj4Ty4qGgsAgsaAGqja5t6CE+fYs8Q34FsxTsYgIRm0VXqtPm4aYTQ4PwKbmMPEOgEsXBywe5Y+QB0u/WuNyhgwgYP5cy1IS3HA1HmbTisi0zLEfkVWSEQKBgCuP36zoA88NHjwvStSNZrsR1SiMEN16YQgXDUEhKARglGXYd3n/b1Cx3E7n14+1Evo6DBtrf1h8WjSrK4A0lN1vPnfhcVqcTV3uAzHwsz6P3aJFhU8SaWUhK2POXCDsaKx1FGTqVpJFrom8zoBIFsiD9iMnqdJXvH3CoqhRUFDNAoGAEJdwU2ZHCXDRR1LW8WaU3/u+VOh3qnh3qdPTqb+ra74t3OsTUcGvhsGPTJQ1r5UjJk+nGFiu+IGT9+FwWjVDQo0SiEIHWfdMPAl28uNG1SkQIIXg+eQ4aUmaVgMnfrjaY4LoXVBFMFJxngslgXWIk/kGPjQkpzsBhOi/awnLSsECgYEAkSEb3CXfq1r/8qXMTzI+A9CGPr++aC2H6ytFNGJq4J+P40u1tcsfkwNGcQ0Hp+Qz3FHBYFuMxtjXDq0QSvVKEhdV9bjlZhTqN3lqWcCukU3ESqRbxsIj9izuncpxSP7G19WEU0anGD9ev+QWYdHPTBY9nn1+H0tkJjqh4XkRBuY= \ No newline at end of file diff --git a/src/test/resources/client_public.der b/src/test/resources/client_public.der new file mode 100644 index 0000000..58b132e --- /dev/null +++ b/src/test/resources/client_public.der @@ -0,0 +1 @@ +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2W+CvtvJCmHtQrxz1hyQCyRUt/ehzhZgb/mp6QFVjAxgVMgFm1hKsZkwFde3AR4iAowwwjRQaTmS1syIlKXVigNCaPlbvc4Fkj1Mhnvy4pOBhTWd/IH6JX3ShpyzRZ5+JxUf37GUO4YOMFg2qyZoSfmUi0oTs9riG+C2ipNqstdnOmXqbn4K25PU8FmUIl5M6gVm62Q6cNKaedAs6CMBJ2Cfmu74W/fI6XkviY56ec1pRY7/UYMzkFDsMDiuFntoDQFXhQuQT/ba5JaU4dWyZYreAhAh+vHwho4KEzlPdlG4LnIMgODuRVTxkGDwDLomTBhWqlxNhO89V8GCDAC+FQIDAQAB \ No newline at end of file diff --git a/src/test/resources/content.txt b/src/test/resources/content.txt new file mode 100644 index 0000000..f2afb1a --- /dev/null +++ b/src/test/resources/content.txt @@ -0,0 +1,4 @@ +{ + "method" : "ping", + "id" : "daa31852" +} \ No newline at end of file diff --git a/src/test/resources/server_private.der b/src/test/resources/server_private.der new file mode 100644 index 0000000..62d8d46 --- /dev/null +++ b/src/test/resources/server_private.der @@ -0,0 +1 @@ +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDxcYLVvKYHpxJQe49Z7boilJfmp/uYAr4rQNN2El9nPG3hVRYIsmhzIeByU7ZJLn0EG5D2G6T4SlydfbHbHK3NMciTgmyAZRJl10z/KIlPG1n6DaK5Oo6VT9ty+uI7JKFdQQwzSrPP2u4KNERqK4vtfsxdiAcMXS/hUncID4ARvmigmcTOTcosdH57axSqf1xfJJ12zl3QPb6wppsBAJrZ811Ll8eZYhFoQwe0oE3T5Q0aqK0Ecgh4cYhF63nEAKkcPOMxkhcZWpr3YzqD7Rj9VAzk7xRM/QJ1SjsVwdB+YCQK1tbTloTY3BqtEib9ErZvjlaB26GZbV32kNsPnwHXAgMBAAECggEAJBVtUskzXRBsjcexmGSNfW6MtyWi1ciPKEKzd8FuLa0b1OHU/a7AKnjFJQD6zLwcZflCtG1UPeFLLyRiaNdD6FdI3TbQRW4Vjk/bi4TA5Kg3TcYs7BbiyVDagLgbCHDEhv3aN24yKl3TVoYSNXXVn0RkgZP7Ta89oSSkcnlyj/QFOA8RfIm5q+qiAPvOqFf8NKlm0hZDrxWHG/OduYHq25S9ohNzymyM+1CYTrVFZCTfscDvLBDd2MVpNRyxoQquiMlfIEUBGlu9uFWy9Hovv8Sd3irgvcBtjL8iPaMzJe3p6T83KL2AgXHcYT7r9Vlvqib5x1iTYvlid25zzQ19IQKBgQD1BISfPugEp+fAdoGHOygG+gzNE8/1ldhnA9bTCZZ3FQBTI2lPRZBFDKuirc6glbCHiWrd8HoJ3BO3kbGzq4EDBf0VDFby/7nkrroTW+RIn+THlfciWgjSATGgCPOHmvM6JmIpuYsbKkdmV4ITVWwvLPxDAwlMnHyJOuYTj8xJ4QKBgQD8Q/rdWoRBSVCrDb0QO/Or5FAJELmYFtFWBBCEpadr9ci0e/mSbbZlXjP98m4XesIIRpcpG3gU8P3hKB7H60ynPN6Jyw33YhIlJHaEjYISN/h5Vw0ybQkyFR9CBRjOp59CBcb8AsdA/OQjxFz8h46PbPLCWCR5kM3tKbuNobBytwKBgQC4Rr+gLWW/KrEolXhxxtIh/SpniwEbSanKQJ7vdgSOZ2MpJDbuAfmxlQf5gBMpv6tXJMkVRuniRH0n0RH/eXu8VGK10+QJOsAK+EbGjJQy8t7UJTwLv/9mQrOaE2FlmepYz8mAbCXtNm0g0avo8pQ9Hu5TUBNMZV1csMmd6MbSwQKBgQDit+X6kqNSWaXaVdqZgIga8HLN8u4aNkelWrnNvWOer6LWMqW2aEwJBoULsponF/jSnz6zfzCJAZ3qgbhITLzzgM0wYgIHV2ifYQnzT4qa/RqfUxFVRJGDJWCWYSZOdG+5Up/nVkflrGMNkilP/DSvymbTK4x8hRvODje1rp96OQKBgFmXLpHPN8WAXP7VVyb3RqYYRgtxXjY2yj/CYwnXl0k4Uji08S9Ke2AqljiSzmZs1Wh1UBLap90F0smRVHmYgwl2rPjNiXbyKd4W9R4vEVYgEmcnvzba107o76qFmEbyW/K7a7K/jKaH8KAytgR/cHd+SIBctcDv8uKmZ1MJT9p8 \ No newline at end of file diff --git a/src/test/resources/server_public.der b/src/test/resources/server_public.der new file mode 100644 index 0000000..4bc983c --- /dev/null +++ b/src/test/resources/server_public.der @@ -0,0 +1 @@ +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8XGC1bymB6cSUHuPWe26IpSX5qf7mAK+K0DTdhJfZzxt4VUWCLJocyHgclO2SS59BBuQ9huk+EpcnX2x2xytzTHIk4JsgGUSZddM/yiJTxtZ+g2iuTqOlU/bcvriOyShXUEMM0qzz9ruCjREaiuL7X7MXYgHDF0v4VJ3CA+AEb5ooJnEzk3KLHR+e2sUqn9cXySdds5d0D2+sKabAQCa2fNdS5fHmWIRaEMHtKBN0+UNGqitBHIIeHGIRet5xACpHDzjMZIXGVqa92M6g+0Y/VQM5O8UTP0CdUo7FcHQfmAkCtbW05aE2NwarRIm/RK2b45WgduhmW1d9pDbD58B1wIDAQAB \ No newline at end of file