Makes one-time-pad and substitution cipher real encryption compatible
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good
This commit is contained in:
@@ -34,10 +34,10 @@ public class CommandEncrypt implements TabExecutor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
EncryptionStyle encryptionStyle = arguments.length == 2 ? EncryptionStyle.getFromString(arguments[1]) : EncryptionStyle.SUBSTITUTION;
|
EncryptionStyle encryptionStyle = arguments.length == 2 ? EncryptionStyle.getFromString(arguments[1]) : EncryptionStyle.AES;
|
||||||
|
|
||||||
// AES is the only reliable method for retaining the plaintext
|
// AES is the only reliable method for retaining the plaintext
|
||||||
if (BooksWithoutBorders.getConfiguration().useRealEncryption()) {
|
if (BooksWithoutBorders.getConfiguration().useRealEncryption() && !encryptionStyle.isRealEncryptionSupported()) {
|
||||||
encryptionStyle = EncryptionStyle.AES;
|
encryptionStyle = EncryptionStyle.AES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,11 +132,14 @@ public class CommandEncrypt implements TabExecutor {
|
|||||||
@NotNull
|
@NotNull
|
||||||
protected List<String> doTabCompletion(@NotNull String[] args, boolean groupEncrypt) {
|
protected List<String> doTabCompletion(@NotNull String[] args, boolean groupEncrypt) {
|
||||||
int argumentsCount = args.length;
|
int argumentsCount = args.length;
|
||||||
|
boolean useRealEncryption = BooksWithoutBorders.getConfiguration().useRealEncryption();
|
||||||
|
|
||||||
List<String> encryptionStyles = new ArrayList<>();
|
List<String> encryptionStyles = new ArrayList<>();
|
||||||
for (EncryptionStyle encryptionStyle : EncryptionStyle.values()) {
|
for (EncryptionStyle encryptionStyle : EncryptionStyle.values()) {
|
||||||
|
if (!useRealEncryption || encryptionStyle.isRealEncryptionSupported()) {
|
||||||
encryptionStyles.add(encryptionStyle.toString());
|
encryptionStyles.add(encryptionStyle.toString());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (groupEncrypt) {
|
if (groupEncrypt) {
|
||||||
if (argumentsCount == 1) {
|
if (argumentsCount == 1) {
|
||||||
@@ -150,9 +153,6 @@ public class CommandEncrypt implements TabExecutor {
|
|||||||
if (argumentsCount == 1) {
|
if (argumentsCount == 1) {
|
||||||
return List.of("<password>");
|
return List.of("<password>");
|
||||||
} else if (argumentsCount == 2) {
|
} else if (argumentsCount == 2) {
|
||||||
if (BooksWithoutBorders.getConfiguration().useRealEncryption()) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
return TabCompletionHelper.filterMatchingStartsWith(encryptionStyles, args[1]);
|
return TabCompletionHelper.filterMatchingStartsWith(encryptionStyles, args[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,38 +10,53 @@ public enum EncryptionStyle {
|
|||||||
/**
|
/**
|
||||||
* Possibly lossy encryption using DNA codons
|
* Possibly lossy encryption using DNA codons
|
||||||
*/
|
*/
|
||||||
DNA("dna"),
|
DNA("dna", false),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple cipher using the key to substitute one character for another
|
* A simple cipher using the key to substitute one character for another
|
||||||
*/
|
*/
|
||||||
SUBSTITUTION("substitution"),
|
SUBSTITUTION("substitution", true),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A military-grade encryption cypher
|
* A military-grade encryption cypher
|
||||||
*/
|
*/
|
||||||
AES("aes"),
|
AES("aes", true),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An unbreakable encryption method assuming the key is completely random and never used more than once, ever
|
* An unbreakable encryption method assuming the key is completely random and never used more than once, ever
|
||||||
*/
|
*/
|
||||||
ONE_TIME_PAD("onetimepad"),
|
ONE_TIME_PAD("onetimepad", true),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Just a way of using magic text to make text illegible
|
* Just a way of using magic text to make text illegible
|
||||||
*/
|
*/
|
||||||
MAGIC("magic"),
|
MAGIC("magic", false),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final boolean realEncryptionSupported;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new encryption style
|
* Instantiates a new encryption style
|
||||||
*
|
*
|
||||||
* @param name <p>The human-readable encryption style name</p>
|
* @param name <p>The human-readable encryption style name</p>
|
||||||
|
* @param realEncryptionSupported <p>Whether the encryption style can be used for real encryption</p>
|
||||||
*/
|
*/
|
||||||
EncryptionStyle(@NotNull String name) {
|
EncryptionStyle(@NotNull String name, boolean realEncryptionSupported) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.realEncryptionSupported = realEncryptionSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this encryption style supports real encryption
|
||||||
|
*
|
||||||
|
* <p>Real encryption means that only the cypher text is stored on disk, so the server owner cannot simply check the
|
||||||
|
* contents of encrypted books.</p>
|
||||||
|
*
|
||||||
|
* @return <p>True if this encryption style supports real encryption</p>
|
||||||
|
*/
|
||||||
|
public boolean isRealEncryptionSupported() {
|
||||||
|
return this.realEncryptionSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,7 +72,7 @@ public enum EncryptionStyle {
|
|||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return SUBSTITUTION;
|
return AES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package net.knarcraft.bookswithoutborders.encryption;
|
package net.knarcraft.bookswithoutborders.encryption;
|
||||||
|
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.EncryptionHelper;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -26,12 +27,12 @@ public class OneTimePad implements Encryptor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable String encryptText(@NotNull String input) {
|
public @Nullable String encryptText(@NotNull String input) {
|
||||||
return oneTimePad(input);
|
return oneTimePad(input, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable String decryptText(@NotNull String input) {
|
public @Nullable String decryptText(@NotNull String input) {
|
||||||
return oneTimePad(input);
|
return oneTimePad(input, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,10 +42,15 @@ public class OneTimePad implements Encryptor {
|
|||||||
* the same key is used more than once.</p>
|
* the same key is used more than once.</p>
|
||||||
*
|
*
|
||||||
* @param input <p>The input to encrypt/decrypt</p>
|
* @param input <p>The input to encrypt/decrypt</p>
|
||||||
|
* @param encrypt <p>Whether to encrypt or decrypt the input</p>
|
||||||
* @return <p>The encrypted/decrypted output</p>
|
* @return <p>The encrypted/decrypted output</p>
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public String oneTimePad(@NotNull String input) {
|
public String oneTimePad(@NotNull String input, boolean encrypt) {
|
||||||
|
if (!encrypt) {
|
||||||
|
input = new String(EncryptionHelper.hexStringToByteArray(input), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
String longKey;
|
String longKey;
|
||||||
try {
|
try {
|
||||||
final MessageDigest digest = MessageDigest.getInstance("SHA3-256");
|
final MessageDigest digest = MessageDigest.getInstance("SHA3-256");
|
||||||
@@ -58,7 +64,12 @@ public class OneTimePad implements Encryptor {
|
|||||||
for (int i = 0; i < input.length(); i++) {
|
for (int i = 0; i < input.length(); i++) {
|
||||||
output.append((char) (input.charAt(i) ^ longKey.charAt(i % longKey.length())));
|
output.append((char) (input.charAt(i) ^ longKey.charAt(i % longKey.length())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (encrypt) {
|
||||||
|
return EncryptionHelper.bytesToHex(output.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
|
} else {
|
||||||
return output.toString();
|
return output.toString();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
package net.knarcraft.bookswithoutborders.encryption;
|
package net.knarcraft.bookswithoutborders.encryption;
|
||||||
|
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.EncryptionHelper;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,6 +51,10 @@ public class SubstitutionCipher implements Encryptor {
|
|||||||
return output.toString();
|
return output.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!encrypt) {
|
||||||
|
input = new String(EncryptionHelper.hexStringToByteArray(input), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
// converts each number in the key to an integer and adds to an array
|
// converts each number in the key to an integer and adds to an array
|
||||||
int[] offsetArray = getOffsetArray(this.key);
|
int[] offsetArray = getOffsetArray(this.key);
|
||||||
|
|
||||||
@@ -68,8 +74,13 @@ public class SubstitutionCipher implements Encryptor {
|
|||||||
offsetPosition = 0;
|
offsetPosition = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (encrypt) {
|
||||||
|
return EncryptionHelper.bytesToHex(output.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
|
} else {
|
||||||
return output.toString();
|
return output.toString();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tokenizes a key and generates an offset array for substitution
|
* Tokenizes a key and generates an offset array for substitution
|
||||||
|
@@ -12,7 +12,7 @@ en:
|
|||||||
SUCCESS_PAGE_DELETED: "Page deleted!"
|
SUCCESS_PAGE_DELETED: "Page deleted!"
|
||||||
SUCCESS_BOOK_LOADED: "Book created!"
|
SUCCESS_BOOK_LOADED: "Book created!"
|
||||||
SUCCESS_MIGRATION_STARTED: "Starting book migration..."
|
SUCCESS_MIGRATION_STARTED: "Starting book migration..."
|
||||||
SUCCESS_RELOADED: "BooksWithoutBorders configuration reloaded!"
|
SUCCESS_RELOADED: "Configuration, books and language strings reloaded!"
|
||||||
SUCCESS_SAVED: "Book Saved as &e\"{fileName}\"&r"
|
SUCCESS_SAVED: "Book Saved as &e\"{fileName}\"&r"
|
||||||
ACTION_COPY: "copy"
|
ACTION_COPY: "copy"
|
||||||
ACTION_CLEAR: "clear"
|
ACTION_CLEAR: "clear"
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
package net.knarcraft.bookswithoutborders;
|
|
||||||
|
|
||||||
import net.knarcraft.bookswithoutborders.encryption.GenenCrypt;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
public class GenenCryptTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void encryptDecryptTest() {
|
|
||||||
GenenCrypt gc = new GenenCrypt("Another Key");
|
|
||||||
gc.printCodonTable();
|
|
||||||
String encrypted = gc.encryptText("Hello World!");
|
|
||||||
|
|
||||||
assertNotNull(encrypted);
|
|
||||||
|
|
||||||
assertEquals("HELLO WORLD!", gc.decryptText(encrypted));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -13,21 +13,16 @@ public class AESTest {
|
|||||||
String plainText = "Flåklypa";
|
String plainText = "Flåklypa";
|
||||||
String password = "TqOZdpY9RjjjVE9JjCWVecUYObv5MYidByrpI3cxjoY=";
|
String password = "TqOZdpY9RjjjVE9JjCWVecUYObv5MYidByrpI3cxjoY=";
|
||||||
|
|
||||||
System.out.println("Plaintext: " + plainText);
|
|
||||||
System.out.println("Encryption password: " + password);
|
|
||||||
|
|
||||||
AESConfiguration configuration = new AESConfiguration(new byte[]{-85, 103, -82, 71, 119, 28, 73, -75, -81, 102, -127, -125, -8, -75, 81, -111},
|
AESConfiguration configuration = new AESConfiguration(new byte[]{-85, 103, -82, 71, 119, 28, 73, -75, -81, 102, -127, -125, -8, -75, 81, -111},
|
||||||
new byte[]{(byte) 104, -42, 63, 31, -120, -2, 14, -119, 35, 122, 109, -64, 122, 117, 33, -85}, password);
|
new byte[]{(byte) 104, -42, 63, 31, -120, -2, 14, -119, 35, 122, 109, -64, 122, 117, 33, -85}, password);
|
||||||
AES aes = new AES(configuration);
|
AES aes = new AES(configuration);
|
||||||
|
|
||||||
String cypherText = aes.encryptText(plainText);
|
String cypherText = aes.encryptText(plainText);
|
||||||
System.out.println("Cypher text: " + cypherText);
|
|
||||||
|
|
||||||
assertNotNull(cypherText);
|
assertNotNull(cypherText);
|
||||||
assertNotEquals(plainText, cypherText);
|
assertNotEquals(plainText, cypherText);
|
||||||
|
|
||||||
String decrypted = aes.decryptText(cypherText);
|
String decrypted = aes.decryptText(cypherText);
|
||||||
System.out.println("Decrypted: " + decrypted);
|
|
||||||
assertEquals(plainText, decrypted);
|
assertEquals(plainText, decrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,8 +12,12 @@ public class GenenCryptTest {
|
|||||||
@Test
|
@Test
|
||||||
public void encryptDecryptTest() {
|
public void encryptDecryptTest() {
|
||||||
String encryptionKey = EncryptionHelper.getNumberKeyFromStringKey("My secret password!");
|
String encryptionKey = EncryptionHelper.getNumberKeyFromStringKey("My secret password!");
|
||||||
String plaintext = "Very secret &4colored&r message.";
|
String plaintext = "Very secret &4colored&r message. That might be quite long. Of course, the length might " +
|
||||||
|
"cause problems, especially as the gene encryption requires several characters for every encrypted " +
|
||||||
|
"character. Also, the hexadecimal representation of the original text is encrypted. It is unknown if " +
|
||||||
|
"that might represent an increase in length.";
|
||||||
GenenCrypt genenCrypt = new GenenCrypt(encryptionKey);
|
GenenCrypt genenCrypt = new GenenCrypt(encryptionKey);
|
||||||
|
genenCrypt.printCodonTable();
|
||||||
|
|
||||||
String cypherText = genenCrypt.encryptText(plaintext);
|
String cypherText = genenCrypt.encryptText(plaintext);
|
||||||
|
|
||||||
|
@@ -10,8 +10,9 @@ public class OneTimePadTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void oneTimePadTest() {
|
public void oneTimePadTest() {
|
||||||
String plaintext = "Very secret text that should be kept secret";
|
String plaintext = "Very secret text that should be kept secret. It should be noted that several characters, " +
|
||||||
String key = "Very secret key!";
|
"like !\"#¤%&/()=?`§|@£${[]}'*,.-;:_<>µ need to be tested. Also foreign characters, like: øæåØÆÅ";
|
||||||
|
String key = "Very secret key that you will never guess!¤%&/";
|
||||||
|
|
||||||
OneTimePad oneTimePad = new OneTimePad(key);
|
OneTimePad oneTimePad = new OneTimePad(key);
|
||||||
String cypherText = oneTimePad.encryptText(plaintext);
|
String cypherText = oneTimePad.encryptText(plaintext);
|
||||||
|
@@ -11,8 +11,9 @@ public class SubstitutionCipherTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encryptDecryptTest() {
|
public void encryptDecryptTest() {
|
||||||
String plaintext = "Very secret text that should be kept secret";
|
String plaintext = "Very secret text that should be kept secret. It should be noted that several characters, " +
|
||||||
String integerKey = EncryptionHelper.getNumberKeyFromStringKey("Very secret key!");
|
"like !\"#¤%&/()=?`§|@£${[]}'*,.-;:_<>µ need to be tested. Also foreign characters, like: øæåØÆÅ";
|
||||||
|
String integerKey = EncryptionHelper.getNumberKeyFromStringKey("Very secret key that you will never guess!¤%&/");
|
||||||
SubstitutionCipher substitutionCipher = new SubstitutionCipher(integerKey);
|
SubstitutionCipher substitutionCipher = new SubstitutionCipher(integerKey);
|
||||||
String cypherText = substitutionCipher.encryptText(plaintext);
|
String cypherText = substitutionCipher.encryptText(plaintext);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user