mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-10 14:26:45 +00:00
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.
This commit is contained in:
parent
46483b2bf8
commit
a04207b5e0
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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() {
|
||||
|
@ -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");
|
||||
|
@ -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<key.length){
|
||||
return key[i];
|
||||
} else {
|
||||
return plaintext[i-key.length];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
protected char decryptionShiftAt(int position, char[] cyphertext, char[] key, char[] partial_plaintext){
|
||||
if (i<key.length){
|
||||
return key[i];
|
||||
} else {
|
||||
return partial_plaintext[i-key.length];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
public class CaesarCypher extends ShiftSubstitutionCypher {
|
||||
|
||||
public CaesarCypher(String charset){
|
||||
super(charset);
|
||||
}
|
||||
|
||||
public CaesarCypher(){
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the first character of the key as the shift, and ignores the rest.
|
||||
*/
|
||||
@override
|
||||
protected char encryptionShiftAt(int position, char[] plaintext, char[] key, char[] partial_cyphertext){
|
||||
return key[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the first character of the key as the shift, and ignores the rest.
|
||||
*/
|
||||
@override
|
||||
protected char decryptionShiftAt(int position, char[] cyphertext, char[] key, char[] partial_plaintext){
|
||||
return key[0];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
|
||||
public class CryptoException extends Exception {
|
||||
|
||||
public CryptoException () {
|
||||
|
||||
}
|
||||
|
||||
public CryptoException (String message) {
|
||||
super (message);
|
||||
}
|
||||
|
||||
public CryptoException (Throwable cause) {
|
||||
super (cause);
|
||||
}
|
||||
|
||||
public CryptoException (String message, Throwable cause) {
|
||||
super (message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
public class CryptoProvider{
|
||||
|
||||
public static final int NO_CYPHER = 0x0000;
|
||||
public static final int CAESAR_CYPHER = 0x0001;
|
||||
public static final int VIGENERE_CYPHER = 0x0002;
|
||||
public static final int AUTOKEY_CYPHER = 0x0003;
|
||||
|
||||
public static final int PASSWORD_LENGTH = 8; // Same as CubotComPort.MESSAGE_LENGTH
|
||||
|
||||
private charset;
|
||||
private password_generator;
|
||||
|
||||
public CryptoProvider(String charset){
|
||||
this.charset = charset;
|
||||
this.password_generator = new RandomStringGenerator(PASSWORD_LENGTH,charset);
|
||||
}
|
||||
|
||||
public CryptoProvider(){
|
||||
this(RandomStringGenerator.ALPHANUMERIC_CHARSET);
|
||||
}
|
||||
|
||||
public Cypher getCypher(int cypherId){
|
||||
switch (cypherId){
|
||||
case NO_CYPHER:
|
||||
return new NoCypher(charset);
|
||||
case CAESAR_CYPHER:
|
||||
return new CaesarCypher(charset);
|
||||
case VIGENERE_CYPHER:
|
||||
return new VigenereCypher(charset);
|
||||
case AUTOKEY_CYPHER:
|
||||
return new AutokeyCypher(charset);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRandomPassword(){
|
||||
return this.password_generator.nextString().toCharArray();
|
||||
}
|
||||
|
||||
}
|
13
Server/src/main/java/net/simon987/server/crypto/Cypher.java
Normal file
13
Server/src/main/java/net/simon987/server/crypto/Cypher.java
Normal file
@ -0,0 +1,13 @@
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
interface Cypher {
|
||||
|
||||
public char[] encrypt(char[] plaintext, char[] key);
|
||||
|
||||
public char[] decrypt(char[] cyphertext, char[] key);
|
||||
|
||||
public String textCharset();
|
||||
|
||||
public String keyCharset();
|
||||
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
public class InvalidCharsetException extends Exception {
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
|
||||
public class InvalidCharsetException extends CryptoException {
|
||||
|
||||
public InvalidCharsetException () {
|
||||
|
||||
}
|
||||
@ -13,4 +17,6 @@ public class InvalidCharsetException extends Exception {
|
||||
|
||||
public InvalidCharsetException (String message, Throwable cause) {
|
||||
super (message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
|
||||
public class InvalidKeyException extends CryptoException {
|
||||
|
||||
public InvalidKeyException () {
|
||||
|
||||
}
|
||||
|
||||
public InvalidKeyException (String message) {
|
||||
super (message);
|
||||
}
|
||||
|
||||
public InvalidKeyException (Throwable cause) {
|
||||
super (cause);
|
||||
}
|
||||
|
||||
public InvalidKeyException (String message, Throwable cause) {
|
||||
super (message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
public abstract class NoCypher implements Cypher {
|
||||
|
||||
private String charset;
|
||||
|
||||
public NoCypher(String charset){
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
public NoCypher(){
|
||||
this(RandomStringGenerator.alphanum);
|
||||
}
|
||||
|
||||
public char[] encrypt(char[] plaintext, char[] key){
|
||||
char[] cyphertext = new char[plaintext.length];
|
||||
for (int i = 0; i< plaintext.length; i++){
|
||||
char p = plaintext[i];
|
||||
int p_ind = charset.indexOf(p);
|
||||
if (p_ind == -1){
|
||||
throw InvalidCharsetException("Plaintext contains invalid character: "+p);
|
||||
}
|
||||
cyphertext[i] = p;
|
||||
}
|
||||
return cyphertext;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public char[] decrypt(char[] cyphertext, char[] key){
|
||||
char[] plaintext = new char[cyphertext.length];
|
||||
for (int i = 0; i< cyphertext.length; i++){
|
||||
char c = cyphertext[i];
|
||||
int c_ind = charset.indexOf(c);
|
||||
if (c_ind == -1){
|
||||
throw InvalidCharsetException("Cyphertext contains invalid character: "+c);
|
||||
}
|
||||
plaintext[i] = c;
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
public String textCharset(){
|
||||
return charset;
|
||||
}
|
||||
|
||||
public String keyCharset(){
|
||||
return charset;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
*
|
||||
* Based on the RandomString class by erickson:
|
||||
* https://stackoverflow.com/questions/41107/how-to-generate-a-random-alpha-numeric-string
|
||||
*
|
||||
*/
|
||||
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomStringGenerator {
|
||||
|
||||
/**
|
||||
* Generate a random string.
|
||||
*/
|
||||
public String nextString() {
|
||||
for (int idx = 0; idx < buf.length; ++idx)
|
||||
buf[idx] = charset[random.nextInt(charset.length)];
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
public static final String UPPER_ALPHA_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
public static final String LOWER_ALPHA_CHARSET = UPPER_ALPHA_CHARSET.toLowerCase(Locale.ROOT);
|
||||
public static final String NUMERIC_CHARSET = "0123456789";
|
||||
public static final String ALPHANUMERIC_CHARSET = UPPER_ALPHA_CHARSET + LOWER_ALPHA_CHARSET + NUMERIC_CHARSET;
|
||||
|
||||
private final Random random;
|
||||
|
||||
private final char[] charset;
|
||||
|
||||
private final char[] buf;
|
||||
|
||||
public RandomStringGenerator(int length, Random random, String charset) {
|
||||
if (length < 1) throw new IllegalArgumentException();
|
||||
if (charset.length() < 2) throw new IllegalArgumentException();
|
||||
this.random = Objects.requireNonNull(random);
|
||||
this.charset = charset.toCharArray();
|
||||
this.buf = new char[length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alphanumeric string generator.
|
||||
*/
|
||||
public RandomStringGenerator(int length, Random random) {
|
||||
this(length, random, alphanum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alphanumeric string generator using the given charset.
|
||||
*/
|
||||
public RandomStringGenerator(int length, String charset) {
|
||||
this(length, new SecureRandom(), ALPHANUMERIC_CHARSET);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an alphanumeric strings from a secure generator.
|
||||
*/
|
||||
public RandomStringGenerator(int length) {
|
||||
this(length, new SecureRandom(),ALPHANUMERIC_CHARSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create 8-character alphanumeric strings from a secure generator.
|
||||
*/
|
||||
public RandomStringGenerator() {
|
||||
this(8);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
public abstract class ShiftSubstitutionCypher implements Cypher {
|
||||
|
||||
private String charset;
|
||||
|
||||
public ShiftSubstitutionCypher(String charset){
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
public ShiftSubstitutionCypher(){
|
||||
this(RandomStringGenerator.alphanum);
|
||||
}
|
||||
|
||||
protected abstract char encryptionShiftAt(int position, char[] plaintext, char[] key, char[] partial_cyphertext);
|
||||
protected abstract char decryptionShiftAt(int position, char[] cyphertext, char[] key, char[] partial_plaintext);
|
||||
|
||||
public char[] encrypt(char[] plaintext, char[] key){
|
||||
if (key.length==0){
|
||||
throw InvalidKeyException("Key is empty");
|
||||
}
|
||||
int charset_length = charset.length();
|
||||
char[] cyphertext = new char[plaintext.length];
|
||||
for (int i = 0; i< plaintext.length; i++){
|
||||
char p = plaintext[i];
|
||||
char k = encryptionShiftAt(i,plaintext,key,cyphertext);
|
||||
int p_ind = charset.indexOf(p);
|
||||
if (p_ind == -1){
|
||||
throw InvalidCharsetException("Plaintext contains invalid character: "+p);
|
||||
}
|
||||
int k_ind = charset.indexOf(k);
|
||||
if (k_ind == -1){
|
||||
throw InvalidCharsetException("Key contains invalid character: "+k);
|
||||
}
|
||||
int c_int = (p_ind+k_ind)%charset_length;
|
||||
char c = charset.charAt(c_int);
|
||||
cyphertext[i] = c;
|
||||
}
|
||||
return cyphertext;
|
||||
}
|
||||
|
||||
public char[] decrypt(char[] cyphertext, char[] key){
|
||||
if (key.length==0){
|
||||
throw InvalidKeyException("Key is empty");
|
||||
}
|
||||
int charset_length = charset.length();
|
||||
char[] plaintext = new char[cyphertext.length];
|
||||
for (int i = 0; i< cyphertext.length; i++){
|
||||
char c = cyphertext[i];
|
||||
char k = decryptionShiftAt(i,cyphertext,key,plaintext);
|
||||
int c_ind = charset.indexOf(c);
|
||||
if (c_ind == -1){
|
||||
throw InvalidCharsetException("Cyphertext contains invalid character: "+c);
|
||||
}
|
||||
int k_ind = charset.indexOf(k);
|
||||
if (k_ind == -1){
|
||||
throw InvalidCharsetException("Password contains invalid character: "+k);
|
||||
}
|
||||
int p_int = (c_ind-k_ind)%charset_length;
|
||||
char p = charset.charAt(p_int);
|
||||
plaintext[i] = p;
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
public String textCharset(){
|
||||
return charset;
|
||||
}
|
||||
|
||||
public String keyCharset(){
|
||||
return charset;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package net.simon987.server.crypto;
|
||||
|
||||
public class VigenereCypher extends ShiftSubstitutionCypher {
|
||||
|
||||
public VigenereCypher(String charset){
|
||||
super(charset);
|
||||
}
|
||||
|
||||
public VigenereCypher(){
|
||||
super();
|
||||
}
|
||||
|
||||
@override
|
||||
protected char encryptionShiftAt(int position, char[] plaintext, char[] key, char[] partial_cyphertext){
|
||||
int j = i % key.length;
|
||||
return key[j];
|
||||
}
|
||||
|
||||
@override
|
||||
protected char decryptionShiftAt(int position, char[] cyphertext, char[] key, char[] partial_plaintext){
|
||||
int j = i % key.length;
|
||||
return key[j];
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user