Skip to content

Instantly share code, notes, and snippets.

@EudyContreras
Last active August 19, 2016 09:05
Show Gist options
  • Save EudyContreras/4916356e503742001bc331b19e6b9536 to your computer and use it in GitHub Desktop.
Save EudyContreras/4916356e503742001bc331b19e6b9536 to your computer and use it in GitHub Desktop.
Program which can be used for encrypting strings. The program uses a multi-step encryption system for encrypting Strings.
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
/**
* <h1>String Encrypter</h1>
*
* This programs allows you encrypt a String and store as a byte array.
* the program provides a simple encryption set of methods which make use of
* scrambling/adding/replacing/swapping/ the core structure of the String.
* The encrypted message is the store as byte array object which can be sent through sockets
* or stored locally. In order to be able to view the content of the String the object
* must be passed through the decrypt method of this program which will format and reconstruc the
* String to it's original state.
*
* If the message is infiltrated while stored as an encrypted byte array whether if it is traveling
* through a socket or store locally on a system. the thief wont be able to see
* the content of the message without the key used by this class
*
* @author Eudy Contreras
* @version 1.1
* @since 2016-08-16
*/
public class StringEncrypter {
private static char[] added = {'L','3','5','G','0','Ä','1','0',
'A','D','9','Å','N','C','0','Y',
'W','S','8','Ö','4','V','4','1',
'Q','7','K','6','O','3','6','X',
'8','3','2','9','0','5','7'};
/*
* Meps which hold the encryption base and key data structures.
*/
private static final Map<Character, Character> PLAIN_MAP = new HashMap<Character, Character>();
private static final Map<Character, Character> KEY_MAP = new HashMap<Character, Character>();
private static final Map<String, String> PLAIN_BYTE_MAP = new HashMap<String, String>();
private static final Map<String, String> PLAIN_KEY_MAP = new HashMap<String, String>();
/**
* This values determined the swap indexes at which the swapping methods
* will operate. More swapp indexes may be added for increase security.
*/
private final static int SWAP_INDEX_1 = 2;
private final static int SWAP_INDEX_2 = 6;
private final static int SWAP_INDEX_3 = 4;
private final static int SWAP_INDEX_4 = 3;
/*
* The higher the number the more random characters will be added to the encryption.
* The number set here will affect the performance of the application. The higher the
* number the lower the performance will be but the more populated with random characters
* he encryption will be.
* HIgher = more secure but slower.
* Lower = less secure but faster.
* recommended: 6
*/
private static int max_decoys = 5;
/*
* The index in which the actually code character will be inserted.
* the index must be a number between 0 and the max_decoys value-1.
*/
private static int insertion_index = 2;
/**
* Method used for encrypting a String. The String passed through
* this method will be encrypted and returned as byte array.
* The String will go through a series of encryption and obfuscation
* methods in order to assure that the contents of the String are kept
* private and secure.
* This method allows the input of a custom password to be associated with the
* generated key. The password will be needed for decryption of Strings
* which were encrypted using the submitted password.
* <p>
* @param message String message which you wish to encrypt.
* @param password :The password to be associated with the encryption. The password must be at least 6 characters long.
* The password must be at least 6 characters long.
* @return Returns the String given String as an encrypted byte array.
*/
public static byte[] encrypt(String message,Password password){
return encrypt(message,password,null, null);
}
/**
* Method used for encrypting a String. The String passed through
* this method will be encrypted and returned as byte array.
* The String will go through a series of encryption and obfuscation
* method in order to assure that the contents of the String are kept
* private and secure.
* This method allows the input of a custom character set and a password
* which are to be associated with the generated key. both the password and
* the submitted character set will be needed for decryption of Strings which were encrypted using the
* submitted password and character set.
* <p>
* @param message String message which you wish to encrypt.
* @param password :The password to be associated with the encryption. The password must be at least 6 characters long.
* @param new_CharSet :The character set used by the encrypted String. The character
* set cannot contain any duplicates and must be at least 40 characters long.
* @return Returns the String given String as an encrypted byte array.
*/
public static byte[] encrypt(String message, Password password, char[] new_CharSet){
return encrypt(message,password,new_CharSet, null);
}
/**
* Method used for encrypting a String. The String passed through
* this method will be encrypted and returned as byte array.
* The String will go through a series of encryption and obfuscation
* method in order to assure that the contents of the String are kept
* private and secure.
* This method allows the input of a custom character set, a password and the security level
* which is to be associated with the generated key. The password, the security level and
* the submitted character set will be needed for decryption of Strings which were encrypted using the
* submitted password, character set and security level.
* <p>
* @param message String message which you wish to encrypt.
* @param password :The password to be associated with the encryption. The password must be at least 6 characters long.
* @param new_CharSet :The character set used by the encrypted String. The character
* set cannot contain any duplicates and must be at least 40 characters long.
* @param security :The level of security which is to be assign to the encrypted message. The higher the security level
* the higher the level of encryption but also the slower the encryption process will be. The lower the security level
* the lower the encryption but the faster the encryption will be.
* @return Returns the String given String as an encrypted byte array.
*/
public static byte[] encrypt(String message, Password password, char[] new_CharSet, SecurityLevel security){
if(prepareEncryption(new_CharSet, password, security)){
String cypher = addRandom(message).toString();
byte[] encryption = cypher.getBytes(StandardCharsets.UTF_8);
byte[] swapped_Bytes = revertBytes(EncryptionUtils.toByteObject(encryption));
return swapBytes(swapped_Bytes);
}else{
return null;
}
}
/**
* Method used for decrypting a String in the form
* of a encrypted byte array. The array will go through a series
* of decryption methods in order to uncover the original content.
* This method allows the input of the password associated with
* the encrypted file which is needed in order to be able to view the file.
* <p>
* @param encryption :byte array containing the encrypted String.
* @param password :The password associated to the file. Needed in order
* to view the file! The password must match the password used to encrypt the file
* @return :Returns a decypted String.
*/
public static String decrypt(byte[] encryption, Password password){
return decrypt(encryption,password,null,null);
}
/**
* Method used for decrypting a String in the form
* of a encrypted byte array. The array will go through a series
* of decryption methods in order to uncover the original content.
*
* This method allows the input of the character set and the password
* associated with the encrypted file. Both the character set and the password
* are needed in order to view the original String content
* <p>
* @param encryption :byte array containing the encrypted String.
* @param password :The password associated to the file. Needed in order
* to view the file! The password must match the password used to encrypt the file
* @param new_CharSet :The character set associated with the encrypted file.
* needed in order to view the file! Must match the character set used to encrypt the String
* @return Returns a decypted String.
*/
public static String decrypt(byte[] encryption, Password password, char[] new_CharSet){
return decrypt(encryption,password,new_CharSet,null);
}
/**
* Method used for decrypting a String in the form
* of a encrypted byte array. The array will go through a series
* of decryption methods in order to uncover the original content.
*
* This method allows the input of the character set, the password and the security level
* associated with the encrypted file. All of the inputs are needed in order to view the original
* content of the file.
* <p>
* @param encryption :byte array containing the encrypted String.
* @param password :The password associated to the file. Needed in order
* to view the file! The password must match the password used to encrypt the String.
* @param new_CharSet :The character set associated with the encrypted file.Must match the character
* set used to encrypt the String.
* @param security :The security level which is associated with the encrypted String.Muse match
* the security level used to encrypt the String.
* @return Returns a decypted String.
*/
public static String decrypt(byte[] encryption, Password password, char[] new_CharSet, SecurityLevel security){
if(prepareEncryption(new_CharSet, password, security)){
byte[] unswapped_Bytes = revertBytesBack(EncryptionUtils.toByteObject(unSwapBytes(encryption)));
List<String> list = EncryptionUtils.fromStringToList(new String(unswapped_Bytes, StandardCharsets.UTF_8),", ");
EncryptedMessage unScrambled = removeRandom(list);
String decyphered = revertSubstitution(unScrambled);
return decyphered;
}
else{
return "";
}
}
/*
* Method in charged of processing the encryption and decryption request made
* by the user. This method will perform checks on the validity of the password and the character
* set if any. If both the password and the character set are valid the method will then generate a key
* and allow the encryption to proceed further.
*/
private static boolean prepareEncryption(char[] new_CharSet, Password password, SecurityLevel security){
boolean duplicates = false;
String[] byte_Plain =
{"1","2","3","4","5","6","7","8","9","0"};
char[] plain_char_set =
{'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','Ö','Ä','Å','0','1','2',
'3','4','5','6','7','8','9',' ',
',','?','.','!'};
if (password.isPasswordOk() && new_CharSet != null) {
duplicates = EncryptionUtils.containsDuplicates(new_CharSet) ;
if(!duplicates && new_CharSet.length>=40) {
KeyGenerator keyGen = new KeyGenerator(password.getPassword(),new_CharSet, byte_Plain);
setSecurityLevel(password.getPassword(), security);
KEY_MAP.clear();
PLAIN_MAP.clear();
PLAIN_KEY_MAP.clear();
PLAIN_BYTE_MAP.clear();
for (int i = 0; i < new_CharSet.length; i++) {
PLAIN_MAP.put(keyGen.getBase_key()[i], keyGen.getNew_Key()[i]);
KEY_MAP.put(keyGen.getNew_Key()[i], keyGen.getBase_key()[i]);
}
for (int i = 0; i < byte_Plain.length; i++) {
PLAIN_BYTE_MAP.put(keyGen.getBase_Byte()[i], keyGen.getNew_Byte()[i]);
PLAIN_KEY_MAP.put(keyGen.getNew_Byte()[i], keyGen.getBase_Byte()[i]);
}
return true;
}
else if(duplicates && new_CharSet.length>=40){
new InvalidCharacterSetException("The submitted character set contains duplicates!");
return false;
}
else if(!duplicates && new_CharSet.length<40){
new InvalidCharacterSetException("The submitted character set does not meet the character amount specification!");
return false;
}
else{
new InvalidCharacterSetException("The submitted character set contains less than then minimum allow amount of characters!");
return false;
}
}
else if (password.isPasswordOk() && new_CharSet == null) {
KeyGenerator keyGen = new KeyGenerator(password.getPassword(),plain_char_set, byte_Plain);
setSecurityLevel(password.getPassword(), security);
KEY_MAP.clear();
PLAIN_MAP.clear();
PLAIN_KEY_MAP.clear();
PLAIN_BYTE_MAP.clear();
for (int i = 0; i < plain_char_set.length; i++) {
PLAIN_MAP.put(keyGen.getBase_key()[i], keyGen.getNew_Key()[i]);
KEY_MAP.put(keyGen.getNew_Key()[i], keyGen.getBase_key()[i]);
}
for (int i = 0; i < byte_Plain.length; i++) {
PLAIN_BYTE_MAP.put(keyGen.getBase_Byte()[i], keyGen.getNew_Byte()[i]);
PLAIN_KEY_MAP.put(keyGen.getNew_Byte()[i], keyGen.getBase_Byte()[i]);
}
return true;
} else {
new InvalidPasswordException("The submitted password is not valid");
return false;
}
}
/*
* Method used to swap the elements of the input array.
* The elements will be swapped using 4 nested loops with
* different swap indexes. The elements are swapped around
* millions of times
*/
public static char[] swapCharacters(char[] chars){
for(int i1 = 0; i1<chars.length-SWAP_INDEX_1; i1++){
char temp = chars[i1];
chars[i1] = chars[i1+SWAP_INDEX_1];
chars[i1+SWAP_INDEX_1] = temp;
for(int i2 = 0; i2<chars.length-SWAP_INDEX_2; i2++){
char temp2 = chars[i2];
chars[i2] = chars[i2+SWAP_INDEX_2];
chars[i2+SWAP_INDEX_2] = temp2;
for(int i3 = 0; i3<chars.length-SWAP_INDEX_3; i3++){
char temp3 = chars[i3];
chars[i3] = chars[i3+SWAP_INDEX_3];
chars[i3+SWAP_INDEX_3] = temp3;
for(int i4 = SWAP_INDEX_4; i4<chars.length; i4++){
char temp4 = chars[i4];
chars[i4] = chars[i4-SWAP_INDEX_4];
chars[i4-SWAP_INDEX_4] = temp4;
}
}
}
}
return chars;
}
/*
* Method used to swap the elements which were previously swapped
* by the swapCharacters method back to their original index. The swap
*/
private static char[] revertCharacterSwap(char[] chars) {
for (int i1 = chars.length - (SWAP_INDEX_1+1); i1 >= 0; i1--) {
for (int i2 = chars.length - (SWAP_INDEX_2+1); i2 >= 0; i2--) {
for (int i3 = chars.length - (SWAP_INDEX_3+1); i3 >= 0; i3--) {
for (int i4 = chars.length - 1; i4 >= (SWAP_INDEX_4); i4--) {
char temp4 = chars[i4];
chars[i4] = chars[i4 - SWAP_INDEX_4];
chars[i4 - SWAP_INDEX_4] = temp4;
}
char temp3 = chars[i3];
chars[i3] = chars[i3 + SWAP_INDEX_3];
chars[i3 + SWAP_INDEX_3] = temp3;
}
char temp2 = chars[i2];
chars[i2] = chars[i2 + SWAP_INDEX_2];
chars[i2 + SWAP_INDEX_2] = temp2;
}
char temp = chars[i1];
chars[i1] = chars[i1 + SWAP_INDEX_1];
chars[i1 + SWAP_INDEX_1] = temp;
}
return chars;
}
/*
* Method which swaps the elements match to the character set
* with the corresponding key element. The method will also create
* an array holing information about the case of each character. The method
* will also perform a character swap with a call to the swapCharacters method. After
* the process is completed this method will return a set of characters holding the
* coded message along with a set of characters holding case information. The
* two are divided by a special sequence of symbols in order to distinguish the
* the two. The return message will then be passed further for further encryption.
*/
private final static EncryptedMessage applySubstitution(char[] message) {
char[] case_Binary = new char[message.length];
char[] code_Message = new char[message.length];
for(int i = 0; i < message.length; i++) {
if (Character.isUpperCase(message[i])) {
case_Binary[i] = '1';
}
if (Character.isLowerCase(message[i])) {
case_Binary[i] = '0';
}
code_Message[i] = Character.toUpperCase(message[i]);
if(PLAIN_MAP.containsKey(code_Message[i])){
code_Message[i] = PLAIN_MAP.get(code_Message[i]);
}
}
return new EncryptedMessage(swapCharacters(code_Message),case_Binary);
}
/*
* Method which reverts the character substitution performed by the
* applySubstitution. It does this by reverting the pattern in which the substitution
* was made. This will separate and analyze the message along with the case data
* and once this is done it will also perform a call to the revertCharacterSwap method
* in order to also unswap the order of the characters to their original state.
* Once the substitution and the character swap has been reversed it will further
* analyze case data determine the case of each character. Upon completion it
* will return the decrypted message.
*/
private final static String revertSubstitution(EncryptedMessage message) {
char[] code_Message = revertCharacterSwap(message.getCharMessage());
char[] case_Message = message.getCharCase();
for (int i = 0; i < code_Message.length; i++) {
if(KEY_MAP.containsKey(code_Message[i])){
code_Message[i] = KEY_MAP.get(code_Message[i]);
}
if (case_Message[i] == '1') {
code_Message[i] = Character.toUpperCase(code_Message[i]);
}
if (case_Message[i] == '0') {
code_Message[i] = Character.toLowerCase(code_Message[i]);
}
}
return String.valueOf(code_Message);
}
/*
* Method used to further increases the obfuscation level of the message by adding
* random numbers and characters to the body of the already encrypted message. This
* is done at key places of the message in order to allow the subtraction of the original
* version of the encryption without having to deal with the extract characters and numbers
* added by this function. The function a
* the process can then be reversed with an additional key.
*/
private final static LinkedList<String> addRandom(String code) {
LinkedList<String> cypherList = new LinkedList<>();
EncryptedMessage case_and_code = applySubstitution(code.toCharArray());
String code_message = case_and_code.getMessage();
String code_case = case_and_code.getCase();
for (int index = 0; index < code_message.length(); index++) {
cypherList.add(EncryptionUtils.getRandomString(max_decoys,code_message.charAt(index),insertion_index));
}
cypherList.addFirst("" + (EncryptionUtils.getRandomInterval(100,999)));
cypherList.addLast(code_case + EncryptionUtils.getRandomInterval(100,999)+EncryptionUtils.getRandomString(2));
return cypherList;
}
/*
* Method used to remove all previously added obfuscation elements. The method
* will loop through the values of a given list and it will filter the orignal's
* message values into their respective char arrays, one holding the code and the
* other holding the case related data.
*/
private final static EncryptedMessage removeRandom(List<String> cypher_List) {
StringBuilder string_Builder = new StringBuilder();
char[] case_message = new char[cypher_List.get(cypher_List.size()-1).length()-5];
char[] code_message = new char[cypher_List.size()-1];
for (int index = 0; index < cypher_List.size() - 1; index++) {
if (index >= 1){
try{
string_Builder.append(String.valueOf(cypher_List.get(index).toCharArray()[insertion_index]));
}catch(ArrayIndexOutOfBoundsException e){ /*TODO NOTHING*/}
}
if (index < case_message.length){
case_message[index] = cypher_List.get(cypher_List.size() - 1).toCharArray()[index];
}
}
code_message = string_Builder.toString().toCharArray();
return new EncryptedMessage(code_message, case_message);
}
/*
* Method used to further encrypt the message by replacing the
* first first digit of every value on every index of the byte array
* except for indexes that hold a negative value. This method converts
* the byte value to String which is than formated and casted back to
* a byte. A modification can be perform that may allow each index to
* be replace using a numerical value check!
*/
private final static Byte[] replaceBytes(Byte[] bytes) {
Byte[] temp_Bytes = Arrays.copyOf(bytes, bytes.length);
for (int i = 0; i < temp_Bytes.length; i++) {
if (temp_Bytes[i]>=0) {
String temp_String = String.valueOf(temp_Bytes[i]);
String new_Value = PLAIN_BYTE_MAP.get(Integer.toString(temp_Bytes[i]).substring(0, 1))+ temp_String.substring(1);
temp_Bytes[i] = Byte.valueOf(new_Value);
}
}
return temp_Bytes;
}
/*
* Method used to revert the previously replaced bytes back to
* to normal. The byte array will go through an identical procedure
* as the one performed in the replace bytes method in order to
* give each byte index the original value of the first index.
*/
private final static Byte[] revertByteReplacement(Byte[] bytes) {
Byte[] temp_Bytes = Arrays.copyOf(bytes, bytes.length);
for (int i = 0; i < temp_Bytes.length; i++) {
if (temp_Bytes[i]>=0) {
String temp_String = String.valueOf(temp_Bytes[i]);
String new_Value = PLAIN_KEY_MAP.get(Integer.toString(temp_Bytes[i]).substring(0, 1))+ temp_String.substring(1);
temp_Bytes[i] = Byte.valueOf(new_Value);
}
}
return temp_Bytes;
}
/*
* Method used to swap the elements of the input array.
* The elements will be swapped using 3 nested loops with
* different swap indexes. The elements are swapped around
* millions of times.
*/
private final static byte[] swapBytes(byte[] bytes){
for(int i1 = 0; i1<bytes.length-SWAP_INDEX_1; i1++){
byte temp = bytes[i1];
bytes[i1] = bytes[i1+SWAP_INDEX_1];
bytes[i1+SWAP_INDEX_1] = temp;
for(int i2 = 0; i2<bytes.length-SWAP_INDEX_2; i2++){
byte temp2 = bytes[i2];
bytes[i2] = bytes[i2+SWAP_INDEX_2];
bytes[i2+SWAP_INDEX_2] = temp2;
for(int i3 = SWAP_INDEX_4; i3<bytes.length; i3++){
byte temp3 = bytes[i3];
bytes[i3] = bytes[i3-SWAP_INDEX_4];
bytes[i3-SWAP_INDEX_4] = temp3;
}
}
}
return bytes;
}
/*
* Method used to swap the elements which were previously swapped
* by the swapBytes method back to their original index. The swap
*/
private final static byte[] unSwapBytes(byte[] bytes){
for (int i1 = bytes.length - (SWAP_INDEX_1+1); i1 >= 0; i1--) {
for (int i2 = bytes.length - (SWAP_INDEX_2+1); i2 >= 0; i2--) {
for (int i3 = bytes.length - 1; i3 >= (SWAP_INDEX_4); i3--) {
byte temp3 = bytes[i3];
bytes[i3] = bytes[i3 - SWAP_INDEX_4];
bytes[i3 - SWAP_INDEX_4] = temp3;
}
byte temp2 = bytes[i2];
bytes[i2] = bytes[i2 + SWAP_INDEX_2];
bytes[i2 + SWAP_INDEX_2] = temp2;
}
byte temp = bytes[i1];
bytes[i1] = bytes[i1 + SWAP_INDEX_1];
bytes[i1 + SWAP_INDEX_1] = temp;
}
return bytes;
}
/**
* Reverses the byte array for further increase obfuscation.
*/
private final static byte[] revertBytes(Byte[] encryption){
Byte[] byte_Array = encryption;
List<Byte> byte_List = Arrays.asList(byte_Array);
Collections.reverse(byte_List);
return EncryptionUtils.toPrimitives(replaceBytes(byte_Array));
}
/**
* Reverses the byte array to its original state
*/
private final static byte[] revertBytesBack(Byte[] encryption){
Byte[] byte_Array = encryption;
List<Byte> byte_List = Arrays.asList(byte_Array);
Collections.reverse(byte_List);
return EncryptionUtils.toPrimitives(revertByteReplacement(byte_Array));
}
/*
* Method which checks the security level required by the user
* and base on the specifications it will adjust the amount of characters per character
* which are to be added to the encrypted message. The higher the security level the
* higher the number of added characters and vice versa.
*/
private final static void setSecurityLevel(String password, SecurityLevel security){
if(security!=null){
switch(security){
case LOW:
max_decoys = 1;
insertion_index = 0;
break;
case MEDIUM:
max_decoys = 4;
insertion_index = 3;
break;
case HIGH:
max_decoys = 8;
insertion_index = 2;
break;
case VERY_HIGH:
max_decoys = 16;
insertion_index = 4;
break;
default:
break;
}
}
}
/**
* <h1>Encrypted Message</h1>
*
* This class is used as a wrapper containing both
* the code of the actual String and case data of
* said String.
*
* @author Eudy Contreras
* @version 1.1
* @since 2016-08-16
*/
private static class EncryptedMessage{
private final String code_message;
private final String case_message;
public EncryptedMessage(char[] codeX, char[] caseX){
this.code_message = String.valueOf(codeX);
this.case_message = String.valueOf(caseX);
}
private final String getMessage(){
return code_message;
}
private final String getCase(){
return case_message;
}
private final char[] getCharMessage(){
return code_message.toCharArray();
}
private final char[] getCharCase(){
return case_message.toCharArray();
}
}
/**
* <h1>Encryption Utility</h1>
*
* This class contains various functions used by the program.
*
* @author Eudy Contreras
* @version 1.1
* @since 2016-08-16
*/
public static class EncryptionUtils{
/*
* Method which converts an Object byte array to a primitive type.
*/
private static byte[] toPrimitives(Byte[] byte_Object){
byte[] bytes = new byte[byte_Object.length];
int i = 0;
for(Byte byte_Objects : byte_Object)bytes[i++] = byte_Objects;
return bytes;
}
/*
* Method which converts a primitive byte array to an object byte array.
*/
private static Byte[] toByteObject(byte[] byte_prime) {
Byte[] bytes = new Byte[byte_prime.length];
int i = 0;
for (byte byte_Primes : byte_prime) bytes[i++] = byte_Primes;
return bytes;
}
/*
* Method which converts an Object byte array to a primitive type.
*/
@SuppressWarnings("unused")
private static char[] toCharPrimitive(Character[] char_Object){
char[] chars = new char[char_Object.length];
int i = 0;
for(Character char_Objects : char_Object)chars[i++] = char_Objects;
return chars;
}
/*
* Method which converts a primitive byte array to an object byte array.
*/
@SuppressWarnings("unused")
private static Character[] toCharObject(char[] char_prime) {
Character[] chars = new Character[char_prime.length];
int i = 0;
for (char chars_Primes : char_prime) chars[i++] = chars_Primes;
return chars;
}
/*
* Method which prints the content of a byte array.
*/
public static void printBytes(byte[] byteEncryption){
if(byteEncryption!=null){
System.out.println(Base64.encode(byteEncryption));
}
}
/*
* Method which splits a String at a given character sequence
* and returns List made out of all the sections.
*/
private static List<String> fromStringToList(String list, String sequence) {
return Arrays.asList(list.split(sequence));
}
/*
* Method which generates a secure random within a
* given range.
*/
private static int getRandom(int value){
SecureRandom rand = new SecureRandom();
return rand.nextInt(value);
}
/*
* Method which generates a secure random within a
* given interval.
*/
private static int getRandomInterval(int minValue, int maxValue) {
SecureRandom rand = new SecureRandom();
return rand.nextInt(maxValue + 1 - minValue) + minValue;
}
/*
* Method which returns a random String of the specified
* Length containing a non random element located at the given index.
*/
private static String getRandomString(int length, char code, int index){
char[] randomString = new char[length];
for(int i = 0;i<length; i++){
randomString[i] =added[getRandom(added.length)];
if(i==index){
randomString[i] = code;
}
}
return String.valueOf(randomString);
}
/*
* Method which returns a random String of the specified
* Length.
*/
private static String getRandomString(int length){
char[] randomString = new char[length];
for(int i = 0;i<length; i++){
randomString[i] =added[getRandom(added.length)];
}
return String.valueOf(randomString);
}
/*
* Method which checks if a char array contains any duplicate values
*/
public static boolean containsDuplicates(final char[] chars) {
final int max_size = 99999;
BitSet bitset = new BitSet(max_size + 1);
bitset.set(0, max_size, false);
for (int item : chars) {
if (!bitset.get(item)) {
bitset.set(item, true);
} else
return true;
}
return false;
}
}
/**
* Class which is in charge of generating new unique keys based on the
* the given password and character set if any. Each
* @author Eudy Contreras
*
*/
private static class KeyGenerator {
private char[] char_key_set;
private char[] char_base_set;
private String[] byte_key_set;
private String[] byte_base_set;
private SecureRandom charRandom;
private SecureRandom byteRandom;
public KeyGenerator(String password, char[] charSet, String[] byteSet) {
this.charRandom = this.getSha1Prng();
this.byteRandom = this.getSha1Prng();
this.generateKey(password,charRandom,charSet);
this.generateKey(password,byteRandom,byteSet);
this.shuffle(char_key_set,charRandom,ShuffelMethod.RICHARD_DURSTENFELD_SHUFFLE);
this.shuffle(byte_key_set,byteRandom);
}
/*
* Creates a new key based on a given password. The password given will
* always reproduce the same key if combined with the same set of
* characters.
*/
private void generateKey(String password,SecureRandom charRandom, char[] baseChars) {
charRandom.setSeed(password.getBytes(StandardCharsets.UTF_8));
char_base_set = new char[baseChars.length];
char_base_set = Arrays.copyOf(baseChars, baseChars.length);
char_key_set = new char[char_base_set.length];
char_key_set = Arrays.copyOf(char_base_set, baseChars.length);
}
private void generateKey(String password, SecureRandom byteRandom, String[] baseBytes) {
byteRandom.setSeed(password.getBytes(StandardCharsets.UTF_8));
byte_base_set = new String[baseBytes.length];
byte_base_set = Arrays.copyOf(baseBytes, baseBytes.length);
byte_key_set = new String[byte_base_set.length];
byte_key_set = Arrays.copyOf(byte_base_set, baseBytes.length);
}
/*
* Method which securely shuffles an array using different conventional
* methods
*/
private void shuffle(char[] char_key,SecureRandom charRandom, ShuffelMethod method) {
switch (method) {
case FISHER_YATES_SHUFFLE:
int index;
for (int i = char_key.length - 1; i > 0; i--) {
index = charRandom.nextInt(i + 1);
if (index != i) {
char_key[index] ^= char_key[i];
char_key[i] ^= char_key[index];
char_key[index] ^= char_key[i];
}
}
break;
case RICHARD_DURSTENFELD_SHUFFLE:
for (int i = char_key.length - 1; i > 0; i--) {
index = charRandom.nextInt(i + 1);
char temp = char_key[index];
char_key[index] = char_key[i];
char_key[i] = temp;
}
break;
default:
break;
}
}
/*
* Method which securely shuffles an array using different conventional
* methods
*/
private void shuffle(String[] byte_key, SecureRandom byteRandom) {
int index;
for (int i = byte_key.length - 1; i > 0; i--) {
index = byteRandom.nextInt(i + 1);
String temp = byte_key[index];
byte_key[index] = byte_key[i];
byte_key[i] = temp;
}
}
private SecureRandom getSha1Prng() {
try {
return SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
private enum ShuffelMethod {
FISHER_YATES_SHUFFLE, RICHARD_DURSTENFELD_SHUFFLE,
}
private char[] getBase_key() {
return char_base_set;
}
private String[] getBase_Byte() {
return byte_base_set;
}
private char[] getNew_Key() {
return char_key_set;
}
private String[] getNew_Byte() {
return byte_key_set;
}
}
/**
* Password class used by the String Encryption Utility
* the pass word must contain at least 6 character.
* @author Eudy Contreras
*
*/
public static class Password{
private String password;
public Password(String password){
this.password = password;
}
private String getPassword(){
return password;
}
private boolean isPasswordOk(){
return password.length()>=6 && password!=null;
}
}
public enum SecurityLevel{
LOW,MEDIUM,HIGH,VERY_HIGH
}
private static class InvalidPasswordException extends Exception {
private static final long serialVersionUID = 1L;
public InvalidPasswordException(String message) {
super(message);
System.err.println(this.getMessage());
System.err.println("Please look at the documentation for more information");
}
}
private static class InvalidCharacterSetException extends Exception {
private static final long serialVersionUID = 1L;
public InvalidCharacterSetException(String message) {
super(message);
System.err.println(this.getMessage());
System.err.println("Please look at the documentation for more information");
}
}
public static void main(String[] args) {
char[] new_char_set =
{'D',' ','F','G','H','Ä','U','J',
'A','L','Z','Å','N',',','P','Q',
'W','S','T','Ö','.','V','R','X',
'Y','M','!','B','O','4','6','1',
'8','3','2','9','0','5','7','E',
'C','?','I','K','$','/','@','*'};
char[] plain_char_set =
{'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','Ö','Ä','Å','0','1','2',
'3','4','5','6','7','8','9',' ',
',','?','.','!'};
long encrypt_start_time = System.currentTimeMillis();
byte[] encryption = StringEncrypter.encrypt("Your message is now secure!", new Password("password"));
long encrypt_end_time = System.currentTimeMillis();
System.out.println("Encryption speed: "+(encrypt_end_time - encrypt_start_time)+ " Milliseconds");
System.out.println("Actual encrypted message:");
System.out.println("////////////////////////////////////////////////////////////////////////////////");
System.out.println("");
EncryptionUtils.printBytes(encryption);
System.out.println("");
System.out.println("////////////////////////////////////////////////////////////////////////////////");
long decrypt_start_time = System.currentTimeMillis();
System.out.println(StringEncrypter.decrypt(encryption,new Password("password")));
System.out.println(StringEncrypter.decrypt(Base64.decode("HJYTHTgcPiMcHBgNGhw+HBgcOBgYJBzDGhMOHTYzPh80HIUcwx8+GBgcDYUdOBwYGB9fPh8cNjMzNyQYPhwLGD4QNcM+GDU+wxgdPhwfYgs0Djgkwz5fDSY+OBIRMxA2Iic5HBhfND43GITDEhgYOT4LPpZhPhgdEyM1DZYcPhwaCz4+GBg5NjcyORwzwxwzNzI3MzQeJsMzGAs+HGEzEF83Mzc+GBw3hDMcHA4cNCVRPjY4GBEyEYVTOT4YNxwHPiccHA4YGDQYHBzDNhwaOT8+BwccGBgcHBw0ND4+NR0cHJY1HAc+NTI2Bx1h"),new Password("password")));
long decrypt_end_time = System.currentTimeMillis();
System.out.println("Decryption speed: "+(decrypt_end_time - decrypt_start_time)+ " Milliseconds");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment