This question is related to String Encryption String Encryption which is a previous post made by me regarding this question. I was advised to make another question for another round of reviews so here it goes. I try to follow nearly all of the recommendations given by the community and this is the end result.
This question is related to String Encryption which is a previous post made by me regarding this question. I was advised to make another question for another round of reviews so here it goes. I try to follow nearly all of the recommendations given by the community and this is the end result.
This question is related to String Encryption which is a previous post made by me regarding this question. I was advised to make another question for another round of reviews so here it goes. I try to follow nearly all of the recommendations given by the community and this is the end result.
import java.nio.charset.Charset;
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;
/**
* <h1>String Encrypter</h1>
*
* This programs allows you encrypt a Stringstring 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 Stringstring.
* 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 Stringstring the object
* must be passed through the decrypt method of this program which will format and reconstruc the
* Stringstring 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 final static Charset format = Charset.forName("UTF-8");
private final static char[] added plain = {'L','3','5','G','0','Ä','1','0',
{'A','D''B','9''C','Å''D','N''E','C''F','0''G','Y''H',
'W''I','S''J','8''K','Ö''L','4''M','V''N','4''O','1''P',
'Q','7''R','K''S','6''T','O''U','3''V','6''W','X',
'8''Y','3''Z','2''Ö','9''Ä','Å','0','5''1','7'};
/*'2',
* Meps which hold the encryption base and key data'3','4','5','6','7','8','9',' 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 final static finalchar[] Map<String,key String> plain_Byte_Map = new HashMap<String {'D',' String>()','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'};
private final static finalchar[] Map<Stringadded =
{'L','3','5','G','0','Ä','1','0',
String> key_Byte_Map = new HashMap<String 'A','D','9','Å','N','C','0','Y',
String>() 'W','S','8','Ö','4','V','4','1',
'Q','7','K','6','O','3','6','X',
'8','3','2','9','0','5','7'};
private final static String[] byte_Plain =
{"1","2","3","4","5","6","7","8","9","0"};
private final static String[] byte_Key =
{"8","0","5","4","9","6","1","3","7","2"};
private final static Map<Character, Character> plain_Map;
static
{
plain_Map = new HashMap<Character, Character>();
for(int i = 0; i<plain.length; i++){
plain_Map.put(plain[i],key[i]);
}
}
private final static Map<Character, Character> key_Map;
static
{
key_Map = new HashMap<Character, Character>();
for(int i = 0; i<plain.length; i++){
key_Map.put(key[i],plain[i]);
}
}
private static Map<String, String> plain_Byte_Map;
static
{
plain_Byte_Map = new HashMap<String, String>();
for(int i = 0; i<byte_Plain.length; i++){
plain_Byte_Map.put(byte_Plain[i],byte_Key[i]);
}
}
private final static Map<String, String> key_Byte_Map;
static
{
key_Byte_Map = new HashMap<String, String>();
for(int i = 0; i<byte_Plain.length; i++){
key_Byte_Map.put(byte_Key[i],byte_Plain[i]);
}
}
/**
* 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 performace 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 final static int max_additions = 5;6;
/*
* The index in which the actually code character will be inserted.added too
* the index must be a number between 0 and the max_additions value-1.
*/
private final static int insertion_index = 2;
/**
* Method used for encrypting a Stringstring. The String passed through
* this method will be encrypted and returned as byte array.
* The Stringstring will go through a series of encryption and obsfuscation
* methodsmethod in order to assure that the contents of the string are kept
* private static and secure.
*
* @param message String message which you wish to encrypt.
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message){
return encrypt(message,null,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 obsfuscation
* method in order to assure that the contents of the string are kept
* private and secure.
* This method allows the input of a custom passwordkey set to be associatedused
* by this program in replacement of the originals. The key must contain all letters of the
* swedish dictionary as well as a space character represented as
* a character with a space in between and the standard comma sign.
* generated * <h1>Knowing the key. Theused passwordby willthis beprogram neededis fornot decryptionenough ofin Stringsorder
* whichto weredecode encryptedthe usingcontent of the submittedstrings password.encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param passwordnew_Key :The passwordkey to be associatedpassed withas thea encryptionnew replacement key. The passwordkey set must be at least 6 * be 44 characters long and cannot contain duplicates. If the key is
* not 44 characters long it will simply be ignore and not used. The passwordkey
* must becontain atthe leaststandard 6comma, charactersperiod, longquestion mark, exclamation mark
* as well as the space chararcter ' '.
* @return Returns the Stringstring given Stringstring as an encrypted byte array.
*/
public static byte[] encrypt(String message,Password passwordchar[]new_Key){
return encrypt(message,password,null,new_Key,null);
}
/**
* Method used for encrypting a Stringstring. The String passed through
* this method will be encrypted and returned as byte array.
* The Stringstring will go through a series of encryption and obsfuscation
* method in order to assure that the contents of the Stringstring are kept
* private and secure.
* This method allows the input of a custom character set and a passwordkey set to be used
* whichby arethis toprogram bein associatedreplacement withof the generated keyoriginals. bothThe thecharacter passwordsets andpassed through
* thethis submittedconstructor cannot contain any duplicates.
* <p>
* <h1>The character set willand the key set must be needed for decryption * of Stringsequal whichlenghts wereand encryptedneither usingthe character set nor the key may have repeating elements.
* submittedEvery passwordelement andfound in the character set. must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param passwordnew_CharSet :The passwordnew character set to be associatedpassed withas thea encryptionnew chararcter set. The passwordcharacter
must be at least 6* charactersset longcannot contain duplicates.
* @param new_CharSetnew_Key :The characterkey setto usedbe bypassed theas encrypteda Stringnew replacement key. The characterkey set must contain
* set cannotall containthe anycharacters duplicatespresent andin mustthe becharacter atset leastand 40cannot characterscontain long.duplicates
* @return Returns the Stringstring given Stringstring as an encrypted byte array.
*/
public static byte[] encrypt(String message, Password password, char[] new_CharSet, char[]new_Key){
return encrypt(message,password,new_CharSet,new_Key,null);
}
/**
* Method used for encrypting a Stringstring. The String passed through
* this method will be encrypted and returned as byte array.
* The Stringstring will go through a series of encryption and obsfuscation
* method in order to assure that the contents of the Stringstring are kept
* private and secure.
* This method allows the input of a custom character set, akey passwordset and theByte securitykey levelto be used
* whichby isthis toprogram bein associatedreplacement withof the generated keyoriginals. The password,character thesets securitypassed levelthrough
and * this constructor cannot contain any duplicates.
* the<p>
submitted * <h1>The character set willand the key set must be needed for decryption * of Stringsequal whichlenghts wereand encryptedneither usingthe character set nor the key may have repeating elements.
* submittedEvery password,element found in the character set must be present in the key set and securitymost level.preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* The byte key must contain 10 unique digits with numbers
* from 0 to 9 in any desired order.
*
* <h1>Knowing the byte key used by this program is not enough in order
* to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param passwordnew_CharSet :The password to be associated with the encryption. The password must be at least 6 characters long.
new character set to be *passed @paramas new_CharSeta :Thenew characterchararcter set used by the encrypted String. The character
* set cannot contain any duplicates and must be at least 40 characters long.
* @param securitynew_Key :The level of security which iskey to be assignpassed toas thea encryptednew messagereplacement key. The higherkey theset securitymust levelcontain
* all the highercharacters present in the levelcharacter ofset encryptionand butcannot alsocontain theduplicates
slower the encryption process will* be.@param new_byte_Key :The lowerkey theto securitybe levelpassed as a new replacement key.
* theThe lowerkey theset encryptionmus butbe the10 fastercharacters thelong encryptionand willcannot becontain duplicates.
* @return Returns the Stringstring given Stringstring as an encrypted byte array.
*/
public static byte[] encrypt(String message, Password password, char[] new_CharSet, SecurityLevelchar[]new_Key, securityString[] new_byte_Key){
if(prepareEncryptionsetCharset_setKey_setByteKey(new_CharSet, passwordnew_Key, security)new_byte_Key){;
String cypher = addRandom(message).toString();
byte[] encryption = cypher.getBytes(format);
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 orignal content
*
* @param encryption :byte array containing the encrypted string.
* @return :Returns a decypted string.
*/
public static String decrypt(byte[] encryption){
return decrypt(encryption,null,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 orignal content.
* This method allows the input of a custom key set to be used
* by this program in replacement of the passwordoriginals. associatedThe key must contain all letters of the
* swedish dictionary as well as a space character represented as
* a character with a space in between and the standard comma sign.
*
* <h1>Knowing the encryptedkey fileused whichby this program is needednot enough in order to be able * to viewdecode the file.content of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted Stringstring.
* @param passwordnew_Key :The password associatedkey to thebe filepassed as a new replacement key. NeededThe inkey orderset must
* tobe view44 characters long and cannot contain duplicates. If the file!key is
* not 44 characters long it will simply be ignore and not used. The passwordkey
* must matchcontain the passwordstandard usedcomma, toperiod, encryptquestion mark, exclamation mark
* as well as the filespace chararcter ' '.
* @return :Returns a decypted Stringstring.
*/
public static String decrypt(byte[] encryption, Passwordchar[] passwordnew_Key){
return decrypt(encryption,password,null,new_Key,null);
}
/**
* Method used for decrypting a Stringstring in the form
* of a encrypted byte array. The array will go through a series
* of decryption methods in order to uncover the orignal content.
*
* This method allows the input of thea custom character set and thea password
key set to be used
* associated with the encrypted* file.by Boththis theprogram characterin setreplacement andof the password
originals. The character sets passed *through
are needed in order to* viewthis theconstructor originalcannot Stringcontain contentany duplicates.
* <p>
* @param encryption<h1>The :bytecharacter arrayset containingand the encryptedkey String.set must be
* @paramof passwordequal :Thelenghts passwordand associatedneither tothe character set nor the filekey may have repeating elements. Needed * Every element found in orderthe character set must be present in the key set and most preferably
* toat viewa thedifferent file!index<h1>
The password must match * <p>
* <h1>Knowing either the passwordchararcter set or the key used by this program doest not garantee
* the ability to encryptdecode the filecontent of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted string.
* @param new_CharSet :The new character set associatedto withbe thepassed encryptedas filea new chararcter set. The character
* neededset incannot ordercontain duplicates.
* @param new_Key :The key to viewbe passed as a new replacement key. The key set must contain
* all the file!characters Mustpresent matchin the character set used toand encryptcannot thecontain Stringduplicates
* @return Returns a decypted Stringstring.
*/
public static String decrypt(byte[] encryption, Password password, char[] new_CharSet, char[]new_Key){
return decrypt(encryption,password,new_CharSet,new_Key,null);
}
/**
* Method used for decrypting a Stringstring in the form
* of a encrypted byte array. The array will go through a series
* of decryption methods in order to uncover the orignal content.
*
* This method allows the input of thea custom character set, thekey passwordset and theByte securitykey levelto be used
* associated withby thethis encryptedprogram file.in Allreplacement of the inputs are needed inoriginals. orderThe tocharacter viewsets thepassed originalthrough
* contentthis ofconstructor thecannot filecontain any duplicates.
* <p>
* @param encryption<h1>The :bytecharacter arrayset containingand the encryptedkey String.set must be
* @paramof passwordequal :Thelenghts passwordand associatedneither tothe character set nor the filekey may have repeating elements. Needed * Every element found in orderthe character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to viewdecode the filecontent of the strings encrypted by this program!</h1>
* <p>
* The passwordbyte key must matchcontain 10 unique digits with numbers
* from 0 to 9 in any desired order.
*
* <h1>Knowing the passwordbyte key used by this program is not enough in order
* to encryptdecode the Stringcontent of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted string.
* @param new_CharSet :The new character set associatedto withbe thepassed encryptedas file.Musta matchnew thechararcter set. The character
* set used to encryptcannot thecontain Stringduplicates.
* @param securitynew_Key :The securitykey levelto whichbe ispassed associatedas witha thenew encryptedreplacement Stringkey.Muse matchThe key set must contain
* all the securitycharacters levelpresent usedin the character set and cannot contain duplicates
* @param new_byte_Key :The key to encryptbe thepassed Stringas a new replacement key.
* The key set mus be 10 characters long and cannot contain duplicates.
* @return Returns a decypted Stringstring.
*/
public static String decrypt(byte[] encryption, Password password, char[] new_CharSet, SecurityLevelchar[]new_Key, securityString[] new_byte_Key){
if(prepareEncryptionsetCharset_setKey_setByteKey(new_CharSet, passwordnew_Key, security)new_byte_Key){;
byte[] unswapped_Bytes = revertBytesBack(EncryptionUtils.toByteObject(unSwapBytes(encryption)));
List<String> list = EncryptionUtils.fromStringToList(new String(unswapped_Bytes, format),", ");
EncryptedMessage unScrambled = removeRandom(list);
String decyphered = revertSubstitution(unScrambled);
return decyphered;
}
else{
return "";
}
}
/*
* Method incharged 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',' ',
',','?','.','!'};
private static ifvoid (password.isPasswordOksetCharset_setKey_setByteKey() &&char[] new_CharSet != null) {
, duplicateschar[]new_Key, =String[] EncryptionUtils.containsDuplicates(new_CharSetnew_byte_Key) ;{
if(new_Key!duplicates=null && new_CharSet.length>=40) {
KeyGenerator keyGen =!=null new&& KeyGenerator(passwordnew_Key.getPassword(),new_CharSet, byte_Plain);
length == setSecurityLevel(passwordnew_CharSet.getPassword(), securitylength);{
key_Map.clear();
plain_Map.clear();
key_Byte_Map.clear();
plain_Byte_Map.clear();
for(int i = 0; i < new_CharSeti<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]new_Key[i], keyGen.getNew_Byte()[i]new_CharSet[i]);
key_Byte_Mapplain_Map.put(keyGen.getNew_Byte()[i]new_CharSet[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!"new_Key[i]);
return false;
}
}
else if (password.isPasswordOk()new_Key!=null && new_CharSet == null) {
KeyGenerator keyGen =new_CharSet==null new&& KeyGenerator(passwordnew_Key.getPassword(),plain_char_set, byte_Plain);
setSecurityLevel(passwordlength==plain.getPassword(), securitylength);{
key_Map.clear();
plain_Map.clear();
key_Byte_Map.clear();
plain_Byte_Map.clear();
for(int i = 0; i < plain_char_seti<key.length; i++){
plain_Map.put(keyGen.getBase_key()[i], keyGen.getNew_Key()[i]);
key_Map.put(keyGen.getNew_Key()[i]new_Key[i], keyGen.getBase_key()[i]plain[i]);
}
}
for (int i = 0; iif(new_byte_Key!=null <&& byte_Plainnew_byte_Key.length; i++length==byte_Plain.length){
key_Byte_Map.clear();
plain_Byte_Map.put(keyGen.getBase_Byte for()[i],int keyGeni = 0; i<byte_Plain.getNew_Byte()[i]length; i++);{
key_Byte_Map.put(keyGen.getNew_Byte()[i]new_byte_Key[i], keyGen.getBase_Byte()[i]byte_Plain[i]);
}
return true;
} else {
new InvalidPasswordException("The submitted password is not valid");
return false;
}
}
/*
* Method used to swapp 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
*/
private 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 swapp 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
* whith the correspondnt 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 peform 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 wil 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 obsfuscation 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 substraction of the oginal
* version of the encryption witout having to deal with the extrac 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_additions,code_message.charAt(index),insertion_index));
}
}
cypherList.addFirst("" + (EncryptionUtils.getRandomInterval(100,999)));
cypherList.addLastadd(String.valueOf(code_case) + EncryptionUtils.getRandomInterval(100,999)+EncryptionUtils.getRandomStringgetRandom(210));
return cypherList;
}
/*
* Method used to remove all previously added obsfuscation 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
* othe 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]; 2];
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 Stringstring 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 (Integer.toString(temp_Bytes[i]).charAt(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 throug 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 (Integer.toString(temp_Bytes[i]).charAt(0) != '-') {
String temp_String = String.valueOf(temp_Bytes[i]);
String new_Value = key_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 swapp 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 swapp 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){
// SecureRandom rand = new SecureRandom();
// rand.setSeed(password.getBytes(format));
switch(security){
case LOW:
max_additions = 1;
insertion_index = 0;
break;
case MEDIUM:
max_additions = 4;
insertion_index = 3;
break;
case HIGH:
max_additions = 6;
insertion_index = 2;
break;
case VERY_HIGH:
max_additions = 10;
insertion_index = 7;
break;
default:
break;
}
}
}
/**
* <h1>Encrypted Message</h1>
*
* This class is used as a wrapper containing both
* the code of the actual Stringstring and case data of
* said Stringstring.
*
* @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);
}
public final String getMessage(){
return code_message;
}
public final String getCase(){
return case_message;
}
public final char[] getCharMessage(){
return code_message.toCharArray();
}
public 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日
*/
publicprivate 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.
*/
publicprivate static String printBytes(byte[] binaryEncription){
if(binaryEncription!=null){
return new String(binaryEncription, format);
}
else
return "";
}
/*
* Method which splits a Stringstring 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 Stringstring of the specified
* lenght 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 radom Stringstring of the specified
* lenght.
*/
@SuppressWarnings("unused")
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 = new SecureRandom();
private SecureRandom byteRandom = new SecureRandom();
public KeyGenerator(String password, char[] charSet, String[] byteSet) {
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(format));
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(format));
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;
}
}
public enum ShuffelMethod {
FISHER_YATES_SHUFFLE, RICHARD_DURSTENFELD_SHUFFLE,
}
public char[] getBase_key() {
return char_base_set;
}
public String[] getBase_Byte() {
return byte_base_set;
}
public char[] getNew_Key() {
return char_key_set;
}
public 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','Ö','EncryptionUtils.','V','R','X',
'Y','M','!','B','O','4','6','1',
'8','3','2','9','0','5','7','E',
'C','?','I','K','$','/'getRandomString(10,'@''Ö','*'}1);
long encrypt_start_time = System.currentTimeMillis();
byte[] encryption = StringEncrypter.encrypt("Your message"What is now secureup!!", newNot Password("password"),new_char_set,much SecurityLevel.MEDIUMwhy??");
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("");
System.out.println(EncryptionUtils.printBytes(encryption));
System.out.println("");
System.out.println("////////////////////////////////////////////////////////////////////////////////");
// System.out.println(Arrays.toString(encryption));
long decrypt_start_time = System.currentTimeMillis();
System.out.println(StringEncrypter.decrypt(encryption,new Password("password"),new_char_set,SecurityLevel.MEDIUM));
long decrypt_end_time = System.currentTimeMillis();
System.out.println("Decryption speed: "+(decrypt_end_time - decrypt_start_time)+ " Milliseconds");
}
}
I know the code is long but I tried to documented well and structure it to make easy to read. I sincerely appreciate all your time and I hope my question is well formulated and on topic.
import java.nio.charset.Charset;
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;
/**
* <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 final static Charset format = Charset.forName("UTF-8");
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> key_Byte_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 performace 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_additions = 5;
/*
* The index in which the actually code character will be inserted.
* the index must be a number between 0 and the max_additions 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 obsfuscation
* 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 obsfuscation
* 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 obsfuscation
* 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(format);
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 orignal 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 orignal 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 orignal 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, format),", ");
EncryptedMessage unScrambled = removeRandom(list);
String decyphered = revertSubstitution(unScrambled);
return decyphered;
}
else{
return "";
}
}
/*
* Method incharged 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();
key_Byte_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]);
key_Byte_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();
key_Byte_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]);
key_Byte_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 swapp 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
*/
private 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 swapp 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
* whith the correspondnt 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 peform 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 wil 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 obsfuscation 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 substraction of the oginal
* version of the encryption witout having to deal with the extrac 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_additions,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 obsfuscation 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
* othe 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 (Integer.toString(temp_Bytes[i]).charAt(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 throug 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 (Integer.toString(temp_Bytes[i]).charAt(0) != '-') {
String temp_String = String.valueOf(temp_Bytes[i]);
String new_Value = key_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 swapp 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 swapp 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){
// SecureRandom rand = new SecureRandom();
// rand.setSeed(password.getBytes(format));
switch(security){
case LOW:
max_additions = 1;
insertion_index = 0;
break;
case MEDIUM:
max_additions = 4;
insertion_index = 3;
break;
case HIGH:
max_additions = 6;
insertion_index = 2;
break;
case VERY_HIGH:
max_additions = 10;
insertion_index = 7;
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);
}
public final String getMessage(){
return code_message;
}
public final String getCase(){
return case_message;
}
public final char[] getCharMessage(){
return code_message.toCharArray();
}
public 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 String printBytes(byte[] binaryEncription){
if(binaryEncription!=null){
return new String(binaryEncription, format);
}
else
return "";
}
/*
* 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
* lenght 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 radom String of the specified
* lenght.
*/
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 = new SecureRandom();
private SecureRandom byteRandom = new SecureRandom();
public KeyGenerator(String password, char[] charSet, String[] byteSet) {
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(format));
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(format));
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;
}
}
public enum ShuffelMethod {
FISHER_YATES_SHUFFLE, RICHARD_DURSTENFELD_SHUFFLE,
}
public char[] getBase_key() {
return char_base_set;
}
public String[] getBase_Byte() {
return byte_base_set;
}
public char[] getNew_Key() {
return char_key_set;
}
public 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','$','/','@','*'};
long encrypt_start_time = System.currentTimeMillis();
byte[] encryption = StringEncrypter.encrypt("Your message is now secure!!", new Password("password"),new_char_set, SecurityLevel.MEDIUM);
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("");
System.out.println(EncryptionUtils.printBytes(encryption));
System.out.println("");
System.out.println("////////////////////////////////////////////////////////////////////////////////");
// System.out.println(Arrays.toString(encryption));
long decrypt_start_time = System.currentTimeMillis();
System.out.println(StringEncrypter.decrypt(encryption,new Password("password"),new_char_set,SecurityLevel.MEDIUM));
long decrypt_end_time = System.currentTimeMillis();
System.out.println("Decryption speed: "+(decrypt_end_time - decrypt_start_time)+ " Milliseconds");
}
}
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* <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 final static Charset format = Charset.forName("UTF-8");
private final static char[] plain =
{'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',' ',
',','?','.','!'};
private final static char[] key = {'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'};
private final 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'};
private final static String[] byte_Plain =
{"1","2","3","4","5","6","7","8","9","0"};
private final static String[] byte_Key =
{"8","0","5","4","9","6","1","3","7","2"};
private final static Map<Character, Character> plain_Map;
static
{
plain_Map = new HashMap<Character, Character>();
for(int i = 0; i<plain.length; i++){
plain_Map.put(plain[i],key[i]);
}
}
private final static Map<Character, Character> key_Map;
static
{
key_Map = new HashMap<Character, Character>();
for(int i = 0; i<plain.length; i++){
key_Map.put(key[i],plain[i]);
}
}
private static Map<String, String> plain_Byte_Map;
static
{
plain_Byte_Map = new HashMap<String, String>();
for(int i = 0; i<byte_Plain.length; i++){
plain_Byte_Map.put(byte_Plain[i],byte_Key[i]);
}
}
private final static Map<String, String> key_Byte_Map;
static
{
key_Byte_Map = new HashMap<String, String>();
for(int i = 0; i<byte_Plain.length; i++){
key_Byte_Map.put(byte_Key[i],byte_Plain[i]);
}
}
/**
* This values determined the swap indexes at which the swapping methods
* will operate.
*/
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 performace of the application. The higher the
* number the lower the performance will be but the more populated with random characters
* he encryption will be.
*/
private final static int max_additions = 6;
/*
* The index in which the actually code character will be added too
* the index must be a number between 0 and max_additions-1.
*/
private final 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 obsfuscation
* method in order to assure that the contents of the string are kept
* private static and secure.
*
* @param message String message which you wish to encrypt.
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message){
return encrypt(message,null,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 obsfuscation
* method in order to assure that the contents of the string are kept
* private and secure.
* This method allows the input of a custom key set to be used
* by this program in replacement of the originals. The key must contain all letters of the
* swedish dictionary as well as a space character represented as
* a character with a space in between and the standard comma sign.
* * <h1>Knowing the key used by this program is not enough in order
* to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param new_Key :The key to be passed as a new replacement key. The key set must * be 44 characters long and cannot contain duplicates. If the key is
* not 44 characters long it will simply be ignore and not used. The key
* must contain the standard comma, period, question mark, exclamation mark
* as well as the space chararcter ' '.
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message,char[]new_Key){
return encrypt(message,null,new_Key,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 obsfuscation
* 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 key set to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be * of equal lenghts and neither the character set nor the key may have repeating elements.
* Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param new_CharSet :The new character set to be passed as a new chararcter set. The character
* set cannot contain duplicates.
* @param new_Key :The key to be passed as a new replacement key. The key set must contain
* all the characters present in the character set and cannot contain duplicates
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message, char[] new_CharSet, char[]new_Key){
return encrypt(message,new_CharSet,new_Key,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 obsfuscation
* 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, key set and Byte key to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be * of equal lenghts and neither the character set nor the key may have repeating elements.
* Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* The byte key must contain 10 unique digits with numbers
* from 0 to 9 in any desired order.
*
* <h1>Knowing the byte key used by this program is not enough in order
* to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param new_CharSet : The new character set to be passed as a new chararcter set. The character
* set cannot contain duplicates.
* @param new_Key :The key to be passed as a new replacement key. The key set must contain
* all the characters present in the character set and cannot contain duplicates
* @param new_byte_Key :The key to be passed as a new replacement key.
* The key set mus be 10 characters long and cannot contain duplicates.
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message, char[] new_CharSet, char[]new_Key, String[] new_byte_Key){
setCharset_setKey_setByteKey(new_CharSet,new_Key,new_byte_Key);
String cypher = addRandom(message).toString();
byte[] encryption = cypher.getBytes(format);
byte[] swapped_Bytes = revertBytes(EncryptionUtils.toByteObject(encryption));
return swapBytes(swapped_Bytes);
}
/**
* 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 orignal content
*
* @param encryption :byte array containing the encrypted string.
* @return :Returns a decypted string.
*/
public static String decrypt(byte[] encryption){
return decrypt(encryption,null,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 orignal content.
* This method allows the input of a custom key set to be used
* by this program in replacement of the originals. The key must contain all letters of the
* swedish dictionary as well as a space character represented as
* a character with a space in between and the standard comma sign.
*
* <h1>Knowing the key used by this program is not enough in order * to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted string.
* @param new_Key :The key to be passed as a new replacement key. The key set must
* be 44 characters long and cannot contain duplicates. If the key is
* not 44 characters long it will simply be ignore and not used. The key
* must contain the standard comma, period, question mark, exclamation mark
* as well as the space chararcter ' '.
* @return Returns a decypted string.
*/
public static String decrypt(byte[] encryption, char[] new_Key){
return decrypt(encryption,null,new_Key,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 orignal content.
*
* This method allows the input of a custom character set and a key set to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be
* of equal lenghts and neither the character set nor the key may have repeating elements. * Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted string.
* @param new_CharSet :The new character set to be passed as a new chararcter set. The character
* set cannot contain duplicates.
* @param new_Key :The key to be passed as a new replacement key. The key set must contain
* all the characters present in the character set and cannot contain duplicates
* @return Returns a decypted string.
*/
public static String decrypt(byte[] encryption, char[] new_CharSet, char[]new_Key){
return decrypt(encryption,new_CharSet,new_Key,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 orignal content.
*
* This method allows the input of a custom character set, key set and Byte key to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be
* of equal lenghts and neither the character set nor the key may have repeating elements. * Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* The byte key must contain 10 unique digits with numbers
* from 0 to 9 in any desired order.
*
* <h1>Knowing the byte key used by this program is not enough in order
* to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted string.
* @param new_CharSet :The new character set to be passed as a new chararcter set. The character
* set cannot contain duplicates.
* @param new_Key :The key to be passed as a new replacement key. The key set must contain
* all the characters present in the character set and cannot contain duplicates
* @param new_byte_Key :The key to be passed as a new replacement key.
* The key set mus be 10 characters long and cannot contain duplicates.
* @return Returns a decypted string.
*/
public static String decrypt(byte[] encryption, char[] new_CharSet, char[]new_Key, String[] new_byte_Key){
setCharset_setKey_setByteKey(new_CharSet,new_Key,new_byte_Key);
byte[] unswapped_Bytes = revertBytesBack(EncryptionUtils.toByteObject(unSwapBytes(encryption)));
List<String> list = EncryptionUtils.fromStringToList(new String(unswapped_Bytes, format),", ");
EncryptedMessage unScrambled = removeRandom(list);
String decyphered = revertSubstitution(unScrambled);
return decyphered;
}
private static void setCharset_setKey_setByteKey(char[] new_CharSet, char[]new_Key, String[] new_byte_Key){
if(new_Key!=null && new_CharSet!=null && new_Key.length == new_CharSet.length){
key_Map.clear();
plain_Map.clear();
for(int i = 0; i<new_CharSet.length; i++){
key_Map.put(new_Key[i],new_CharSet[i]);
plain_Map.put(new_CharSet[i], new_Key[i]);
}
}
else if(new_Key!=null && new_CharSet==null && new_Key.length==plain.length){
key_Map.clear();
for(int i = 0; i<key.length; i++){
key_Map.put(new_Key[i],plain[i]);
}
}
if(new_byte_Key!=null && new_byte_Key.length==byte_Plain.length){
key_Byte_Map.clear();
for(int i = 0; i<byte_Plain.length; i++){
key_Byte_Map.put(new_byte_Key[i],byte_Plain[i]);
}
}
}
/*
* Method used to swapp 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
*/
private 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 swapp 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
* whith the correspondnt 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 peform 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 wil 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 obsfuscation 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 substraction of the oginal
* version of the encryption witout having to deal with the extrac 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_additions,code_message.charAt(index),insertion_index));
}
cypherList.addFirst("" + (EncryptionUtils.getRandomInterval(100,999)));
cypherList.add(String.valueOf(code_case) + EncryptionUtils.getRandom(10));
return cypherList;
}
/*
* Method used to remove all previously added obsfuscation 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
* othe 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.size()- 2];
char[] code_message = new char[cypher_List.size()-1];
for (int index = 0; index < cypher_List.size() - 1; index++) {
if (index >= 1)
string_Builder.append(String.valueOf(cypher_List.get(index).toCharArray()[insertion_index]));
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 (Integer.toString(temp_Bytes[i]).charAt(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 throug 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 (Integer.toString(temp_Bytes[i]).charAt(0) != '-') {
String temp_String = String.valueOf(temp_Bytes[i]);
String new_Value = key_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 swapp 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 swapp 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));
}
/**
* <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);
}
public final String getMessage(){
return code_message;
}
public final String getCase(){
return case_message;
}
public final char[] getCharMessage(){
return code_message.toCharArray();
}
public 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日
*/
private 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 prints the content of a byte array.
*/
private static String printBytes(byte[] binaryEncription){
return new String(binaryEncription, format);
}
/*
* 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
* lenght 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 radom string of the specified
* lenght.
*/
@SuppressWarnings("unused")
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);
}
}
public static void main(String[] args) {
// EncryptionUtils.getRandomString(10,'Ö',1);
long encrypt_start_time = System.currentTimeMillis();
byte[] encryption = StringEncrypter.encrypt("What is up!!, Not much why??");
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("");
System.out.println(EncryptionUtils.printBytes(encryption));
System.out.println("");
System.out.println("////////////////////////////////////////////////////////////////////////////////");
// System.out.println(Arrays.toString(encryption));
long decrypt_start_time = System.currentTimeMillis();
System.out.println(StringEncrypter.decrypt(encryption));
long decrypt_end_time = System.currentTimeMillis();
System.out.println("Decryption speed: "+(decrypt_end_time - decrypt_start_time)+ " Milliseconds");
}
}
I know the code is long but I tried to documented well and structure it to make easy to read. I sincerely appreciate all your time and I hope my question is well formulated and on topic.
- 195
- 7
import java.nio.charset.Charset;
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;
/**
* <h1>String Encrypter</h1>
*
* This programs allows you encrypt a stringString 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 stringString.
* 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 stringString the object
* must be passed through the decrypt method of this program which will format and reconstruc the
* stringString 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 final static Charset format = Charset.forName("UTF-8");
private final static char[] plain =
added = {'A''L','B''3','C''5','D''G','E''0','F''Ä','G''1','H''0',
'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''A','8''D','9',' ''Å',
''N',''C','?''0','.''Y','!'};
private final static char[] key =
{'D',' ','F','G','H','Ä','U','J',
'A','L','Z','Å','N',',','P','Q',
'W','S','T''8','Ö','.''4','V','R','X',
'Y','M','!','B','O','4','6','1',
'8','3','2','9','0','5','7','E',
'C','?','I','K'};
private final static char[] added =
{'L''Q','3''7','5''K','G''6','0''O','Ä''3','1''6','0''X',
'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'};
private final static String[] byte_Plain =/*
* {"1","2","3","4","5","6","7","8","9","0"};
Meps which hold the privateencryption finalbase staticand String[]key byte_Keydata =structures.
{"8","0","5","4","9","6","1","3","7","2"};
*/
private final static final Map<Character, Character> plain_Map;
static
{
plain_Map = new HashMap<Character, Character>();
for(int i = 0; i<plain.length; i++){
plain_Map.put(plain[i],key[i]);
}
}
private final static final Map<Character, Character> key_Map;
static
{
key_Map = new HashMap<Character, Character>();
for(int i = 0; i<plain.length; i++){
key_Map.put(key[i],plain[i]);
}
}
private static final Map<String, String> plain_Byte_Map;
static
{
plain_Byte_Map = new HashMap<String, String>();
private static final Map<String, for(intString> ikey_Byte_Map = 0; i<byte_Plain.length; i++){
new HashMap<String, plain_Byte_Map.putString>(byte_Plain[i],byte_Key[i]);
}
}
private final static Map<String, String> key_Byte_Map;
static
{
key_Byte_Map = new HashMap<String, String>();
for(int i = 0; i<byte_Plain.length; i++){
key_Byte_Map.put(byte_Key[i],byte_Plain[i]);
}
}
/**
* 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 performace 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 final static int max_additions = 6;5;
/*
* The index in which the actually code character will be added tooinserted.
* the index must be a number between 0 and the max_additions value-1.
*/
private final 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 obsfuscation
* method in order to assure that the contents of the string are kept
* private static and secure.
*
* @param message String message which you wish to encrypt.
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message){
return encrypt(message,null,null,null);
}
/**
* Method used for encrypting a stringString. The String passed through
* this method will be encrypted and returned as byte array.
* The stringString will go through a series of encryption and obsfuscation
* methodmethods in order to assure that the contents of the stringString are kept
* private and secure.
* This method allows the input of a custom key setpassword to be used
* by this program in replacement of the originals. The key must contain all letters of the
* swedish dictionary as well as a space character represented as
* a characterassociated with a space in between and the standard comma sign.
*
* <h1>Knowing thegenerated key. usedThe bypassword thiswill programbe isneeded notfor enoughdecryption inof orderStrings
* to decodewhich thewere contentencrypted ofusing the strings encrypted by thissubmitted program!</h1>password.
* <p>
* @param message String message which you wish to encrypt.
* @param new_Keypassword :The keypassword to be passed as aassociated newwith replacementthe keyencryption. The key setpassword must be *at beleast 446 characters long and cannot contain duplicates. If the key is
* not 44 characters long it will simply be ignore and not used. The key
*password must contain the standard comma, period, question mark, exclamation mark
* as well asbe theat spaceleast chararcter6 'characters 'long.
* @return Returns the stringString given stringString as an encrypted byte array.
*/
public static byte[] encrypt(String message,char[]new_KeyPassword password){
return encrypt(message,nullpassword,new_Keynull,null);
}
/**
* Method used for encrypting a stringString. The String passed through
* this method will be encrypted and returned as byte array.
* The stringString will go through a series of encryption and obsfuscation
* method in order to assure that the contents of the stringString are kept
* private and secure.
* This method allows the input of a custom character set and a key set to be usedpassword
* bywhich thisare programto inbe replacementassociated ofwith the originals. The character sets passed through
* this constructor cannot contain anygenerated duplicateskey.
* <p>
* <h1>The character set andboth the key set must be
* of equal lenghtspassword and neither the character set nor the key may have repeating elements.
* Every element found in the submitted character set mustwill be present in the key set and most preferably
* at a different index<h1>
* <p>
needed for *decryption <h1>Knowingof eitherStrings thewhich chararcterwere setencrypted orusing the key used by this program doest not garantee
* the ability to decode the content of the stringssubmitted encryptedpassword byand thischaracter program!</h1>set.
* <p>
* @param message String message which you wish to encrypt.
* @param new_CharSetpassword :The new character setpassword to be passed as aassociated newwith chararcterthe setencryption. The character
password must be *at setleast cannot6 containcharacters duplicateslong.
* @param new_Keynew_CharSet :The key to becharacter passedset asused aby newthe replacementencrypted keyString. The key set must containcharacter
* allset thecannot characterscontain presentany induplicates theand charactermust setbe andat cannotleast contain40 duplicatescharacters long.
* @return Returns the stringString given stringString as an encrypted byte array.
*/
public static byte[] encrypt(String message, char[]Password new_CharSetpassword, char[]new_Keychar[] new_CharSet){
return encrypt(message,new_CharSetpassword,new_Keynew_CharSet,null);
}
/**
* Method used for encrypting a stringString. The String passed through
* this method will be encrypted and returned as byte array.
* The stringString will go through a series of encryption and obsfuscation
* method in order to assure that the contents of the stringString are kept
* private and secure.
* This method allows the input of a custom character set, keya setpassword and Byte key tothe besecurity usedlevel
* bywhich thisis programto inbe replacementassociated ofwith the originalsgenerated key. The character sets passed through
* this constructorpassword, cannotthe containsecurity anylevel duplicates.and
* <p>
*the <h1>Thesubmitted character set and the key set mustwill be needed for *decryption of equal lenghts and neitherStrings thewhich characterwere setencrypted norusing the key may have repeating elements.
* Every element found insubmitted thepassword, character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* The byte key must contain 10 unique digits with numbers
* from 0 to 9 in any desiredsecurity orderlevel.
*
* <h1>Knowing the byte key used by this program is not enough in order
* to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param new_CharSetpassword :The newpassword characterto setbe toassociated with the encryption. The password must be passedat asleast a6 newcharacters chararcterlong.
* @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 new_Keysecurity :The keylevel of security which is to be passed asassign ato newthe replacementencrypted keymessage. The keyhigher setthe mustsecurity containlevel
* all the characters present inhigher the character set and cannot contain duplicates
level of encryption but also *the @paramslower new_byte_Keythe :Theencryption keyprocess towill be passed. asThe alower newthe replacementsecurity key.level
* The keythe setlower musthe beencryption 10but charactersthe longfaster andthe cannotencryption containwill duplicatesbe.
* @return Returns the stringString given stringString as an encrypted byte array.
*/
public static byte[] encrypt(String message, char[]Password new_CharSetpassword, char[]new_Keychar[] new_CharSet, String[]SecurityLevel new_byte_Keysecurity){
setCharset_setKey_setByteKey(new_CharSet,new_Key,new_byte_Key);
if(prepareEncryption(new_CharSet, password, security)){
String cypher = addRandom(message).toString();
byte[] encryption = cypher.getBytes(format);
byte[] swapped_Bytes = revertBytes(EncryptionUtils.toByteObject(encryption));
return swapBytes(swapped_Bytes);
}
/**
* 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 orignal content
*
* @param encryption :byte array containing the encrypted string.
* @return :Returns a decypted string.
*/
public static String decrypt(byte[] encryption){
return decrypt(encryption,null,null,null);
}
}else{
return null;
}
}
/**
* Method used for decrypting a stringString in the form
* of a encrypted byte array. The array will go through a series
* of decryption methods in order to uncover the orignal content.
* This method allows the input of a custom key set to be used
* by this program in replacement of the originals. The key must contain all letters of the
* swedish dictionary as well as a space character represented as
* apassword characterassociated with a space in between and the standard comma sign.
*
* <h1>Knowing the key used byencrypted thisfile programwhich is not enoughneeded in order * to decodebe theable contentto ofview the strings encrypted by this program!</h1>file.
* <p>
* @param encryption :byte array containing the encrypted stringString.
* @param new_Keypassword :The key to be passed aspassword aassociated newto replacementthe keyfile. The keyNeeded setin mustorder
* be 44 characters long and cannot contain duplicates.to Ifview the key is
* not 44 characters long it will simply be ignore and not used.file! The key
*password must containmatch the standard comma, period, question mark, exclamation mark
*password asused wellto asencrypt the space chararcter ' '.file
* @return :Returns a decypted stringString.
*/
public static String decrypt(byte[] encryption, char[]Password new_Keypassword){
return decrypt(encryption,nullpassword,new_Keynull,null);
}
/**
* Method used for decrypting a stringString in the form
* of a encrypted byte array. The array will go through a series
* of decryption methods in order to uncover the orignal content.
*
* This method allows the input of a custom character set and a key set to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must bepassword
* of equal lenghts and neither the character setassociated norwith the key may have repeatingencrypted elementsfile. * Every element found inBoth the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garanteepassword
* the abilityare toneeded decodein theorder contentto ofview the strings encrypted byoriginal thisString program!</h1>content
* <p>
* @param encryption :byte array containing the encrypted stringString.
* @param new_CharSetpassword :The new characterpassword setassociated to bethe passedfile. asNeeded ain neworder
chararcter set. * to view the file! The character
password must match the password *used setto cannotencrypt containthe duplicates.file
* @param new_Keynew_CharSet :The key to becharacter passedset asassociated awith newthe replacementencrypted keyfile. The key set must contain
* needed in order *to allview the charactersfile! presentMust inmatch the character set andused cannotto containencrypt duplicatesthe String
* @return Returns a decypted stringString.
*/
public static String decrypt(byte[] encryption, char[]Password new_CharSetpassword, char[]new_Keychar[] new_CharSet){
return decrypt(encryption,new_CharSetpassword,new_Keynew_CharSet,null);
}
/**
* Method used for decrypting a stringString in the form
* of a encrypted byte array. The array will go through a series
* of decryption methods in order to uncover the orignal content.
*
* This method allows the input of a custom character set, key set and Byte key to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be
* of equal lenghts and neither the character set nor the key may have repeating elements.
* Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* The byte key must contain 10 unique digits with numbers
* from 0 to 9 in any desired order.
*
* <h1>KnowingThis method allows the byteinput keyof usedthe bycharacter thisset, programthe ispassword notand enoughthe insecurity orderlevel
* toassociated decodewith the contentencrypted file. All of the stringsinputs encryptedare byneeded thisin program!</h1>order to view the original
* content of the file.
* <p>
* @param encryption :byte array containing the encrypted stringString.
* @param new_CharSetpassword :The new characterpassword setassociated to bethe passedfile. asNeeded ain neworder
chararcter set. * to view the file! The character
password must match the password *used setto cannotencrypt containthe duplicatesString.
* @param new_Keynew_CharSet :The key to becharacter passedset asassociated awith newthe replacementencrypted keyfile. The keyMust setmatch mustthe containcharacter
* all theset charactersused presentto inencrypt the character set and cannot contain duplicatesString.
* @param new_byte_Keysecurity :The keysecurity tolevel bewhich passedis asassociated awith newthe replacementencrypted keyString.Muse match
* The key set mus bethe 10security characterslevel longused andto cannotencrypt containthe duplicatesString.
* @return Returns a decypted stringString.
*/
public static String decrypt(byte[] encryption, char[]Password new_CharSetpassword, char[]new_Keychar[] new_CharSet, String[]SecurityLevel new_byte_Keysecurity){
setCharset_setKey_setByteKeyif(prepareEncryption(new_CharSet,new_Key password,new_byte_Key security);){
byte[] unswapped_Bytes = revertBytesBack(EncryptionUtils.toByteObject(unSwapBytes(encryption)));
List<String> list = EncryptionUtils.fromStringToList(new String(unswapped_Bytes, format),", ");
EncryptedMessage unScrambled = removeRandom(list);
String decyphered = revertSubstitution(unScrambled);
return decyphered;
}
else{
return "";
}
}
/*
* Method incharged 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"};
private static void setCharset_setKey_setByteKey(char[] new_CharSetplain_char_set =
{'A','B','C','D','E','F','G','H', char[]new_Key 'I','J','K','L','M','N','O','P',
String[] new_byte_Key){ 'Q','R','S','T','U','V','W','X',
'Y','Z','Ö','Ä','Å','0','1','2',
'3','4','5','6','7','8','9',' ',
',','?','.','!'};
if(new_Key!=nullpassword.isPasswordOk() && new_CharSet!=null= &&null) new_Key{
duplicates = EncryptionUtils.lengthcontainsDuplicates(new_CharSet) ==;
if(!duplicates && new_CharSet.lengthlength>=40){
KeyGenerator keyGen = new KeyGenerator(password.getPassword(),new_CharSet, byte_Plain);
setSecurityLevel(password.getPassword(), security);
key_Map.clear();
plain_Map.clear();
key_Byte_Map.clear();
plain_Byte_Map.clear();
for(int i = 0; i<new_CharSeti < new_CharSet.length; i++){
plain_Map.put(keyGen.getBase_key()[i], keyGen.getNew_Key()[i]);
key_Map.put(new_Key[i]keyGen.getNew_Key()[i],new_CharSet[i] keyGen.getBase_key()[i]);
plain_Map}
for (int i = 0; i < byte_Plain.length; i++) {
plain_Byte_Map.put(new_CharSet[i]keyGen.getBase_Byte()[i], new_Key[i]keyGen.getNew_Byte()[i]);
key_Byte_Map.put(keyGen.getNew_Byte()[i], keyGen.getBase_Byte()[i]);
}
return true;
}
}
else if(new_Key!=null && new_CharSet==nullduplicates && new_Key.length==plainnew_CharSet.lengthlength>=40){
key_Map.clear();
new forInvalidCharacterSetException(int"The isubmitted =character 0;set i<key.length;contains i++duplicates!"){;
key_Map.put(new_Key[i],plain[i]);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(new_byte_Key!=nullpassword.isPasswordOk() && new_byte_Keynew_CharSet == null) {
KeyGenerator keyGen = new KeyGenerator(password.length==byte_PlaingetPassword(),plain_char_set, byte_Plain);
setSecurityLevel(password.lengthgetPassword(){, security);
key_Map.clear();
plain_Map.clear();
key_Byte_Map.clear();
plain_Byte_Map.clear();
for(int i = 0; i<byte_Plaini < 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]);
key_Byte_Map.put(new_byte_Key[i]keyGen.getNew_Byte()[i],byte_Plain[i] keyGen.getBase_Byte()[i]);
}
return true;
} else {
new InvalidPasswordException("The submitted password is not valid");
return false;
}
}
/*
* Method used to swapp 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
*/
private 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 swapp 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
* whith the correspondnt 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 peform 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 wil 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 obsfuscation 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 substraction of the oginal
* version of the encryption witout having to deal with the extrac 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_additions,code_message.charAt(index),insertion_index));
}
cypherList.addFirst("" + (EncryptionUtils.getRandomInterval(100,999)));
cypherList.add(String.valueOfaddLast(code_case) + EncryptionUtils.getRandomgetRandomInterval(10100,999)+EncryptionUtils.getRandomString(2));
return cypherList;
}
/*
* Method used to remove all previously added obsfuscation 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
* othe 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()- 2];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 stringString 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 (Integer.toString(temp_Bytes[i]).charAt(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 throug 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 (Integer.toString(temp_Bytes[i]).charAt(0) != '-') {
String temp_String = String.valueOf(temp_Bytes[i]);
String new_Value = key_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 swapp 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 swapp 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){
// SecureRandom rand = new SecureRandom();
// rand.setSeed(password.getBytes(format));
switch(security){
case LOW:
max_additions = 1;
insertion_index = 0;
break;
case MEDIUM:
max_additions = 4;
insertion_index = 3;
break;
case HIGH:
max_additions = 6;
insertion_index = 2;
break;
case VERY_HIGH:
max_additions = 10;
insertion_index = 7;
break;
default:
break;
}
}
}
/**
* <h1>Encrypted Message</h1>
*
* This class is used as a wrapper containing both
* the code of the actual stringString and case data of
* said stringString.
*
* @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);
}
public final String getMessage(){
return code_message;
}
public final String getCase(){
return case_message;
}
public final char[] getCharMessage(){
return code_message.toCharArray();
}
public 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日
*/
privatepublic 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.
*/
privatepublic static String printBytes(byte[] binaryEncription){
if(binaryEncription!=null){
return new String(binaryEncription, format);
}
else
return "";
}
/*
* Method which splits a stringString 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 stringString of the specified
* lenght 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 radom stringString of the specified
* lenght.
*/
@SuppressWarnings("unused")
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 = new SecureRandom();
private SecureRandom byteRandom = new SecureRandom();
public KeyGenerator(String password, char[] charSet, String[] byteSet) {
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(format));
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(format));
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;
}
}
public enum ShuffelMethod {
FISHER_YATES_SHUFFLE, RICHARD_DURSTENFELD_SHUFFLE,
}
public char[] getBase_key() {
return char_base_set;
}
public String[] getBase_Byte() {
return byte_base_set;
}
public char[] getNew_Key() {
return char_key_set;
}
public 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) {
// EncryptionUtils.getRandomString(10 char[] new_char_set =
{'D',' ','F','G','H','Ä','U','J',
'A','L','Z','Å','N',',','P','Q',
'W','S','T','Ö',1)'.','V','R','X',
'Y','M','!','B','O','4','6','1',
'8','3','2','9','0','5','7','E',
'C','?','I','K','$','/','@','*'};
long encrypt_start_time = System.currentTimeMillis();
byte[] encryption = StringEncrypter.encrypt("What"Your message is upnow secure!!", Notnew muchPassword("password"),new_char_set, why??"SecurityLevel.MEDIUM);
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("");
System.out.println(EncryptionUtils.printBytes(encryption));
System.out.println("");
System.out.println("////////////////////////////////////////////////////////////////////////////////");
// System.out.println(Arrays.toString(encryption));
long decrypt_start_time = System.currentTimeMillis();
System.out.println(StringEncrypter.decrypt(encryption,new Password("password"),new_char_set,SecurityLevel.MEDIUM));
long decrypt_end_time = System.currentTimeMillis();
System.out.println("Decryption speed: "+(decrypt_end_time - decrypt_start_time)+ " Milliseconds");
}
}
I know the code is long but I tried to documented well and structure it to make easy to read. I sincerely appreciate all your time and I hope my question is well formulated and on topic.
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* <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 final static Charset format = Charset.forName("UTF-8");
private final static char[] plain =
{'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',' ',
',','?','.','!'};
private final static char[] key =
{'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'};
private final 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'};
private final static String[] byte_Plain =
{"1","2","3","4","5","6","7","8","9","0"};
private final static String[] byte_Key =
{"8","0","5","4","9","6","1","3","7","2"};
private final static Map<Character, Character> plain_Map;
static
{
plain_Map = new HashMap<Character, Character>();
for(int i = 0; i<plain.length; i++){
plain_Map.put(plain[i],key[i]);
}
}
private final static Map<Character, Character> key_Map;
static
{
key_Map = new HashMap<Character, Character>();
for(int i = 0; i<plain.length; i++){
key_Map.put(key[i],plain[i]);
}
}
private static Map<String, String> plain_Byte_Map;
static
{
plain_Byte_Map = new HashMap<String, String>();
for(int i = 0; i<byte_Plain.length; i++){
plain_Byte_Map.put(byte_Plain[i],byte_Key[i]);
}
}
private final static Map<String, String> key_Byte_Map;
static
{
key_Byte_Map = new HashMap<String, String>();
for(int i = 0; i<byte_Plain.length; i++){
key_Byte_Map.put(byte_Key[i],byte_Plain[i]);
}
}
/**
* This values determined the swap indexes at which the swapping methods
* will operate.
*/
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 performace of the application. The higher the
* number the lower the performance will be but the more populated with random characters
* he encryption will be.
*/
private final static int max_additions = 6;
/*
* The index in which the actually code character will be added too
* the index must be a number between 0 and max_additions-1.
*/
private final 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 obsfuscation
* method in order to assure that the contents of the string are kept
* private static and secure.
*
* @param message String message which you wish to encrypt.
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message){
return encrypt(message,null,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 obsfuscation
* method in order to assure that the contents of the string are kept
* private and secure.
* This method allows the input of a custom key set to be used
* by this program in replacement of the originals. The key must contain all letters of the
* swedish dictionary as well as a space character represented as
* a character with a space in between and the standard comma sign.
*
* <h1>Knowing the key used by this program is not enough in order
* to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param new_Key :The key to be passed as a new replacement key. The key set must * be 44 characters long and cannot contain duplicates. If the key is
* not 44 characters long it will simply be ignore and not used. The key
* must contain the standard comma, period, question mark, exclamation mark
* as well as the space chararcter ' '.
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message,char[]new_Key){
return encrypt(message,null,new_Key,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 obsfuscation
* 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 key set to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be
* of equal lenghts and neither the character set nor the key may have repeating elements.
* Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param new_CharSet :The new character set to be passed as a new chararcter set. The character
* set cannot contain duplicates.
* @param new_Key :The key to be passed as a new replacement key. The key set must contain
* all the characters present in the character set and cannot contain duplicates
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message, char[] new_CharSet, char[]new_Key){
return encrypt(message,new_CharSet,new_Key,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 obsfuscation
* 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, key set and Byte key to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be * of equal lenghts and neither the character set nor the key may have repeating elements.
* Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* The byte key must contain 10 unique digits with numbers
* from 0 to 9 in any desired order.
*
* <h1>Knowing the byte key used by this program is not enough in order
* to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param message String message which you wish to encrypt.
* @param new_CharSet :The new character set to be passed as a new chararcter set. The character
* set cannot contain duplicates.
* @param new_Key :The key to be passed as a new replacement key. The key set must contain
* all the characters present in the character set and cannot contain duplicates
* @param new_byte_Key :The key to be passed as a new replacement key.
* The key set mus be 10 characters long and cannot contain duplicates.
* @return Returns the string given string as an encrypted byte array.
*/
public static byte[] encrypt(String message, char[] new_CharSet, char[]new_Key, String[] new_byte_Key){
setCharset_setKey_setByteKey(new_CharSet,new_Key,new_byte_Key);
String cypher = addRandom(message).toString();
byte[] encryption = cypher.getBytes(format);
byte[] swapped_Bytes = revertBytes(EncryptionUtils.toByteObject(encryption));
return swapBytes(swapped_Bytes);
}
/**
* 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 orignal content
*
* @param encryption :byte array containing the encrypted string.
* @return :Returns a decypted string.
*/
public static String decrypt(byte[] encryption){
return decrypt(encryption,null,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 orignal content.
* This method allows the input of a custom key set to be used
* by this program in replacement of the originals. The key must contain all letters of the
* swedish dictionary as well as a space character represented as
* a character with a space in between and the standard comma sign.
*
* <h1>Knowing the key used by this program is not enough in order * to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted string.
* @param new_Key :The key to be passed as a new replacement key. The key set must
* be 44 characters long and cannot contain duplicates. If the key is
* not 44 characters long it will simply be ignore and not used. The key
* must contain the standard comma, period, question mark, exclamation mark
* as well as the space chararcter ' '.
* @return Returns a decypted string.
*/
public static String decrypt(byte[] encryption, char[] new_Key){
return decrypt(encryption,null,new_Key,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 orignal content.
*
* This method allows the input of a custom character set and a key set to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be
* of equal lenghts and neither the character set nor the key may have repeating elements. * Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted string.
* @param new_CharSet :The new character set to be passed as a new chararcter set. The character
* set cannot contain duplicates.
* @param new_Key :The key to be passed as a new replacement key. The key set must contain
* all the characters present in the character set and cannot contain duplicates
* @return Returns a decypted string.
*/
public static String decrypt(byte[] encryption, char[] new_CharSet, char[]new_Key){
return decrypt(encryption,new_CharSet,new_Key,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 orignal content.
*
* This method allows the input of a custom character set, key set and Byte key to be used
* by this program in replacement of the originals. The character sets passed through
* this constructor cannot contain any duplicates.
* <p>
* <h1>The character set and the key set must be
* of equal lenghts and neither the character set nor the key may have repeating elements.
* Every element found in the character set must be present in the key set and most preferably
* at a different index<h1>
* <p>
* <h1>Knowing either the chararcter set or the key used by this program doest not garantee
* the ability to decode the content of the strings encrypted by this program!</h1>
* <p>
* The byte key must contain 10 unique digits with numbers
* from 0 to 9 in any desired order.
*
* <h1>Knowing the byte key used by this program is not enough in order
* to decode the content of the strings encrypted by this program!</h1>
* <p>
* @param encryption :byte array containing the encrypted string.
* @param new_CharSet :The new character set to be passed as a new chararcter set. The character
* set cannot contain duplicates.
* @param new_Key :The key to be passed as a new replacement key. The key set must contain
* all the characters present in the character set and cannot contain duplicates
* @param new_byte_Key :The key to be passed as a new replacement key.
* The key set mus be 10 characters long and cannot contain duplicates.
* @return Returns a decypted string.
*/
public static String decrypt(byte[] encryption, char[] new_CharSet, char[]new_Key, String[] new_byte_Key){
setCharset_setKey_setByteKey(new_CharSet,new_Key,new_byte_Key);
byte[] unswapped_Bytes = revertBytesBack(EncryptionUtils.toByteObject(unSwapBytes(encryption)));
List<String> list = EncryptionUtils.fromStringToList(new String(unswapped_Bytes, format),", ");
EncryptedMessage unScrambled = removeRandom(list);
String decyphered = revertSubstitution(unScrambled);
return decyphered;
}
private static void setCharset_setKey_setByteKey(char[] new_CharSet, char[]new_Key, String[] new_byte_Key){
if(new_Key!=null && new_CharSet!=null && new_Key.length == new_CharSet.length){
key_Map.clear();
plain_Map.clear();
for(int i = 0; i<new_CharSet.length; i++){
key_Map.put(new_Key[i],new_CharSet[i]);
plain_Map.put(new_CharSet[i], new_Key[i]);
}
}
else if(new_Key!=null && new_CharSet==null && new_Key.length==plain.length){
key_Map.clear();
for(int i = 0; i<key.length; i++){
key_Map.put(new_Key[i],plain[i]);
}
}
if(new_byte_Key!=null && new_byte_Key.length==byte_Plain.length){
key_Byte_Map.clear();
for(int i = 0; i<byte_Plain.length; i++){
key_Byte_Map.put(new_byte_Key[i],byte_Plain[i]);
}
}
}
/*
* Method used to swapp 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
*/
private 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 swapp 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
* whith the correspondnt 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 peform 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 wil 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 obsfuscation 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 substraction of the oginal
* version of the encryption witout having to deal with the extrac 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_additions,code_message.charAt(index),insertion_index));
}
cypherList.addFirst("" + (EncryptionUtils.getRandomInterval(100,999)));
cypherList.add(String.valueOf(code_case) + EncryptionUtils.getRandom(10));
return cypherList;
}
/*
* Method used to remove all previously added obsfuscation 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
* othe 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.size()- 2];
char[] code_message = new char[cypher_List.size()-1];
for (int index = 0; index < cypher_List.size() - 1; index++) {
if (index >= 1)
string_Builder.append(String.valueOf(cypher_List.get(index).toCharArray()[insertion_index]));
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 (Integer.toString(temp_Bytes[i]).charAt(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 throug 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 (Integer.toString(temp_Bytes[i]).charAt(0) != '-') {
String temp_String = String.valueOf(temp_Bytes[i]);
String new_Value = key_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 swapp 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 swapp 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));
}
/**
* <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);
}
public final String getMessage(){
return code_message;
}
public final String getCase(){
return case_message;
}
public final char[] getCharMessage(){
return code_message.toCharArray();
}
public 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日
*/
private 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 prints the content of a byte array.
*/
private static String printBytes(byte[] binaryEncription){
return new String(binaryEncription, format);
}
/*
* 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
* lenght 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 radom string of the specified
* lenght.
*/
@SuppressWarnings("unused")
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);
}
}
public static void main(String[] args) {
// EncryptionUtils.getRandomString(10,'Ö',1);
long encrypt_start_time = System.currentTimeMillis();
byte[] encryption = StringEncrypter.encrypt("What is up!!, Not much why??");
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("");
System.out.println(EncryptionUtils.printBytes(encryption));
System.out.println("");
System.out.println("////////////////////////////////////////////////////////////////////////////////");
// System.out.println(Arrays.toString(encryption));
long decrypt_start_time = System.currentTimeMillis();
System.out.println(StringEncrypter.decrypt(encryption));
long decrypt_end_time = System.currentTimeMillis();
System.out.println("Decryption speed: "+(decrypt_end_time - decrypt_start_time)+ " Milliseconds");
}
}
I know the code is long but I tried to documented well and structure it to make easy to read. I sincerely appreciate all your time and I hope my question is well formulated and on topic.
import java.nio.charset.Charset;
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;
/**
* <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 final static Charset format = Charset.forName("UTF-8");
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> key_Byte_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 performace 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_additions = 5;
/*
* The index in which the actually code character will be inserted.
* the index must be a number between 0 and the max_additions 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 obsfuscation
* 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 obsfuscation
* 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 obsfuscation
* 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(format);
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 orignal 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 orignal 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 orignal 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, format),", ");
EncryptedMessage unScrambled = removeRandom(list);
String decyphered = revertSubstitution(unScrambled);
return decyphered;
}
else{
return "";
}
}
/*
* Method incharged 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();
key_Byte_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]);
key_Byte_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();
key_Byte_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]);
key_Byte_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 swapp 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
*/
private 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 swapp 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
* whith the correspondnt 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 peform 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 wil 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 obsfuscation 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 substraction of the oginal
* version of the encryption witout having to deal with the extrac 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_additions,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 obsfuscation 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
* othe 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 (Integer.toString(temp_Bytes[i]).charAt(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 throug 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 (Integer.toString(temp_Bytes[i]).charAt(0) != '-') {
String temp_String = String.valueOf(temp_Bytes[i]);
String new_Value = key_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 swapp 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 swapp 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){
// SecureRandom rand = new SecureRandom();
// rand.setSeed(password.getBytes(format));
switch(security){
case LOW:
max_additions = 1;
insertion_index = 0;
break;
case MEDIUM:
max_additions = 4;
insertion_index = 3;
break;
case HIGH:
max_additions = 6;
insertion_index = 2;
break;
case VERY_HIGH:
max_additions = 10;
insertion_index = 7;
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);
}
public final String getMessage(){
return code_message;
}
public final String getCase(){
return case_message;
}
public final char[] getCharMessage(){
return code_message.toCharArray();
}
public 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 String printBytes(byte[] binaryEncription){
if(binaryEncription!=null){
return new String(binaryEncription, format);
}
else
return "";
}
/*
* 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
* lenght 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 radom String of the specified
* lenght.
*/
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 = new SecureRandom();
private SecureRandom byteRandom = new SecureRandom();
public KeyGenerator(String password, char[] charSet, String[] byteSet) {
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(format));
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(format));
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;
}
}
public enum ShuffelMethod {
FISHER_YATES_SHUFFLE, RICHARD_DURSTENFELD_SHUFFLE,
}
public char[] getBase_key() {
return char_base_set;
}
public String[] getBase_Byte() {
return byte_base_set;
}
public char[] getNew_Key() {
return char_key_set;
}
public 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','$','/','@','*'};
long encrypt_start_time = System.currentTimeMillis();
byte[] encryption = StringEncrypter.encrypt("Your message is now secure!!", new Password("password"),new_char_set, SecurityLevel.MEDIUM);
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("");
System.out.println(EncryptionUtils.printBytes(encryption));
System.out.println("");
System.out.println("////////////////////////////////////////////////////////////////////////////////");
// System.out.println(Arrays.toString(encryption));
long decrypt_start_time = System.currentTimeMillis();
System.out.println(StringEncrypter.decrypt(encryption,new Password("password"),new_char_set,SecurityLevel.MEDIUM));
long decrypt_end_time = System.currentTimeMillis();
System.out.println("Decryption speed: "+(decrypt_end_time - decrypt_start_time)+ " Milliseconds");
}
}