From 46483b2bf81d7c1acc43bac99e3fe1f91ae2c59c Mon Sep 17 00:00:00 2001 From: sg495 Date: Mon, 8 Jan 2018 20:40:50 +0100 Subject: [PATCH 1/2] Added a RandomString class from stackoverflow, to generate random alphanumeric strings (to be used as passwords). Added some code to VaultDoor, including random password generation and code to encrypt/decrypt under a Vernam-like cypher. Modified door opening policy to include the possibility of keeping the door open. --- .../vaultplugin/InvalidCharsetException.java | 16 ++ .../simon987/vaultplugin/RandomString.java | 68 +++++++++ .../net/simon987/vaultplugin/VaultDoor.java | 137 ++++++++++++++---- Server/src/main/resources/config.properties | 4 + 4 files changed, 193 insertions(+), 32 deletions(-) create mode 100644 Plugin Vault/src/main/java/net/simon987/vaultplugin/InvalidCharsetException.java create mode 100644 Plugin Vault/src/main/java/net/simon987/vaultplugin/RandomString.java diff --git a/Plugin Vault/src/main/java/net/simon987/vaultplugin/InvalidCharsetException.java b/Plugin Vault/src/main/java/net/simon987/vaultplugin/InvalidCharsetException.java new file mode 100644 index 0000000..8894b49 --- /dev/null +++ b/Plugin Vault/src/main/java/net/simon987/vaultplugin/InvalidCharsetException.java @@ -0,0 +1,16 @@ +public class InvalidCharsetException extends Exception { + public InvalidCharsetException () { + + } + + public InvalidCharsetException (String message) { + super (message); + } + + public InvalidCharsetException (Throwable cause) { + super (cause); + } + + public InvalidCharsetException (String message, Throwable cause) { + super (message, cause); + } \ No newline at end of file diff --git a/Plugin Vault/src/main/java/net/simon987/vaultplugin/RandomString.java b/Plugin Vault/src/main/java/net/simon987/vaultplugin/RandomString.java new file mode 100644 index 0000000..791e21c --- /dev/null +++ b/Plugin Vault/src/main/java/net/simon987/vaultplugin/RandomString.java @@ -0,0 +1,68 @@ +/** + * + * RandomString class by erickson + * https://stackoverflow.com/questions/41107/how-to-generate-a-random-alpha-numeric-string + * + */ + + +import java.security.SecureRandom; +import java.util.Locale; +import java.util.Objects; +import java.util.Random; + +public class RandomString { + + /** + * Generate a random string. + */ + public String nextString() { + for (int idx = 0; idx < buf.length; ++idx) + buf[idx] = symbols[random.nextInt(symbols.length)]; + return new String(buf); + } + + public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public static final String lower = upper.toLowerCase(Locale.ROOT); + + public static final String digits = "0123456789"; + + public static final String alphanum = upper + lower + digits; + + private final Random random; + + private final char[] symbols; + + private final char[] buf; + + public RandomString(int length, Random random, String symbols) { + if (length < 1) throw new IllegalArgumentException(); + if (symbols.length() < 2) throw new IllegalArgumentException(); + this.random = Objects.requireNonNull(random); + this.symbols = symbols.toCharArray(); + this.buf = new char[length]; + } + + /** + * Create an alphanumeric string generator. + */ + public RandomString(int length, Random random) { + this(length, random, alphanum); + } + + /** + * Create an alphanumeric strings from a secure generator. + */ + public RandomString(int length) { + this(length, new SecureRandom()); + } + + /** + * Create session identifiers. + */ + public RandomString() { + this(21); + } + +} \ No newline at end of file diff --git a/Plugin Vault/src/main/java/net/simon987/vaultplugin/VaultDoor.java b/Plugin Vault/src/main/java/net/simon987/vaultplugin/VaultDoor.java index 5103a8a..ab900d4 100644 --- a/Plugin Vault/src/main/java/net/simon987/vaultplugin/VaultDoor.java +++ b/Plugin Vault/src/main/java/net/simon987/vaultplugin/VaultDoor.java @@ -6,6 +6,7 @@ import net.simon987.server.game.GameObject; import net.simon987.server.game.Programmable; import net.simon987.server.game.Updatable; import net.simon987.server.logging.LogManager; +import net.simon987.vaultplugin.RandomString; import java.util.Arrays; @@ -19,31 +20,45 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up */ private char[] password; + private RandomString random_string_generator; + /** * Whether or not the vault door is opened */ - private boolean opened; + private boolean open = false; - private int openedTimer; /** * Number of ticks to remain the door open */ - private static final int OPEN_TIME = 4; //todo load from config + private int OPEN_TIME = GameServer.INSTANCE.getConfig().getInt("vault_door_open_time"); + private int openedTimer = 0; + + private int password_length; + private int cypher_id; + + public VaultDoor(int password_length, int cypher_id){ + this.password_length = password_length; + this.cypher_id = cypher_id; + this.random_string_generator = new RandomString(password_length); + + password = getRandomPassword(); + } @Override public void update() { - - if (openedTimer <= 0) { - - //Door was opened for OPEN_TIME, close it and regen password - password = getRandomPassword(); - opened = false; - - LogManager.LOGGER.fine("Closed Vault door ID: " + getObjectId()); - } else { - openedTimer--; + if (open){ + if (openedTimer <= 0) { + //Door was open for OPEN_TIME, close it and regen password + password = getRandomPassword(); + open = false; + openedTimer = 0; + LogManager.LOGGER.fine("Closed Vault door ID: " + getObjectId()); + } + else{ + openedTimer--; + } } } @@ -51,45 +66,102 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up @Override public boolean sendMessage(char[] message) { - System.out.println("VAULT: sendMessage" + new String(message));//todo rmv - - if (!opened) { - - if (Arrays.equals(message, password)) { - opened = true; - openedTimer = OPEN_TIME; - - LogManager.LOGGER.fine("Opened Vault door ID: " + getObjectId()); + if (Arrays.equals(message, password)) { + if (!open) { + openVault(); + } + else{ + keepVaultOpen(); } - return true; - } else { - //Can't receive messages when opened + } + else { return false; } } + private void openVault(){ + open = true; + openedTimer = OPEN_TIME; + LogManager.LOGGER.fine("Opened Vault door ID: " + getObjectId()); + } + + private void keepVaultOpen(){ + open = true; + openedTimer = OPEN_TIME; + } + @Override public boolean enter(GameObject object) { - LogManager.LOGGER.fine("VAULT enter " + opened); - - if (opened) { + LogManager.LOGGER.fine("VAULT enter " + open); + if (open) { //TODO: Enter in the vault - - return true; } else { return false; } - } + /** + * Generates a random alphanumeric string using the RandomString class + */ private static char[] getRandomPassword() { - return "12345678".toCharArray();//todo actual random password + return random_string_generator.nextString().toCharArray(); } + + + private char[] encryptVernam(char[] plaintext){ + String charset = random_string_generator.alphanum; + int charset_length = charset.length(); + int plaintext_length = plaintext.length; + char[] cyphertext = new char[plaintext_length]; + for (int i = 0; i< plaintext_length; i++){ + int j = i % password_length; + char p = plaintext[i]; + char q = password[j]; + int p_ind = charset.indexOf(p); + if (p_ind == -1){ + throw InvalidCharsetException("Plaintext contains non-alphanumeric character: "+p); + } + int q_ind = charset.indexOf(q); + if (q_ind == -1){ + throw InvalidCharsetException("Password contains non-alphanumeric character: "+q); // this should NEVER happen + } + int c_int = (p_ind+q_ind)%charset_length; + char c = charset.charAt(c_int); + cyphertext[i] = c; + } + return cyphertext; + } + + private char[] decryptVernam(char[] cyphertext){ + String charset = random_string_generator.alphanum; + int charset_length = charset.length(); + int cyphertext_length = cyphertext.length; + char[] plaintext = new char[cyphertext_length]; + for (int i = 0; i< cyphertext_length; i++){ + int j = i % password_length; + char c = cyphertext[i]; + char q = password[j]; + int c_ind = charset.indexOf(c); + if (c_ind == -1){ + throw InvalidCharsetException("Cyphertext contains non-alphanumeric character: "+c); + } + int q_ind = charset.indexOf(q); + if (q_ind == -1){ + throw InvalidCharsetException("Password contains non-alphanumeric character: "+q); // this should NEVER happen + } + int p_int = (c_ind-q_ind)%charset_length; + char p = charset.charAt(p_int); + plaintext[i] = p; + } + return plaintext; + } + + @Override public char getMapInfo() { return MAP_INFO; @@ -99,4 +171,5 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up public BasicDBObject mongoSerialise() { return null; } + } diff --git a/Server/src/main/resources/config.properties b/Server/src/main/resources/config.properties index 1c925dc..4647df3 100644 --- a/Server/src/main/resources/config.properties +++ b/Server/src/main/resources/config.properties @@ -84,3 +84,7 @@ wg_maxCopperCount=2 # ---------------------------------------------- # Maximum execution time of user code in ms user_timeout=100 + + +# ---------------------------------------------- +vault_door_open_time=4 \ No newline at end of file From a04207b5e0e90ad2ac2b592da7cabc8d0394d06a Mon Sep 17 00:00:00 2001 From: sg495 Date: Tue, 9 Jan 2018 17:14:31 +0100 Subject: [PATCH 2/2] Added some cyphers for use in vault doors. 1. Created net.simon987.server.crypto package and moved RandomStringGenerator there. 2. Created CryptoProvider class, added a global instance to GameServer for use by game entities. 3. Created interface for cyphers, abstract class for shift substitution cyphers, classes for no cypher, Caesar cypher, Vigenere cypher and autokey cypher. 4. Created some Crypto exceptions. 5. Removed static encryption/decryption methods from VaultDoor, and moved getRandomPassword() to the global CryptoProvider instance. --- .../simon987/vaultplugin/RandomString.java | 68 ---------------- .../net/simon987/vaultplugin/VaultDoor.java | 80 +++---------------- .../java/net/simon987/server/GameServer.java | 8 ++ .../simon987/server/crypto/AutokeyCypher.java | 31 +++++++ .../simon987/server/crypto/CaesarCypher.java | 29 +++++++ .../server/crypto/CryptoException.java | 22 +++++ .../server/crypto/CryptoProvider.java | 43 ++++++++++ .../net/simon987/server/crypto/Cypher.java | 13 +++ .../crypto}/InvalidCharsetException.java | 10 ++- .../server/crypto/InvalidKeyException.java | 22 +++++ .../net/simon987/server/crypto/NoCypher.java | 50 ++++++++++++ .../server/crypto/RandomStringGenerator.java | 74 +++++++++++++++++ .../crypto/ShiftSubstitutionCypher.java | 73 +++++++++++++++++ .../server/crypto/VigenereCypher.java | 25 ++++++ 14 files changed, 407 insertions(+), 141 deletions(-) delete mode 100644 Plugin Vault/src/main/java/net/simon987/vaultplugin/RandomString.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/AutokeyCypher.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/CaesarCypher.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/CryptoException.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/CryptoProvider.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/Cypher.java rename {Plugin Vault/src/main/java/net/simon987/vaultplugin => Server/src/main/java/net/simon987/server/crypto}/InvalidCharsetException.java (74%) create mode 100644 Server/src/main/java/net/simon987/server/crypto/InvalidKeyException.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/NoCypher.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/RandomStringGenerator.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/ShiftSubstitutionCypher.java create mode 100644 Server/src/main/java/net/simon987/server/crypto/VigenereCypher.java diff --git a/Plugin Vault/src/main/java/net/simon987/vaultplugin/RandomString.java b/Plugin Vault/src/main/java/net/simon987/vaultplugin/RandomString.java deleted file mode 100644 index 791e21c..0000000 --- a/Plugin Vault/src/main/java/net/simon987/vaultplugin/RandomString.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * - * RandomString class by erickson - * https://stackoverflow.com/questions/41107/how-to-generate-a-random-alpha-numeric-string - * - */ - - -import java.security.SecureRandom; -import java.util.Locale; -import java.util.Objects; -import java.util.Random; - -public class RandomString { - - /** - * Generate a random string. - */ - public String nextString() { - for (int idx = 0; idx < buf.length; ++idx) - buf[idx] = symbols[random.nextInt(symbols.length)]; - return new String(buf); - } - - public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - public static final String lower = upper.toLowerCase(Locale.ROOT); - - public static final String digits = "0123456789"; - - public static final String alphanum = upper + lower + digits; - - private final Random random; - - private final char[] symbols; - - private final char[] buf; - - public RandomString(int length, Random random, String symbols) { - if (length < 1) throw new IllegalArgumentException(); - if (symbols.length() < 2) throw new IllegalArgumentException(); - this.random = Objects.requireNonNull(random); - this.symbols = symbols.toCharArray(); - this.buf = new char[length]; - } - - /** - * Create an alphanumeric string generator. - */ - public RandomString(int length, Random random) { - this(length, random, alphanum); - } - - /** - * Create an alphanumeric strings from a secure generator. - */ - public RandomString(int length) { - this(length, new SecureRandom()); - } - - /** - * Create session identifiers. - */ - public RandomString() { - this(21); - } - -} \ No newline at end of file diff --git a/Plugin Vault/src/main/java/net/simon987/vaultplugin/VaultDoor.java b/Plugin Vault/src/main/java/net/simon987/vaultplugin/VaultDoor.java index ab900d4..c75378c 100644 --- a/Plugin Vault/src/main/java/net/simon987/vaultplugin/VaultDoor.java +++ b/Plugin Vault/src/main/java/net/simon987/vaultplugin/VaultDoor.java @@ -6,7 +6,7 @@ import net.simon987.server.game.GameObject; import net.simon987.server.game.Programmable; import net.simon987.server.game.Updatable; import net.simon987.server.logging.LogManager; -import net.simon987.vaultplugin.RandomString; +import net.simon987.server.crypto.CryptoProvider; import java.util.Arrays; @@ -32,17 +32,15 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up * Number of ticks to remain the door open */ private int OPEN_TIME = GameServer.INSTANCE.getConfig().getInt("vault_door_open_time"); - private int openedTimer = 0; - private int password_length; + private int openedTimer = 0; private int cypher_id; - public VaultDoor(int password_length, int cypher_id){ - this.password_length = password_length; + public VaultDoor(int cypher_id){ this.cypher_id = cypher_id; - this.random_string_generator = new RandomString(password_length); + this.random_string_generator = new RandomStringGenerator(PASSWORD_LENGTH); - password = getRandomPassword(); + password = GameServer.INSTANCE.getConfig().getRandomPassword(); } @@ -51,12 +49,11 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up if (open){ if (openedTimer <= 0) { //Door was open for OPEN_TIME, close it and regen password - password = getRandomPassword(); + password = GameServer.INSTANCE.getConfig().getRandomPassword(); open = false; openedTimer = 0; LogManager.LOGGER.fine("Closed Vault door ID: " + getObjectId()); - } - else{ + } else { openedTimer--; } } @@ -69,13 +66,11 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up if (Arrays.equals(message, password)) { if (!open) { openVault(); - } - else{ + } else { keepVaultOpen(); } return true; - } - else { + } else { return false; } } @@ -104,63 +99,6 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up } } - /** - * Generates a random alphanumeric string using the RandomString class - */ - private static char[] getRandomPassword() { - return random_string_generator.nextString().toCharArray(); - } - - - - private char[] encryptVernam(char[] plaintext){ - String charset = random_string_generator.alphanum; - int charset_length = charset.length(); - int plaintext_length = plaintext.length; - char[] cyphertext = new char[plaintext_length]; - for (int i = 0; i< plaintext_length; i++){ - int j = i % password_length; - char p = plaintext[i]; - char q = password[j]; - int p_ind = charset.indexOf(p); - if (p_ind == -1){ - throw InvalidCharsetException("Plaintext contains non-alphanumeric character: "+p); - } - int q_ind = charset.indexOf(q); - if (q_ind == -1){ - throw InvalidCharsetException("Password contains non-alphanumeric character: "+q); // this should NEVER happen - } - int c_int = (p_ind+q_ind)%charset_length; - char c = charset.charAt(c_int); - cyphertext[i] = c; - } - return cyphertext; - } - - private char[] decryptVernam(char[] cyphertext){ - String charset = random_string_generator.alphanum; - int charset_length = charset.length(); - int cyphertext_length = cyphertext.length; - char[] plaintext = new char[cyphertext_length]; - for (int i = 0; i< cyphertext_length; i++){ - int j = i % password_length; - char c = cyphertext[i]; - char q = password[j]; - int c_ind = charset.indexOf(c); - if (c_ind == -1){ - throw InvalidCharsetException("Cyphertext contains non-alphanumeric character: "+c); - } - int q_ind = charset.indexOf(q); - if (q_ind == -1){ - throw InvalidCharsetException("Password contains non-alphanumeric character: "+q); // this should NEVER happen - } - int p_int = (c_ind-q_ind)%charset_length; - char p = charset.charAt(p_int); - plaintext[i] = p; - } - return plaintext; - } - @Override public char getMapInfo() { diff --git a/Server/src/main/java/net/simon987/server/GameServer.java b/Server/src/main/java/net/simon987/server/GameServer.java index bc41d72..e2e09e9 100644 --- a/Server/src/main/java/net/simon987/server/GameServer.java +++ b/Server/src/main/java/net/simon987/server/GameServer.java @@ -14,6 +14,7 @@ import net.simon987.server.logging.LogManager; import net.simon987.server.plugin.PluginManager; import net.simon987.server.user.User; import net.simon987.server.webserver.SocketServer; +import net.simon987.server.crypto.CryptoProvider; import java.io.File; import java.net.UnknownHostException; @@ -36,6 +37,8 @@ public class GameServer implements Runnable { private DayNightCycle dayNightCycle; + private CryptoProvider cryptoProvider; + public GameServer() { this.config = new ServerConfiguration("config.properties"); @@ -45,6 +48,7 @@ public class GameServer implements Runnable { maxExecutionTime = config.getInt("user_timeout"); + cryptoProvider = new CryptoProvider(); dayNightCycle = new DayNightCycle(); @@ -79,6 +83,10 @@ public class GameServer implements Runnable { return eventDispatcher; } + public CryptoProvider getCryptoProvider(){ + return cryptoProvider; + } + @Override public void run() { LogManager.LOGGER.info("(G) Started game loop"); diff --git a/Server/src/main/java/net/simon987/server/crypto/AutokeyCypher.java b/Server/src/main/java/net/simon987/server/crypto/AutokeyCypher.java new file mode 100644 index 0000000..707d3a0 --- /dev/null +++ b/Server/src/main/java/net/simon987/server/crypto/AutokeyCypher.java @@ -0,0 +1,31 @@ +package net.simon987.server.crypto; + +public class AutokeyCypher extends ShiftSubstitutionCypher { + + public AutokeyCypher(String charset){ + super(charset); + } + + public AutokeyCypher(){ + super(); + } + + @override + protected char encryptionShiftAt(int position, char[] plaintext, char[] key, char[] partial_cyphertext){ + if (i